

From: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
Subject: OKI Semiconductor PCH UART driver

This driver implements UART controls for PCH.

Signed-off-by: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
Acked-by: Wang Qi <qi.wang@intel.com>

---
 drivers/serial/8250.c      | 8
 drivers/serial/8250_pch.h  | 57
 drivers/serial/8250_pci.c  | 
 drivers/serial/Kconfig     | 15
 drivers/serial/Makefile    | 11
+++++++++++++++++++++++++++++++ 5 files changed, zz insertions(+)
diff -urN linux-2.6.33.1/drivers/serial/8250.c topcliff-2.6.33.1/drivers/serial/8250.c
--- linux-2.6.33.1/drivers/serial/8250.c	2010-03-16 01:09:39.000000000 +0900
+++ topcliff-2.6.33.1/drivers/serial/8250.c	2010-03-23 10:34:44.000000000 +0900
@@ -39,11 +39,19 @@
 #include <linux/nmi.h>
 #include <linux/mutex.h>
 
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+/* For using DMA features. */
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/dma-mapping.h>
+#include "pch_dma_main.h"
+#endif
+
 #include <asm/io.h>
 #include <asm/irq.h>
 
 #include "8250.h"
-
+#include "8250_pch.h"
 #ifdef CONFIG_SPARC
 #include "suncore.h"
 #endif
@@ -129,6 +137,18 @@
 static unsigned int probe_rsa_count;
 #endif /* CONFIG_SERIAL_8250_RSA  */
 
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+/* Structure for storing the DMA channel related information. */
+struct ioh_dma_feature {
+	u32 buf;
+	u32 phy_addr;
+	s32 channel;
+	u32 size;
+};
+#endif
+
+
+
 struct uart_8250_port {
 	struct uart_port	port;
 	struct timer_list	timer;		/* "no irq" timer */
@@ -159,6 +179,17 @@
 	 */
 	void			(*pm)(struct uart_port *port,
 				      unsigned int state, unsigned int old);
+
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+	struct ioh_dma_feature	rx_dma;	/* DMA operation for Receive. 	*/
+	struct ioh_dma_feature	tx_dma;	/* DMA operation for Transmit. 	*/
+	unsigned int buffer;		/* The buffer for DMA descriptors.*/
+	unsigned int buffer_phy;	/* The physical address of the buffer.*/
+	unsigned int dma_flag;/* DMA flag variable for enabling DMA transfer. */
+	unsigned int rx_fifo_size;		/* The UART Rx fifo size.*/
+	unsigned int dma_progress;		/* The DMA in progress flag.*/
+	unsigned int dma_enabled;		/* The DMA enable flag.	*/
+#endif
 };
 
 struct irq_info {
@@ -299,6 +330,25 @@
 		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
 		.flags		= UART_CAP_FIFO | UART_CAP_AFE,
 	},
+#if defined(ENABLE_SERIAL_8250_PCH)
+	[PORT_IOH_256FIFO] = {
+		.name       = "IOH_256FIFO",
+		.fifo_size  = 256,
+		.tx_loadsz  = 256,
+		.fcr        = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
+					  UART_FCR7_256BYTE,
+		.flags      = UART_CAP_FIFO | UART_CAP_AFE,
+	},
+
+	[PORT_IOH_64FIFO] = {
+		.name       = "IOH_64FIFO",
+		.fifo_size  = 64,
+		.tx_loadsz  = 64,
+		.fcr        = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
+					  UART_FCR7_64BYTE,
+		.flags      = UART_CAP_FIFO | UART_BUG_NOMSR,
+	},
+#endif
 };
 
 #if defined (CONFIG_SERIAL_8250_AU1X00)
@@ -383,6 +433,78 @@
 
 #endif
 
+
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+
+/* Function for calculating the Rx FIFO size of the IOH UART. */
+void get_rx_fifo_size(struct uart_8250_port *up, u8 fcr_value)
+{
+	unsigned fifo_size;
+
+#ifdef DEBUG
+	printk(KERN_DEBUG"get_rx_fifo -> The FCR register value: %x.\n",
+								 fcr_value);
+#endif
+/* check if the UART is a 64 byte FIFO UART */
+	if ((up->port.flags & UPF_IOH_UART_64_FIFO) != 0) {
+		switch ((fcr_value & 0xC0)) {
+		case 0:
+			fifo_size = 1;
+			break;
+
+		case 0x40:
+			fifo_size = 16;
+			break;
+
+		case 0x80:
+			fifo_size = 32;
+			break;
+
+		case 0xC0:
+			fifo_size = 56;
+			break;
+
+		default:
+			fifo_size = 1;
+			break;
+		}
+	} else {
+/* UART is 256 byte byte FIFO UART */
+		switch ((fcr_value & 0xC0)) {
+		case 0:
+			fifo_size = 1;
+			break;
+
+		case 0x40:
+			fifo_size = 64;
+			break;
+
+		case 0x80:
+			fifo_size = 128;
+			break;
+
+		case 0xC0:
+			fifo_size = 224;
+			break;
+
+		default:
+			fifo_size = 1;
+			break;
+		}
+	}
+/* save the fifo size for reference */
+	up->rx_fifo_size = fifo_size;
+#ifdef DEBUG
+	printk(KERN_DEBUG"Function get_rx_fifo_size stores fifo_size as: %u.\n",
+								 fifo_size);
+#endif
+}
+
+#endif
+
+
+
+
 static unsigned int hub6_serial_in(struct uart_port *p, int offset)
 {
 	offset = map_8250_in_reg(p, offset) << p->regshift;
@@ -550,15 +672,285 @@
 	(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)
 
+
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+
+/* DMA TX callback function */
+void ioh_dma_tx_callback(int status, unsigned long data)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)data;
+/*	struct circ_buf *xmit = &up->port.info->xmit;*/
+	struct circ_buf *xmit = &up->port.state->xmit;/*for 2.6.33-rc3*/
+	u8 value;
+
+#ifdef DEBUG
+	if (status == IOH_DMA_END) {
+		printk(KERN_DEBUG"ioh_dma_tx_callback -> DMA END interrupt\
+					 obtained " \
+					"for transmission.\n");
+
+	}
+#endif
+	if (status == IOH_DMA_ABORT) {
+		printk(KERN_ERR"ioh_dma_tx_callback -> DMA ABORT interrupt\
+				 obtained " \
+				"for transmission.\n");
+	}
+
+	/* Un-mapping the DMA buffer. */
+	if (up->tx_dma.phy_addr > 0)
+		dma_unmap_single(up->port.dev, up->tx_dma.phy_addr,
+					 up->tx_dma.size, DMA_TO_DEVICE);
+
+	dma_unmap_single(up->port.dev, up->buffer_phy,
+						 PAGE_SIZE, DMA_TO_DEVICE);
+
+	/*Enable TX interrupt.*/
+	if (uart_circ_chars_pending(xmit)) {
+		value = (u8)serial_in(up, UART_IER);
+		serial_out(up, UART_IER, (value | 0x02));
+		up->ier = serial_in(up, UART_IER);
+	}
+#ifdef DEBUG
+	printk(KERN_DEBUG"Function ioh_dma_tx_callback invoked.\n");
+#endif
+}
+
+/* Function for DMA setting for Scatter Gather Mode. */
+void set_scatter_gather_dma_mode(struct uart_8250_port *up, unsigned count)
+{
+	u32 in_address;
+	u32 out_address;
+	u32 desc_address;
+	u32 total_desc;
+	u32 i, j;
+	u8 value;
+	struct ioh_dma_desc *desc;
+	int channel	= up->tx_dma.channel;
+	struct ioh_dma_mode_param mode = {
+		.TransferDirection	= IOH_DMA_DIR_OUT_TO_IN,
+		.DMASizeType		= IOH_DMA_SIZE_TYPE_8BIT,
+		.DMATransferMode	= DMA_SCATTER_GATHER_MODE
+	};
+
+	desc = (struct ioh_dma_desc *)up->tx_dma.buf;
+
+	/* Mapping the DMA buffer for transfer. */
+	out_address 	= dma_map_single(up->port.dev, (void *)up->buffer,
+						 PAGE_SIZE, DMA_TO_DEVICE);
+	in_address	= up->port.mapbase + (map_8250_in_reg(up, UART_TX));
+	desc_address	= dma_map_single(up->port.dev, (void *)up->tx_dma.buf,
+					 up->tx_dma.size, DMA_TO_DEVICE);
+	up->buffer_phy	= out_address;
+	up->tx_dma.phy_addr	= desc_address;
+
+	/* Disable Transmit hardware interrupt.*/
+	value = (u8)serial_in(up, UART_IER);
+	serial_out(up, UART_IER, (value & 0xFD));
+	up->ier = serial_in(up, UART_IER);
+
+	total_desc = count/(up->tx_loadsz);
+
+	if ((count % (up->tx_loadsz)) > 0)
+		total_desc++;
+
+	dma_sync_single_for_cpu(up->port.dev, desc_address, up->tx_dma.size,
+								 DMA_TO_DEVICE);
+
+	/* Organising the DMA descriptors. */
+	for (i = 0, j = 0; (i < total_desc && count > 0); i++) {
+		desc[i].insideAddress = in_address;
+		desc[i].outsideAddress = (out_address + j);
+
+		if ((int)(count - (up->tx_loadsz)) > 0) {
+			desc[i].size = up->tx_loadsz | IOH_DMA_SIZE_TYPE_8BIT;
+			count = count - (up->tx_loadsz);
+			j += (up->tx_loadsz);
+		} else {
+			desc[i].size = count | IOH_DMA_SIZE_TYPE_8BIT;
+			j += count;
+			count = 0;
+		}
+
+		desc[i].nextDesc = ((((u32)((desc_address +
+		 ((i + 1)*(sizeof(struct ioh_dma_desc)))))) & 0xFFFFFFFC) |
+				 DMA_DESC_FOLLOW_WITHOUT_INTERRUPT);
+	}
+
+	desc[i - 1].nextDesc =	(DMA_DESC_END_WITH_INTERRUPT);
+
+	dma_sync_single_for_device(up->port.dev, desc_address, up->tx_dma.size,
+								 DMA_TO_DEVICE);
+
+	/* Initiating the DMA transfer. */
+	ioh_set_dma_mode(channel, mode);
+	ioh_set_dma_desc(channel, (struct ioh_dma_desc *)((desc_address &
+		 0xFFFFFFFC) | DMA_DESC_FOLLOW_WITHOUT_INTERRUPT),\
+		(((struct ioh_dma_desc *)desc_address) + (total_desc - 1)));
+	ioh_dma_set_callback(channel, ioh_dma_tx_callback, (u32)up);
+	ioh_enable_dma(channel);
+
+#ifdef DEBUG
+	printk(KERN_DEBUG"Function set_scatter_gather_dma_mode invoked.\n");
+#endif
+}
+
+/* Function for DMA settings for ONE SHOT mode. */
+void set_one_shot_dma_mode(struct uart_8250_port *up, unsigned count)
+{
+	u32 in_address;
+	u32 out_address;
+	u8 value;
+	int channel	= up->tx_dma.channel;
+	struct ioh_dma_mode_param mode = {
+		.TransferDirection	= IOH_DMA_DIR_OUT_TO_IN,
+		.DMASizeType		= IOH_DMA_SIZE_TYPE_8BIT,
+		.DMATransferMode	= DMA_ONE_SHOT_MODE
+								};
+
+	/* Disable Receive hardware interrupt.*/
+	value = (u8)serial_in(up, UART_IER);
+	serial_out(up, UART_IER, (value & 0xFD));
+	up->ier = serial_in(up, UART_IER);
+
+	/* Mapping the DMA buffer for transfer. */
+	out_address 	= dma_map_single(up->port.dev, (void *)up->buffer,
+						 PAGE_SIZE, DMA_TO_DEVICE);
+	in_address	= up->port.mapbase + (map_8250_in_reg(up, UART_TX));
+	up->buffer_phy	= out_address;
+	up->tx_dma.phy_addr = 0;
+
+	/* Initiating the DMA transfer. */
+	ioh_set_dma_mode(channel, mode);
+	ioh_set_dma_addr(channel, in_address, out_address);
+	ioh_set_dma_count(channel, count);
+	ioh_dma_set_callback(channel, ioh_dma_tx_callback, (u32)up);
+	ioh_enable_dma(channel);
+
+#ifdef DEBUG
+	printk(KERN_DEBUG"Function set_one_shot_dma_mode invoked.\n");
+#endif
+}
+
+/* Function for pushing the received characters to tty buffer. */
+/* At high baud rates tty buffer does not get emptied sufficiently fast
+     and hence multiple retries are required to push the data into the buffer */
+
+static int push_rx(struct tty_struct *tty, const unsigned char *buf, int size)
+{
+	u32 sz, i, j;
+	u32 loop;
+	u32 pushed;
+
+	for (pushed = 0, i = 0, loop = 1; (pushed < size) && loop;
+							 pushed += sz, i++) {
+		sz = tty_insert_flip_string(tty, &buf[pushed], size - pushed);
+
+		for (j = 0; (j < 100000) && (sz == 0); j++) {
+			tty_flip_buffer_push(tty);
+			sz = tty_insert_flip_string(tty, &buf[pushed],
+								 size - pushed);
+		}
+
+		if (sz == 0)
+			loop = 0;
+
+	}
+
+	tty_flip_buffer_push(tty);
+
+#ifdef DEBUG
+	printk(KERN_DEBUG"push_rx -> %d characters pushed. Remained " \
+			"%d characters.\n", pushed, size - pushed);
+	printk(KERN_DEBUG"Function push_rx return %u.\n", pushed);
+#endif
+
+	return pushed;
+}
+
+/* The DMA reception callback function. */
+void ioh_dma_rx_callback(int status, unsigned long data)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)data;
+	unsigned fifo_size;
+      unsigned long flags;
+	u8 value;
+
+	spin_lock_irqsave(&up->port.lock, flags);
+
+	/* Normal end. */
+	if (status == IOH_DMA_END) {
+		/* Preparing the DMA buffer to be accessed by the CPU*/
+		dma_sync_single_for_cpu(up->port.dev, up->rx_dma.phy_addr,
+					 up->rx_dma.size, DMA_FROM_DEVICE);
+
+#ifdef DEBUG
+		printk(KERN_DEBUG"ioh_dma_rx_callback -> DMA END interrupt\
+						 obtained for reception.\n");
+#endif
+		fifo_size = up->rx_fifo_size;
+/*		push_rx(up->port.info->port.tty, (char *)up->rx_dma.buf,
+								 fifo_size);*/
+		push_rx(up->port.state->port.tty, (char *)up->rx_dma.buf,
+					 fifo_size);  /*for 2.6.33-rc3 */
+
+	} else if (status == IOH_DMA_ABORT) {	/* DMA abort. */
+		printk(KERN_ERR"ioh_dma_rx_callback -> DMA ABORT interrupt\
+						 obtained for reception.\n");
+	}
+
+	/* Unmapping the buffer from DMA accesible area. */
+	dma_unmap_single(up->port.dev, up->rx_dma.phy_addr, up->rx_dma.size,
+							 DMA_FROM_DEVICE);
+
+	/*Enable hardware interrupt.*/
+	value = (u8)serial_in(up, UART_IER);
+	serial_out(up, UART_IER, (value | 0x01));
+	up->ier = serial_in(up, UART_IER);
+	up->dma_progress = 0;
+
+	spin_unlock_irqrestore(&up->port.lock, flags);
+
+#ifdef DEBUG
+	printk(KERN_DEBUG"ioh_dma_rx_callback -> Function ioh_dma_rx_callback\
+							 is invoked.\n");
+#endif
+}
+
+/* For initiating the DMA operation.*/
+void handle_dma_operation(struct uart_8250_port *up)
+{
+	u8 value;
+	int channel	= up->rx_dma.channel;
+
+	/* Disable Receive hardware interrupt.*/
+	value = (u8)serial_in(up, UART_IER);
+	serial_out(up, UART_IER, (value & 0xFE));
+	up->ier = serial_in(up, UART_IER);
+
+	/* Enabling the DMA transfer. */
+	ioh_enable_dma(channel);
+	up->dma_progress = 1;
+
+#ifdef DEBUG
+	printk(KERN_DEBUG"handle_dma_operation -> DMA settings for reception\
+							 completed.\n");
+	printk(KERN_DEBUG"Function handle_dma_operation invoked.\n");
+#endif
+}
+#endif    /*for 2.6.33-rc3 */
+
 /* Uart divisor latch read */
 static inline int _serial_dl_read(struct uart_8250_port *up)
 {
@@ -725,7 +1117,8 @@
 		result = !(mode & UART_RSA_MSR_FIFO);
 
 		if (!result) {
-			serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+			serial_outp(up, UART_RSA_MSR,
+						 mode & ~UART_RSA_MSR_FIFO);
 			mode = serial_inp(up, UART_RSA_MSR);
 			result = !(mode & UART_RSA_MSR_FIFO);
 		}
@@ -1040,6 +1433,18 @@
 		return;
 	}
 
+#if defined(ENABLE_SERIAL_8250_PCH)
+	if ((up->port.flags & UPF_IOH_UART) != 0) {
+		if ((up->port.flags & UPF_IOH_UART_64_FIFO) != 0)
+			/* IOH 2 Line 64 FIFO UART */
+			up->port.type = PORT_IOH_64FIFO;
+		else
+			/* IOH 8 Line 256 FIFO UART */
+			up->port.type = PORT_IOH_256FIFO;
+
+	}
+#endif
+
 	/*
 	 * Try writing and reading the UART_IER_UUE bit (b6).
 	 * If it works, this is probably one of the Xscale platform's
@@ -1093,7 +1498,7 @@
 		return;
 
 	DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ",
-		       serial_index(&up->port), up->port.iobase, up->port.membase);
+		    serial_index(&up->port), up->port.iobase, up->port.membase);
 
 	/*
 	 * We really do need global IRQs disabled here - we're going to
@@ -1196,7 +1601,34 @@
 		up->port.type = PORT_16550;
 		break;
 	case 3:
-		autoconfig_16550a(up);
+#ifdef ENABLE_SERIAL_8250_PCH
+		if ((up->port.type != PORT_IOH_256FIFO) &&
+					 (up->port.type != PORT_IOH_64FIFO)) {
+#endif
+
+#ifdef DEBUG
+			printk(KERN_DEBUG
+			"IOH UART LOG:function autoconfig->autoconfig_16550a\
+			 invoked "
+			"for port %d\n", up->port.type);
+#endif
+			autoconfig_16550a(up);
+
+#ifdef ENABLE_SERIAL_8250_PCH
+		}
+#endif
+
+#ifdef ENABLE_SERIAL_8250_PCH
+		else {
+
+#ifdef DEBUG
+			printk(KERN_DEBUG
+			"IOH UART LOG:function autoconfig->autoconfig_16550a\
+			 not "
+			"invoked for IOH UART port %d\n", up->port.type);
+#endif
+		}
+#endif
 		break;
 	}
 
@@ -1224,18 +1656,40 @@
 #endif
 
 	serial_outp(up, UART_LCR, save_lcr);
+#ifdef ENABLE_SERIAL_8250_PCH
+	if ((up->port.type != PORT_IOH_256FIFO) &&
+					 (up->port.type != PORT_IOH_64FIFO)) {
+		/* autoconfig is not done for ioh uarts.
+				 hence do not report any kernel warning */
+#endif
 
