📄 pc300_drv.c
字号:
#define USE_PCI_CLOCKstatic char rcsid[] = // Important note:// This string must have this exact format, including the space on its end"Revision: 4.1.0 Date: 2003/11/19 ";/* * pc300.c Cyclades-PC300(tm) Driver. * * Author: Ivan Passos <ivan.passos@cyclades.com> * Maintainer: PC300 Maintainer <pc300@cyclades.com> * * Copyright: (c) 1999-2003 Cyclades Corp. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/ioport.h>#include <linux/pci.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/net.h>#include <linux/skbuff.h>#include <linux/if_arp.h>#include <linux/netdevice.h>#include <linux/spinlock.h>#include <linux/if.h>#include <linux/version.h>#include <net/arp.h>#include <asm/io.h>#include <asm/uaccess.h>#include <net/syncppp.h>#include "pc300.h"#define CPC_LOCK(card,flags) \ do { \ spin_lock_irqsave(&card->card_lock, flags); \ } while (0)#define CPC_UNLOCK(card,flags) \ do { \ spin_unlock_irqrestore(&card->card_lock, flags); \ } while (0)#undef PC300_DEBUG_PCI#undef PC300_DEBUG_INTR#undef PC300_DEBUG_TX#undef PC300_DEBUG_RX#undef PC300_DEBUG_OTHERstatic struct pci_device_id cpc_pci_dev_id[] __devinitdata = { /* PC300/RSV or PC300/X21, 2 chan */ {0x120e, 0x300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x300}, /* PC300/RSV or PC300/X21, 1 chan */ {0x120e, 0x301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x301}, /* PC300/TE, 2 chan */ {0x120e, 0x310, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x310}, /* PC300/TE, 1 chan */ {0x120e, 0x311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x311}, /* PC300/TE-M, 2 chan */ {0x120e, 0x320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x320}, /* PC300/TE-M, 1 chan */ {0x120e, 0x321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x321}, /* End of table */ {0,},};MODULE_DEVICE_TABLE(pci, cpc_pci_dev_id);#ifndef cpc_min#define cpc_min(a,b) (((a)<(b))?(a):(b))#endif#ifndef cpc_max#define cpc_max(a,b) (((a)>(b))?(a):(b))#endif/* prototypes */static void tx_dma_buf_pt_init(pc300_t *, int);static void tx_dma_buf_init(pc300_t *, int);static void rx_dma_buf_pt_init(pc300_t *, int);static void rx_dma_buf_init(pc300_t *, int);static void tx_dma_buf_check(pc300_t *, int);static void rx_dma_buf_check(pc300_t *, int);static void cpc_intr(int, void *, struct pt_regs *);static struct net_device_stats *cpc_get_stats(struct net_device *);static int clock_rate_calc(uclong, uclong, int *);static uclong detect_ram(pc300_t *);static void plx_init(pc300_t *);static void cpc_trace(struct net_device *, struct sk_buff *, char);static int cpc_attach(hdlc_device *, unsigned short, unsigned short);#ifdef CONFIG_PC300_MLPPPvoid cpc_tty_init(pc300dev_t * dev);void cpc_tty_unregister_service(pc300dev_t * pc300dev);void cpc_tty_receive(pc300dev_t * pc300dev);void cpc_tty_trigger_poll(pc300dev_t * pc300dev);void cpc_tty_reset_var(void);#endif/************************//*** DMA Routines ***//************************/static void tx_dma_buf_pt_init(pc300_t * card, int ch){ int i; int ch_factor = ch * N_DMA_TX_BUF; volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase + DMA_TX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); for (i = 0; i < N_DMA_TX_BUF; i++, ptdescr++) { cpc_writel(&ptdescr->next, (uclong) (DMA_TX_BD_BASE + (ch_factor + ((i + 1) & (N_DMA_TX_BUF - 1))) * sizeof(pcsca_bd_t))); cpc_writel(&ptdescr->ptbuf, (uclong) (DMA_TX_BASE + (ch_factor + i) * BD_DEF_LEN)); }}static void tx_dma_buf_init(pc300_t * card, int ch){ int i; int ch_factor = ch * N_DMA_TX_BUF; volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase + DMA_TX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); for (i = 0; i < N_DMA_TX_BUF; i++, ptdescr++) { memset_io(ptdescr, 0, sizeof(pcsca_bd_t)); cpc_writew(&ptdescr->len, 0); cpc_writeb(&ptdescr->status, DST_OSB); } tx_dma_buf_pt_init(card, ch);}static void rx_dma_buf_pt_init(pc300_t * card, int ch){ int i; int ch_factor = ch * N_DMA_RX_BUF; volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); for (i = 0; i < N_DMA_RX_BUF; i++, ptdescr++) { cpc_writel(&ptdescr->next, (uclong) (DMA_RX_BD_BASE + (ch_factor + ((i + 1) & (N_DMA_RX_BUF - 1))) * sizeof(pcsca_bd_t))); cpc_writel(&ptdescr->ptbuf, (uclong) (DMA_RX_BASE + (ch_factor + i) * BD_DEF_LEN)); }}static void rx_dma_buf_init(pc300_t * card, int ch){ int i; int ch_factor = ch * N_DMA_RX_BUF; volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); for (i = 0; i < N_DMA_RX_BUF; i++, ptdescr++) { memset_io(ptdescr, 0, sizeof(pcsca_bd_t)); cpc_writew(&ptdescr->len, 0); cpc_writeb(&ptdescr->status, 0); } rx_dma_buf_pt_init(card, ch);}static void tx_dma_buf_check(pc300_t * card, int ch){ volatile pcsca_bd_t *ptdescr; int i; ucshort first_bd = card->chan[ch].tx_first_bd; ucshort next_bd = card->chan[ch].tx_next_bd; printk("#CH%d: f_bd = %d(0x%08x), n_bd = %d(0x%08x)\n", ch, first_bd, TX_BD_ADDR(ch, first_bd), next_bd, TX_BD_ADDR(ch, next_bd)); for (i = first_bd, ptdescr = (pcsca_bd_t *) (card->hw.rambase + TX_BD_ADDR(ch, first_bd)); i != ((next_bd + 1) & (N_DMA_TX_BUF - 1)); i = (i + 1) & (N_DMA_TX_BUF - 1), ptdescr = (pcsca_bd_t *) (card->hw.rambase + TX_BD_ADDR(ch, i))) { printk("\n CH%d TX%d: next=0x%lx, ptbuf=0x%lx, ST=0x%x, len=%d", ch, i, (uclong) cpc_readl(&ptdescr->next), (uclong) cpc_readl(&ptdescr->ptbuf), cpc_readb(&ptdescr->status), cpc_readw(&ptdescr->len)); } printk("\n");}#ifdef PC300_DEBUG_OTHER/* Show all TX buffer descriptors */static void tx1_dma_buf_check(pc300_t * card, int ch){ volatile pcsca_bd_t *ptdescr; int i; ucshort first_bd = card->chan[ch].tx_first_bd; ucshort next_bd = card->chan[ch].tx_next_bd; uclong scabase = card->hw.scabase; printk ("\nnfree_tx_bd = %d \n", card->chan[ch].nfree_tx_bd); printk("#CH%d: f_bd = %d(0x%08x), n_bd = %d(0x%08x)\n", ch, first_bd, TX_BD_ADDR(ch, first_bd), next_bd, TX_BD_ADDR(ch, next_bd)); printk("TX_CDA=0x%08lx, TX_EDA=0x%08lx\n", (uclong) cpc_readl(scabase + DTX_REG(CDAL, ch)), (uclong) cpc_readl(scabase + DTX_REG(EDAL, ch))); for (i = 0; i < N_DMA_TX_BUF; i++) { ptdescr = (pcsca_bd_t *) (card->hw.rambase + TX_BD_ADDR(ch, i)); printk("\n CH%d TX%d: next=0x%lx, ptbuf=0x%lx, ST=0x%x, len=%d", ch, i, (uclong) cpc_readl(&ptdescr->next), (uclong) cpc_readl(&ptdescr->ptbuf), cpc_readb(&ptdescr->status), cpc_readw(&ptdescr->len)); } printk("\n");}#endif static void rx_dma_buf_check(pc300_t * card, int ch){ volatile pcsca_bd_t *ptdescr; int i; ucshort first_bd = card->chan[ch].rx_first_bd; ucshort last_bd = card->chan[ch].rx_last_bd; int ch_factor; ch_factor = ch * N_DMA_RX_BUF; printk("#CH%d: f_bd = %d, l_bd = %d\n", ch, first_bd, last_bd); for (i = 0, ptdescr = (pcsca_bd_t *) (card->hw.rambase + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); i < N_DMA_RX_BUF; i++, ptdescr++) { if (cpc_readb(&ptdescr->status) & DST_OSB) printk ("\n CH%d RX%d: next=0x%lx, ptbuf=0x%lx, ST=0x%x, len=%d", ch, i, (uclong) cpc_readl(&ptdescr->next), (uclong) cpc_readl(&ptdescr->ptbuf), cpc_readb(&ptdescr->status), cpc_readw(&ptdescr->len)); } printk("\n");}int dma_get_rx_frame_size(pc300_t * card, int ch){ volatile pcsca_bd_t *ptdescr; ucshort first_bd = card->chan[ch].rx_first_bd; int rcvd = 0; volatile ucchar status; ptdescr = (pcsca_bd_t *)(card->hw.rambase + RX_BD_ADDR(ch, first_bd)); while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { rcvd += cpc_readw(&ptdescr->len); first_bd = (first_bd + 1) & (N_DMA_RX_BUF - 1); if ((status & DST_EOM) || (first_bd == card->chan[ch].rx_last_bd)) { /* Return the size of a good frame or incomplete bad frame * (dma_buf_read will clean the buffer descriptors in this case). */ return (rcvd); } ptdescr = (pcsca_bd_t *)(card->hw.rambase + cpc_readl(&ptdescr->next)); } return (-1);}/* * dma_buf_write: writes a frame to the Tx DMA buffers * NOTE: this function writes one frame at a time. */int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len){ int i, nchar; volatile pcsca_bd_t *ptdescr; int tosend = len; ucchar nbuf = ((len - 1) / BD_DEF_LEN) + 1; if (nbuf >= card->chan[ch].nfree_tx_bd) { return -ENOMEM; } for (i = 0; i < nbuf; i++) { ptdescr = (pcsca_bd_t *) (card->hw.rambase + TX_BD_ADDR(ch, card->chan[ch].tx_next_bd)); nchar = cpc_min(BD_DEF_LEN, tosend); if (cpc_readb(&ptdescr->status) & DST_OSB) { memcpy_toio((void *)(card->hw.rambase + cpc_readl(&ptdescr->ptbuf)), &ptdata[len - tosend], nchar); cpc_writew(&ptdescr->len, nchar); card->chan[ch].nfree_tx_bd--; if ((i + 1) == nbuf) { /* This must be the last BD to be used */ cpc_writeb(&ptdescr->status, DST_EOM); } else { cpc_writeb(&ptdescr->status, 0); } } else { return -ENOMEM; } tosend -= nchar; card->chan[ch].tx_next_bd = (card->chan[ch].tx_next_bd + 1) & (N_DMA_TX_BUF - 1); } /* If it gets to here, it means we have sent the whole frame */ return 0;}/* * dma_buf_read: reads a frame from the Rx DMA buffers * NOTE: this function reads one frame at a time. */int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb){ int nchar; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; volatile pcsca_bd_t *ptdescr; int rcvd = 0; volatile ucchar status; ptdescr = (pcsca_bd_t *) (card->hw.rambase + RX_BD_ADDR(ch, chan->rx_first_bd)); while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { nchar = cpc_readw(&ptdescr->len); if ((status & (DST_OVR | DST_CRC | DST_RBIT | DST_SHRT | DST_ABT)) || (nchar > BD_DEF_LEN)) { if (nchar > BD_DEF_LEN) status |= DST_RBIT; rcvd = -status; /* Discard remaining descriptors used by the bad frame */ while (chan->rx_first_bd != chan->rx_last_bd) { cpc_writeb(&ptdescr->status, 0); chan->rx_first_bd = (chan->rx_first_bd+1) & (N_DMA_RX_BUF-1); if (status & DST_EOM) break; ptdescr = (pcsca_bd_t *) (card->hw.rambase + cpc_readl(&ptdescr->next)); status = cpc_readb(&ptdescr->status); } break; } if (nchar != 0) { if (skb) { memcpy_fromio(skb_put(skb, nchar), (void *)(card->hw.rambase+cpc_readl(&ptdescr->ptbuf)),nchar); } rcvd += nchar; } cpc_writeb(&ptdescr->status, 0); cpc_writeb(&ptdescr->len, 0); chan->rx_first_bd = (chan->rx_first_bd + 1) & (N_DMA_RX_BUF - 1); if (status & DST_EOM) break; ptdescr = (pcsca_bd_t *) (card->hw.rambase + cpc_readl(&ptdescr->next)); } if (rcvd != 0) { /* Update pointer */ chan->rx_last_bd = (chan->rx_first_bd - 1) & (N_DMA_RX_BUF - 1); /* Update EDA */ cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), RX_BD_ADDR(ch, chan->rx_last_bd)); } return (rcvd);}void tx_dma_stop(pc300_t * card, int ch){ uclong scabase = card->hw.scabase; ucchar drr_ena_bit = 1 << (5 + 2 * ch); ucchar drr_rst_bit = 1 << (1 + 2 * ch); /* Disable DMA */ cpc_writeb(scabase + DRR, drr_ena_bit); cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit);}void rx_dma_stop(pc300_t * card, int ch){ uclong scabase = card->hw.scabase; ucchar drr_ena_bit = 1 << (4 + 2 * ch); ucchar drr_rst_bit = 1 << (2 * ch); /* Disable DMA */ cpc_writeb(scabase + DRR, drr_ena_bit); cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit);}void rx_dma_start(pc300_t * card, int ch){ uclong scabase = card->hw.scabase; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; /* Start DMA */ cpc_writel(scabase + DRX_REG(CDAL, ch), RX_BD_ADDR(ch, chan->rx_first_bd)); if (cpc_readl(scabase + DRX_REG(CDAL,ch)) != RX_BD_ADDR(ch, chan->rx_first_bd)) { cpc_writel(scabase + DRX_REG(CDAL, ch), RX_BD_ADDR(ch, chan->rx_first_bd)); } cpc_writel(scabase + DRX_REG(EDAL, ch), RX_BD_ADDR(ch, chan->rx_last_bd)); cpc_writew(scabase + DRX_REG(BFLL, ch), BD_DEF_LEN); cpc_writeb(scabase + DSR_RX(ch), DSR_DE); if (!(cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) { cpc_writeb(scabase + DSR_RX(ch), DSR_DE); }}/*************************//*** FALC Routines ***//*************************/void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd){ uclong falcbase = card->hw.falcbase; unsigned long i = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -