patch-2.4.23 linux-2.4.23/drivers/net/wan/dscc4.c

Next file: linux-2.4.23/drivers/net/wan/farsync.c
Previous file: linux-2.4.23/drivers/net/wan/c101.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.22/drivers/net/wan/dscc4.c linux-2.4.23/drivers/net/wan/dscc4.c
@@ -47,7 +47,7 @@
  * Tx direction
  * When the tx ring is full, the xmit routine issues a call to netdev_stop.
  * The device is supposed to be enabled again during an ALLS irq (we could
- * use HI but as it's easy to loose events, it's fscked).
+ * use HI but as it's easy to lose events, it's fscked).
  *
  * Rx direction
  * The received frames aren't supposed to span over multiple receiving areas.
@@ -80,7 +80,6 @@
  * - misc crapectomy.
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -108,10 +107,15 @@
 #include <linux/hdlc.h>
 
 /* Version */
-static const char version[] = "$Id: dscc4.c,v 1.159 2002/04/10 22:05:17 romieu Exp $ for Linux\n";
+static const char version[] = "$Id: dscc4.c,v 1.173 2003/09/20 23:55:34 romieu Exp $ for Linux\n";
 static int debug;
 static int quartz;
 
+#ifdef CONFIG_DSCC4_PCI_RST
+static DECLARE_MUTEX(dscc4_sem);
+static u32 dscc4_pci_config_store[16];
+#endif
+
 #define	DRV_NAME	"dscc4"
 
 #undef DSCC4_POLLING
@@ -164,8 +168,15 @@
 
 #define SOURCE_ID(flags)	(((flags) >> 28) & 0x03)
 #define TO_SIZE(state)		(((state) >> 16) & 0x1fff)
-#define TO_STATE(len)		cpu_to_le32(((len) & TxSizeMax) << 16)
-#define RX_MAX(len)		((((len) >> 5) + 1) << 5)
+
+/*
+ * Given the operating range of Linux HDLC, the 2 defines below could be
+ * made simpler. However they are a fine reminder for the limitations of
+ * the driver: it's better to stay < TxSizeMax and < RxSizeMax.
+ */
+#define TO_STATE_TX(len)	cpu_to_le32(((len) & TxSizeMax) << 16)
+#define TO_STATE_RX(len)	cpu_to_le32((RX_MAX(len) % RxSizeMax) << 16)
+#define RX_MAX(len)		((((len) >> 5) + 1) << 5)	/* Cf RLCR */
 #define SCC_REG_START(dpriv)	(SCC_START+(dpriv->dev_id)*SCC_OFFSET)
 
 struct dscc4_pci_priv {
@@ -256,6 +267,10 @@
 #define IMR     0x54
 #define ISR     0x58
 
+#define GPDIR	0x0400
+#define GPDATA	0x0404
+#define GPIM	0x0408
+
 /* Bit masks */
 #define EncodingMask	0x00700000
 #define CrcMask		0x00000003
@@ -272,7 +287,8 @@
 #define Idt		0x00080000
 #define TxSccRes	0x01000000
 #define RxSccRes	0x00010000
-#define TxSizeMax	0x1fff
+#define TxSizeMax	0x1fff		/* Datasheet DS1 - 11.1.1.1 */
+#define RxSizeMax	0x1ffc		/* Datasheet DS1 - 11.1.2.1 */
 
 #define Ccr0ClockMask	0x0000003f
 #define Ccr1LoopMask	0x00000200
@@ -283,6 +299,7 @@
 #define Hold		0x40000000
 #define SccBusy		0x10000000
 #define PowerUp		0x80000000
+#define Vis		0x00001000
 #define FrameOk		(FrameVfr | FrameCrc)
 #define FrameVfr	0x80
 #define FrameRdo	0x40
@@ -319,10 +336,19 @@
 #define Arf		0x00000002
 #define ArAck		0x00000001
 
-/* Misc */
+/* State flags */
+#define Ready		0x00000000
 #define NeedIDR		0x00000001
 #define NeedIDT		0x00000002
 #define RdoSet		0x00000004
+#define FakeReset	0x00000008
+
+/* 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 *);
@@ -487,9 +513,9 @@
 	skb = dev_alloc_skb(len);
 	dpriv->rx_skbuff[dirty] = skb;
 	if (skb) {
-	skb->dev = dev;
-		skb->protocol = htons(ETH_P_HDLC);
-	skb->mac.raw = skb->data;
+		skb->dev = dev;
+		skb->protocol = hdlc_type_trans(skb, dev);
+		skb->mac.raw = skb->data;
 		rx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data,
 					     len, PCI_DMA_FROMDEVICE);
 	} else {
@@ -566,15 +592,19 @@
 	return (i >= 0 ) ? i : -EAGAIN;
 }
 
-/* Requires protection against interrupt */
+#if 0 /* dscc4_{rx/tx}_reset are both unreliable - more tweak needed */
 static void dscc4_rx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&dpriv->pci_priv->lock, flags);
 	/* 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);
+	spin_unlock_irqrestore(&dpriv->pci_priv->lock, flags);
 }
 
 static void dscc4_tx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev)
@@ -582,7 +612,7 @@
 	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.
@@ -596,6 +626,7 @@
 	if (dscc4_do_action(dev, "Rdt") < 0)
 		printk(KERN_ERR "%s: Tx reset failed\n", dev->name);
 }
+#endif
 
 /* TODO: (ab)use this function to refill a completely depleted RX ring. */
 static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv,
@@ -619,6 +650,8 @@
 		stats->rx_packets++;
 		stats->rx_bytes += pkt_len;
 		skb_put(skb, pkt_len);
+		if (netif_running(dev))
+			skb->protocol = hdlc_type_trans(skb, dev);
 		skb->dev->last_rx = jiffies;
 		netif_rx(skb);
 	} else {
@@ -661,8 +694,8 @@
 	kfree(ppriv);
 }
 
-static int __init dscc4_init_one(struct pci_dev *pdev,
-				  const struct pci_device_id *ent)
+static int __devinit dscc4_init_one(struct pci_dev *pdev,
+				    const struct pci_device_id *ent)
 {
 	struct dscc4_pci_priv *priv;
 	struct dscc4_dev_priv *dpriv;
@@ -805,7 +838,8 @@
 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);
 
@@ -813,29 +847,21 @@
 	 * No address recognition/crc-CCITT/cts enabled
 	 * Shared flags transmission disabled - cf errata DS5 p.11
 	 * Carrier detect disabled - cf errata p.14
+	 * FIXME: carrier detection/polarity may be handled more gracefully.
 	 */
-	scc_writel(0x021c8000, dpriv, dev, CCR1);
+	scc_writel(0x02408000, dpriv, dev, CCR1);
 
 	/* crc not forwarded - Cf errata DS5 p.11 */
 	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)
 {
 	struct dscc4_pci_priv *ppriv;
 	struct dscc4_dev_priv *root;
-	int i = 0;
+	int i, ret = -ENOMEM;
 
 	root = (struct dscc4_dev_priv *)
 		kmalloc(dev_per_card*sizeof(*root), GFP_KERNEL);
@@ -867,6 +893,8 @@
 		d->tx_timeout = dscc4_tx_timeout;
 		d->watchdog_timeo = TX_TIMEOUT;
 
+		SET_MODULE_OWNER(d);
+
 		dpriv->dev_id = i;
 		dpriv->pci_priv = ppriv;
 		spin_lock_init(&dpriv->lock);
@@ -874,31 +902,40 @@
 		hdlc->xmit = dscc4_start_xmit;
 		hdlc->attach = dscc4_hdlc_attach;
 
-	        if (register_hdlc_device(hdlc)) {
+		ret = register_hdlc_device(hdlc);
+		if (ret < 0) {
 			printk(KERN_ERR "%s: unable to register\n", DRV_NAME);
 			goto err_unregister;
 	        }
-		hdlc->proto = IF_PROTO_HDLC;
-		SET_MODULE_OWNER(d);
+
 		dscc4_init_registers(dpriv, d);
 		dpriv->parity = PARITY_CRC16_PR0_CCITT;
 		dpriv->encoding = ENCODING_NRZ;
+
+		ret = dscc4_init_ring(d);
+		if (ret < 0) {
+			unregister_hdlc_device(hdlc);
+			goto err_unregister;
+		}
 	}
-	if (dscc4_set_quartz(root, quartz) < 0)
+	ret = dscc4_set_quartz(root, quartz);
+	if (ret < 0)
 		goto err_unregister;
 	ppriv->root = root;
 	spin_lock_init(&ppriv->lock);
 	pci_set_drvdata(pdev, ppriv);
-	return 0;
+	return ret;
 
 err_unregister:
-	while (--i >= 0)
+	while (--i >= 0) {
+		dscc4_release_ring(root + i);
 		unregister_hdlc_device(&root[i].hdlc);
+	}
 	kfree(ppriv);
 err_free_dev:
 	kfree(root);
 err_out:
-	return -1;
+	return ret;
 };
 
 /* FIXME: get rid of the unneeded code */
@@ -932,6 +969,46 @@
 	return 0;
 }
 
+#ifdef CONFIG_DSCC4_PCI_RST
+/*
+ * Some DSCC4-based cards wires the GPIO port and the PCI #RST pin together
+ * so as to provide a safe way to reset the asic while not the whole machine
+ * rebooting.
+ *
+ * This code doesn't need to be efficient. Keep It Simple
+ */
+static void dscc4_pci_reset(struct pci_dev *pdev, u32 ioaddr)
+{
+	int i;
+
+	down(&dscc4_sem);
+	for (i = 0; i < 16; i++)
+		pci_read_config_dword(pdev, i << 2, dscc4_pci_config_store + i);
+
+	/* Maximal LBI clock divider (who cares ?) and whole GPIO range. */
+	writel(0x001c0000, ioaddr + GMODE);
+	/* Configure GPIO port as output */
+	writel(0x0000ffff, ioaddr + GPDIR);
+	/* Disable interruption */
+	writel(0x0000ffff, ioaddr + GPIM);
+
+	writel(0x0000ffff, ioaddr + GPDATA);
+	writel(0x00000000, ioaddr + GPDATA);
+
+	/* Flush posted writes */
+	readl(ioaddr + GSTAR);
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(10);
+
+	for (i = 0; i < 16; i++)
+		pci_write_config_dword(pdev, i << 2, dscc4_pci_config_store[i]);
+	up(&dscc4_sem);
+}
+#else
+#define dscc4_pci_reset(pdev,ioaddr)	do {} while (0)
+#endif /* CONFIG_DSCC4_PCI_RST */
+
 static int dscc4_open(struct net_device *dev)
 {
 	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
@@ -949,12 +1026,29 @@
 
 	ppriv = dpriv->pci_priv;
 
-	if ((ret = dscc4_init_ring(dev)))
-		goto err_out;
+	/*
+	 * Due to various bugs, there is no way to reliably reset a
+	 * specific port (manufacturer's dependant special PCI #RST wiring
+	 * apart: it affects all ports). Thus the device goes in the best
+	 * silent mode possible at dscc4_close() time and simply claims to
+	 * be up if it's opened again. It still isn't possible to change
+	 * the HDLC configuration without rebooting but at least the ports
+	 * can be up/down ifconfig'ed without killing the host.
+	 */
+	if (dpriv->flags & FakeReset) {
+		dpriv->flags &= ~FakeReset;
+		scc_patchl(0, PowerUp, dpriv, dev, CCR0);
+		scc_patchl(0, 0x00050000, dpriv, dev, CCR2);
+		scc_writel(EventsMask, dpriv, dev, IMR);
+		printk(KERN_INFO "%s: up again.\n", dev->name);
+		goto done;
+	}
 
 	/* IDT+IDR during XPR */
 	dpriv->flags = NeedIDR | NeedIDT;
 
+	scc_patchl(0, PowerUp | Vis, dpriv, dev, CCR0);
+
 	/*
 	 * The following is a bit paranoid...
 	 *
@@ -965,15 +1059,17 @@
 	if (scc_readl_star(dpriv, dev) & SccBusy) {
 		printk(KERN_ERR "%s busy. Try later\n", dev->name);
 		ret = -EAGAIN;
-		goto err_free_ring;
+		goto err_out;
 	} 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 ?).
@@ -984,12 +1080,13 @@
 	 */
 	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)
 		dscc4_tx_print(dev, dpriv, "Open");
 
+done:
 	netif_start_queue(dev);
 
         init_timer(&dpriv->timer);
@@ -1001,8 +1098,9 @@
 
 	return 0;
 
-err_free_ring:
-	dscc4_release_ring(dpriv);
+err_disable_scc_events:
+	scc_writel(0xffffffff, dpriv, dev, IMR);
+	scc_patchl(PowerUp | Vis, 0, dpriv, dev, CCR0);
 err_out:
 	hdlc_close(hdlc);
 	MOD_DEC_USE_COUNT;
@@ -1027,7 +1125,7 @@
 	next = dpriv->tx_current%TX_RING_SIZE;
 	dpriv->tx_skbuff[next] = skb;
 	tx_fd = dpriv->tx_fd + next;
-	tx_fd->state = FrameEnd | TO_STATE(skb->len);
+	tx_fd->state = FrameEnd | TO_STATE_TX(skb->len);
 	tx_fd->data = pci_map_single(ppriv->pdev, skb->data, skb->len,
 				     PCI_DMA_TODEVICE);
 	tx_fd->complete = 0x00000000;
@@ -1058,19 +1156,17 @@
 {
 	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
 	hdlc_device *hdlc = dev_to_hdlc(dev);
-	unsigned long flags;
 
 	del_timer_sync(&dpriv->timer);
 	netif_stop_queue(dev);
 
-	spin_lock_irqsave(&dpriv->pci_priv->lock, flags);
-	dscc4_rx_reset(dpriv, dev);
-	spin_unlock_irqrestore(&dpriv->pci_priv->lock, flags);
+	scc_patchl(PowerUp | Vis, 0, dpriv, dev, CCR0);
+	scc_patchl(0x00050000, 0, dpriv, dev, CCR2);
+	scc_writel(0xffffffff, dpriv, dev, IMR);
 
-	dscc4_tx_reset(dpriv, dev);
+	dpriv->flags |= FakeReset;
 
 	hdlc_close(hdlc);
-	dscc4_release_ring(dpriv);
 
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -1080,13 +1176,56 @@
 {
 	int ret = 0;
 
-#ifdef CONFIG_DSCC4_CLOCK_ON_TWO_PORTS_ONLY
+#ifdef CONFIG_DSCC4_PCISYNC
 	if (port >= 2)
 		ret = -1;
 #endif
 	return ret;
 }
 
+/*
+ * DS1 p.137: "There are a total of 13 different clocking modes..."
+ *                                  ^^
+ * Design choices:
+ * - by default, assume a clock is provided on pin RxClk/TxClk (clock mode 0a).
+ *   Clock mode 3b _should_ work but the testing seems to make this point
+ *   dubious (DIY testing requires setting CCR0 at 0x00000033).
+ *   This is supposed to provide least surprise "DTE like" behavior.
+ * - if line rate is specified, clocks are assumed to be locally generated.
+ *   A quartz must be available (on pin XTAL1). Modes 6b/7b are used. Choosing
+ *   between these it automagically done according on the required frequency
+ *   scaling. Of course some rounding may take place.
+ * - no high speed mode (40Mb/s). May be trivial to do but I don't have an
+ *   appropriate external clocking device for testing.
+ * - no time-slot/clock mode 5: shameless lazyness.
+ *
+ * The clock signals wiring can be (is ?) manufacturer dependant. Good luck.
+ *
+ * BIG FAT WARNING: if the device isn't provided enough clocking signal, it
+ * won't pass the init sequence. For example, straight back-to-back DTE without
+ * external clock will fail when dscc4_open() (<- 'ifconfig hdlcx xxx') is
+ * called.
+ *
+ * Typos lurk in datasheet (missing divier in clock mode 7a figure 51 p.153
+ * DS0 for example)
+ * 
+ * Clock mode related bits of CCR0:
+ *     +------------ TOE: output TxClk (0b/2b/3a/3b/6b/7a/7b only)
+ *     | +---------- SSEL: sub-mode select 0 -> a, 1 -> b
+ *     | | +-------- High Speed: say 0
+ *     | | | +-+-+-- Clock Mode: 0..7
+ *     | | | | | |
+ * -+-+-+-+-+-+-+-+
+ * x|x|5|4|3|2|1|0| lower bits
+ *
+ * Division factor of BRR: k = (N+1)x2^M (total divider = 16xk in mode 6b)
+ *            +-+-+-+------------------ M (0..15)
+ *            | | | |     +-+-+-+-+-+-- N (0..63)
+ *    0 0 0 0 | | | | 0 0 | | | | | |
+ * ...-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *    f|e|d|c|b|a|9|8|7|6|5|4|3|2|1|0| lower bits
+ *
+ */
 static int dscc4_set_clock(struct net_device *dev, u32 *bps, u32 *state)
 {
 	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
@@ -1123,13 +1262,13 @@
 		}
 		brr = (m << 8) | n;
 		divider = n << m;
-		if (!(*state & 0x00000001)) /* Clock mode 6b */
+		if (!(*state & 0x00000001)) /* ?b mode mask => clock mode 6b */
 			divider <<= 4;
 		*bps = xtal / divider;
 	} else {
 		/*
 		 * External clock - DTE
-		 * "state" already reflects Clock mode 0a.
+		 * "state" already reflects Clock mode 0a (CCR0 = 0xzzzzzz00).
 		 * Nothing more to be done
 		 */
 		brr = 0;
@@ -1168,6 +1307,11 @@
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
+		if (dpriv->flags & FakeReset) {
+			printk(KERN_INFO "%s: please reset the device"
+			       " before this command\n", dev->name);
+			return -EPERM;
+		}
 		if (copy_from_user(&dpriv->settings, line, size))
 			return -EFAULT;
 		ret = dscc4_set_iface(dpriv, dev);
@@ -1221,12 +1365,12 @@
 	if (bps) { /* DCE */
 		printk(KERN_DEBUG "%s: generated RxClk (DCE)\n", dev->name);
 		if (settings->clock_rate != bps) {
-			settings->clock_rate = bps;
 			printk(KERN_DEBUG "%s: clock adjusted (%08d -> %08d)\n",
-				dev->name, dpriv->settings.clock_rate, bps);
+				dev->name, settings->clock_rate, bps);
+			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);
@@ -1332,6 +1476,8 @@
 	state = readl(ioaddr + GSTAR);
 	if (!state)
 		goto out;
+	if (debug > 3)
+		printk(KERN_DEBUG "%s: GSTAR = 0x%08x\n", DRV_NAME, state);
 	writel(state, ioaddr + GSTAR);
 
 	if (state & Arf) {
@@ -1377,6 +1523,9 @@
 	cur = dpriv->iqtx_current%IRQ_RING_SIZE;
 	state = dpriv->iqtx[cur];
 	if (!state) {
+		if (debug > 4)
+			printk(KERN_DEBUG "%s: Tx ISR = 0x%08x\n", dev->name,
+			       state);
 		if ((debug > 1) && (loop > 1))
 			printk(KERN_DEBUG "%s: Tx irq loop=%d\n", dev->name, loop);
 		if (loop && netif_queue_stopped(dev))
@@ -1431,7 +1580,7 @@
 			 * 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->state = FrameEnd | TO_STATE_TX(2*DUMMY_SKB_SIZE);
 			tx_fd->complete = 0x00000000;
 			tx_fd->jiffies = 0;
 
@@ -1463,9 +1612,19 @@
 		}
 		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) {
@@ -1500,7 +1659,8 @@
 				goto try;
 		}
 		if (state & Cd) {
-			printk(KERN_INFO "%s: CD transition\n", dev->name);
+			if (debug > 0)
+				printk(KERN_INFO "%s: CD transition\n", dev->name);
 			if (!(state &= ~Cd)) /* DEBUG */
 				goto try;
 		}
@@ -1542,6 +1702,9 @@
 	if (!(state & SccEvt)){
 		struct RxFD *rx_fd;
 
+		if (debug > 4)
+			printk(KERN_DEBUG "%s: Rx ISR = 0x%08x\n", dev->name,
+			       state);
 		state &= 0x00ffffff;
 		if (state & Err) { /* Hold or reset */
 			printk(KERN_DEBUG "%s: Rx ERR\n", dev->name);
@@ -1718,7 +1881,7 @@
 
 		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->state = FrameEnd | TO_STATE_TX(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;
@@ -1749,7 +1912,7 @@
 	dpriv->tx_dirty = 0xffffffff;
 	i = dpriv->tx_current = 0;
 	do {
-		tx_fd->state = FrameEnd | TO_STATE(2*DUMMY_SKB_SIZE);
+		tx_fd->state = FrameEnd | TO_STATE_TX(2*DUMMY_SKB_SIZE);
 		tx_fd->complete = 0x00000000;
 	        /* FIXME: NULL should be ok - to be tried */
 	        tx_fd->data = dpriv->tx_fd_dma;
@@ -1757,7 +1920,7 @@
 					(++i%TX_RING_SIZE)*sizeof(*tx_fd));
 	} while (i < TX_RING_SIZE);
 
-	if (dscc4_init_dummy_skb(dpriv) < 0)
+	if (dscc4_init_dummy_skb(dpriv) == NULL)
 		goto err_free_dma_tx;
 
 	memset(dpriv->rx_skbuff, 0, sizeof(struct sk_buff *)*RX_RING_SIZE);
@@ -1767,7 +1930,7 @@
 	        rx_fd->state1 = HiDesc;
 	        rx_fd->state2 = 0x00000000;
 	        rx_fd->end = 0xbabeface;
-	        rx_fd->state1 |= TO_STATE(RX_MAX(HDLC_MAX_MRU));
+	        rx_fd->state1 |= TO_STATE_RX(HDLC_MAX_MRU);
 		// FIXME: return value verifiee mais traitement suspect
 		if (try_get_rx_skb(dpriv, dev) >= 0)
 			dpriv->rx_dirty++;
@@ -1785,7 +1948,7 @@
 	return -ENOMEM;
 }
 
-static void __exit dscc4_remove_one(struct pci_dev *pdev)
+static void __devexit dscc4_remove_one(struct pci_dev *pdev)
 {
 	struct dscc4_pci_priv *ppriv;
 	struct dscc4_dev_priv *root;
@@ -1796,12 +1959,16 @@
 	root = ppriv->root;
 
 	ioaddr = hdlc_to_dev(&root->hdlc)->base_addr;
+
+	dscc4_pci_reset(pdev, ioaddr);
+
 	free_irq(pdev->irq, root);
 	pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), ppriv->iqcfg,
 			    ppriv->iqcfg_dma);
 	for (i = 0; i < dev_per_card; i++) {
 		struct dscc4_dev_priv *dpriv = root + i;
 
+		dscc4_release_ring(dpriv);
 		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32),
 				    dpriv->iqrx, dpriv->iqrx_dma);
 		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32),
@@ -1843,6 +2010,7 @@
 	return 0;
 }
 
+#ifndef MODULE
 static int __init dscc4_setup(char *str)
 {
 	int *args[] = { &debug, &quartz, NULL }, **p = args;
@@ -1853,8 +2021,9 @@
 }
 
 __setup("dscc4.setup=", dscc4_setup);
+#endif /* MODULE */
 
-static struct pci_device_id dscc4_pci_tbl[] __devinitdata = {
+static struct pci_device_id dscc4_pci_tbl[] = {
 	{ PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_DSCC4,
 	        PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0,}
@@ -1865,7 +2034,7 @@
 	.name		= DRV_NAME,
 	.id_table	= dscc4_pci_tbl,
 	.probe		= dscc4_init_one,
-	.remove		= dscc4_remove_one,
+	.remove		= __devexit_p(dscc4_remove_one),
 };
 
 static int __init dscc4_init_module(void)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)