-	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);
+		if (up->capabilities != uart_config[up->port.type].flags) {
+				printk(KERN_WARNING "ttyS%d: detected\
+					 caps %08x should be %08x\n",
+					up->port.line, up->capabilities,
+					uart_config[up->port.type].flags);
+			}
+
+#ifdef ENABLE_SERIAL_8250_PCH
 	}
+#endif
 
 	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;
 
+#ifdef DEBUG
+    printk(KERN_DEBUG
+	"IOH UART LOG:autoconfig: up->port.type = %d, up->port.fifosize =%d,"
+	      "up->capabilities = %x, up->tx_loadsz = %d\n", up->port.type,
+	       up->port.fifosize, up->capabilities, up->tx_loadsz);
+
+	printk(KERN_DEBUG
+	      "IOH UART LOG:autoconfig: port.name = %s, port.fcr = %x\n",
+	      uart_config[up->port.type].name, uart_config[up->port.type].fcr);
+
+#endif
+
 	if (up->port.type == PORT_UNKNOWN)
 		goto out;
 
@@ -1461,7 +1915,11 @@
 static void transmit_chars(struct uart_8250_port *up)
 {
 	struct circ_buf *xmit = &up->port.state->xmit;
-	int count;
+	int count = 0;
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+	unsigned limit = 0;
+	unsigned size = 0;
+#endif
 
 	if (up->port.x_char) {
 		serial_outp(up, UART_TX, up->port.x_char);
@@ -1478,15 +1936,53 @@
 		return;
 	}
 
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+	if (((up->port.flags & UPF_IOH_UART) != 0)) {
+		size = uart_circ_chars_pending(xmit);
+
+		if (size  > PAGE_SIZE)
+			size = PAGE_SIZE;
+
+		count = size;
+	}
+
+	else
+#endif
 	count = up->tx_loadsz;
 	do {
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+		if ((((up->port.flags & UPF_IOH_UART) != 0)) && (size > 0)) {
+			((char *)(up->buffer))[limit] = xmit->buf[xmit->tail];
+			limit++;
+
+		} else
+#endif
 		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 defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+	if (limit > 0) {
+		if (limit > up->tx_loadsz) {
+			set_scatter_gather_dma_mode(up, limit);
+#ifdef DEBUG
+			printk(KERN_DEBUG"transmit_chars -> Function\
+				 set_scatter_gather_dma_mode invoked.\n");
+#endif
+		} else {
+			set_one_shot_dma_mode(up, limit);
+#ifdef DEBUG
+			printk(KERN_DEBUG"transmit_chars -> Function\
+					 set_one_shot_dma_mode invoked.\n");
+#endif
+		}
+	}
+#endif
+
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 		uart_write_wakeup(&up->port);
 
@@ -1494,6 +1990,10 @@
 
 	if (uart_circ_empty(xmit))
 		__stop_tx(up);
+
+#ifdef DEBUG
+	printk(KERN_DEBUG"Function transmit_chars invoked.\n");
+#endif
 }
 
 static unsigned int check_modem_status(struct uart_8250_port *up)
@@ -1509,9 +2009,11 @@
 		if (status & UART_MSR_DDSR)
 			up->port.icount.dsr++;
 		if (status & UART_MSR_DDCD)
-			uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+			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);
+			uart_handle_cts_change(&up->port,
+						 status & UART_MSR_CTS);
 
 		wake_up_interruptible(&up->port.state->port.delta_msr_wait);
 	}
@@ -1533,13 +2035,36 @@
 
 	DEBUG_INTR("status = %x...", status);
 
-	if (status & (UART_LSR_DR | UART_LSR_BI))
-		receive_chars(up, &status);
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+	if ((up->dma_flag) && (up->dma_enabled)) {
+		/* If reception has to be done through DMA. */
+#ifdef DEBUG
+		printk(KERN_DEBUG"serial8250_handle_port ->\
+				 Proceeding to handle reception " \
+				"interrupt through DMA operation.\n");
+#endif
+		handle_dma_operation(up);
+	} else {
+#endif
+
+		if ((status & (UART_LSR_DR | UART_LSR_BI))
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+			&& (!up->dma_progress)
+#endif
+			)
+			receive_chars(up, &status);
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+	}
+#endif
 	check_modem_status(up);
 	if (status & UART_LSR_THRE)
 		transmit_chars(up);
 
 	spin_unlock_irqrestore(&up->port.lock, flags);
+
+#ifdef DEBUG
+	printk(KERN_DEBUG"serial8250_handle_port invoked.\n");
+#endif
 }
 
 /*
@@ -1575,6 +2100,26 @@
 
 		iir = serial_in(up, UART_IIR);
 		if (!(iir & UART_IIR_NO_INT)) {
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+			/* Determing whether the receive FIFO is full. */
+			if ((iir & UART_IIR_RDI) && !(iir & 0x8) &&
+				 ((up->port.flags & UPF_IOH_UART) != 0)) {
+
+				up->dma_flag = 1;
+
+#ifdef DEBUG
+				printk(KERN_DEBUG"serial8250_interrupt ->\
+					 DMA Mode enabled for reception.\n");
+#endif
+			} else {
+				up->dma_flag = 0;
+#ifdef DEBUG
+				printk(KERN_DEBUG"serial8250_interrupt ->\
+					 DMA Mode disabled for reception.\n");
+#endif
+			}
+#endif
+
 			serial8250_handle_port(up);
 
 			handled = 1;
@@ -1946,6 +2491,167 @@
 	unsigned char lsr, iir;
 	int retval;
 
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+	/* Initialising the device for DMA support. */
+	int dma_flag = 0;
+	up->dma_progress = 0;
+	up->dma_enabled = 0;
+
+	if ((up->port.flags & UPF_IOH_UART) != 0) {
+		struct pci_dev pdev;
+
+/*		switch((up->port.flags & 0xE000000))*/
+		switch ((up->port.flags & (UPF_IOH_UART | UPF_IOH_UART_BIT0 |
+						 UPF_IOH_UART_BIT1))) {
+		case UPF_IOH_UART0:
+#ifdef DEBUG
+			printk(KERN_DEBUG"serial8250_startup ->\
+							 UART0 detected.\n");
+#endif
+			pdev.device = PCI_DEVICE_ID_IOH_UART0;
+			up->port.mctrl |= TIOCM_RTS;
+			break;
+
+		case UPF_IOH_UART1:
+#ifdef DEBUG
+			printk(KERN_DEBUG"serial8250_startup ->\
+							 UART1 detected.\n");
+#endif
+			pdev.device = PCI_DEVICE_ID_IOH_UART1;
+			break;
+
+		case UPF_IOH_UART2:
+#ifdef DEBUG
+			printk(KERN_DEBUG"serial8250_startup ->\
+							 UART2 detected.\n");
+#endif
+			pdev.device = PCI_DEVICE_ID_IOH_UART2;
+			break;
+
+		case UPF_IOH_UART3:
+#ifdef DEBUG
+			printk(KERN_DEBUG"serial8250_startup ->\
+							 UART3 detected.\n");
+#endif
+			pdev.device = PCI_DEVICE_ID_IOH_UART3;
+			break;
+
+		default:
+			break;
+		}
+
+		/* Allocating space for DMA buffer. */
+		up->rx_dma.buf = (u32)__get_free_page(GFP_KERNEL|GFP_DMA);
+		if (!(up->rx_dma.buf)) {
+			printk(KERN_ERR"serial8250_startup -> DMA buffer\
+					 allocation " \
+					"failed for Rx DMA buffer.\n");
+			return -ENOMEM;
+		}
+
+		/* For transmission process. */
+		up->tx_dma.buf = (u32)__get_free_page(GFP_KERNEL|GFP_DMA);
+		if (!(up->tx_dma.buf)) {
+			free_page(up->rx_dma.buf);
+			printk(KERN_ERR"serial8250_startup -> DMA buffer\
+					 allocation " \
+					"failed for TX DMA buffer.\n");
+			return -ENOMEM;
+		}
+
+		/* For copying of transmit data. */
+		up->buffer = (u32)__get_free_page(GFP_KERNEL|GFP_DMA);
+		if (!(up->buffer)) {
+			free_page(up->rx_dma.buf);
+			free_page(up->tx_dma.buf);
+			printk(KERN_ERR"serial8250_startup -> DMA buffer\
+					 allocation " \
+					"failed for Buffer.\n");
+			return -ENOMEM;
+		}
+
+		up->rx_dma.size = PAGE_SIZE;
+		up->tx_dma.size = PAGE_SIZE;
+
+		/* Requesting for DMA channel for reception. */
+		up->rx_dma.channel = ioh_request_dma(&pdev,
+							 IOH_DMA_RX_DATA_REQ0);
+		if (up->rx_dma.channel < 0) {
+			free_page(up->rx_dma.buf);
+			free_page(up->tx_dma.buf);
+			free_page(up->buffer);
+			up->rx_dma.buf = 0;
+			up->tx_dma.buf = 0;
+			up->buffer = 0;
+
+			printk(KERN_ERR"serial8250_startup -> DMA channel\
+					 allocation for " \
+					"reception failed.\n");
+			return -EIO;
+		}
+
+		/* Requesting DMA channel for transmission. */
+		up->tx_dma.channel = ioh_request_dma(&pdev,
+							 IOH_DMA_TX_DATA_REQ0);
+		if (up->tx_dma.channel < 0) {
+			free_page(up->rx_dma.buf);
+			free_page(up->tx_dma.buf);
+			free_page(up->buffer);
+			up->rx_dma.buf = 0;
+			up->tx_dma.buf = 0;
+			up->buffer = 0;
+			ioh_free_dma(up->rx_dma.channel);
+
+			printk(KERN_ERR"serial8250_startup -> DMA channel\
+							 allocation for " \
+					"transmission failed.\n");
+			return -EIO;
+		}
+
+		/* Performing DMA settings for reception. */
+		{
+			u32 in_address;
+			u32 out_address;
+			u32 size;
+			int channel	= up->rx_dma.channel;
+			struct ioh_dma_mode_param mode = {
+				.TransferDirection	= IOH_DMA_DIR_IN_TO_OUT,
+				.DMASizeType	= IOH_DMA_SIZE_TYPE_8BIT,
+				.DMATransferMode	= DMA_ONE_SHOT_MODE
+			};
+
+			/* Mapping the DMA buffer to DMA accessible area and
+						 obtaining its base address. */
+			out_address = dma_map_single(up->port.dev,
+						 (void *)up->rx_dma.buf,
+						 up->rx_dma.size,
+						 DMA_FROM_DEVICE);
+			in_address	= up->port.mapbase +
+						 (map_8250_in_reg(up, UART_RX));
+			size		= up->rx_fifo_size;
+			up->rx_dma.phy_addr	= out_address;
+
+			/* Setting the DMA settings. */
+			(void)ioh_set_dma_mode(channel, mode);
+			(void)ioh_set_dma_addr(channel, in_address,
+								 out_address);
+			(void)ioh_set_dma_count(channel, size);
+			(void)ioh_dma_set_callback(channel, ioh_dma_rx_callback,
+								 (u32)up);
+		}
+
+		dma_flag = 1;
+
+#ifdef DEBUG
+		printk(KERN_DEBUG"serial8250_startup -> Buffer Allocation\
+							 successful and DMA " \
+				"channels obtained are Reception: %d\
+						 Transmission: %d.\n", \
+				up->rx_dma.channel, up->tx_dma.channel);
+#endif
+	}
+#endif
+
 	up->capabilities = uart_config[up->port.type].flags;
 	up->mcr = 0;
 
@@ -1996,6 +2702,21 @@
 	    (serial_inp(up, UART_LSR) == 0xff)) {
 		printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
 		       serial_index(&up->port));
+
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+	/* Releasing the DMA resources on failure.*/
+	if (dma_flag == 1) {
+		ioh_free_dma(up->rx_dma.channel);
+		ioh_free_dma(up->tx_dma.channel);
+		free_page(up->rx_dma.buf);
+		free_page(up->tx_dma.buf);
+		free_page(up->buffer);
+		up->rx_dma.buf = 0;
+		up->tx_dma.buf = 0;
+		up->buffer = 0;
+	}
+#endif
+
 		return -ENODEV;
 	}
 
@@ -2008,9 +2729,11 @@
 		serial_outp(up, UART_LCR, 0xbf);
 
 		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_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_FCTR, fctr | UART_FCTR_TRGD |
+								 UART_FCTR_TX);
 		serial_outp(up, UART_TRG, UART_TRG_96);
 
 		serial_outp(up, UART_LCR, 0);
