⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpsc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
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);	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;}/* ****************************************************************************** * * Interrupt Handling Routines * ****************************************************************************** */static int mpsc_rx_intr(struct mpsc_port_info *pi){	struct mpsc_rx_desc *rxre;	struct tty_struct *tty = pi->port.info->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);		/* 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)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -