Subject: [PATCH] au1k_ir - fix for 2.6

From: Stephen Hemminger <[email-masked]>
Date: Tue, 9 Dec 2003 15:54:40 -0800

This fixes some of the issues with the Alchemy irda driver for MIPS on
2.6.0-test11.  Tested with cross compile.  This driver is probably obsolete
but it is one of the two remaining users of dev_alloc

Changes:
	* irqreturn_t for irq routine
	* alloc_irdadev instead of dev_alloc
	* should work as non module

Some mips build notes:
	* no way to enable the device at present since drivers/net/irda/Kconfig
	  expects MIPS_A1000 and arch/mips/Kconfig defines SOC_AU1000!
	* include/asm-mips/timex.h does not define CLOCK_TICK_RATE for this
	  that type.  Code should probably be:

#ifdef CONFIG_SGI_IP22
#define CLOCK_TICK_RATE		1000000
#else
#define CLOCK_TICK_RATE		1193182
#endif

diff -Nru a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
--- a/drivers/net/irda/au1k_ir.c	Mon Dec  8 13:44:44 2003
+++ b/drivers/net/irda/au1k_ir.c	Mon Dec  8 13:44:44 2003
@@ -54,18 +54,17 @@
 #include <net/irda/irda_device.h>
 #include "net/irda/au1000_ircc.h"
 
-static int au1k_irda_net_init(struct net_device *);
 static int au1k_irda_start(struct net_device *);
 static int au1k_irda_stop(struct net_device *dev);
 static int au1k_irda_hard_xmit(struct sk_buff *, struct net_device *);
 static int au1k_irda_rx(struct net_device *);
-static void au1k_irda_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t au1k_irda_interrupt(int, void *, struct pt_regs *);
 static void au1k_tx_timeout(struct net_device *);
 static struct net_device_stats *au1k_irda_stats(struct net_device *);
 static int au1k_irda_ioctl(struct net_device *, struct ifreq *, int);
 static int au1k_irda_set_speed(struct net_device *dev, int speed);
 
-static void *dma_alloc(size_t, dma_addr_t *);
+static void *dma_alloc(size_t);
 static void dma_free(void *, size_t);
 
 static int qos_mtt_bits = 0x07;  /* 1 ms or more */
@@ -81,7 +80,7 @@
  * IrDA peripheral bug. You have to read the register
  * twice to get the right value.
  */
-u32 read_ir_reg(u32 addr) 
+static u32 read_ir_reg(u32 addr) 
 { 
 	readl(addr);
 	return readl(addr);
@@ -93,32 +92,23 @@
  * has the virtual and dma address of a buffer suitable for 
  * both, receive and transmit operations.
  */
-static db_dest_t *GetFreeDB(struct au1k_private *aup)
+static inline db_dest_t *GetFreeDB(struct au1k_private *aup)
 {
 	db_dest_t *pDB;
 	pDB = aup->pDBfree;
 
-	if (pDB) {
+	if (pDB) 
 		aup->pDBfree = pDB->pnext;
-	}
-	return pDB;
-}
 
-static void ReleaseDB(struct au1k_private *aup, db_dest_t *pDB)
-{
-	db_dest_t *pDBfree = aup->pDBfree;
-	if (pDBfree)
-		pDBfree->pnext = pDB;
-	aup->pDBfree = pDB;
+	return pDB;
 }
 
-
 /*
   DMA memory allocation, derived from pci_alloc_consistent.
   However, the Au1000 data cache is coherent (when programmed
   so), therefore we return KSEG0 address, not KSEG1.
 */
-static void *dma_alloc(size_t size, dma_addr_t * dma_handle)
+static void *dma_alloc(size_t size)
 {
 	void *ret;
 	int gfp = GFP_ATOMIC | GFP_DMA;
@@ -127,8 +117,7 @@
 
 	if (ret != NULL) {
 		memset(ret, 0, size);
-		*dma_handle = virt_to_bus(ret);
-		ret = KSEG0ADDR(ret);
+		ret = (void *) KSEG0ADDR(ret);
 	}
 	return ret;
 }
@@ -136,7 +125,7 @@
 
 static void dma_free(void *vaddr, size_t size)
 {
-	vaddr = KSEG0ADDR(vaddr);
+	vaddr = (void *) KSEG0ADDR(vaddr);
 	free_pages((unsigned long) vaddr, get_order(size));
 }
 
@@ -155,48 +144,7 @@
 	}
 }
 
