Commit ca5589cd authored by François Romieu's avatar François Romieu Committed by Linus Torvalds

[PATCH] 2.4.8 - dscc4 update 12/13

- just say no to +/-1 arithmetic when not needed;
- pot-pourri of misc cleanup;
- *new*: support of boot-time parameters
parent bb42d290
...@@ -392,7 +392,7 @@ static inline void dscc4_do_tx(struct dscc4_dev_priv *dpriv, ...@@ -392,7 +392,7 @@ static inline void dscc4_do_tx(struct dscc4_dev_priv *dpriv,
struct net_device *dev) struct net_device *dev)
{ {
dpriv->ltda = dpriv->tx_fd_dma + 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); writel(dpriv->ltda, dev->base_addr + CH0LTDA + dpriv->dev_id*4);
/* Flush posted writes *NOW* */ /* Flush posted writes *NOW* */
readl(dev->base_addr + CH0LTDA + dpriv->dev_id*4); readl(dev->base_addr + CH0LTDA + dpriv->dev_id*4);
...@@ -408,7 +408,7 @@ static inline void dscc4_rx_update(struct dscc4_dev_priv *dpriv, ...@@ -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) 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, 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, ...@@ -437,6 +437,13 @@ int state_check(u32 state, struct dscc4_dev_priv *dpriv, struct net_device *dev,
return ret; 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) static void dscc4_release_ring(struct dscc4_dev_priv *dpriv)
{ {
struct pci_dev *pdev = dpriv->pci_priv->pdev; struct pci_dev *pdev = dpriv->pci_priv->pdev;
...@@ -445,10 +452,8 @@ static void dscc4_release_ring(struct dscc4_dev_priv *dpriv) ...@@ -445,10 +452,8 @@ static void dscc4_release_ring(struct dscc4_dev_priv *dpriv)
struct sk_buff **skbuff; struct sk_buff **skbuff;
int i; int i;
pci_free_consistent(pdev, TX_RING_SIZE*sizeof(struct TxFD), tx_fd, pci_free_consistent(pdev, TX_TOTAL_SIZE, tx_fd, dpriv->tx_fd_dma);
dpriv->tx_fd_dma); pci_free_consistent(pdev, RX_TOTAL_SIZE, rx_fd, dpriv->rx_fd_dma);
pci_free_consistent(pdev, RX_RING_SIZE*sizeof(struct RxFD), rx_fd,
dpriv->rx_fd_dma);
skbuff = dpriv->tx_skbuff; skbuff = dpriv->tx_skbuff;
for (i = 0; i < TX_RING_SIZE; i++) { for (i = 0; i < TX_RING_SIZE; i++) {
...@@ -928,7 +933,7 @@ static int dscc4_open(struct net_device *dev) ...@@ -928,7 +933,7 @@ static int dscc4_open(struct net_device *dev)
ppriv = dpriv->pci_priv; ppriv = dpriv->pci_priv;
if (dscc4_init_ring(dev)) if ((ret = dscc4_init_ring(dev)))
goto err_out; goto err_out;
/* IDT+IDR during XPR */ /* IDT+IDR during XPR */
...@@ -943,14 +948,15 @@ static int dscc4_open(struct net_device *dev) ...@@ -943,14 +948,15 @@ static int dscc4_open(struct net_device *dev)
*/ */
if (scc_readl_star(dpriv, dev) & SccBusy) { if (scc_readl_star(dpriv, dev) & SccBusy) {
printk(KERN_ERR "%s busy. Try later\n", dev->name); printk(KERN_ERR "%s busy. Try later\n", dev->name);
ret = -EAGAIN;
goto err_free_ring; goto err_free_ring;
} else } else
printk(KERN_INFO "%s: available. Good\n", dev->name); 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); 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; goto err_free_ring;
/* /*
...@@ -960,11 +966,14 @@ static int dscc4_open(struct net_device *dev) ...@@ -960,11 +966,14 @@ static int dscc4_open(struct net_device *dev)
* WARNING, a really missing XPR usually means a hardware * WARNING, a really missing XPR usually means a hardware
* reset is needed. Suggestions anyone ? * 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"); printk(KERN_ERR "%s: %s timeout\n", DRV_NAME, "XPR");
goto err_free_ring; goto err_free_ring;
} }
if (debug > 2)
dscc4_tx_print(dev, dpriv, "Open");
netif_start_queue(dev); netif_start_queue(dev);
init_timer(&dpriv->timer); init_timer(&dpriv->timer);
...@@ -999,7 +1008,7 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -999,7 +1008,7 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct TxFD *tx_fd; struct TxFD *tx_fd;
int next; int next;
next = (dpriv->tx_current+1)%TX_RING_SIZE; next = dpriv->tx_current%TX_RING_SIZE;
dpriv->tx_skbuff[next] = skb; dpriv->tx_skbuff[next] = skb;
tx_fd = dpriv->tx_fd + next; tx_fd = dpriv->tx_fd + next;
tx_fd->state = FrameEnd | TO_STATE(skb->len); 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) ...@@ -1017,8 +1026,10 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies; dev->trans_start = jiffies;
if (debug > 2)
dscc4_tx_print(dev, dpriv, "Xmit");
/* To be cleaned(unsigned int)/optimized. Later, ok ? */ /* 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); netif_stop_queue(dev);
if (dscc4_tx_quiescent(dpriv, dev)) if (dscc4_tx_quiescent(dpriv, dev))
...@@ -1310,8 +1321,8 @@ static void dscc4_irq(int irq, void *token, struct pt_regs *ptregs) ...@@ -1310,8 +1321,8 @@ static void dscc4_irq(int irq, void *token, struct pt_regs *ptregs)
} }
state &= ~ArAck; state &= ~ArAck;
if (state & Cfg) { if (state & Cfg) {
if (debug) if (debug > 0)
printk(KERN_DEBUG "CfgIV\n"); printk(KERN_DEBUG "%s: CfgIV\n", DRV_NAME);
if (priv->iqcfg[priv->cfg_cur++%IRQ_RING_SIZE] & Arf) if (priv->iqcfg[priv->cfg_cur++%IRQ_RING_SIZE] & Arf)
printk(KERN_ERR "%s: %s failed\n", dev->name, "CFG"); printk(KERN_ERR "%s: %s failed\n", dev->name, "CFG");
if (!(state &= ~Cfg)) if (!(state &= ~Cfg))
...@@ -1349,14 +1360,12 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, ...@@ -1349,14 +1360,12 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv,
if ((debug > 1) && (loop > 1)) if ((debug > 1) && (loop > 1))
printk(KERN_DEBUG "%s: Tx irq loop=%d\n", dev->name, loop); printk(KERN_DEBUG "%s: Tx irq loop=%d\n", dev->name, loop);
if (loop && netif_queue_stopped(dev)) 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); netif_wake_queue(dev);
if (netif_running(dev) && dscc4_tx_quiescent(dpriv, dev) && if (netif_running(dev) && dscc4_tx_quiescent(dpriv, dev) &&
!dscc4_tx_done(dpriv)) { !dscc4_tx_done(dpriv))
dscc4_do_tx(dpriv, dev); dscc4_do_tx(dpriv, dev);
printk(KERN_INFO "%s: re-enabled\n", dev->name);
}
return; return;
} }
loop++; loop++;
...@@ -1372,6 +1381,8 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, ...@@ -1372,6 +1381,8 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv,
struct sk_buff *skb; struct sk_buff *skb;
struct TxFD *tx_fd; struct TxFD *tx_fd;
if (debug > 2)
dscc4_tx_print(dev, dpriv, "Alls");
/* /*
* DataComplete can't be trusted for Tx completion. * DataComplete can't be trusted for Tx completion.
* Cf errata DS5 p.8 * Cf errata DS5 p.8
...@@ -1438,6 +1449,8 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, ...@@ -1438,6 +1449,8 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv,
scc_addr = dev->base_addr + 0x0c*dpriv->dev_id; scc_addr = dev->base_addr + 0x0c*dpriv->dev_id;
/* Keep this order: IDT before IDR */ /* Keep this order: IDT before IDR */
if (dpriv->flags & NeedIDT) { if (dpriv->flags & NeedIDT) {
if (debug > 2)
dscc4_tx_print(dev, dpriv, "Xpr");
ring = dpriv->tx_fd_dma + ring = dpriv->tx_fd_dma +
(dpriv->tx_dirty%TX_RING_SIZE)* (dpriv->tx_dirty%TX_RING_SIZE)*
sizeof(struct TxFD); sizeof(struct TxFD);
...@@ -1622,7 +1635,7 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv, ...@@ -1622,7 +1635,7 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv,
dscc4_rx_skb(dpriv, dev); dscc4_rx_skb(dpriv, dev);
} while (1); } while (1);
if (debug) { if (debug > 0) {
if (dpriv->flags & RdoSet) if (dpriv->flags & RdoSet)
printk(KERN_DEBUG printk(KERN_DEBUG
"%s: no RDO in Rx data\n", DRV_NAME); "%s: no RDO in Rx data\n", DRV_NAME);
...@@ -1665,61 +1678,70 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv, ...@@ -1665,61 +1678,70 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv,
} }
} }
/*
* 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) static int dscc4_init_ring(struct net_device *dev)
{ {
struct dscc4_dev_priv *dpriv = dscc4_priv(dev); struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
struct pci_dev *pdev = dpriv->pci_priv->pdev;
struct TxFD *tx_fd; struct TxFD *tx_fd;
struct RxFD *rx_fd; struct RxFD *rx_fd;
void *ring;
int i; int i;
tx_fd = (struct TxFD *) pci_alloc_consistent(dpriv->pci_priv->pdev, ring = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &dpriv->rx_fd_dma);
TX_RING_SIZE*sizeof(*tx_fd), &dpriv->tx_fd_dma); if (!ring)
if (!tx_fd)
goto err_out; goto err_out;
rx_fd = (struct RxFD *) pci_alloc_consistent(dpriv->pci_priv->pdev, dpriv->rx_fd = rx_fd = (struct RxFD *) ring;
RX_RING_SIZE*sizeof(*rx_fd), &dpriv->rx_fd_dma);
if (!rx_fd)
goto err_free_dma_tx;
dpriv->tx_fd = tx_fd; ring = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &dpriv->tx_fd_dma);
dpriv->rx_fd = rx_fd; 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 { do {
tx_fd->state = FrameEnd | TO_STATE(2*DUMMY_SKB_SIZE); tx_fd->state = FrameEnd | TO_STATE(2*DUMMY_SKB_SIZE);
tx_fd->complete = 0x00000000; tx_fd->complete = 0x00000000;
/* FIXME: NULL should be ok - to be tried */ /* FIXME: NULL should be ok - to be tried */
tx_fd->data = dpriv->tx_fd_dma; tx_fd->data = dpriv->tx_fd_dma;
dpriv->tx_skbuff[i] = NULL;
(tx_fd++)->next = (u32)(dpriv->tx_fd_dma + (tx_fd++)->next = (u32)(dpriv->tx_fd_dma +
(++i%TX_RING_SIZE)*sizeof(*tx_fd)); (++i%TX_RING_SIZE)*sizeof(*tx_fd));
} while (i < TX_RING_SIZE); } while (i < TX_RING_SIZE);
{ if (dscc4_init_dummy_skb(dpriv) < 0)
/*
* 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)
goto err_free_dma_tx; goto err_free_dma_tx;
skb->len = DUMMY_SKB_SIZE;
memcpy(skb->data, version, strlen(version)%DUMMY_SKB_SIZE); memset(dpriv->rx_skbuff, 0, sizeof(struct sk_buff *)*RX_RING_SIZE);
tx_fd = dpriv->tx_fd; i = dpriv->rx_dirty = dpriv->rx_current = 0;
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;
do { do {
/* size set by the host. Multiple of 4 bytes please */ /* size set by the host. Multiple of 4 bytes please */
rx_fd->state1 = HiDesc; rx_fd->state1 = HiDesc;
...@@ -1736,10 +1758,11 @@ static int dscc4_init_ring(struct net_device *dev) ...@@ -1736,10 +1758,11 @@ static int dscc4_init_ring(struct net_device *dev)
return 0; return 0;
err_free_dma_tx: err_free_dma_tx:
pci_free_consistent(dpriv->pci_priv->pdev, TX_RING_SIZE*sizeof(*tx_fd), pci_free_consistent(pdev, TX_TOTAL_SIZE, ring, dpriv->tx_fd_dma);
tx_fd, dpriv->tx_fd_dma); err_free_dma_rx:
pci_free_consistent(pdev, RX_TOTAL_SIZE, rx_fd, dpriv->rx_fd_dma);
err_out: err_out:
return -1; return -ENOMEM;
} }
static void __exit dscc4_remove_one(struct pci_dev *pdev) 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, ...@@ -1805,6 +1828,17 @@ static int dscc4_hdlc_attach(hdlc_device *hdlc, unsigned short encoding,
return 0; 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 = { static struct pci_device_id dscc4_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_DSCC4, { PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_DSCC4,
PCI_ANY_ID, PCI_ANY_ID, }, PCI_ANY_ID, PCI_ANY_ID, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment