Commit 1bcf2af4 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] dscc4: scc changes

From: Francois Romieu <romieu@fr.zoreil.com>

- more #define for specific bits;
- more scc_patchl use;
- just say no to bozo programming:
  + SCC core _really_ disabled at startup;
  + Interrupts Mask Register setup and SCC core activation are
    done as late as possible (i.e. in dscc4_open());
  + they are reverted if dscc4_open() fails;
  + as well as unconditionnaly in dscc4_close();
- more or less paranoid quirk in Xpr handler.
parent 171c33e5
...@@ -291,6 +291,7 @@ struct dscc4_dev_priv { ...@@ -291,6 +291,7 @@ struct dscc4_dev_priv {
#define Hold 0x40000000 #define Hold 0x40000000
#define SccBusy 0x10000000 #define SccBusy 0x10000000
#define PowerUp 0x80000000 #define PowerUp 0x80000000
#define Vis 0x00001000
#define FrameOk (FrameVfr | FrameCrc) #define FrameOk (FrameVfr | FrameCrc)
#define FrameVfr 0x80 #define FrameVfr 0x80
#define FrameRdo 0x40 #define FrameRdo 0x40
...@@ -331,6 +332,12 @@ struct dscc4_dev_priv { ...@@ -331,6 +332,12 @@ struct dscc4_dev_priv {
#define NeedIDR 0x00000001 #define NeedIDR 0x00000001
#define NeedIDT 0x00000002 #define NeedIDT 0x00000002
#define RdoSet 0x00000004 #define RdoSet 0x00000004
/* Don't mask RDO. Ever. */
#ifdef DSCC4_POLLING
#define EventsMask 0xfffeef7f
#else
#define EventsMask 0xfffa8f7a
#endif
/* Functions prototypes */ /* Functions prototypes */
static inline void dscc4_rx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); static inline void dscc4_rx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *);
...@@ -579,7 +586,7 @@ static void dscc4_rx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev) ...@@ -579,7 +586,7 @@ static void dscc4_rx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev)
{ {
/* Cf errata DS5 p.6 */ /* Cf errata DS5 p.6 */
writel(0x00000000, dev->base_addr + CH0LRDA + dpriv->dev_id*4); writel(0x00000000, dev->base_addr + CH0LRDA + dpriv->dev_id*4);
scc_writel(~PowerUp & scc_readl(dpriv, CCR0), dpriv, dev, CCR0); scc_patchl(PowerUp, 0, dpriv, dev, CCR0);
readl(dev->base_addr + CH0LRDA + dpriv->dev_id*4); readl(dev->base_addr + CH0LRDA + dpriv->dev_id*4);
writel(MTFi|Rdr, dev->base_addr + dpriv->dev_id*0x0c + CH0CFG); writel(MTFi|Rdr, dev->base_addr + dpriv->dev_id*0x0c + CH0CFG);
writel(Action, dev->base_addr + GCMDR); writel(Action, dev->base_addr + GCMDR);
...@@ -590,7 +597,7 @@ static void dscc4_tx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev) ...@@ -590,7 +597,7 @@ static void dscc4_tx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev)
u16 i = 0; u16 i = 0;
/* Cf errata DS5 p.7 */ /* Cf errata DS5 p.7 */
scc_writel(~PowerUp & scc_readl(dpriv, CCR0), dpriv, dev, CCR0); scc_patchl(PowerUp, 0, dpriv, dev, CCR0);
scc_writel(0x00050000, dpriv, dev, CCR2); scc_writel(0x00050000, dpriv, dev, CCR2);
/* /*
* Must be longer than the time required to fill the fifo. * Must be longer than the time required to fill the fifo.
...@@ -815,7 +822,8 @@ static int __init dscc4_init_one(struct pci_dev *pdev, ...@@ -815,7 +822,8 @@ static int __init dscc4_init_one(struct pci_dev *pdev,
static void dscc4_init_registers(struct dscc4_dev_priv *dpriv, static void dscc4_init_registers(struct dscc4_dev_priv *dpriv,
struct net_device *dev) struct net_device *dev)
{ {
scc_writel(0x80001000, dpriv, dev, CCR0); /* No interrupts, SCC core disabled. Let's relax */
scc_writel(0x00000000, dpriv, dev, CCR0);
scc_writel(LengthCheck | (HDLC_MAX_MRU >> 5), dpriv, dev, RLCR); scc_writel(LengthCheck | (HDLC_MAX_MRU >> 5), dpriv, dev, RLCR);
...@@ -830,15 +838,6 @@ static void dscc4_init_registers(struct dscc4_dev_priv *dpriv, ...@@ -830,15 +838,6 @@ static void dscc4_init_registers(struct dscc4_dev_priv *dpriv,
scc_writel(0x00050008 & ~RxActivate, dpriv, dev, CCR2); scc_writel(0x00050008 & ~RxActivate, dpriv, dev, CCR2);
// crc forwarded // crc forwarded
//scc_writel(0x00250008 & ~RxActivate, dpriv, dev, CCR2); //scc_writel(0x00250008 & ~RxActivate, dpriv, dev, CCR2);
/* Don't mask RDO. Ever. */
#ifdef DSCC4_POLLING
scc_writel(0xfffeef7f, dpriv, dev, IMR); /* Interrupt mask */
#else
//scc_writel(0xfffaef7f, dpriv, dev, IMR); /* Interrupt mask */
//scc_writel(0xfffaef7e, dpriv, dev, IMR); /* Interrupt mask */
scc_writel(0xfffa8f7a, dpriv, dev, IMR); /* Interrupt mask */
#endif
} }
static int dscc4_found1(struct pci_dev *pdev, unsigned long ioaddr) static int dscc4_found1(struct pci_dev *pdev, unsigned long ioaddr)
...@@ -964,6 +963,8 @@ static int dscc4_open(struct net_device *dev) ...@@ -964,6 +963,8 @@ static int dscc4_open(struct net_device *dev)
/* IDT+IDR during XPR */ /* IDT+IDR during XPR */
dpriv->flags = NeedIDR | NeedIDT; dpriv->flags = NeedIDR | NeedIDT;
scc_patchl(0, PowerUp | Vis, dpriv, dev, CCR0);
/* /*
* The following is a bit paranoid... * The following is a bit paranoid...
* *
...@@ -978,11 +979,13 @@ static int dscc4_open(struct net_device *dev) ...@@ -978,11 +979,13 @@ static int dscc4_open(struct net_device *dev)
} else } else
printk(KERN_INFO "%s: available. Good\n", dev->name); printk(KERN_INFO "%s: available. Good\n", dev->name);
scc_writel(EventsMask, dpriv, dev, IMR);
/* Posted write is flushed in the wait_ack 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 ((ret = dscc4_wait_ack_cec(dpriv, dev, "Cec")) < 0) if ((ret = dscc4_wait_ack_cec(dpriv, dev, "Cec")) < 0)
goto err_free_ring; goto err_disable_scc_events;
/* /*
* I would expect XPR near CE completion (before ? after ?). * I would expect XPR near CE completion (before ? after ?).
...@@ -993,7 +996,7 @@ static int dscc4_open(struct net_device *dev) ...@@ -993,7 +996,7 @@ static int dscc4_open(struct net_device *dev)
*/ */
if ((ret = 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_disable_scc_events;
} }
if (debug > 2) if (debug > 2)
...@@ -1010,7 +1013,10 @@ static int dscc4_open(struct net_device *dev) ...@@ -1010,7 +1013,10 @@ static int dscc4_open(struct net_device *dev)
return 0; return 0;
err_disable_scc_events:
scc_writel(0xffffffff, dpriv, dev, IMR);
err_free_ring: err_free_ring:
scc_patchl(PowerUp | Vis, 0, dpriv, dev, CCR0);
dscc4_release_ring(dpriv); dscc4_release_ring(dpriv);
err_out: err_out:
hdlc_close(hdlc); hdlc_close(hdlc);
...@@ -1077,6 +1083,9 @@ static int dscc4_close(struct net_device *dev) ...@@ -1077,6 +1083,9 @@ static int dscc4_close(struct net_device *dev)
dscc4_tx_reset(dpriv, dev); dscc4_tx_reset(dpriv, dev);
scc_patchl(PowerUp | Vis, 0, dpriv, dev, CCR0);
scc_writel(0xffffffff, dpriv, dev, IMR);
hdlc_close(hdlc); hdlc_close(hdlc);
dscc4_release_ring(dpriv); dscc4_release_ring(dpriv);
...@@ -1277,7 +1286,7 @@ static int dscc4_clock_setting(struct dscc4_dev_priv *dpriv, ...@@ -1277,7 +1286,7 @@ static int dscc4_clock_setting(struct dscc4_dev_priv *dpriv,
settings->clock_rate = bps; settings->clock_rate = bps;
} }
} else { /* DTE */ } else { /* DTE */
state |= 0x80001000; state |= PowerUp | Vis;
printk(KERN_DEBUG "%s: external RxClk (DTE)\n", dev->name); printk(KERN_DEBUG "%s: external RxClk (DTE)\n", dev->name);
} }
scc_writel(state, dpriv, dev, CCR0); scc_writel(state, dpriv, dev, CCR0);
...@@ -1522,9 +1531,19 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, ...@@ -1522,9 +1531,19 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv,
} }
if (state & Xpr) { if (state & Xpr) {
u32 scc_addr, ring; u32 scc_addr, ring;
int i;
/*
* - the busy condition happens (sometimes);
* - it doesn't seem to make the handler unreliable.
*/
for (i = 1; i; i <<= 1) {
if (!(scc_readl_star(dpriv, dev) & SccBusy))
break;
}
if (!i)
printk(KERN_INFO "%s busy in irq\n", dev->name);
if (scc_readl_star(dpriv, dev) & SccBusy)
printk(KERN_ERR "%s busy. Fatal\n", dev->name);
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) {
......
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