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.



 25-akpm/drivers/net/wan/dscc4.c |   53 +++++++++++++++++++++++++++-------------
 1 files changed, 36 insertions(+), 17 deletions(-)

diff -puN drivers/net/wan/dscc4.c~dscc4-4 drivers/net/wan/dscc4.c
--- 25/drivers/net/wan/dscc4.c~dscc4-4	Fri Aug 15 13:54:20 2003
+++ 25-akpm/drivers/net/wan/dscc4.c	Fri Aug 15 13:54:20 2003
@@ -291,6 +291,7 @@ struct dscc4_dev_priv {
 #define Hold		0x40000000
 #define SccBusy		0x10000000
 #define PowerUp		0x80000000
+#define Vis		0x00001000
 #define FrameOk		(FrameVfr | FrameCrc)
 #define FrameVfr	0x80
 #define FrameRdo	0x40
@@ -331,6 +332,12 @@ struct dscc4_dev_priv {
 #define NeedIDR		0x00000001
 #define NeedIDT		0x00000002
 #define RdoSet		0x00000004
+/* Don't mask RDO. Ever. */
+#ifdef DSCC4_POLLING
+#define EventsMask	0xfffeef7f
+#else
+#define EventsMask	0xfffa8f7a
+#endif
 
 /* Functions prototypes */
 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_
 {
 	/* Cf errata DS5 p.6 */
 	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);
 	writel(MTFi|Rdr, dev->base_addr + dpriv->dev_id*0x0c + CH0CFG);
 	writel(Action, dev->base_addr + GCMDR);
@@ -590,7 +597,7 @@ static void dscc4_tx_reset(struct dscc4_
 	u16 i = 0;
 
 	/* 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);
 	/*
 	 * Must be longer than the time required to fill the fifo.
@@ -815,7 +822,8 @@ err_out:
 static void dscc4_init_registers(struct dscc4_dev_priv *dpriv,
 				 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);
 
@@ -830,15 +838,6 @@ static void dscc4_init_registers(struct 
 	scc_writel(0x00050008 & ~RxActivate, dpriv, dev, CCR2);
 	// crc forwarded
 	//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)
@@ -964,6 +963,8 @@ static int dscc4_open(struct net_device 
 	/* IDT+IDR during XPR */
 	dpriv->flags = NeedIDR | NeedIDT;
 
+	scc_patchl(0, PowerUp | Vis, dpriv, dev, CCR0);
+
 	/*
 	 * The following is a bit paranoid...
 	 *
@@ -978,11 +979,13 @@ static int dscc4_open(struct net_device 
 	} else
 		printk(KERN_INFO "%s: available. Good\n", dev->name);
 
+	scc_writel(EventsMask, dpriv, dev, IMR);
+
 	/* Posted write is flushed in the wait_ack loop */
 	scc_writel(TxSccRes | RxSccRes, dpriv, dev, CMDR);
 
 	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 ?).
@@ -993,7 +996,7 @@ static int dscc4_open(struct net_device 
 	 */
 	if ((ret = dscc4_xpr_ack(dpriv)) < 0) {
 		printk(KERN_ERR "%s: %s timeout\n", DRV_NAME, "XPR");
-		goto err_free_ring;
+		goto err_disable_scc_events;
 	}
 	
 	if (debug > 2)
@@ -1010,7 +1013,10 @@ static int dscc4_open(struct net_device 
 
 	return 0;
 
+err_disable_scc_events:
+	scc_writel(0xffffffff, dpriv, dev, IMR);
 err_free_ring:
+	scc_patchl(PowerUp | Vis, 0, dpriv, dev, CCR0);
 	dscc4_release_ring(dpriv);
 err_out:
 	hdlc_close(hdlc);
@@ -1077,6 +1083,9 @@ static int dscc4_close(struct net_device
 
 	dscc4_tx_reset(dpriv, dev);
 
+	scc_patchl(PowerUp | Vis, 0, dpriv, dev, CCR0);
+	scc_writel(0xffffffff, dpriv, dev, IMR);
+
 	hdlc_close(hdlc);
 	dscc4_release_ring(dpriv);
 
@@ -1277,7 +1286,7 @@ static int dscc4_clock_setting(struct ds
 			settings->clock_rate = bps;
 		}
 	} else { /* DTE */
-		state |= 0x80001000;
+		state |= PowerUp | Vis;
 		printk(KERN_DEBUG "%s: external RxClk (DTE)\n", dev->name);
 	}
 	scc_writel(state, dpriv, dev, CCR0);
@@ -1522,9 +1531,19 @@ try:
 		}
 		if (state & Xpr) {
 			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;
 			/* Keep this order: IDT before IDR */
 			if (dpriv->flags & NeedIDT) {

_