[patch] drivers/net/cs89x0.c

From: Andrew Morton (andrewm@uow.edu.au)
Date: Sat Aug 26 2000 - 11:17:48 EST


Linus,

this is a patch from Jason Gunthorpe which fixes this driver's
EEPROM handling for use in the Cirrus CL-PS7500FE ARM target.

It also fixes a couple of error return values:
- return ENODEV;
+ return -ENODEV;

It passes x86 testing.

This patch also contains my fifth attempt since March to
update cs89x0.txt. Make my day :)

--- linux-2.4.0-test7/drivers/net/cs89x0.c Tue Jul 11 22:21:15 2000
+++ linux-akpm/drivers/net/cs89x0.c Sun Aug 13 22:55:38 2000
@@ -61,6 +61,11 @@
                     : MOD_INC/DEC race fix (see
                     : http://www.uwsg.indiana.edu/hypermail/linux/kernel/0003.3/1532.html)
 
+ Andrew Morton : andrewm@uow.edu.au / Kernel 2.4.0-test7-pre2
+ : Enhanced EEPROM support to cover more devices,
+ : abstracted IRQ mapping to support CONFIG_ARCH_CLPS7500 arch
+ : (Jason Gunthorpe <jgg@ualberta.ca>)
+
 */
 
 static char *version =
@@ -128,10 +133,26 @@
 
 #include "cs89x0.h"
 
-/* First, a few definitions that the brave might change. */
-/* A zero-terminated list of I/O addresses to be probed. */
+/* First, a few definitions that the brave might change.
+ A zero-terminated list of I/O addresses to be probed. Some special flags..
+ Addr & 1 = Read back the address port, look for signature and reset
+ the page window before probing
+ Addr & 3 = Reset the page window and probe
+ The CLPS eval board has the Cirrus chip at 0x80090300, in ARM IO space,
+ but it is possible that a Cirrus board could be plugged into the ISA
+ slots. */
+/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps
+ them to system IRQ numbers. This mapping is card specific and is set to
+ the configuration of the Cirrus Eval board for this chip. */
+#ifdef CONFIG_ARCH_CLPS7500
+static unsigned int netcard_portlist[] __initdata =
+ { 0x80090303, 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
+static unsigned int cs8900_irq_map[] = {12,0,0,0};
+#else
 static unsigned int netcard_portlist[] __initdata =
    { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
+static unsigned int cs8900_irq_map[] = {10,11,12,5};
+#endif
 
 #if DEBUGGING
 static unsigned int net_debug = DEBUGGING;
@@ -343,7 +364,7 @@
                 dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
                 if (dev->priv == 0)
                 {
- retval = ENOMEM;
+ retval = -ENOMEM;
                         goto out;
                 }
                 lp = (struct net_local *)dev->priv;
@@ -362,18 +383,20 @@
 
         /* if they give us an odd I/O address, then do ONE write to
            the address port, to get it back to address zero, where we
- expect to find the EISA signature word. */
+ expect to find the EISA signature word. An IO with a base of 0x3
+ will skip the test for the ADD_PORT. */
         if (ioaddr & 1) {
- ioaddr &= ~1;
- if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG)
- return -ENODEV;
+ if ((ioaddr & 2) != 2)
+ if ((inw((ioaddr & ~3)+ ADD_PORT) & ADD_MASK) != ADD_SIG)
+ return -ENODEV;
+ ioaddr &= ~3;
                 outw(PP_ChipID, ioaddr + ADD_PORT);
         }
 
- if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
- {
- retval = ENODEV;
- goto out1;
+ if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
+ {
+ retval = -ENODEV;
+ goto out1;
         }
 
         /* Fill in the 'dev' fields. */
@@ -403,15 +426,77 @@
                dev->base_addr);
 
         reset_chip(dev);
+
+ /* Here we read the current configuration of the chip. If there
+ is no Extended EEPROM then the idea is to not disturb the chip
+ configuration, it should have been correctly setup by automatic
+ EEPROM read on reset. So, if the chip says it read the EEPROM
+ the driver will always do *something* instead of complain that
+ adapter_cnf is 0. */
+ if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) ==
+ (EEPROM_OK|EEPROM_PRESENT)) {
+ /* Load the MAC. */
+ for (i=0; i < ETH_ALEN/2; i++) {
+ unsigned int Addr;
+ Addr = readreg(dev, PP_IA+i*2);
+ dev->dev_addr[i*2] = Addr & 0xFF;
+ dev->dev_addr[i*2+1] = Addr >> 8;
+ }
+
+ /* Load the Adapter Configuration.
+ Note: Barring any more specific information from some
+ other source (ie EEPROM+Schematics), we would not know
+ how to operate a 10Base2 interface on the AUI port.
+ However, since we do read the status of HCB1 and use
+ settings that always result in calls to control_dc_dc(dev,0)
+ a BNC interface should work if the enable pin
+ (dc/dc converter) is on HCB1. It will be called AUI
+ however. */
+
+ lp->adapter_cnf = 0;
+ i = readreg(dev, PP_LineCTL);
+ /* Preserve the setting of the HCB1 pin. */
+ if ((i & (HCB1 | HCB1_ENBL)) == (HCB1 | HCB1_ENBL))
+ lp->adapter_cnf |= A_CNF_DC_DC_POLARITY;
+ /* Save the sqelch bit */
+ if ((i & LOW_RX_SQUELCH) == LOW_RX_SQUELCH)
+ lp->adapter_cnf |= A_CNF_EXTND_10B_2 | A_CNF_LOW_RX_SQUELCH;
+ /* Check if the card is in 10Base-t only mode */
+ if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == 0)
+ lp->adapter_cnf |= A_CNF_10B_T | A_CNF_MEDIA_10B_T;
+ /* Check if the card is in AUI only mode */
+ if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUI_ONLY)
+ lp->adapter_cnf |= A_CNF_AUI | A_CNF_MEDIA_AUI;
+ /* Check if the card is in Auto mode. */
+ if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUTO_AUI_10BASET)
+ lp->adapter_cnf |= A_CNF_AUI | A_CNF_10B_T |
+ A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO;
+
+ /* IRQ. Other chips already probe, see below. */
+ if (lp->chip_type == CS8900)
+ lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK;
+
+ printk( "[Cirrus EEPROM] ");
+ }
 
- /* First check to see if an EEPROM is attached*/
+ printk("\n");
+
+ /* First check to see if an EEPROM is attached. */
         if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0)
- printk(KERN_WARNING "\ncs89x0: No EEPROM, relying on command line....\n");
+ printk(KERN_WARNING "cs89x0: No EEPROM, relying on command line....\n");
         else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) {
                 printk(KERN_WARNING "\ncs89x0: EEPROM read failed, relying on command line.\n");
         } else if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) {
- printk(KERN_WARNING "\ncs89x0: EEPROM checksum bad, relying on command line\n");
+ /* Check if the chip was able to read its own configuration starting
+ at 0 in the EEPROM*/
+ if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) !=
+ (EEPROM_OK|EEPROM_PRESENT))
+ printk(KERN_WARNING "cs89x0: Extended EEPROM checksum bad and no Cirrus EEPROM, relying on command line\n");
+
         } else {
+ /* This reads an extended EEPROM that is not documented
+ in the CS8900 datasheet. */
+
                 /* get transmission control word but keep the autonegotiation bits */
                 if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
                 /* Store adapter configuration */
@@ -464,17 +549,12 @@
         } else {
                 i = lp->isa_config & INT_NO_MASK;
                 if (lp->chip_type == CS8900) {
- /* the table that follows is dependent upon how you wired up your cs8900
- * in your system. The table is the same as the cs8900 engineering demo
- * board. irq_map also depends on the contents of the table. Also see
- * write_irq, which is the reverse mapping of the table below. */
- switch(i) {
- case 0: i = 10; break;
- case 1: i = 11; break;
- case 2: i = 12; break;
- case 3: i = 5; break;
- default: printk("\ncs89x0: bug: isa_config is %d\n", i);
- }
+ /* Translate the IRQ using the IRQ mapping table. */
+ if (i > sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]))
+ printk("\ncs89x0: bug: isa_config is %d\n", i);
+ else
+ i = cs8900_irq_map[i];
+
                         lp->irq_map = CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */
                 } else {
                         int irq_map_buff[IRQ_MAP_LEN/2];
@@ -490,7 +570,7 @@
                         dev->irq = i;
         }
 