@@ -2076,8 +2799,22 @@
 		mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout));
 	} else {
 		retval = serial_link_irq_chain(up);
-		if (retval)
+		if (retval) {
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+			/* Releasing the DMA resources on failure.*/
+			if (dma_flag == 1) {
+				ioh_free_dma(up->rx_dma.channel);
+				ioh_free_dma(up->tx_dma.channel);
+				free_page(up->rx_dma.buf);
+				free_page(up->tx_dma.buf);
+				free_page(up->buffer);
+				up->rx_dma.buf = 0;
+				up->tx_dma.buf = 0;
+				up->buffer = 0;
+			}
+		#endif
 			return retval;
+		}
 	}
 
 	/*
@@ -2124,7 +2861,8 @@
 	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",
+			pr_debug("ttyS%d - enabling bad tx status\
+				 workarounds\n",
 				 serial_index(port));
 		}
 	} else {
@@ -2172,6 +2910,31 @@
 	struct uart_8250_port *up = (struct uart_8250_port *)port;
 	unsigned long flags;
 
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+	/* Releasing the DMA resources on exit.*/
+	if ((up->port.flags & UPF_IOH_UART) != 0) {
+		if (up->rx_dma.channel >= 0)
+			ioh_free_dma(up->rx_dma.channel);
+		if (up->tx_dma.channel >= 0)
+			ioh_free_dma(up->tx_dma.channel);
+
+		if (up->rx_dma.buf)
+			free_page(up->rx_dma.buf);
+		if (up->tx_dma.buf)
+			free_page(up->tx_dma.buf);
+		if (up->buffer)
+			free_page(up->buffer);
+
+		up->rx_dma.buf = 0;
+		up->tx_dma.buf = 0;
+		up->buffer = 0;
+
+#ifdef DEBUG
+		printk(KERN_DEBUG"serial8250_shutdown -> DMA buffers and\
+							 channels released.\n");
+#endif
+	}
+#endif
 	/*
 	 * Disable interrupts from this port
 	 */
@@ -2214,7 +2977,8 @@
 		serial_unlink_irq_chain(up);
 }
 
-static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
+static unsigned int serial8250_get_divisor(struct uart_port *port,
+							 unsigned int baud)
 {
 	unsigned int quot;
 
@@ -2242,6 +3006,7 @@
 	unsigned char cval, fcr = 0;
 	unsigned long flags;
 	unsigned int baud, quot;
+	unsigned int bdrate;
 
 	switch (termios->c_cflag & CSIZE) {
 	case CS5:
@@ -2278,6 +3043,11 @@
 				  port->uartclk / 16);
 	quot = serial8250_get_divisor(port, baud);
 
+#ifdef DEBUG
+	printk(KERN_DEBUG "IOH UART LOG:max_baud: %d\n,baud :%d\n quot:%d\n"
+							, max_baud, baud, quot);
+#endif
+
 	/*
 	 * Oxford Semi 952 rev B workaround
 	 */
@@ -2285,12 +3055,37 @@
 		quot++;
 
 	if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
-		if (baud < 2400)
+		if (baud < 2400) {
 			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
-		else
-			fcr = uart_config[up->port.type].fcr;
+
+#ifdef ENABLE_SERIAL_8250_PCH
+				if ((up->port.flags & UPF_IOH_UART) != 0)
+					/*This enables 256 byte FIFO
+								for UART 0.*/
+					fcr |= UART_FCR7_64BYTE;
+
+#endif
+			} else
+				fcr = uart_config[up->port.type].fcr;
 	}
 
+#if defined(ENABLE_SERIAL_8250_PCH) && defined(ENABLE_PCH_DMA_FEATURE)
+	/* Deciding whether to use DMA feature or not.*/
+	if ((baud >= 38400) && ((up->port.flags & UPF_IOH_UART) != 0))
+		up->dma_enabled = 1;
+	else
+		up->dma_enabled = 0;
+
+
+	get_rx_fifo_size(up, fcr);
+
+#ifdef DEBUG
+	printk(KERN_DEBUG"serial8250_set_termios -> The Rx fifo size is: %u\n",
+							 up->rx_fifo_size);
+#endif
+
+#endif
+
 	/*
 	 * MCR-based auto flow control.  When AFE is enabled, RTS will be
 	 * deasserted when the receive FIFO contains more characters than
@@ -2409,8 +3204,22 @@
 	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))
+
+	bdrate = tty_termios_baud_rate(termios);
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "tty_termios_baud_rate value:%d\n", bdrate);
+#endif
+
+	if (bdrate) {
 		tty_termios_encode_baud_rate(termios, baud, baud);
+
+#ifdef DEBUG
+		printk(KERN_DEBUG "termios->c_ispeed:%d\n,\
+			 termios->c_ospeed:%d\n "
+			, termios->c_ispeed, termios->c_ospeed);
+#endif
+	}
 }
 
 static void
@@ -2580,18 +3389,24 @@
 	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 (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
@@ -2686,6 +3501,7 @@
 		up->port.regshift = old_serial_port[i].iomem_reg_shift;
 		set_io_from_upio(&up->port);
 		up->port.irqflags |= irqflag;
+
 	}
 }
 
@@ -2967,7 +3783,8 @@
 		port.irqflags		|= irqflag;
 		ret = serial8250_register_port(&port);
 		if (ret < 0) {
-			dev_err(&dev->dev, "unable to register port at index %d "
+			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);
@@ -3044,7 +3861,8 @@
  */
 static DEFINE_MUTEX(serial_mutex);
 
-static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
+static
+struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
 {
 	int i;
 
@@ -3251,7 +4069,8 @@
 	" (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_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");
diff -urN linux-2.6.33.1/drivers/serial/8250_pch.h topcliff-2.6.33.1/drivers/serial/8250_pch.h
--- linux-2.6.33.1/drivers/serial/8250_pch.h	1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33.1/drivers/serial/8250_pch.h	2010-03-23 10:34:44.000000000 +0900
@@ -0,0 +1,57 @@
+/*!
+ * @file 8250_pch.h
+ * @brief Provides the macro definitions used by all files.
+ * @version 1.0.0.0
+ * @section
+ * 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.
+ */
+
+/*
+ * History:
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
+ * All rights reserved.
+ *
+ * created:
+ *	OKISEMI 03/16/2010
+ *
+ */
+
+#ifndef __IOH_8250_PCH_H__
+#define __IOH_8250_PCH_H__
+
+#define PORT_IOH_256FIFO	128	/* IOH UART with 256 byte FIFO */
+#define PORT_IOH_64FIFO		129	/* IOH UART with 64 byte FIFO */
+
+/* flags for IOH port detection */
+/* The below fields are used to identify the IOH UART port 0 to 3 */
+#define UPF_IOH_UART_BIT0 ((__force upf_t) (1 << 17))
+#define UPF_IOH_UART_BIT1  ((__force upf_t) (1 << 18))
+
+#define UPF_IOH_UART 			((__force upf_t) (1 << 19))
+#define UPF_IOH_UART0 			((UPF_IOH_UART) | (0))
+#define UPF_IOH_UART1	((UPF_IOH_UART) | ((__force upf_t) (UPF_IOH_UART_BIT0)))
+#define UPF_IOH_UART2	((UPF_IOH_UART) | ((__force upf_t) (UPF_IOH_UART_BIT1)))
+#define UPF_IOH_UART3	((UPF_IOH_UART) | ((__force upf_t) (UPF_IOH_UART_BIT0 |\
+							 UPF_IOH_UART_BIT1)))
+#define UPF_IOH_UART_64_FIFO 	((__force upf_t) (UPF_IOH_UART3))
+
+#define UART_FCR7_256BYTE	0x20 /* Go into 256 byte FIFO mode (IOH UART) */
+
+/* Intel IOH GE UART PCI device IDs */
+#define PCI_DEVICE_ID_IOH_UART0	(0x8811)
+#define PCI_DEVICE_ID_IOH_UART1	(0x8812)
+#define PCI_DEVICE_ID_IOH_UART2	(0x8813)
+#define PCI_DEVICE_ID_IOH_UART3	(0x8814)
+
+#endif
diff -urN linux-2.6.33.1/drivers/serial/8250_pci.c topcliff-2.6.33.1/drivers/serial/8250_pci.c
--- linux-2.6.33.1/drivers/serial/8250_pci.c	2010-03-16 01:09:39.000000000 +0900
+++ topcliff-2.6.33.1/drivers/serial/8250_pci.c	2010-03-23 10:34:44.000000000 +0900
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/pci_ids.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -27,7 +28,7 @@
 #include <asm/io.h>
 
 #include "8250.h"
