📄 dscc4.c
字号:
dev_id = dpriv->dev_id; writel(0x00050000, ioaddr + SCC_REG_START(dev_id) + CCR2); writel(MTFi|Rdr|Rdt, ioaddr + CH0CFG + dev_id*0x0c); /* Reset Rx/Tx */ writel(0x00000001, ioaddr + GCMDR); dscc4_release_ring(dpriv); MOD_DEC_USE_COUNT; return 0;}static int dscc4_set_clock(struct net_device *dev, u32 *bps, u32 *state){ struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv; u32 brr; *state &= ~Ccr0ClockMask; if (*bps) { /* DCE */ u32 n = 0, m = 0, divider; int xtal; xtal = dpriv->pci_priv->xtal_hz; if (!xtal) return -1; divider = xtal / *bps; if (divider > BRR_DIVIDER_MAX) { divider >>= 4; *state |= 0x00000036; /* Clock mode 6b (BRG/16) */ } else *state |= 0x00000037; /* Clock mode 7b (BRG) */ if (divider >> 22) { n = 63; m = 15; } else if (divider) { /* Extraction of the 6 highest weighted bits */ m = 0; while (0xffffffc0 & divider) { m++; divider >>= 1; } n = divider; } brr = (m << 8) | n; divider = n << m; if (!(*state & 0x00000001)) /* Clock mode 6b */ divider <<= 4; *bps = xtal / divider; } else { /* DTE */ /* * "state" already reflects Clock mode 0a. * Nothing more to be done */ brr = 0; } writel(brr, dev->base_addr + BRR + SCC_REG_START(dpriv->dev_id)); return 0;}#ifdef LATER_PLEASE/* * -*- [RFC] Configuring Synchronous Interfaces in Linux -*- */// FIXME: MEDIA already defined in linux/hdlc.h#define HDLC_MEDIA_V35 0#define HDLC_MEDIA_RS232 1#define HDLC_MEDIA_X21 2#define HDLC_MEDIA_E1 3#define HDLC_MEDIA_HSSI 4#define HDLC_CODING_NRZ 0#define HDLC_CODING_NRZI 1#define HDLC_CODING_FM0 2#define HDLC_CODING_FM1 3#define HDLC_CODING_MANCHESTER 4#define HDLC_CRC_NONE 0#define HDLC_CRC_16 1#define HDLC_CRC_32 2#define HDLC_CRC_CCITT 3/* RFC: add the crc reset value ? */struct hdlc_physical { u8 media; u8 coding; u32 rate; u8 crc; u8 crc_siz; /* 2 or 4 bytes */ u8 shared_flags; /* Discouraged on the DSCC4 */};// FIXME: PROTO already defined in linux/hdlc.h#define HDLC_PROTO_RAW 0#define HDLC_PROTO_FR 1#define HDLC_PROTO_X25 2#define HDLC_PROTO_PPP 3#define HDLC_PROTO_CHDLC 4struct hdlc_protocol { u8 proto; union { } u;};struct screq { u16 media_group; union { struct hdlc_physical hdlc_phy; struct hdlc_protocol hdlc_proto; } u;};// FIXME: go sub-module static struct { u16 coding; u16 bits;} map[] = { {HDLC_CODING_NRZ, 0x00}, {HDLC_CODING_NRZI, 0x20}, {HDLC_CODING_FM0, 0x40}, {HDLC_CODING_FM1, 0x50}, {HDLC_CODING_MANCHESTER, 0x60}, {65535, 0x00}};#endif /* LATER_PLEASE */static int dscc4_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ struct dscc4_dev_priv *dpriv = dev->priv; u32 state, ioaddr; if (dev->flags & IFF_UP) return -EBUSY; switch (cmd) { /* Set built-in quartz frequency */ case SIOCDEVPRIVATE: { u32 hz; hz = ifr->ifr_ifru.ifru_ivalue; if (hz >= 33000000) /* 33 MHz */ return -EOPNOTSUPP; dpriv->pci_priv->xtal_hz = hz; return 0; } /* Set/unset loopback */ case SIOCDEVPRIVATE+1: { u32 flags; ioaddr = dev->base_addr + CCR1 + SCC_REG_START(dpriv->dev_id); state = readl(ioaddr); flags = ifr->ifr_ifru.ifru_ivalue; if (flags & 0x00000001) { printk(KERN_DEBUG "%s: loopback\n", dev->name); state |= 0x00000100; } else { printk(KERN_DEBUG "%s: normal\n", dev->name); state &= ~0x00000100; } writel(state, ioaddr); return 0; }#ifdef LATER_PLEASE case SIOCDEVPRIVATE+2: { { struct screq scr; err = copy_from_user(&scr, ifr->ifr_ifru.ifru_data, sizeof(struct screq)); if (err) return err; do { if (scr.u.hdlc_phy.coding == map[i].coding) break; } while (map[++i].coding != 65535); if (!map[i].coding) return -EOPNOTSUPP; ioaddr = dev->base_addr + CCR0 + SCC_REG_START(dpriv->dev_id); state = readl(ioaddr) & ~EncodingMask; state |= (u32)map[i].bits << 16; writel(state, ioaddr); printk("state: %08x\n", state); /* DEBUG */ return 0; } case SIOCDEVPRIVATE+3: { struct screq *scr = (struct screq *)ifr->ifr_ifru.ifru_data; ioaddr = dev->base_addr + CCR0 + SCC_REG_START(dpriv->dev_id); state = (readl(ioaddr) & EncodingMask) >> 16; do { if (state == map[i].bits) break; } while (map[++i].coding); return put_user(map[i].coding, (u16 *)scr->u.hdlc_phy.coding); }#endif /* LATER_PLEASE */ case HDLCSCLOCKRATE: { u32 state, bps; bps = ifr->ifr_ifru.ifru_ivalue; ioaddr = dev->base_addr + CCR0 + SCC_REG_START(dpriv->dev_id); state = readl(ioaddr); if(dscc4_set_clock(dev, &bps, &state) < 0) return -EOPNOTSUPP; if (bps) { /* DCE */ printk(KERN_DEBUG "%s: generated RxClk (DCE)\n", dev->name); ifr->ifr_ifru.ifru_ivalue = bps; } else { /* DTE */ state = 0x80001000; printk(KERN_DEBUG "%s: external RxClk (DTE)\n", dev->name); } writel(state, ioaddr); return 0; } case HDLCGCLOCKRATE: { u32 brr; int bps; brr = readl(dev->base_addr + BRR + SCC_REG_START(dpriv->dev_id)); bps = dpriv->pci_priv->xtal_hz >> (brr >> 8); bps /= (brr & 0x3f) + 1; ifr->ifr_ifru.ifru_ivalue = bps; return 0; } default: return -EOPNOTSUPP; }}static int dscc4_change_mtu(struct net_device *dev, int mtu){ /* FIXME: chainsaw coded... */ if ((mtu <= 3) || (mtu > 65531)) return -EINVAL; if(dev->flags & IFF_UP) return -EBUSY; dev->mtu = mtu; return(0);}static void dscc4_irq(int irq, void *dev_instance, struct pt_regs *ptregs){ struct net_device *dev = dev_instance; struct dscc4_pci_priv *priv; u32 ioaddr, state; unsigned long flags; int i; priv = ((struct dscc4_dev_priv *)dev->priv)->pci_priv; /* * FIXME: shorten the protected area (set some bit telling we're * in an interrupt or increment some work-to-do counter etc...) */ spin_lock_irqsave(&priv->lock, flags); ioaddr = dev->base_addr; state = readl(ioaddr + GSTAR); if (!state) goto out; writel(state, ioaddr + GSTAR); if (state & Arf) { printk(KERN_ERR "%s: failure (Arf). Harass the maintener\n", dev->name); goto out; } state &= ~ArAck; if (state & Cfg) { if (debug) printk(KERN_DEBUG "CfgIV\n"); if (priv->iqcfg[priv->cfg_cur++%IRQ_RING_SIZE] & Arf) printk(KERN_ERR "%s: %s failed\n", dev->name, "CFG"); if (!(state &= ~Cfg)) goto out; } if (state & RxEvt) { i = dev_per_card - 1; do { dscc4_rx_irq(priv, dev + i); } while (--i >= 0); state &= ~RxEvt; } if (state & TxEvt) { i = dev_per_card - 1; do { dscc4_tx_irq(priv, dev + i); } while (--i >= 0); state &= ~TxEvt; }out: spin_unlock_irqrestore(&priv->lock, flags);}static __inline__ void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, struct net_device *dev){ struct dscc4_dev_priv *dpriv = dev->priv; u32 state; int cur, loop = 0;try: cur = dpriv->iqtx_current%IRQ_RING_SIZE; state = dpriv->iqtx[cur]; if (!state) {#ifdef DEBUG if (loop > 1) printk(KERN_DEBUG "%s: Tx irq loop=%d\n", dev->name, loop);#endif if (loop && netif_queue_stopped(dev)) if ((dpriv->tx_dirty + 8) >= dpriv->tx_current) netif_wake_queue(dev); return; } loop++; dpriv->iqtx[cur] = 0; dpriv->iqtx_current++;#ifdef DEBUG_PARANOID if (SOURCE_ID(state) != dpriv->dev_id) { printk(KERN_DEBUG "%s (Tx): Source Id=%d, state=%08x\n", dev->name, SOURCE_ID(state), state ); return; } if (state & 0x0df80c00) { printk(KERN_DEBUG "%s (Tx): state=%08x (UFO alert)\n", dev->name, state); return; }#endif // state &= 0x0fffffff; /* Tracking the analyzed bits */ if (state & SccEvt) { if (state & Alls) { struct TxFD *tx_fd; struct sk_buff *skb; cur = dpriv->tx_dirty%TX_RING_SIZE; tx_fd = dpriv->tx_fd + cur; skb = dpriv->tx_skbuff[cur]; /* XXX: hideous kludge - to be removed "later" */ if (!skb) { printk(KERN_ERR "%s: NULL skb in tx_irq at index %d\n", dev->name, cur); goto try; } dpriv->tx_dirty++; // MUST be after skb test /* Happens sometime. Don't know what triggers it */ if (!(tx_fd->complete & DataComplete)) { u32 ioaddr, isr; ioaddr = dev->base_addr + SCC_REG_START(dpriv->dev_id) + ISR; isr = readl(ioaddr); printk(KERN_DEBUG "%s: DataComplete=0 cur=%d isr=%08x state=%08x\n", dev->name, cur, isr, state); writel(isr, ioaddr); dpriv->stats.tx_dropped++; } else { tx_fd->complete &= ~DataComplete; if (tx_fd->state & FrameEnd) { dpriv->stats.tx_packets++; dpriv->stats.tx_bytes += skb->len; } } dpriv->tx_skbuff[cur] = NULL; pci_unmap_single(ppriv->pdev, tx_fd->data, skb->len, PCI_DMA_TODEVICE); tx_fd->data = 0; /* DEBUG */ dev_kfree_skb_irq(skb);{ // DEBUG cur = (dpriv->tx_dirty-1)%TX_RING_SIZE; tx_fd = dpriv->tx_fd + cur; tx_fd->state |= Hold;} if (!(state &= ~Alls)) goto try; } /* * Transmit Data Underrun */ if (state & Xdu) { printk(KERN_ERR "dscc4: XDU. Contact maintainer\n"); dpriv->flags = NeedIDT; /* Tx reset */ writel(MTFi | Rdt, dev->base_addr + 0x0c*dpriv->dev_id + CH0CFG); writel(0x00000001, dev->base_addr + GCMDR); return; } if (state & Xmr) { /* Frame needs to be sent again - FIXME */ //dscc4_start_xmit(dpriv->tx_skbuff[dpriv->tx_dirty], dev); if (!(state &= ~0x00002000)) /* DEBUG */ goto try; } if (state & Xpr) { unsigned long ioaddr = dev->base_addr; unsigned long scc_offset; u32 scc_addr; scc_offset = ioaddr + SCC_REG_START(dpriv->dev_id); scc_addr = ioaddr + 0x0c*dpriv->dev_id; if (readl(scc_offset + STAR) & SccBusy) printk(KERN_DEBUG "%s busy. Fatal\n", dev->name); /* * Keep this order: IDT before IDR */ if (dpriv->flags & NeedIDT) { writel(MTFi | Idt, scc_addr + CH0CFG); writel(dpriv->tx_fd_dma + (dpriv->tx_dirty%TX_RING_SIZE)* sizeof(struct TxFD), scc_addr + CH0BTDA); if(dscc4_do_action(dev, "IDT")) goto err_xpr; dpriv->flags &= ~NeedIDT; mb(); } if (dpriv->flags & NeedIDR) { writel(MTFi | Idr, scc_addr + CH0CFG); writel(dpriv->rx_fd_dma + (dpriv->rx_current%RX_RING_SIZE)* sizeof(struct RxFD), scc_addr + CH0BRDA);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -