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

[PATCH] 2.4.8 - dscc4 update 5/13

- DEBUG_PARANOIA was bad. "if (debug > x) {" is nice;
- state_check() now has only one return point;
- try_get_rx_skb() cosmetic;
- dscc4_rx_update() belongs to HOLD mode to LxDA changes;
- dscc4_wait_ack_cec() behaves like dscc4_xpr_ack();
- dscc4_rx_skb() refill logic is ready for LxDA mode and does everything
  to fulfill what its name suggests.
- document some errata voodoo in dscc4_init_one();
- dscc4_init_ring() should handle try_get_rx_skb() failure.
parent aefad917
...@@ -402,24 +402,32 @@ static inline void dscc4_do_tx(struct dscc4_dev_priv *dpriv, ...@@ -402,24 +402,32 @@ static inline void dscc4_do_tx(struct dscc4_dev_priv *dpriv,
readl(dev->base_addr + CH0LTDA + dpriv->dev_id*4); readl(dev->base_addr + CH0LTDA + dpriv->dev_id*4);
} }
int state_check(u32 state, struct dscc4_dev_priv *dpriv, static inline void dscc4_rx_update(struct dscc4_dev_priv *dpriv,
struct net_device *dev, const char *msg) struct net_device *dev)
{ {
#ifdef DEBUG_PARANOIA dpriv->lrda = dpriv->rx_fd_dma +
((dpriv->rx_dirty - 1)%RX_RING_SIZE)*sizeof(struct RxFD);
writel(dpriv->lrda, dev->base_addr + CH0LRDA + dpriv->dev_id*4);
}
int state_check(u32 state, struct dscc4_dev_priv *dpriv, struct net_device *dev,
const char *msg)
{
int ret = 0;
if (debug > 1) {
if (SOURCE_ID(state) != dpriv->dev_id) { if (SOURCE_ID(state) != dpriv->dev_id) {
printk(KERN_DEBUG "%s (%s): Source Id=%d, state=%08x\n", printk(KERN_DEBUG "%s (%s): Source Id=%d, state=%08x\n",
dev->name, msg, SOURCE_ID(state), state ); dev->name, msg, SOURCE_ID(state), state );
return -1; ret = -1;
} }
if (state & 0x0df80c00) { if (state & 0x0df80c00) {
printk(KERN_DEBUG "%s (%s): state=%08x (UFO alert)\n", printk(KERN_DEBUG "%s (%s): state=%08x (UFO alert)\n",
dev->name, msg, state); dev->name, msg, state);
return -1; ret = -1;
} }
return 0; }
#else return ret;
return 1;
#endif
} }
void inline reset_TxFD(struct TxFD *tx_fd) { void inline reset_TxFD(struct TxFD *tx_fd) {
...@@ -464,40 +472,49 @@ static void dscc4_release_ring(struct dscc4_dev_priv *dpriv) ...@@ -464,40 +472,49 @@ static void dscc4_release_ring(struct dscc4_dev_priv *dpriv)
} }
} }
void inline try_get_rx_skb(struct dscc4_dev_priv *priv, int cur, struct net_device *dev) inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv, struct net_device *dev)
{ {
unsigned int dirty = dpriv->rx_dirty%RX_RING_SIZE;
struct RxFD *rx_fd = dpriv->rx_fd + dirty;
struct sk_buff *skb; struct sk_buff *skb;
int ret = 0;
skb = dev_alloc_skb(RX_MAX(HDLC_MAX_MRU)); skb = dev_alloc_skb(RX_MAX(HDLC_MAX_MRU));
priv->rx_skbuff[cur] = skb; dpriv->rx_skbuff[dirty] = skb;
if (!skb) { if (skb) {
priv->rx_fd[cur--].data = (u32) NULL;
priv->rx_fd[cur%RX_RING_SIZE].state1 |= Hold;
return;
}
skb->dev = dev; skb->dev = dev;
skb->protocol = htons(ETH_P_IP); skb->protocol = htons(ETH_P_IP);
skb->mac.raw = skb->data; skb->mac.raw = skb->data;
priv->rx_fd[cur].data = pci_map_single(priv->pci_priv->pdev, skb->data, rx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data,
skb->len, PCI_DMA_FROMDEVICE); skb->len, PCI_DMA_FROMDEVICE);
} else {
rx_fd->data = (u32) NULL;
ret = -1;
}
return ret;
} }
/* /*
* IRQ/thread/whatever safe * IRQ/thread/whatever safe
*/ */
static int dscc4_wait_ack_cec(u32 ioaddr, struct net_device *dev, char *msg) static int dscc4_wait_ack_cec(struct dscc4_dev_priv *dpriv,
struct net_device *dev, char *msg)
{ {
s16 i = 0; s8 i = 0;
while (readl(ioaddr + STAR) & SccBusy) { do {
if (i++ < 0) { if (!(scc_readl_star(dpriv, dev) & SccBusy)) {
printk(KERN_ERR "%s: %s timeout\n", dev->name, msg); printk(KERN_DEBUG "%s: %s ack (%d try)\n", dev->name,
return -1; msg, i);
goto done;
} }
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(10);
rmb(); rmb();
} } while (++i > 0);
printk(KERN_DEBUG "%s: %s ack (%d try)\n", dev->name, msg, i); printk(KERN_ERR "%s: %s timeout\n", dev->name, msg);
return 0; done:
return (i >= 0) ? i : -EAGAIN;
} }
static int dscc4_do_action(struct net_device *dev, char *msg) static int dscc4_do_action(struct net_device *dev, char *msg)
...@@ -542,19 +559,24 @@ static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv) ...@@ -542,19 +559,24 @@ static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv)
return (i >= 0 ) ? i : -EAGAIN; return (i >= 0 ) ? i : -EAGAIN;
} }
static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur, static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv,
struct RxFD *rx_fd, struct net_device *dev) struct net_device *dev)
{ {
struct net_device_stats *stats = &dev_to_hdlc(dev)->stats; struct RxFD *rx_fd = dpriv->rx_fd + dpriv->rx_current%RX_RING_SIZE;
struct net_device_stats *stats = &dpriv->hdlc.stats;
struct pci_dev *pdev = dpriv->pci_priv->pdev; struct pci_dev *pdev = dpriv->pci_priv->pdev;
struct sk_buff *skb; struct sk_buff *skb;
int pkt_len; int pkt_len;
skb = dpriv->rx_skbuff[cur]; skb = dpriv->rx_skbuff[dpriv->rx_current++%RX_RING_SIZE];
if (!skb) {
printk(KERN_DEBUG "%s: skb=0 (%s)\n", dev->name, __FUNCTION__);
goto refill;
}
pkt_len = TO_SIZE(rx_fd->state2); pkt_len = TO_SIZE(rx_fd->state2);
pci_dma_sync_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE); pci_dma_sync_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE);
pci_unmap_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE);
if ((skb->data[--pkt_len] & FrameOk) == FrameOk) { if ((skb->data[--pkt_len] & FrameOk) == FrameOk) {
pci_unmap_single(pdev, rx_fd->data, skb->len, PCI_DMA_FROMDEVICE);
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += pkt_len; stats->rx_bytes += pkt_len;
skb->tail += pkt_len; skb->tail += pkt_len;
...@@ -563,7 +585,6 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur, ...@@ -563,7 +585,6 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur,
skb->protocol = htons(ETH_P_HDLC); skb->protocol = htons(ETH_P_HDLC);
skb->dev->last_rx = jiffies; skb->dev->last_rx = jiffies;
netif_rx(skb); netif_rx(skb);
try_get_rx_skb(dpriv, cur, dev);
} else { } else {
if (skb->data[pkt_len] & FrameRdo) if (skb->data[pkt_len] & FrameRdo)
stats->rx_fifo_errors++; stats->rx_fifo_errors++;
...@@ -573,19 +594,20 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur, ...@@ -573,19 +594,20 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur,
stats->rx_length_errors++; stats->rx_length_errors++;
else else
stats->rx_errors++; stats->rx_errors++;
dev_kfree_skb_irq(skb);
} }
rx_fd->state1 |= Hold; refill:
while ((dpriv->rx_dirty - dpriv->rx_current) % RX_RING_SIZE) {
if (try_get_rx_skb(dpriv, dev) < 0)
break;
dpriv->rx_dirty++;
}
dscc4_rx_update(dpriv, dev);
rx_fd->state2 = 0x00000000; rx_fd->state2 = 0x00000000;
rx_fd->end = 0xbabeface; rx_fd->end = 0xbabeface;
if (!rx_fd->data)
return;
rx_fd--;
if (!cur)
rx_fd += RX_RING_SIZE;
rx_fd->state1 &= ~Hold;
} }
static int __init dscc4_init_one (struct pci_dev *pdev, static int __init dscc4_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
struct dscc4_pci_priv *priv; struct dscc4_pci_priv *priv;
...@@ -731,8 +753,11 @@ static void dscc4_init_registers(struct dscc4_dev_priv *dpriv, ...@@ -731,8 +753,11 @@ static void dscc4_init_registers(struct dscc4_dev_priv *dpriv,
scc_writel(LengthCheck | (HDLC_MAX_MRU >> 5), dpriv, dev, RLCR); scc_writel(LengthCheck | (HDLC_MAX_MRU >> 5), dpriv, dev, RLCR);
/* Shared flags transmission disabled - cf errata DS5 p.11 */ /*
/* Carrier detect disabled - cf errata p.14 */ * No address recognition/crc-CCITT/cts enabled
* Shared flags transmission disabled - cf errata DS5 p.11
* Carrier detect disabled - cf errata p.14
*/
scc_writel(0x021c8000, dpriv, dev, CCR1); scc_writel(0x021c8000, dpriv, dev, CCR1);
/* crc not forwarded - Cf errata DS5 p.11 */ /* crc not forwarded - Cf errata DS5 p.11 */
...@@ -933,7 +958,7 @@ static int dscc4_open(struct net_device *dev) ...@@ -933,7 +958,7 @@ static int dscc4_open(struct net_device *dev)
/* Posted write is flushed in the busy-waiting loop */ /* Posted write is flushed in the busy-waiting loop */
scc_writel(TxSccRes | RxSccRes, dpriv, dev, CMDR); scc_writel(TxSccRes | RxSccRes, dpriv, dev, CMDR);
if (dscc4_wait_ack_cec(ioaddr, dev, "Cec")) if (dscc4_wait_ack_cec(dpriv, dev, "Cec"))
goto err_free_ring; goto err_free_ring;
/* /*
...@@ -1528,20 +1553,17 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv, ...@@ -1528,20 +1553,17 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv,
rx_fd = dpriv->rx_fd; rx_fd = dpriv->rx_fd;
} }
//dpriv->rx_needs_refill--; //dpriv->rx_needs_refill--;
try_get_rx_skb(dpriv, cur, dev); try_get_rx_skb(dpriv, dev);
if (!rx_fd->data) if (!rx_fd->data)
goto try; goto try;
rx_fd->state1 &= ~Hold; rx_fd->state1 &= ~Hold;
rx_fd->state2 = 0x00000000; rx_fd->state2 = 0x00000000;
rx_fd->end = 0xbabeface; rx_fd->end = 0xbabeface;
//} }
goto try; goto try;
} }
if (state & Fi) { if (state & Fi) {
cur = dpriv->rx_current%RX_RING_SIZE; dscc4_rx_skb(dpriv, dev);
rx_fd = dpriv->rx_fd + cur;
dscc4_rx_skb(dpriv, cur, rx_fd, dev);
dpriv->rx_current++;
goto try; goto try;
} }
if (state & Hi ) { /* HI bit */ if (state & Hi ) { /* HI bit */
...@@ -1614,7 +1636,7 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv, ...@@ -1614,7 +1636,7 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv,
rx_fd->state2 = 0x00000000; rx_fd->state2 = 0x00000000;
rx_fd->end = 0xbabeface; rx_fd->end = 0xbabeface;
} else } else
dscc4_rx_skb(dpriv, cur, rx_fd, dev); dscc4_rx_skb(dpriv, dev);
} while (1); } while (1);
if (debug) { if (debug) {
...@@ -1728,7 +1750,8 @@ static int dscc4_init_ring(struct net_device *dev) ...@@ -1728,7 +1750,8 @@ static int dscc4_init_ring(struct net_device *dev)
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);
try_get_rx_skb(dpriv, i, dev); if (try_get_rx_skb(dpriv, dev) >= 0)
dpriv->rx_dirty++;
i++; i++;
rx_fd->next = (u32)(dpriv->rx_fd_dma + i*sizeof(struct RxFD)); rx_fd->next = (u32)(dpriv->rx_fd_dma + i*sizeof(struct RxFD));
rx_fd++; rx_fd++;
......
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