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

[PATCH] 2.4.8 - dscc4 update 9/13

- useless code/comment removal;
- HOLD mode -> LxDA mode conversion.
parent 8bc9f530
...@@ -155,14 +155,11 @@ struct RxFD { ...@@ -155,14 +155,11 @@ struct RxFD {
#define CONFIG_DSCC4_DEBUG #define CONFIG_DSCC4_DEBUG
#define DUMMY_SKB_SIZE 64 #define DUMMY_SKB_SIZE 64
/*
* FIXME: TX_HIGH very different from TX_RING_SIZE doesn't make much sense
* for LxDA mode.
*/
#define TX_LOW 8 #define TX_LOW 8
#define TX_HIGH 16
#define TX_RING_SIZE 32 #define TX_RING_SIZE 32
#define RX_RING_SIZE 32 #define RX_RING_SIZE 32
#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct TxFD)
#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct RxFD)
#define IRQ_RING_SIZE 64 /* Keep it a multiple of 32 */ #define IRQ_RING_SIZE 64 /* Keep it a multiple of 32 */
#define TX_TIMEOUT (HZ/10) #define TX_TIMEOUT (HZ/10)
#define DSCC4_HZ_MAX 33000000 #define DSCC4_HZ_MAX 33000000
...@@ -572,6 +569,7 @@ static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv) ...@@ -572,6 +569,7 @@ static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv)
return (i >= 0 ) ? i : -EAGAIN; return (i >= 0 ) ? i : -EAGAIN;
} }
/* Requires protection against interrupt */
static void dscc4_rx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev) static void dscc4_rx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev)
{ {
/* Cf errata DS5 p.6 */ /* Cf errata DS5 p.6 */
...@@ -702,8 +700,8 @@ static int __init dscc4_init_one(struct pci_dev *pdev, ...@@ -702,8 +700,8 @@ static int __init dscc4_init_one(struct pci_dev *pdev,
goto err_out_iounmap; goto err_out_iounmap;
} }
/* power up/little endian/dma core controlled via hold bit */ /* power up/little endian/dma core controlled via lrda/ltda */
writel(0x00000000, ioaddr + GMODE); writel(0x00000001, ioaddr + GMODE);
/* Shared interrupt queue */ /* Shared interrupt queue */
{ {
u32 bits; u32 bits;
...@@ -1046,13 +1044,12 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1046,13 +1044,12 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct dscc4_dev_priv *dpriv = dscc4_priv(dev); struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
struct dscc4_pci_priv *ppriv = dpriv->pci_priv; struct dscc4_pci_priv *ppriv = dpriv->pci_priv;
struct TxFD *tx_fd; struct TxFD *tx_fd;
int cur, next; int next;
cur = dpriv->tx_current++%TX_RING_SIZE; 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 | Hold | TO_STATE(skb->len); tx_fd->state = FrameEnd | TO_STATE(skb->len);
tx_fd->data = pci_map_single(ppriv->pdev, skb->data, skb->len, tx_fd->data = pci_map_single(ppriv->pdev, skb->data, skb->len,
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
tx_fd->complete = 0x00000000; tx_fd->complete = 0x00000000;
...@@ -1064,48 +1061,34 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1064,48 +1061,34 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
while (dscc4_tx_poll(dpriv, dev)); while (dscc4_tx_poll(dpriv, dev));
spin_unlock(&dpriv->lock); spin_unlock(&dpriv->lock);
#endif #endif
/*
* I know there's a window for a race in the following lines but
* dscc4_timer will take good care of it. The chipset eats events
* (especially the net_dev re-enabling ones) thus there is no
* reason to try and be smart.
*/
if ((dpriv->tx_dirty + 16) < dpriv->tx_current)
netif_stop_queue(dev);
tx_fd = dpriv->tx_fd + cur;
tx_fd->state &= ~Hold;
mb(); // FIXME: suppress ?
/*
* One may avoid some pci transactions during intense TX periods.
* Not sure it's worth the pain...
*/
writel((TxPollCmd << dpriv->dev_id) | NoAck, dev->base_addr + GCMDR);
dev->trans_start = jiffies; dev->trans_start = jiffies;
/* To be cleaned(unsigned int)/optimized. Later, ok ? */
if ((++dpriv->tx_current - dpriv->tx_dirty) >= TX_HIGH)
netif_stop_queue(dev);
if (dscc4_tx_quiescent(dpriv, dev))
dscc4_do_tx(dpriv, dev);
return 0; return 0;
} }
static int dscc4_close(struct net_device *dev) static int dscc4_close(struct net_device *dev)
{ {
struct dscc4_dev_priv *dpriv = dscc4_priv(dev); struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
u32 ioaddr = dev->base_addr;
int dev_id;
hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_device *hdlc = dev_to_hdlc(dev);
unsigned long flags;
del_timer_sync(&dpriv->timer); del_timer_sync(&dpriv->timer);
netif_stop_queue(dev); netif_stop_queue(dev);
dev_id = dpriv->dev_id; spin_lock_irqsave(&dpriv->pci_priv->lock, flags);
dscc4_rx_reset(dpriv, dev);
spin_unlock_irqrestore(&dpriv->pci_priv->lock, flags);
writel(0x00050000, ioaddr + SCC_REG_START(dpriv) + CCR2); dscc4_tx_reset(dpriv, dev);
writel(MTFi|Rdr|Rdt, ioaddr + CH0CFG + dev_id*0x0c); /* Reset Rx/Tx */
writel(0x00000001, ioaddr + GCMDR);
readl(ioaddr + GCMDR);
/*
* FIXME: wait for the command ack before returning the memory
* structures to the kernel.
*/
hdlc_close(hdlc); hdlc_close(hdlc);
dscc4_release_ring(dpriv); dscc4_release_ring(dpriv);
...@@ -1415,8 +1398,14 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, ...@@ -1415,8 +1398,14 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv,
printk(KERN_DEBUG "%s: Tx irq loop=%d\n", dev->name, loop); printk(KERN_DEBUG "%s: Tx irq loop=%d\n", dev->name, loop);
#endif #endif
if (loop && netif_queue_stopped(dev)) if (loop && netif_queue_stopped(dev))
if ((dpriv->tx_dirty + 8) >= dpriv->tx_current) if ((dpriv->tx_current - dpriv->tx_dirty) <= TX_LOW)
netif_wake_queue(dev); netif_wake_queue(dev);
if (netif_running(dev) && dscc4_tx_quiescent(dpriv, dev) &&
!dscc4_tx_done(dpriv)) {
dscc4_do_tx(dpriv, dev);
printk(KERN_INFO "%s: re-enabled\n", dev->name);
}
return; return;
} }
loop++; loop++;
...@@ -1428,51 +1417,42 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, ...@@ -1428,51 +1417,42 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv,
if (state & SccEvt) { if (state & SccEvt) {
if (state & Alls) { if (state & Alls) {
struct TxFD *tx_fd; struct net_device_stats *stats = &dpriv->hdlc.stats;
struct sk_buff *skb; struct sk_buff *skb;
struct TxFD *tx_fd;
/*
* DataComplete can't be trusted for Tx completion.
* Cf errata DS5 p.8
*/
cur = dpriv->tx_dirty%TX_RING_SIZE; cur = dpriv->tx_dirty%TX_RING_SIZE;
tx_fd = dpriv->tx_fd + cur; tx_fd = dpriv->tx_fd + cur;
skb = dpriv->tx_skbuff[cur]; skb = dpriv->tx_skbuff[cur];
if (skb) {
/* XXX: hideous kludge - to be removed "later" */ pci_unmap_single(ppriv->pdev, tx_fd->data,
if (!skb) { skb->len, PCI_DMA_TODEVICE);
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) + 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);
dev_to_hdlc(dev)->stats.tx_dropped++;
} else {
tx_fd->complete &= ~DataComplete;
if (tx_fd->state & FrameEnd) { if (tx_fd->state & FrameEnd) {
dev_to_hdlc(dev)->stats.tx_packets++; stats->tx_packets++;
dev_to_hdlc(dev)->stats.tx_bytes += skb->len; stats->tx_bytes += skb->len;
} }
dev_kfree_skb_irq(skb);
dpriv->tx_skbuff[cur] = NULL;
++dpriv->tx_dirty;
} else {
if (debug > 1)
printk(KERN_ERR "%s Tx: NULL skb %d\n",
dev->name, cur);
} }
/*
* If the driver ends sending crap on the wire, it
* will be way easier to diagnose than the (not so)
* random freeze induced by null sized tx frames.
*/
tx_fd->data = tx_fd->next;
tx_fd->state = FrameEnd | TO_STATE(2*DUMMY_SKB_SIZE);
tx_fd->complete = 0x00000000;
tx_fd->jiffies = 0;
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)) if (!(state &= ~Alls))
goto try; goto try;
} }
...@@ -1495,37 +1475,34 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, ...@@ -1495,37 +1475,34 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv,
goto try; goto try;
} }
if (state & Xpr) { if (state & Xpr) {
unsigned long ioaddr = dev->base_addr; u32 scc_addr, ring;
unsigned long scc_offset;
u32 scc_addr;
scc_offset = ioaddr + SCC_REG_START(dpriv); if (scc_readl_star(dpriv, dev) & SccBusy)
scc_addr = ioaddr + 0x0c*dpriv->dev_id; printk(KERN_ERR "%s busy. Fatal\n", dev->name);
if (readl(scc_offset + STAR) & SccBusy) scc_addr = dev->base_addr + 0x0c*dpriv->dev_id;
printk(KERN_DEBUG "%s busy. Fatal\n", /* Keep this order: IDT before IDR */
dev->name);
/*
* Keep this order: IDT before IDR
*/
if (dpriv->flags & NeedIDT) { if (dpriv->flags & NeedIDT) {
writel(MTFi | Idt, scc_addr + CH0CFG); ring = dpriv->tx_fd_dma +
writel(dpriv->tx_fd_dma +
(dpriv->tx_dirty%TX_RING_SIZE)* (dpriv->tx_dirty%TX_RING_SIZE)*
sizeof(struct TxFD), scc_addr + CH0BTDA); sizeof(struct TxFD);
writel(ring, scc_addr + CH0BTDA);
dscc4_do_tx(dpriv, dev);
writel(MTFi | Idt, scc_addr + CH0CFG);
if (dscc4_do_action(dev, "IDT") < 0) if (dscc4_do_action(dev, "IDT") < 0)
goto err_xpr; goto err_xpr;
dpriv->flags &= ~NeedIDT; dpriv->flags &= ~NeedIDT;
mb();
} }
if (dpriv->flags & NeedIDR) { if (dpriv->flags & NeedIDR) {
writel(MTFi | Idr, scc_addr + CH0CFG); ring = dpriv->rx_fd_dma +
writel(dpriv->rx_fd_dma +
(dpriv->rx_current%RX_RING_SIZE)* (dpriv->rx_current%RX_RING_SIZE)*
sizeof(struct RxFD), scc_addr + CH0BRDA); sizeof(struct RxFD);
writel(ring, scc_addr + CH0BRDA);
dscc4_rx_update(dpriv, dev);
writel(MTFi | Idr, scc_addr + CH0CFG);
if (dscc4_do_action(dev, "IDR") < 0) if (dscc4_do_action(dev, "IDR") < 0)
goto err_xpr; goto err_xpr;
dpriv->flags &= ~NeedIDR; dpriv->flags &= ~NeedIDR;
mb(); smp_wmb();
/* Activate receiver and misc */ /* Activate receiver and misc */
scc_writel(0x08050008, dpriv, dev, CCR2); scc_writel(0x08050008, dpriv, dev, CCR2);
} }
...@@ -1538,13 +1515,11 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, ...@@ -1538,13 +1515,11 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv,
#ifdef DSCC4_POLLING #ifdef DSCC4_POLLING
while (!dscc4_tx_poll(dpriv, dev)); while (!dscc4_tx_poll(dpriv, dev));
#endif #endif
printk(KERN_INFO "%s: Tx Hi\n", dev->name);
state &= ~Hi; state &= ~Hi;
} }
/*
* FIXME: it may be avoided. Re-re-re-read the manual.
*/
if (state & Err) { if (state & Err) {
printk(KERN_ERR "%s (Tx): ERR\n", dev->name); printk(KERN_INFO "%s: Tx ERR\n", dev->name);
dev_to_hdlc(dev)->stats.tx_errors++; dev_to_hdlc(dev)->stats.tx_errors++;
state &= ~Err; state &= ~Err;
} }
...@@ -1575,8 +1550,8 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv, ...@@ -1575,8 +1550,8 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv,
state &= 0x00ffffff; state &= 0x00ffffff;
if (state & Err) { /* Hold or reset */ if (state & Err) { /* Hold or reset */
printk(KERN_DEBUG "%s (Rx): ERR\n", dev->name); printk(KERN_DEBUG "%s: Rx ERR\n", dev->name);
cur = dpriv->rx_current; cur = dpriv->rx_current%RX_RING_SIZE;
rx_fd = dpriv->rx_fd + cur; rx_fd = dpriv->rx_fd + cur;
/* /*
* Presume we're not facing a DMAC receiver reset. * Presume we're not facing a DMAC receiver reset.
...@@ -1617,7 +1592,7 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv, ...@@ -1617,7 +1592,7 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv,
} }
} else { /* ! SccEvt */ } else { /* ! SccEvt */
if (debug > 1) { if (debug > 1) {
//FIXME: verifier la presence de tous les evts + indent //FIXME: verifier la presence de tous les evenements
static struct { static struct {
u32 mask; u32 mask;
const char *irq_name; const char *irq_name;
...@@ -1631,11 +1606,10 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv, ...@@ -1631,11 +1606,10 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv,
{ 0, NULL} { 0, NULL}
}, *evt; }, *evt;
state &= 0x00ffffff;
for (evt = evts; evt->irq_name; evt++) { for (evt = evts; evt->irq_name; evt++) {
if (state & evt->mask) { if (state & evt->mask) {
printk(KERN_DEBUG "%s: %s\n", dev->name, printk(KERN_DEBUG "%s: %s\n",
evt->irq_name); dev->name, evt->irq_name);
if (!(state &= ~evt->mask)) if (!(state &= ~evt->mask))
goto try; goto try;
} }
...@@ -1648,18 +1622,15 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv, ...@@ -1648,18 +1622,15 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv,
* Receive Data Overflow (FIXME: fscked) * Receive Data Overflow (FIXME: fscked)
*/ */
if (state & Rdo) { if (state & Rdo) {
u32 ioaddr, scc_offset, scc_addr;
struct RxFD *rx_fd; struct RxFD *rx_fd;
u32 scc_addr;
int cur; int cur;
//if (debug) //if (debug)
// dscc4_rx_dump(dpriv); // dscc4_rx_dump(dpriv);
ioaddr = dev->base_addr; scc_addr = dev->base_addr + 0x0c*dpriv->dev_id;
scc_addr = ioaddr + 0x0c*dpriv->dev_id;
scc_offset = ioaddr + SCC_REG_START(dpriv);
writel(readl(scc_offset + CCR2) & ~RxActivate, scc_patchl(RxActivate, 0, dpriv, dev, CCR2);
scc_offset + CCR2);
/* /*
* This has no effect. Why ? * This has no effect. Why ?
* ORed with TxSccRes, one sees the CFG ack (for * ORed with TxSccRes, one sees the CFG ack (for
...@@ -1696,6 +1667,7 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv, ...@@ -1696,6 +1667,7 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv,
/* /*
* FIXME: must the reset be this violent ? * FIXME: must the reset be this violent ?
*/ */
#warning "FIXME: CH0BRDA"
writel(dpriv->rx_fd_dma + writel(dpriv->rx_fd_dma +
(dpriv->rx_current%RX_RING_SIZE)* (dpriv->rx_current%RX_RING_SIZE)*
sizeof(struct RxFD), scc_addr + CH0BRDA); sizeof(struct RxFD), scc_addr + CH0BRDA);
...@@ -1751,21 +1723,18 @@ static int dscc4_init_ring(struct net_device *dev) ...@@ -1751,21 +1723,18 @@ static int dscc4_init_ring(struct net_device *dev)
dpriv->tx_fd = tx_fd; dpriv->tx_fd = tx_fd;
dpriv->rx_fd = rx_fd; dpriv->rx_fd = rx_fd;
dpriv->rx_current = 0;
dpriv->tx_current = 0;
dpriv->tx_dirty = 0;
/* the dma core of the dscc4 will be locked on the first desc */ i = 0;
for (i = 0; i < TX_RING_SIZE; ) { do {
reset_TxFD(tx_fd); tx_fd->state = FrameEnd | TO_STATE(2*DUMMY_SKB_SIZE);
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; dpriv->tx_skbuff[i] = NULL;
i++; (tx_fd++)->next = (u32)(dpriv->tx_fd_dma +
tx_fd->next = (u32)(dpriv->tx_fd_dma + i*sizeof(struct TxFD)); (++i%TX_RING_SIZE)*sizeof(*tx_fd));
tx_fd++; } while (i < TX_RING_SIZE);
}
(--tx_fd)->next = (u32)dpriv->tx_fd_dma;
{ {
/* /*
* XXX: I would expect the following to work for the first descriptor * XXX: I would expect the following to work for the first descriptor
...@@ -1784,27 +1753,25 @@ static int dscc4_init_ring(struct net_device *dev) ...@@ -1784,27 +1753,25 @@ static int dscc4_init_ring(struct net_device *dev)
goto err_free_dma_tx; goto err_free_dma_tx;
skb->len = DUMMY_SKB_SIZE; skb->len = DUMMY_SKB_SIZE;
memcpy(skb->data, version, strlen(version)%DUMMY_SKB_SIZE); memcpy(skb->data, version, strlen(version)%DUMMY_SKB_SIZE);
tx_fd -= (TX_RING_SIZE - 1); tx_fd = dpriv->tx_fd;
tx_fd->state = 0xc0000000; tx_fd->state = FrameEnd | TO_STATE(DUMMY_SKB_SIZE);
tx_fd->state |= ((u32)(skb->len & TxSizeMax)) << 16;
tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data, tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data,
skb->len, PCI_DMA_TODEVICE); DUMMY_SKB_SIZE, PCI_DMA_TODEVICE);
dpriv->tx_skbuff[0] = skb; dpriv->tx_skbuff[0] = skb;
} }
for (i = 0; i < RX_RING_SIZE; ) { i = 0;
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; /* Hi, no Hold */ rx_fd->state1 = HiDesc;
rx_fd->state2 = 0x00000000; rx_fd->state2 = 0x00000000;
rx_fd->end = 0xbabeface; rx_fd->end = 0xbabeface;
rx_fd->state1 |= (RX_MAX(HDLC_MAX_MRU) << 16); rx_fd->state1 |= (RX_MAX(HDLC_MAX_MRU) << 16);
// FIXME: return value verifiee mais traitement suspect
if (try_get_rx_skb(dpriv, dev) >= 0) if (try_get_rx_skb(dpriv, dev) >= 0)
dpriv->rx_dirty++; dpriv->rx_dirty++;
i++; (rx_fd++)->next = (u32)(dpriv->rx_fd_dma +
rx_fd->next = (u32)(dpriv->rx_fd_dma + i*sizeof(struct RxFD)); (++i%RX_RING_SIZE)*sizeof(*rx_fd));
rx_fd++; } while (i < RX_RING_SIZE);
}
(--rx_fd)->next = (u32)dpriv->rx_fd_dma;
rx_fd->state1 |= 0x40000000; /* Hold */
return 0; return 0;
......
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