This patch set introduces preliminary support for Cavium Networks'
OCTEON processor family. More (but not detailed) information about
these processors may be obtained here:
http://www.caviumnetworks.com/OCTEON_MIPS64.html
This initial patch set adds support for booting an initramfs to a
serial console. Follow-on patch sets will add support for the on-chip
ethernet, USB, PCI, PCIe, I2c and other peripherals.
With this third version of the patches I think we have fixed or
removed most of the parts flagged as objectionable in the first two
rounds of reviews. There was extensive rearrangement of some of the
chip and board support files as well as cleanup of cache, dma, and
interrupt code. Ralf already merged or made equivalent changes for
six of the patches so the set is getting smaller.
I am sending 23 - 27 to linux-serial and linux-kernel and akpm in
hopes that these non-MIPS patches might be reviewed thus enabling the
entire set to eventually be merged.
29 patches to follow as replies (I hope).
David Daney (29):
01 - MIPS: Add Cavium OCTEON processor support files to
arch/mips/cavium-octeon.
02 - MIPS: Add Cavium OCTEON files to
arch/mips/include/asm/mach-cavium-octeon
03 - MIPS: Add Cavium OCTEON processor support files to arch/mips/kernel.
04 - MIPS: Add Cavium OCTEON processor support files to arch/mips/mm.
05 - MIPS: Add Cavium OCTEON processor support files to
arch/mips/cavium-octeon/executive and asm/octeon.
06 - MIPS: For Cavium OCTEON handle hazards as per the R10000 handling.
07 - MIPS: For Cavium OCTEON set hwrena and lazily restore CP2 state.
08 - MIPS: Add Cavium OCTEON to arch/mips/Kconfig
09 - MIPS: Add Cavium OCTEON processor constants.
10 - MIPS: Add Cavium OCTEON specific register definitions to mipsregs.h
11 - MIPS: Override assembler target architecture for octeon.
12 - MIPS: Probe for Cavium OCTEON CPUs.
13 - MIPS: Hook Cavium OCTEON cache init into cache.c
14 - MIPS: Hook up Cavium OCTEON in arch/mips.
15 - MIPS: Modify core io.h macros to account for the Octeon Errata
Core-301.
16 - MIPS: Add Cavium OCTEON cop2/cvmseg state entries to processor.h.
17 - MIPS: Add Cavium OCTEON specific registers to ptrace.h and
asm-offsets.c
18 - MIPS: Add SMP_ICACHE_FLUSH for the Cavium CPU family.
19 - MIPS: Cavium OCTEON: PT vs MFC0 reorder, multiplier state
preservation.
20 - MIPS: Add Cavium OCTEON irq hazard in asmmacro.h.
21 - MIPS: Compute branch returns for Cavium OCTEON specific branch
instructions.
22 - MIPS: Add Cavium OCTEON slot into proper tlb category.
23 - 8250: Don't clobber spinlocks.
24 - 8250: Serial driver changes to support future Cavium OCTEON serial
patches.
25 - Serial: Allow port type to be specified when calling
serial8250_register_port.
26 - 8250: Allow port type to specify bugs that are not probed for.
27 - Serial: UART driver changes for Cavium OCTEON.
28 - MIPS: Adjust the dma-common.c platform hooks.
29 - MIPS: Add defconfig for Cavium OCTEON.
arch/mips/Kconfig | 65 +-
arch/mips/Makefile | 16 +
arch/mips/cavium-octeon/Kconfig | 85 +
arch/mips/cavium-octeon/Makefile | 20 +
arch/mips/cavium-octeon/dma-octeon.c | 31 +
arch/mips/cavium-octeon/executive/Makefile | 24 +
arch/mips/cavium-octeon/executive/cvmx-bootmem.c | 929 +++++++++
arch/mips/cavium-octeon/executive/cvmx-l2c.c | 736 +++++++
arch/mips/cavium-octeon/executive/cvmx-sysinfo.c | 117 ++
arch/mips/cavium-octeon/executive/octeon-model.c | 346 ++++
arch/mips/cavium-octeon/flash_setup.c | 77 +
arch/mips/cavium-octeon/octeon-irq.c | 498 +++++
arch/mips/cavium-octeon/octeon-memcpy.S | 521 +++++
arch/mips/cavium-octeon/serial.c | 187 ++
arch/mips/cavium-octeon/setup.c | 710 +++++++
arch/mips/cavium-octeon/smp.c | 225 +++
arch/mips/cavium-octeon/userio.c | 155 ++
arch/mips/configs/cavium-octeon_defconfig | 1146 +++++++++++
arch/mips/include/asm/asmmacro.h | 10 +
arch/mips/include/asm/cpu-features.h | 3 +
arch/mips/include/asm/cpu.h | 14 +
arch/mips/include/asm/hazards.h | 4 +-
arch/mips/include/asm/io.h | 14 +
.../asm/mach-cavium-octeon/cpu-feature-overrides.h | 62 +
.../include/asm/mach-cavium-octeon/dma-coherence.h | 64 +
arch/mips/include/asm/mach-cavium-octeon/irq.h | 244 +++
.../asm/mach-cavium-octeon/kernel-entry-init.h | 140 ++
arch/mips/include/asm/mach-cavium-octeon/war.h | 26 +
arch/mips/include/asm/mach-generic/dma-coherence.h | 26 +-
arch/mips/include/asm/mach-ip27/dma-coherence.h | 26 +-
arch/mips/include/asm/mach-ip32/dma-coherence.h | 26 +-
arch/mips/include/asm/mach-jazz/dma-coherence.h | 26 +-
arch/mips/include/asm/mach-lemote/dma-coherence.h | 26 +-
arch/mips/include/asm/mipsregs.h | 22 +
arch/mips/include/asm/module.h | 2 +
arch/mips/include/asm/octeon/cvmx-asm.h | 446 +++++
arch/mips/include/asm/octeon/cvmx-bootinfo.h | 238 +++
arch/mips/include/asm/octeon/cvmx-bootmem.h | 403 ++++
arch/mips/include/asm/octeon/cvmx-ciu-defs.h | 1615 ++++++++++++++++
arch/mips/include/asm/octeon/cvmx-gpio-defs.h | 218 +++
arch/mips/include/asm/octeon/cvmx-iob-defs.h | 529 +++++
arch/mips/include/asm/octeon/cvmx-ipd-defs.h | 861 +++++++++
arch/mips/include/asm/octeon/cvmx-l2c-defs.h | 958 +++++++++
arch/mips/include/asm/octeon/cvmx-l2c.h | 328 ++++
arch/mips/include/asm/octeon/cvmx-l2d-defs.h | 368 ++++
arch/mips/include/asm/octeon/cvmx-l2t-defs.h | 140 ++
arch/mips/include/asm/octeon/cvmx-led-defs.h | 239 +++
arch/mips/include/asm/octeon/cvmx-mio-defs.h | 2028 ++++++++++++++++++++
arch/mips/include/asm/octeon/cvmx-packet.h | 64 +
arch/mips/include/asm/octeon/cvmx-platform.h | 56 +
arch/mips/include/asm/octeon/cvmx-pow-defs.h | 697 +++++++
arch/mips/include/asm/octeon/cvmx-spinlock.h | 376 ++++
arch/mips/include/asm/octeon/cvmx-sysinfo.h | 144 ++
arch/mips/include/asm/octeon/cvmx-warn.h | 40 +
arch/mips/include/asm/octeon/cvmx.h | 776 ++++++++
arch/mips/include/asm/octeon/octeon-feature.h | 120 ++
arch/mips/include/asm/octeon/octeon-model.h | 225 +++
arch/mips/include/asm/octeon/octeon.h | 238 +++
arch/mips/include/asm/processor.h | 69 +
arch/mips/include/asm/ptrace.h | 4 +
arch/mips/include/asm/smp.h | 3 +
arch/mips/include/asm/stackframe.h | 46 +
arch/mips/kernel/Makefile | 1 +
arch/mips/kernel/asm-offsets.c | 31 +
arch/mips/kernel/branch.c | 33 +
arch/mips/kernel/cpu-probe.c | 25 +
arch/mips/kernel/genex.S | 4 +
arch/mips/kernel/octeon_switch.S | 506 +++++
arch/mips/kernel/traps.c | 21 +
arch/mips/lib/Makefile | 1 +
arch/mips/mm/Makefile | 1 +
arch/mips/mm/c-octeon.c | 307 +++
arch/mips/mm/cache.c | 6 +
arch/mips/mm/cex-oct.S | 70 +
arch/mips/mm/dma-default.c | 24 +-
arch/mips/mm/tlbex.c | 1 +
drivers/serial/8250.c | 233 ++-
drivers/serial/8250.h | 3 +
drivers/serial/serial_core.c | 7 +-
include/linux/serial_8250.h | 2 +
include/linux/serial_core.h | 7 +-
include/linux/serial_reg.h | 6 +
82 files changed, 19055 insertions(+), 86 deletions(-)
create mode 100644 arch/mips/cavium-octeon/Kconfig
create mode 100644 arch/mips/cavium-octeon/Makefile
create mode 100644 arch/mips/cavium-octeon/dma-octeon.c
create mode 100644 arch/mips/cavium-octeon/executive/Makefile
create mode 100644 arch/mips/cavium-octeon/executive/cvmx-bootmem.c
create mode 100644 arch/mips/cavium-octeon/executive/cvmx-l2c.c
create mode 100644 arch/mips/cavium-octeon/executive/cvmx-sysinfo.c
create mode 100644 arch/mips/cavium-octeon/executive/octeon-model.c
create mode 100644 arch/mips/cavium-octeon/flash_setup.c
create mode 100644 arch/mips/cavium-octeon/octeon-irq.c
create mode 100644 arch/mips/cavium-octeon/octeon-memcpy.S
create mode 100644 arch/mips/cavium-octeon/serial.c
create mode 100644 arch/mips/cavium-octeon/setup.c
create mode 100644 arch/mips/cavium-octeon/smp.c
create mode 100644 arch/mips/cavium-octeon/userio.c
create mode 100644 arch/mips/configs/cavium-octeon_defconfig
create mode 100644 arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
create mode 100644 arch/mips/include/asm/mach-cavium-octeon/dma-coherence.h
create mode 100644 arch/mips/include/asm/mach-cavium-octeon/irq.h
create mode 100644 arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h
create mode 100644 arch/mips/include/asm/mach-cavium-octeon/war.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-asm.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-bootinfo.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-bootmem.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-ciu-defs.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-gpio-defs.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-iob-defs.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-ipd-defs.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-l2c-defs.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-l2c.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-l2d-defs.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-l2t-defs.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-led-defs.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-mio-defs.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-packet.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-platform.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-pow-defs.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-spinlock.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-sysinfo.h
create mode 100644 arch/mips/include/asm/octeon/cvmx-warn.h
create mode 100644 arch/mips/include/asm/octeon/cvmx.h
create mode 100644 arch/mips/include/asm/octeon/octeon-feature.h
create mode 100644 arch/mips/include/asm/octeon/octeon-model.h
create mode 100644 arch/mips/include/asm/octeon/octeon.h
create mode 100644 arch/mips/kernel/octeon_switch.S
create mode 100644 arch/mips/mm/c-octeon.c
create mode 100644 arch/mips/mm/cex-oct.S
Add a bugs field to the serial8250_config and propagate it to the
port's bugs field when the port is registered and configured.
This is a follow on to the previous patch. Now that we can specify
the port type and don't have to probe for it, we can avoid probing for
bugs if they are known with certainty to exist.
The alternative is to load up 8250.c with a bunch of OCTEON specific
special cases in the probing code.
Signed-off-by: David Daney <[email protected]>
---
drivers/serial/8250.c | 2 ++
drivers/serial/8250.h | 1 +
2 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 9d16abb..474ab89 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1212,6 +1212,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
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;
+ up->bugs |= uart_config[up->port.type].bugs;
if (up->port.type == PORT_UNKNOWN)
goto out;
@@ -3062,6 +3063,7 @@ int serial8250_register_port(struct uart_port *port)
uart->port.fifosize = uart_config[port->type].fifo_size;
uart->capabilities = uart_config[port->type].flags;
uart->tx_loadsz = uart_config[port->type].tx_loadsz;
+ uart->bugs = uart_config[port->type].bugs;
}
set_io_fns_from_upio(&uart->port);
diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
index 5202603..c9b3002 100644
--- a/drivers/serial/8250.h
+++ b/drivers/serial/8250.h
@@ -34,6 +34,7 @@ struct serial8250_config {
const char *name;
unsigned short fifo_size;
unsigned short tx_loadsz;
+ unsigned short bugs;
unsigned char fcr;
unsigned int flags;
};
--
1.5.6.5
In order to use Cavium OCTEON specific serial i/o drivers, we first
patch the 8250 driver to use replaceable I/O functions. Compatible
I/O functions are added for existing iotypeS.
An added benefit of this change is that it makes it easy to factor
some of the existing special cases out to board/SOC specific support
code.
The alternative is to load up 8250.c with a bunch of OCTEON specific
iotype code and bug work-arounds.
Signed-off-by: David Daney <[email protected]>
Signed-off-by: Tomaso Paoletti <[email protected]>
---
drivers/serial/8250.c | 192 ++++++++++++++++++++++++++++++-------------
include/linux/serial_8250.h | 2 +
include/linux/serial_core.h | 2 +
3 files changed, 138 insertions(+), 58 deletions(-)
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 8e28750..410478f 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -303,16 +303,16 @@ static const u8 au_io_out_map[] = {
};
/* sane hardware needs no mapping */
-static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_in_reg(struct uart_port *p, int offset)
{
- if (up->port.iotype != UPIO_AU)
+ if (p->iotype != UPIO_AU)
return offset;
return au_io_in_map[offset];
}
-static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_out_reg(struct uart_port *p, int offset)
{
- if (up->port.iotype != UPIO_AU)
+ if (p->iotype != UPIO_AU)
return offset;
return au_io_out_map[offset];
}
@@ -341,16 +341,16 @@ static const u8
[UART_SCR] = 0x2c
};
-static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_in_reg(struct uart_port *p, int offset)
{
- if (up->port.iotype != UPIO_RM9000)
+ if (p->iotype != UPIO_RM9000)
return offset;
return regmap_in[offset];
}
-static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_out_reg(struct uart_port *p, int offset)
{
- if (up->port.iotype != UPIO_RM9000)
+ if (p->iotype != UPIO_RM9000)
return offset;
return regmap_out[offset];
}
@@ -363,108 +363,170 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
#endif
-static unsigned int serial_in(struct uart_8250_port *up, int offset)
+static unsigned int hub6_serial_in_fn(struct uart_port *p, int offset)
{
- unsigned int tmp;
- offset = map_8250_in_reg(up, offset) << up->port.regshift;
+ offset = map_8250_in_reg(p, offset) << p->regshift;
+ outb(p->hub6 - 1 + offset, p->iobase);
+ return inb(p->iobase + 1);
+}
- switch (up->port.iotype) {
- case UPIO_HUB6:
- outb(up->port.hub6 - 1 + offset, up->port.iobase);
- return inb(up->port.iobase + 1);
+static void hub6_serial_out_fn(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);
+}
- case UPIO_MEM:
- case UPIO_DWAPB:
- return readb(up->port.membase + offset);
+static unsigned int mem_serial_in_fn(struct uart_port *p, int offset)
+{
+ offset = map_8250_in_reg(p, offset) << p->regshift;
+ return readb(p->membase + offset);
+}
- case UPIO_RM9000:
- case UPIO_MEM32:
- return readl(up->port.membase + offset);
+static void mem_serial_out_fn(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_fn(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_fn(struct uart_port *p, int offset)
+{
+ offset = map_8250_in_reg(p, offset) << p->regshift;
+ return readl(p->membase + offset);
+}
#ifdef CONFIG_SERIAL_8250_AU1X00
- case UPIO_AU:
- return __raw_readl(up->port.membase + offset);
+static unsigned int au_serial_in_fn(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_fn(struct uart_port *p, int offset, int value)
+{
+ offset = map_8250_out_reg(p, offset) << p->regshift;
+ __raw_writel(value, p->membase + offset);
+}
#endif
- case UPIO_TSI:
- if (offset == UART_IIR) {
- tmp = readl(up->port.membase + (UART_IIR & ~3));
- return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
- } else
- return readb(up->port.membase + offset);
+static unsigned int tsi_serial_in_fn(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);
+}
- default:
- return inb(up->port.iobase + offset);
- }
+static void tsi_serial_out_fn(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);
}
-static void
-serial_out(struct uart_8250_port *up, int offset, int value)
+static void dwapb_serial_out_fn(struct uart_port *p, int offset, int value)
{
- /* Save the offset before it's remapped */
int save_offset = offset;
- offset = map_8250_out_reg(up, offset) << up->port.regshift;
+ offset = map_8250_out_reg(p, offset) << p->regshift;
+ /* Save the LCR value so it can be re-written when a
+ * Busy Detect interrupt occurs. */
+ if (save_offset == UART_LCR) {
+ struct uart_8250_port *up = (struct uart_8250_port *)p;
+ up->lcr = value;
+ }
+ writeb(value, p->membase + offset);
+ /* Read the IER to ensure any interrupt is cleared before
+ * returning from ISR. */
+ if (save_offset == UART_TX || save_offset == UART_IER)
+ value = p->serial_in_fn(p, UART_IER);
+}
- switch (up->port.iotype) {
+static unsigned int io_serial_in_fn(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_fn(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_fns_from_upio(struct uart_port *p)
+{
+ switch (p->iotype) {
case UPIO_HUB6:
- outb(up->port.hub6 - 1 + offset, up->port.iobase);
- outb(value, up->port.iobase + 1);
+ p->serial_in_fn = hub6_serial_in_fn;
+ p->serial_out_fn = hub6_serial_out_fn;
break;
case UPIO_MEM:
- writeb(value, up->port.membase + offset);
+ p->serial_in_fn = mem_serial_in_fn;
+ p->serial_out_fn = mem_serial_out_fn;
break;
case UPIO_RM9000:
case UPIO_MEM32:
- writel(value, up->port.membase + offset);
+ p->serial_in_fn = mem32_serial_in_fn;
+ p->serial_out_fn = mem32_serial_out_fn;
break;
#ifdef CONFIG_SERIAL_8250_AU1X00
case UPIO_AU:
- __raw_writel(value, up->port.membase + offset);
+ p->serial_in_fn = au_serial_in_fn;
+ p->serial_out_fn = au_serial_out_fn;
break;
#endif
case UPIO_TSI:
- if (!((offset == UART_IER) && (value & UART_IER_UUE)))
- writeb(value, up->port.membase + offset);
+ p->serial_in_fn = tsi_serial_in_fn;
+ p->serial_out_fn = tsi_serial_out_fn;
break;
case UPIO_DWAPB:
- /* Save the LCR value so it can be re-written when a
- * Busy Detect interrupt occurs. */
- if (save_offset == UART_LCR)
- up->lcr = value;
- writeb(value, up->port.membase + offset);
- /* Read the IER to ensure any interrupt is cleared before
- * returning from ISR. */
- if (save_offset == UART_TX || save_offset == UART_IER)
- value = serial_in(up, UART_IER);
+ p->serial_in_fn = mem_serial_in_fn;
+ p->serial_out_fn = dwapb_serial_out_fn;
break;
default:
- outb(value, up->port.iobase + offset);
+ p->serial_in_fn = io_serial_in_fn;
+ p->serial_out_fn = io_serial_out_fn;
+ break;
}
}
static void
serial_out_sync(struct uart_8250_port *up, int offset, int value)
{
- switch (up->port.iotype) {
+ struct uart_port *p = &up->port;
+ switch (p->iotype) {
case UPIO_MEM:
case UPIO_MEM32:
#ifdef CONFIG_SERIAL_8250_AU1X00
case UPIO_AU:
#endif
case UPIO_DWAPB:
- serial_out(up, offset, value);
- serial_in(up, UART_LCR); /* safe, no side-effects */
+ p->serial_out_fn(p, offset, value);
+ p->serial_in_fn(p, UART_LCR); /* safe, no side-effects */
break;
default:
- serial_out(up, offset, value);
+ p->serial_out_fn(p, offset, value);
}
}
+#define serial_in(up, offset) \
+ (up->port.serial_in_fn(&(up)->port, (offset)))
+#define serial_out(up, offset, value) \
+ (up->port.serial_out_fn(&(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
@@ -2576,6 +2638,7 @@ static void __init serial8250_isa_init_ports(void)
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_fns_from_upio(&up->port);
if (share_irqs)
up->port.flags |= UPF_SHARE_IRQ;
}
@@ -2769,6 +2832,13 @@ int __init early_serial_setup(struct uart_port *port)
p->flags = port->flags;
p->mapbase = port->mapbase;
p->private_data = port->private_data;
+
+ set_io_fns_from_upio(p);
+ if (port->serial_in_fn)
+ p->serial_in_fn = port->serial_in_fn;
+ if (port->serial_out_fn)
+ p->serial_out_fn = port->serial_out_fn;
+
return 0;
}
@@ -2986,6 +3056,12 @@ int serial8250_register_port(struct uart_port *port)
uart->port.private_data = port->private_data;
if (port->dev)
uart->port.dev = port->dev;
+ set_io_fns_from_upio(&uart->port);
+ /* Possibly override default I/O functions. */
+ if (port->serial_in_fn)
+ uart->port.serial_in_fn = port->serial_in_fn;
+ if (port->serial_out_fn)
+ uart->port.serial_out_fn = port->serial_out_fn;
ret = uart_add_one_port(&serial8250_reg, &uart->port);
if (ret == 0)
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 3d37c94..eb08b04 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -28,6 +28,8 @@ struct plat_serial8250_port {
unsigned char iotype; /* UPIO_* */
unsigned char hub6;
upf_t flags; /* UPF_* flags */
+ unsigned int (*serial_in_fn)(struct uart_port *, int);
+ void (*serial_out_fn)(struct uart_port *, int, int);
};
/*
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index e27f216..40509b0 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -243,6 +243,8 @@ struct uart_port {
spinlock_t lock; /* port lock */
unsigned long iobase; /* in/out[bwl] */
unsigned char __iomem *membase; /* read/write[bwl] */
+ unsigned int (*serial_in_fn)(struct uart_port *, int);
+ void (*serial_out_fn)(struct uart_port *, int, int);
unsigned int irq; /* irq number */
unsigned int uartclk; /* base uart clock */
unsigned int fifosize; /* tx fifo size */
--
1.5.6.5
In serial8250_isa_init_ports(), the port's lock is initialized. We
should not overwrite it. In early_serial_setup(), only copy in the
fields we need. Since the early console code only uses a subset of
the fields, these are sufficient.
Signed-off-by: David Daney <[email protected]>
Signed-off-by: Tomaso Paoletti <[email protected]>
---
drivers/serial/8250.c | 15 +++++++++++++--
1 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 303272a..8e28750 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2752,12 +2752,23 @@ static struct uart_driver serial8250_reg = {
*/
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();
- serial8250_ports[port->line].port = *port;
- serial8250_ports[port->line].port.ops = &serial8250_pops;
+ p = &serial8250_ports[port->line].port;
+ p->iobase = port->iobase;
+ p->membase = port->membase;
+ p->irq = port->irq;
+ 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;
return 0;
}
--
1.5.6.5
Add flag value UPF_FIXED_TYPE which specifies that the UART type is
known and should not be probed. For this case the UARTs properties
are just copied out of the uart_config entry.
This allows us to keep SOC specific 8250 probe code out of 8250.c. In
this case we know the serial hardware will not be changing as it is on
the same silicon as the CPU, and we can specify it with certainty in
the board/cpu setup code.
The alternative is to load up 8250.c with a bunch of OCTEON specific
special cases in the probing code.
Signed-off-by: David Daney <[email protected]>
---
drivers/serial/8250.c | 8 ++++++++
drivers/serial/serial_core.c | 7 +++++--
include/linux/serial_core.h | 2 ++
3 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 410478f..9d16abb 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -3056,6 +3056,14 @@ int serial8250_register_port(struct uart_port *port)
uart->port.private_data = port->private_data;
if (port->dev)
uart->port.dev = port->dev;
+
+ if (port->flags & UPF_FIXED_TYPE) {
+ uart->port.type = port->type;
+ uart->port.fifosize = uart_config[port->type].fifo_size;
+ uart->capabilities = uart_config[port->type].flags;
+ uart->tx_loadsz = uart_config[port->type].tx_loadsz;
+ }
+
set_io_fns_from_upio(&uart->port);
/* Possibly override default I/O functions. */
if (port->serial_in_fn)
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 874786a..7fef45e 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -2198,11 +2198,14 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
* Now do the auto configuration stuff. Note that config_port
* is expected to claim the resources and map the port for us.
*/
- flags = UART_CONFIG_TYPE;
+ flags = 0;
if (port->flags & UPF_AUTO_IRQ)
flags |= UART_CONFIG_IRQ;
if (port->flags & UPF_BOOT_AUTOCONF) {
- port->type = PORT_UNKNOWN;
+ if (!(port->flags & UPF_FIXED_TYPE)) {
+ port->type = PORT_UNKNOWN;
+ flags |= UART_CONFIG_TYPE;
+ }
port->ops->config_port(port, flags);
}
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 40509b0..54e0dce 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -290,6 +290,8 @@ struct uart_port {
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16))
#define UPF_CONS_FLOW ((__force upf_t) (1 << 23))
#define UPF_SHARE_IRQ ((__force upf_t) (1 << 24))
+/* The exact UART type is known and should not be probed. */
+#define UPF_FIXED_TYPE ((__force upf_t) (1 << 27))
#define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28))
#define UPF_FIXED_PORT ((__force upf_t) (1 << 29))
#define UPF_DEAD ((__force upf_t) (1 << 30))
--
1.5.6.5
Cavium UART implementation won't work with the standard 8250 driver
as-is. Define a new uart_config (PORT_OCTEON) and use it to enable
special handling required by the OCTEON's serial port. Two new bug
types are defined.
Signed-off-by: Tomaso Paoletti <[email protected]>
Signed-off-by: David Daney <[email protected]>
---
drivers/serial/8250.c | 16 +++++++++++++++-
drivers/serial/8250.h | 2 ++
include/linux/serial_core.h | 3 ++-
include/linux/serial_reg.h | 6 ++++++
4 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 474ab89..f274e94 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -279,6 +279,14 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO,
},
+ [PORT_OCTEON] = {
+ .name = "OCTEON",
+ .fifo_size = 64,
+ .tx_loadsz = 64,
+ .bugs = UART_BUG_TIMEOUT | UART_BUG_OCTEON_IIR,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+ .flags = UART_CAP_FIFO,
+ },
};
#if defined (CONFIG_SERIAL_8250_AU1X00)
@@ -1554,6 +1562,12 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
up = list_entry(l, struct uart_8250_port, list);
iir = serial_in(up, UART_IIR);
+ if ((up->bugs & UART_BUG_OCTEON_IIR) && (iir & 0xf) == 7) {
+ /* Busy interrupt */
+ serial_in(up, UART_OCTEON_USR);
+ iir = serial_in(up, UART_IIR);
+ }
+
if (!(iir & UART_IIR_NO_INT)) {
serial8250_handle_port(up);
@@ -1714,7 +1728,7 @@ static void serial8250_timeout(unsigned long data)
unsigned int iir;
iir = serial_in(up, UART_IIR);
- if (!(iir & UART_IIR_NO_INT))
+ if (!(iir & UART_IIR_NO_INT) || (up->bugs & UART_BUG_TIMEOUT))
serial8250_handle_port(up);
mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout));
}
diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
index c9b3002..56b3cb7 100644
--- a/drivers/serial/8250.h
+++ b/drivers/serial/8250.h
@@ -49,6 +49,8 @@ struct serial8250_config {
#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
#define UART_BUG_NOMSR (1 << 2) /* UART has buggy MSR status bits (Au1x00) */
#define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */
+#define UART_BUG_TIMEOUT (1 << 4) /* UART should always handle timeout */
+#define UART_BUG_OCTEON_IIR (1 << 5) /* UART OCTEON IIR workaround */
#define PROBE_RSA (1 << 0)
#define PROBE_ANY (~0)
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 54e0dce..c6c7faa 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -40,7 +40,8 @@
#define PORT_NS16550A 14
#define PORT_XSCALE 15
#define PORT_RM9000 16 /* PMC-Sierra RM9xxx internal UART */
-#define PORT_MAX_8250 16 /* max port ID */
+#define PORT_OCTEON 17 /* Cavium OCTEON internal UART */
+#define PORT_MAX_8250 17 /* max port ID */
/*
* ARM specific type numbers. These are not currently guaranteed
diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
index 96c0d93..a96bd50 100644
--- a/include/linux/serial_reg.h
+++ b/include/linux/serial_reg.h
@@ -324,5 +324,11 @@
#define UART_OMAP_SYSC 0x15 /* System configuration register */
#define UART_OMAP_SYSS 0x16 /* System status register */
+/*
+ * Extra serial register definitions for the internal UARTs in Cavium
+ * Networks OCTEON processors.
+ */
+#define UART_OCTEON_USR 0x27 /* UART Status Register */
+
#endif /* _LINUX_SERIAL_REG_H */
--
1.5.6.5