diff options
| -rw-r--r-- | drivers/net/wan/dscc4.c | 148 |
1 files changed, 91 insertions, 57 deletions
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 023115c93cfc..7022a11fab9e 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -392,7 +392,7 @@ static inline void dscc4_do_tx(struct dscc4_dev_priv *dpriv, struct net_device *dev) { dpriv->ltda = dpriv->tx_fd_dma + - (dpriv->tx_current%TX_RING_SIZE)*sizeof(struct TxFD); + ((dpriv->tx_current-1)%TX_RING_SIZE)*sizeof(struct TxFD); writel(dpriv->ltda, dev->base_addr + CH0LTDA + dpriv->dev_id*4); /* Flush posted writes *NOW* */ readl(dev->base_addr + CH0LTDA + dpriv->dev_id*4); @@ -408,7 +408,7 @@ static inline void dscc4_rx_update(struct dscc4_dev_priv *dpriv, static inline unsigned int dscc4_tx_done(struct dscc4_dev_priv *dpriv) { - return (dpriv->tx_current + 1) == dpriv->tx_dirty; + return dpriv->tx_current == dpriv->tx_dirty; } static inline unsigned int dscc4_tx_quiescent(struct dscc4_dev_priv *dpriv, @@ -437,6 +437,13 @@ int state_check(u32 state, struct dscc4_dev_priv *dpriv, struct net_device *dev, return ret; } +void dscc4_tx_print(struct net_device *dev, struct dscc4_dev_priv *dpriv, + char *msg) +{ + printk(KERN_DEBUG "%s: tx_current=%02d tx_dirty=%02d (%s)\n", + dev->name, dpriv->tx_current, dpriv->tx_dirty, msg); +} + static void dscc4_release_ring(struct dscc4_dev_priv *dpriv) { struct pci_dev *pdev = dpriv->pci_priv->pdev; @@ -445,10 +452,8 @@ static void dscc4_release_ring(struct dscc4_dev_priv *dpriv) struct sk_buff **skbuff; int i; - pci_free_consistent(pdev, TX_RING_SIZE*sizeof(struct TxFD), tx_fd, - dpriv->tx_fd_dma); - pci_free_consistent(pdev, RX_RING_SIZE*sizeof(struct RxFD), rx_fd, - dpriv->rx_fd_dma); + pci_free_consistent(pdev, TX_TOTAL_SIZE, tx_fd, dpriv->tx_fd_dma); + pci_free_consistent(pdev, RX_TOTAL_SIZE, rx_fd, dpriv->rx_fd_dma); skbuff = dpriv->tx_skbuff; for (i = 0; i < TX_RING_SIZE; i++) { @@ -928,7 +933,7 @@ static int dscc4_open(struct net_device *dev) ppriv = dpriv->pci_priv; - if (dscc4_init_ring(dev)) + if ((ret = dscc4_init_ring(dev))) goto err_out; /* IDT+IDR during XPR */ @@ -943,14 +948,15 @@ static int dscc4_open(struct net_device *dev) */ if (scc_readl_star(dpriv, dev) & SccBusy) { printk(KERN_ERR "%s busy. Try later\n", dev->name); + ret = -EAGAIN; goto err_free_ring; } else printk(KERN_INFO "%s: available. Good\n", dev->name); - /* Posted write is flushed in the busy-waiting loop */ + /* Posted write is flushed in the wait_ack loop */ scc_writel(TxSccRes | RxSccRes, dpriv, dev, CMDR); - if (dscc4_wait_ack_cec(dpriv, dev, "Cec") < 0) + if ((ret = dscc4_wait_ack_cec(dpriv, dev, "Cec")) < 0) goto err_free_ring; /* @@ -960,11 +966,14 @@ static int dscc4_open(struct net_device *dev) * WARNING, a really missing XPR usually means a hardware * reset is needed. Suggestions anyone ? */ - if (dscc4_xpr_ack(dpriv) < 0) { + if ((ret = dscc4_xpr_ack(dpriv)) < 0) { printk(KERN_ERR "%s: %s timeout\n", DRV_NAME, "XPR"); goto err_free_ring; } + if (debug > 2) + dscc4_tx_print(dev, dpriv, "Open"); + netif_start_queue(dev); init_timer(&dpriv->timer); @@ -999,7 +1008,7 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev) struct TxFD *tx_fd; int next; - next = (dpriv->tx_current+1)%TX_RING_SIZE; + next = dpriv->tx_current%TX_RING_SIZE; dpriv->tx_skbuff[next] = skb; tx_fd = dpriv->tx_fd + next; tx_fd->state = FrameEnd | TO_STATE(skb->len); @@ -1017,8 +1026,10 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; + if (debug > 2) + dscc4_tx_print(dev, dpriv, "Xmit"); /* To be cleaned(unsigned int)/optimized. Later, ok ? */ - if ((++dpriv->tx_current - dpriv->tx_dirty) >= TX_HIGH) + if (!((++dpriv->tx_current - dpriv->tx_dirty)%TX_RING_SIZE)) netif_stop_queue(dev); if (dscc4_tx_quiescent(dpriv, dev)) @@ -1310,8 +1321,8 @@ static void dscc4_irq(int irq, void *token, struct pt_regs *ptregs) } state &= ~ArAck; if (state & Cfg) { - if (debug) - printk(KERN_DEBUG "CfgIV\n"); + if (debug > 0) + printk(KERN_DEBUG "%s: CfgIV\n", DRV_NAME); if (priv->iqcfg[priv->cfg_cur++%IRQ_RING_SIZE] & Arf) printk(KERN_ERR "%s: %s failed\n", dev->name, "CFG"); if (!(state &= ~Cfg)) @@ -1349,14 +1360,12 @@ try: if ((debug > 1) && (loop > 1)) printk(KERN_DEBUG "%s: Tx irq loop=%d\n", dev->name, loop); if (loop && netif_queue_stopped(dev)) - if ((dpriv->tx_current - dpriv->tx_dirty) <= TX_LOW) + if ((dpriv->tx_current - dpriv->tx_dirty)%TX_RING_SIZE) netif_wake_queue(dev); if (netif_running(dev) && dscc4_tx_quiescent(dpriv, dev) && - !dscc4_tx_done(dpriv)) { + !dscc4_tx_done(dpriv)) dscc4_do_tx(dpriv, dev); - printk(KERN_INFO "%s: re-enabled\n", dev->name); - } return; } loop++; @@ -1372,6 +1381,8 @@ try: struct sk_buff *skb; struct TxFD *tx_fd; + if (debug > 2) + dscc4_tx_print(dev, dpriv, "Alls"); /* * DataComplete can't be trusted for Tx completion. * Cf errata DS5 p.8 @@ -1438,6 +1449,8 @@ try: scc_addr = dev->base_addr + 0x0c*dpriv->dev_id; /* Keep this order: IDT before IDR */ if (dpriv->flags & NeedIDT) { + if (debug > 2) + dscc4_tx_print(dev, dpriv, "Xpr"); ring = dpriv->tx_fd_dma + (dpriv->tx_dirty%TX_RING_SIZE)* sizeof(struct TxFD); @@ -1622,7 +1635,7 @@ try: dscc4_rx_skb(dpriv, dev); } while (1); - if (debug) { + if (debug > 0) { if (dpriv->flags & RdoSet) printk(KERN_DEBUG "%s: no RDO in Rx data\n", DRV_NAME); @@ -1665,61 +1678,70 @@ try: } } +/* + * I had expected the following to work for the first descriptor + * (tx_fd->state = 0xc0000000) + * - Hold=1 (don't try and branch to the next descripto); + * - No=0 (I want an empty data section, i.e. size=0); + * - Fe=1 (required by No=0 or we got an Err irq and must reset). + * It failed and locked solid. Thus the introduction of a dummy skb. + * Problem is acknowledged in errata sheet DS5. Joy :o/ + */ +struct sk_buff *dscc4_init_dummy_skb(struct dscc4_dev_priv *dpriv) +{ + struct sk_buff *skb; + + skb = dev_alloc_skb(DUMMY_SKB_SIZE); + if (skb) { + int last = dpriv->tx_dirty%TX_RING_SIZE; + struct TxFD *tx_fd = dpriv->tx_fd + last; + + skb->len = DUMMY_SKB_SIZE; + memcpy(skb->data, version, strlen(version)%DUMMY_SKB_SIZE); + tx_fd->state = FrameEnd | TO_STATE(DUMMY_SKB_SIZE); + tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data, + DUMMY_SKB_SIZE, PCI_DMA_TODEVICE); + dpriv->tx_skbuff[last] = skb; + } + return skb; +} + static int dscc4_init_ring(struct net_device *dev) { struct dscc4_dev_priv *dpriv = dscc4_priv(dev); + struct pci_dev *pdev = dpriv->pci_priv->pdev; struct TxFD *tx_fd; struct RxFD *rx_fd; + void *ring; int i; - tx_fd = (struct TxFD *) pci_alloc_consistent(dpriv->pci_priv->pdev, - TX_RING_SIZE*sizeof(*tx_fd), &dpriv->tx_fd_dma); - if (!tx_fd) + ring = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &dpriv->rx_fd_dma); + if (!ring) goto err_out; - rx_fd = (struct RxFD *) pci_alloc_consistent(dpriv->pci_priv->pdev, - RX_RING_SIZE*sizeof(*rx_fd), &dpriv->rx_fd_dma); - if (!rx_fd) - goto err_free_dma_tx; + dpriv->rx_fd = rx_fd = (struct RxFD *) ring; - dpriv->tx_fd = tx_fd; - dpriv->rx_fd = rx_fd; + ring = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &dpriv->tx_fd_dma); + if (!ring) + goto err_free_dma_rx; + dpriv->tx_fd = tx_fd = (struct TxFD *) ring; - i = 0; + memset(dpriv->tx_skbuff, 0, sizeof(struct sk_buff *)*TX_RING_SIZE); + dpriv->tx_dirty = 0xffffffff; + i = dpriv->tx_current = 0; do { tx_fd->state = FrameEnd | TO_STATE(2*DUMMY_SKB_SIZE); tx_fd->complete = 0x00000000; /* FIXME: NULL should be ok - to be tried */ tx_fd->data = dpriv->tx_fd_dma; - dpriv->tx_skbuff[i] = NULL; (tx_fd++)->next = (u32)(dpriv->tx_fd_dma + (++i%TX_RING_SIZE)*sizeof(*tx_fd)); } while (i < TX_RING_SIZE); -{ - /* - * XXX: I would expect the following to work for the first descriptor - * (tx_fd->state = 0xc0000000) - * - Hold=1 (don't try and branch to the next descripto); - * - No=0 (I want an empty data section, i.e. size=0); - * - Fe=1 (required by No=0 or we got an Err irq and must reset). - * Alas, it fails (and locks solid). Thus the introduction of a dummy - * skb to avoid No=0 (choose one: Ugly [ ] Tasteless [ ] VMS [ ]). - * 2002/01: errata sheet acknowledges the problem [X]. - */ - struct sk_buff *skb; - - skb = dev_alloc_skb(DUMMY_SKB_SIZE); - if (!skb) + if (dscc4_init_dummy_skb(dpriv) < 0) goto err_free_dma_tx; - skb->len = DUMMY_SKB_SIZE; - memcpy(skb->data, version, strlen(version)%DUMMY_SKB_SIZE); - tx_fd = dpriv->tx_fd; - tx_fd->state = FrameEnd | TO_STATE(DUMMY_SKB_SIZE); - tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data, - DUMMY_SKB_SIZE, PCI_DMA_TODEVICE); - dpriv->tx_skbuff[0] = skb; -} - i = 0; + + memset(dpriv->rx_skbuff, 0, sizeof(struct sk_buff *)*RX_RING_SIZE); + i = dpriv->rx_dirty = dpriv->rx_current = 0; do { /* size set by the host. Multiple of 4 bytes please */ rx_fd->state1 = HiDesc; @@ -1736,10 +1758,11 @@ static int dscc4_init_ring(struct net_device *dev) return 0; err_free_dma_tx: - pci_free_consistent(dpriv->pci_priv->pdev, TX_RING_SIZE*sizeof(*tx_fd), - tx_fd, dpriv->tx_fd_dma); + pci_free_consistent(pdev, TX_TOTAL_SIZE, ring, dpriv->tx_fd_dma); +err_free_dma_rx: + pci_free_consistent(pdev, RX_TOTAL_SIZE, rx_fd, dpriv->rx_fd_dma); err_out: - return -1; + return -ENOMEM; } static void __exit dscc4_remove_one(struct pci_dev *pdev) @@ -1805,6 +1828,17 @@ static int dscc4_hdlc_attach(hdlc_device *hdlc, unsigned short encoding, return 0; } +static int __init dscc4_setup(char *str) +{ + int *args[] = { &debug, &quartz, NULL }, **p = args; + + while (*p && (get_option(&str, *p) == 2)) + p++; + return 1; +} + +__setup("dscc4.setup=", dscc4_setup); + static struct pci_device_id dscc4_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_DSCC4, PCI_ANY_ID, PCI_ANY_ID, }, |