-
+#include "8250_pch.h"
 #undef SERIAL_DEBUG_PCI
 
 /*
@@ -726,6 +727,87 @@
 #define NI8430_PORTCON	0x0f
 #define NI8430_PORTCON_TXVR_ENABLE	(1 << 3)
 
+#if defined(ENABLE_SERIAL_8250_PCH)
+
+static int
+pci_ioh_init(struct pci_dev *dev)
+{
+	int retval = 0;
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "IOH UART LOG:function pci_ioh_init invoked \n");
+
+	printk(KERN_DEBUG "IOH UART LOG:function pci_ioh_init->pci_enable_wake invoked \n");
+#endif
+
+	/* disable Wake on UART */
+	pci_enable_wake(dev, PCI_D3hot, 0);
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "IOH UART LOG:function pci_ioh_init return = %d\n",
+								 retval);
+#endif
+
+	return retval;
+}
+
+static int
+pci_ioh_setup(struct serial_private *priv, const struct pciserial_board *board,
+		struct uart_port *port, int idx)
+{
+	int retval = 1 ;
+	unsigned int bar = 0;
+	unsigned int offset = 0;
+
+	if (idx == 0) {
+		/* IOH UART has only 1 channel per device */
+		switch (priv->dev->device) {
+		case PCI_DEVICE_ID_IOH_UART0:
+			port->flags |= UPF_IOH_UART0;
+			break;
+
+		case PCI_DEVICE_ID_IOH_UART1:
+			port->flags |= UPF_IOH_UART1;
+			break;
+
+		case PCI_DEVICE_ID_IOH_UART2:
+			port->flags |= UPF_IOH_UART2;
+			break;
+
+		case PCI_DEVICE_ID_IOH_UART3:
+			port->flags |= UPF_IOH_UART3;
+			break;
+
+		default:
+			break;
+		}
+
+		retval = setup_port(priv, port, bar, offset, board->reg_shift);
+
+		#ifdef ENABLE_PCH_DMA_FEATURE
+			/* Obtaing the Memory Map base for DMA operations. */
+			port->mapbase = pci_resource_start(priv->dev, 1);
+		#ifdef DEBUG
+			printk(KERN_DEBUG"pci_ioh_setup -> The Map Base has been obtained.\n");
+		#endif
+		#endif
+	}
+
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "pci_ioh_setup -> Function pci_ioh_setup invoked \n");
+	printk(KERN_DEBUG "pci_ioh_setup -> board.base_baud = %d, flags = %d,\
+			 num_ports = %d,reg_shift = %d\n",
+			board->base_baud, board->flags,
+			 board->num_ports, board->reg_shift);
+	printk(KERN_DEBUG "pci_ioh_setup -> port->flags =%x\n", port->flags);
+	printk(KERN_DEBUG "Function pci_ioh_setup return = %d\n", retval);
+
+#endif
+	return retval;
+}
+#endif
+
 static int
 pci_ni8430_setup(struct serial_private *priv,
 		 const struct pciserial_board *board,
@@ -918,7 +1000,8 @@
 	    (dev->device & 0xF000) != 0xC000)
 		return 0;
 
-	p = pci_iomap(dev, 0, 5);
+	/*p = pci_iomap(dev, 0, 5);*/
+	p = pci_iomap(dev, 1, 5);
 	if (p == NULL)
 		return -ENOMEM;
 
@@ -1393,6 +1476,43 @@
 		.setup		= pci_default_setup,
 	},
 	/*
+	 * IOH UART
+	 */
+#if defined(ENABLE_SERIAL_8250_PCH)
+	{
+		.vendor     = PCI_VENDOR_ID_INTEL,
+		.device     = PCI_DEVICE_ID_IOH_UART0,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.init		= pci_ioh_init,
+		.setup      = pci_ioh_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_INTEL,
+		.device     = PCI_DEVICE_ID_IOH_UART1,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.init		= pci_ioh_init,
+		.setup      = pci_ioh_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_INTEL,
+		.device     = PCI_DEVICE_ID_IOH_UART2,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.init		= pci_ioh_init,
+		.setup      = pci_ioh_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_INTEL,
+		.device     = PCI_DEVICE_ID_IOH_UART3,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.init		= pci_ioh_init,
+		.setup      = pci_ioh_setup,
+	},
+#endif
+	/*
 	 * Default "match everything" terminator entry
 	 */
 	{
@@ -1571,6 +1691,10 @@
 	pbn_ADDIDATA_PCIe_2_3906250,
 	pbn_ADDIDATA_PCIe_4_3906250,
 	pbn_ADDIDATA_PCIe_8_3906250,
+#if defined(ENABLE_SERIAL_8250_PCH)
+	pbn_ioh_uart_8L_256FIFO,  /* ioh 8 Line UART with 256 byte FIFO */
+	pbn_ioh_uart_2L_64FIFO    /* ioh 2 Line UART with 64 byte FIFO */
+#endif
 };
 
 /*
@@ -2228,6 +2352,27 @@
 		.uart_offset	= 0x200,
 		.first_offset	= 0x1000,
 	},
+
+#if defined(ENABLE_SERIAL_8250_PCH)
+
+	/*
+	 * IOH UART
+	 */
+	[pbn_ioh_uart_8L_256FIFO] = {
+		.flags      = FL_BASE0,
+		.num_ports  = 1,
+		.base_baud  = 115200, 	/* OKISEMI For LSI */
+		.reg_shift  = 0,
+	},
+
+	[pbn_ioh_uart_2L_64FIFO] = {
+		.flags      = FL_BASE0,
+		.num_ports  = 1,
+		.base_baud  = 115200, 	/* OKISEMI For LSI*/
+		.reg_shift  = 0,
+	},
+#endif
+
 };
 
 static const struct pci_device_id softmodem_blacklist[] = {
@@ -2473,8 +2618,20 @@
 		return -EINVAL;
 	}
 
