writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir); 
writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir); 
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);	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->info->							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;}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/396dc44bcac58f464b7b23c345052e37881cccea/ioc4_serial.c/buggy/drivers/serial/ioc4_serial.c