-
-/* 
- * Device has already been stopped at this point.
- */
-static void au1k_irda_net_uninit(struct net_device *dev)
-{
-	dev->hard_start_xmit = NULL;
-	dev->open            = NULL;
-	dev->stop            = NULL;
-	dev->do_ioctl        = NULL;
-	dev->get_stats       = NULL;
-	dev->priv            = NULL;
-}
-
-
-static int au1k_irda_init(void)
-{
-	static unsigned version_printed = 0;
-	struct net_device *dev;
-	int err;
-
-	if (version_printed++ == 0) printk(version);
-
-	rtnl_lock();
-	dev = dev_alloc("irda%d", &err);
-	if (dev) {
-		dev->irq = AU1000_IRDA_RX_INT; /* TX has its own interrupt */
-		dev->init = au1k_irda_net_init;
-		dev->uninit = au1k_irda_net_uninit;
-		err = register_netdevice(dev);
-
-		if (err)
-			kfree(dev);
-		else
-			ir_devs[0] = dev;
-		printk(KERN_INFO "IrDA: Registered device %s\n", dev->name);
-	}
-	rtnl_unlock();
-	return err;
-}
-
-static int au1k_irda_init_iobuf(iobuff_t *io, int size)
+static __init int au1k_irda_init_iobuf(iobuff_t *io, int size)
 {
 	io->head = kmalloc(size, GFP_KERNEL);
 	if (io->head != NULL) {
@@ -208,25 +156,26 @@
 	return io->head ? 0 : -ENOMEM;
 }
 
-static int au1k_irda_net_init(struct net_device *dev)
+static __init int au1k_irda_init(void)
 {
-	struct au1k_private *aup = NULL;
-	int i, retval = 0, err;
+	static unsigned version_printed = 0;
+	struct net_device *dev;
+	struct au1k_private *aup;
 	db_dest_t *pDB, *pDBfree;
-	unsigned long temp;
+	int i, err;
 
-	dev->priv = kmalloc(sizeof(struct au1k_private), GFP_KERNEL);
-	if (dev->priv == NULL) {
-		retval = -ENOMEM;
-		goto out;
-	}
-	memset(dev->priv, 0, sizeof(struct au1k_private));
-	aup = dev->priv;
+	if (version_printed++ == 0) printk(version);
 
+	dev = alloc_irdadev(sizeof(struct au1k_private));
+	if (!dev) 
+		return -ENOMEM;
+
+	aup = dev->priv;
 	err = au1k_irda_init_iobuf(&aup->rx_buff, 14384);
 	if (err)
-		goto out;
+		goto out1;
 
+	dev->irq = AU1000_IRDA_RX_INT; /* TX has its own interrupt */
 	dev->open = au1k_irda_start;
 	dev->hard_start_xmit = au1k_irda_hard_xmit;
 	dev->stop = au1k_irda_stop;
@@ -244,19 +193,19 @@
 	aup->qos.min_turn_time.bits = qos_mtt_bits;
 	irda_qos_bits_to_value(&aup->qos);
 
-
+	err = -ENOMEM;
 	/* Tx ring follows rx ring + 512 bytes */
 	/* we need a 1k aligned buffer */
 	aup->rx_ring[0] = (ring_dest_t *)
-		dma_alloc(2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t)), &temp);
+		dma_alloc(2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t)));
+
+	if (!aup->rx_ring[0])
+		goto out2;
 
 	/* allocate the data buffers */
-	aup->db[0].vaddr = 
-		(void *)dma_alloc(MAX_BUF_SIZE * 2*NUM_IR_DESC, &temp);
-	if (!aup->db[0].vaddr || !aup->rx_ring[0]) {
-		retval = -ENOMEM;
-		goto out;
-	}
+	aup->db[0].vaddr = dma_alloc(MAX_BUF_SIZE * 2*NUM_IR_DESC);
+	if (!aup->db[0].vaddr) 
+		goto out3;
 
 	setup_hw_rings(aup, (u32)aup->rx_ring[0], (u32)aup->rx_ring[0] + 512);
 
@@ -275,16 +224,17 @@
 	/* attach a data buffer to each descriptor */
 	for (i=0; i<NUM_IR_DESC; i++) {
 		pDB = GetFreeDB(aup);
-		if (!pDB) goto out;
+		if (!pDB) goto out4;
 		aup->rx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff);
 		aup->rx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff);
 		aup->rx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff);
 		aup->rx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff);
 		aup->rx_db_inuse[i] = pDB;
 	}
+
 	for (i=0; i<NUM_IR_DESC; i++) {
 		pDB = GetFreeDB(aup);
-		if (!pDB) goto out;
+		if (!pDB) goto out4;
 		aup->tx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff);
 		aup->tx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff);
 		aup->tx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff);
@@ -294,24 +244,28 @@
 		aup->tx_ring[i]->flags = 0;
 		aup->tx_db_inuse[i] = pDB;
 	}
-	return 0;
 
-out:
-	if (aup->db[0].vaddr) 
-		dma_free((void *)aup->db[0].vaddr, 
-				MAX_BUF_SIZE * 2*NUM_IR_DESC);
-	if (aup->rx_ring[0])
-		kfree((void *)aup->rx_ring[0]);
-	if (aup->rx_buff.head)
-		kfree(aup->rx_buff.head);
-	if (dev->priv != NULL)
-		kfree(dev->priv);
-	unregister_netdevice(dev);
-	printk(KERN_ERR "%s: au1k_init_module failed.  Returns %d\n",
-	       dev->name, retval);
-	return retval;
-}
+	err = register_netdev(dev);
+	if (err)
+		goto out4;
+	else {
+		ir_devs[0] = dev;
+		printk(KERN_INFO "IrDA: Registered device %s\n", dev->name);
+	}
+	return err;
 
+ out4:
+	dma_free((void *)aup->db[0].vaddr, 
+		 MAX_BUF_SIZE * 2*NUM_IR_DESC);
+ out3:
+	dma_free((void *)aup->rx_ring[0],
+		 2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t)));
+ out2:
+	kfree(aup->rx_buff.head);
+ out1:
+	free_netdev(dev);
+	return err;
+}
 
 static int au1k_init(struct net_device *dev)
 {
@@ -361,11 +315,8 @@
 	char hwname[32];
 	struct au1k_private *aup = (struct au1k_private *) dev->priv;
 
-	MOD_INC_USE_COUNT;
-
 	if ((retval = au1k_init(dev))) {
 		printk(KERN_ERR "%s: error in au1k_init\n", dev->name);
-		MOD_DEC_USE_COUNT;
 		return retval;
 	}
 
@@ -373,7 +324,6 @@
 					0, dev->name, dev))) {
 		printk(KERN_ERR "%s: unable to get IRQ %d\n", 
 				dev->name, dev->irq);
-		MOD_DEC_USE_COUNT;
 		return retval;
 	}
 	if ((retval = request_irq(AU1000_IRDA_RX_INT, &au1k_irda_interrupt, 
@@ -381,7 +331,6 @@
 		free_irq(AU1000_IRDA_TX_INT, dev);
 		printk(KERN_ERR "%s: unable to get IRQ %d\n", 
 				dev->name, dev->irq);
-		MOD_DEC_USE_COUNT;
 		return retval;
 	}
 
@@ -418,19 +367,20 @@
 	/* disable the interrupt */
 	free_irq(AU1000_IRDA_TX_INT, dev);
 	free_irq(AU1000_IRDA_RX_INT, dev);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 static void __exit au1k_irda_exit(void)
 {
 	struct net_device *dev = ir_devs[0];
-	struct au1k_private *aup = (struct au1k_private *) dev->priv;
+	struct au1k_private *aup;
 
 	if (!dev) {
 		printk(KERN_ERR "au1k_ircc no dev found\n");
 		return;
 	}
+
+	aup = (struct au1k_private *) dev->priv;
 	if (aup->db[0].vaddr)  {
 		dma_free((void *)aup->db[0].vaddr, 
 				MAX_BUF_SIZE * 2*NUM_IR_DESC);
@@ -441,10 +391,16 @@
 				2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t)));
 		aup->rx_ring[0] = 0;
 	}
-	rtnl_lock();
-	unregister_netdevice(dev);
-	rtnl_unlock();
+
+	unregister_netdev(dev);
+
+	dma_free((void *)aup->db[0].vaddr, MAX_BUF_SIZE * 2*NUM_IR_DESC);
+	dma_free((void *)aup->rx_ring[0], 
+		 2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t)));
+	kfree(aup->rx_buff.head);
+
 	ir_devs[0] = 0;
+	free_netdev(dev);
 }

@@ -656,19 +612,21 @@
 }

-void au1k_irda_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t au1k_irda_interrupt(int irq, void *dev_id, 
+				       struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
 
 	if (dev == NULL) {
 		printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name);
-		return;
+		return IRQ_NONE;
 	}
 
 	writel(0, IR_INT_CLEAR); /* ack irda interrupts */
 
 	au1k_irda_rx(dev);
 	au1k_tx_ack(dev);
+	return IRQ_HANDLED;
 }

@@ -859,10 +817,8 @@
 	return &aup->stats;
 }
 
-#ifdef MODULE
 MODULE_AUTHOR("Pete Popov <[email-masked]>");
 MODULE_DESCRIPTION("Au1000 IrDA Device Driver");
 
 module_init(au1k_irda_init);
 module_exit(au1k_irda_exit);
-#endif /* MODULE */

---

From: Jean Tourrilhes <[email-masked]>
Date: Tue, 9 Dec 2003 16:22:14 -0800

> #define CLOCK_TICK_RATE		1193182

	I don't have the hardware and I'm not familiar with MIPS, so
if the authors doesn't answer, we will merge your patch as is.
	Thanks...

	Jean

---

From: Pete Popov <[email-masked]>
Date: 11 Dec 2003 12:06:07 -0800

> if the authors doesn't answer, we will merge your patch as is.

Go ahead.

Pete