+#ifdef DEBUG
+	printk(KERN_DEBUG "IOH UART LOG:function pciserial_init_one ent->vendor"
+	       " = %x\n, ent->device = %x, ent->driver_data = %ld\n  ",
+	       ent->vendor, ent->device, ent->driver_data);
+#endif
+
 	board = &pci_boards[ent->driver_data];
 
+#ifdef DEBUG
+	printk(KERN_DEBUG "IOH UART LOG:function pciserial_init_one board->"
+	      "base_baud = %u\n, board->flags = %d, board->num_ports = %d\n "
+	      , board->base_baud, board->flags, board->num_ports);
+#endif
+
 	rc = pci_enable_device(dev);
 	if (rc)
 		return rc;
@@ -2540,6 +2697,17 @@
 	if (priv)
 		pciserial_suspend_ports(priv);
 
+#if defined(ENABLE_SERIAL_8250_PCH)
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "IOH UART LOG:pciserial_suspend_one->pci_enable_wake"
+	      "invoked \n");
+#endif
+
+
+	pci_enable_wake(dev, PCI_D3hot, 1);
+#endif
+
 	pci_save_state(dev);
 	pci_set_power_state(dev, pci_choose_state(dev, state));
 	return 0;
@@ -2561,6 +2729,17 @@
 		/* FIXME: We cannot simply error out here */
 		if (err)
 			printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n");
+
+#if defined(ENABLE_SERIAL_8250_PCH)
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "IOH UART LOG:pciserial_resume_one->pci_enable_wake"
+	      "invoked \n");
+#endif
+
+	pci_enable_wake(dev, PCI_D3hot, 0);
+#endif
+
 		pciserial_resume_ports(priv);
 	}
 	return 0;
@@ -3649,6 +3828,48 @@
 		0, 0, pbn_b0_1_115200 },
 
 	/*
+	 * IOH UART
+	 */
+#if defined(ENABLE_SERIAL_8250_PCH)
+
+	{   PCI_VENDOR_ID_INTEL,
+		/*device id for ioh uart with 8 i/o lines and 256 byte fifo. */
+		PCI_DEVICE_ID_IOH_UART0,
+		PCI_ANY_ID,
+		PCI_ANY_ID,
+		0,
+		0,
+		pbn_ioh_uart_8L_256FIFO },
+
+	{   PCI_VENDOR_ID_INTEL,
+		/*device id for ioh uart with 2 i/o lines and 256 byte fifo. */
+		PCI_DEVICE_ID_IOH_UART1,
+		PCI_ANY_ID,
+		PCI_ANY_ID,
+		0,
+		0,
+		pbn_ioh_uart_2L_64FIFO },
+
+	{   PCI_VENDOR_ID_INTEL,
+		/*device id for ioh uart with 8 i/o lines and 64 byte fifo. */
+		PCI_DEVICE_ID_IOH_UART2,
+		PCI_ANY_ID,
+		PCI_ANY_ID,
+		0,
+		0,
+		pbn_ioh_uart_2L_64FIFO },
+
+	{   PCI_VENDOR_ID_INTEL,
+		/*device id for ioh uart with 2 i/o lines and 64 byte fifo. */
+		PCI_DEVICE_ID_IOH_UART3,
+		PCI_ANY_ID,
+		PCI_ANY_ID,
+		0,
+		0,
+		pbn_ioh_uart_2L_64FIFO },
+#endif
+
+	/*
 	 * These entries match devices with class COMMUNICATION_SERIAL,
 	 * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
 	 */
diff -urN linux-2.6.33.1/drivers/serial/Kconfig topcliff-2.6.33.1/drivers/serial/Kconfig
--- linux-2.6.33.1/drivers/serial/Kconfig	2010-03-16 01:09:39.000000000 +0900
+++ topcliff-2.6.33.1/drivers/serial/Kconfig	2010-03-23 10:34:44.000000000 +0900
@@ -89,6 +89,21 @@
 	  disable this feature if you only need legacy serial support.
 	  Saves about 9K.
 
+config SERIAL_8250_PCH
+	tristate "PCH PCI serial device support"
+	depends on SERIAL_8250 && PCI && SERIAL_8250_PCI
+	default SERIAL_8250_PCI
+	help
+	  This makes the PCH PCI serial driver to support high speed PCH serial ports.
+
+config SERIAL_8250_PCH_DMA
+	bool "Enable DMA mode of PCH PCI serial device"
+	depends on SERIAL_8250_PCH
+	select PCH_UART_DMA
+	default y
+	help
+	  This makes the PCH PCI serial driver with DMA mode.
+
 config SERIAL_8250_PNP
 	tristate "8250/16550 PNP device support" if EMBEDDED
 	depends on SERIAL_8250 && PNP
diff -urN linux-2.6.33.1/drivers/serial/Makefile topcliff-2.6.33.1/drivers/serial/Makefile
--- linux-2.6.33.1/drivers/serial/Makefile	2010-03-16 01:09:39.000000000 +0900
+++ topcliff-2.6.33.1/drivers/serial/Makefile	2010-03-23 10:34:44.000000000 +0900
@@ -1,6 +1,17 @@
 #
 # Makefile for the kernel serial device drivers.
 #
+#
+#This is needed to enable ioh dma#
+#EXTRA_CFLAGS +=-DENABLE_IOH_DMA_FEATURE
+ifdef CONFIG_SERIAL_8250_PCH
+EXTRA_CFLAGS +=-DENABLE_SERIAL_8250_PCH
+endif
+
+ifdef CONFIG_PCH_UART_DMA
+EXTRA_CFLAGS +=-DENABLE_PCH_DMA_FEATURE
+EXTRA_CFLAGS +=-Idrivers/dma/pch_dma/
+endif
 
 obj-$(CONFIG_SERIAL_CORE) += serial_core.o
 obj-$(CONFIG_SERIAL_21285) += 21285.o