- printk(", IRQ %d", dev->irq);
+ printk(" IRQ %d", dev->irq);
 
 #if ALLOW_DMA
         if (lp->use_dma)
@@ -741,7 +821,9 @@
         struct net_local *lp = (struct net_local *)dev->priv;
         unsigned int selfcontrol;
         int timenow = jiffies;
- /* control the DC to DC convertor in the SelfControl register. */
+ /* control the DC to DC convertor in the SelfControl register.
+ Note: This is hooked up to a general purpose pin, might not
+ always be a DC to DC convertor. */
 
         selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */
         if (((lp->adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)
@@ -753,7 +835,6 @@
         /* Wait for the DC/DC converter to power up - 500ms */
         while (jiffies - timenow < HZ)
                 ;
-
 }
 
 #define DETECTED_NONE 0
@@ -916,13 +997,13 @@
         int i;
 
         if (chip_type == CS8900) {
- switch(irq) {
- case 10: i = 0; break;
- case 11: i = 1; break;
- case 12: i = 2; break;
- case 5: i = 3; break;
- default: i = 3; break;
- }
+ /* Search the mapping table for the corrisponding IRQ pin. */
+ for (i = 0; i != sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]); i++)
+ if (cs8900_irq_map[i] == irq)
+ break;
+ /* Not found */
+ if (i == sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]))
+ i = 3;
                 writereg(dev, PP_CS8900_ISAINT, i);
         } else {
                 writereg(dev, PP_CS8920_ISAINT, irq);
@@ -1636,7 +1717,6 @@
 
 /*
  * Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS
-c cs89x0.c"
  * version-control: t
  * kept-new-versions: 5
  * c-indent-level: 8
--- linux-2.4.0-test7/Documentation/networking/cs89x0.txt Fri Aug 11 19:06:11 2000
+++ linux-akpm/Documentation/networking/cs89x0.txt Fri Aug 4 23:16:13 2000
@@ -308,6 +308,30 @@
 l) If during DMA operation you find erratic behavior or network data
    corruption you should use your PC's BIOS to slow the EISA bus clock.
 
+m) If the cs89x0 driver is compiled directly into the kernel
+ (non-modular) then its I/O address is automatically determined by
+ ISA bus probing. The IRQ number, media options, etc are determined
+ from the card's EEPROM.
+
+n) If the cs89x0 driver is compiled directly into the kernel, DMA
+ mode may be selected by providing the kernel with a boot option
+ 'cs89x0_dma=N' where 'N' is the desired DMA channel number (5, 6 or
+ 7).
+
+ Kernel boot options may be provided on the LILO command line:
+
+ LILO boot: linux cs89x0_dma=5
+
+ or they may be placed in /etc/lilo.conf:
+
+ image=/boot/bzImage-2.3.48
+ append="cs89x0_dma=5"
+ label=linux
+ root=/dev/hda5
+ read-only
+
+ The DMA Rx buffer size is hardwired to 16 kbytes in this mode.
+ (64k mode is not available).
 
 4.0 COMPILING THE DRIVER
 ===============================================================================
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Aug 31 2000 - 21:00:17 EST