Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
PCMCIA Ethernet card
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Networking & Security
View previous topic :: View next topic  
Author Message
speak_see_hear
Apprentice
Apprentice


Joined: 12 Feb 2003
Posts: 168
Location: New Jersey

PostPosted: Thu Jan 27, 2005 3:45 pm    Post subject: PCMCIA Ethernet card Reply with quote

I am trying to install Gentoo on my Laptop. I have a Dynex PCMCIA Network card and cannot get it to connect. What module should I load to get connectivity? Thanks
Back to top
View user's profile Send private message
fatboyjim
Apprentice
Apprentice


Joined: 12 Jul 2004
Posts: 227
Location: UK

PostPosted: Thu Jan 27, 2005 5:02 pm    Post subject: Reply with quote

There is a section for PCMCIA Ethernet cards in the kernel's menuconfig, take a look

(Sorry can't be of more help :P)

Jim
_________________
-----------------------
fatboyjim
Gentoo/AMD64 Arch Tester (Inactive)
Back to top
View user's profile Send private message
speak_see_hear
Apprentice
Apprentice


Joined: 12 Feb 2003
Posts: 168
Location: New Jersey

PostPosted: Thu Jan 27, 2005 5:12 pm    Post subject: Reply with quote

No, I know I can get it running from the kernel, I need to get it running for installation of Gentoo. From what I can tell it needs 8139too as the driver and when I modprobe it, i get IRQ errors.

Thanks
Back to top
View user's profile Send private message
drkstorm
Tux's lil' helper
Tux's lil' helper


Joined: 22 Apr 2004
Posts: 118

PostPosted: Thu Jan 27, 2005 7:00 pm    Post subject: Reply with quote

compile the driver in module form, then

Code:

/etc/init.d/pcmcia start
Back to top
View user's profile Send private message
speak_see_hear
Apprentice
Apprentice


Joined: 12 Feb 2003
Posts: 168
Location: New Jersey

PostPosted: Thu Jan 27, 2005 8:58 pm    Post subject: Reply with quote

Maybe I am not explaining what my problem is very well. I am trying a new installation on my laptop of Gentoo. I have a PCMCIA Nework Card a Dynex DE-E201. In order to do the installation I have to have a network connection. So when I start the installation I enter:
gentoo-nofb dopcmcia

I know that I need to do a modprobe <module name here> but I don't know what module I need to modprobe. Please help.

Thanks
Back to top
View user's profile Send private message
drkstorm
Tux's lil' helper
Tux's lil' helper


Joined: 22 Apr 2004
Posts: 118

PostPosted: Thu Jan 27, 2005 10:13 pm    Post subject: Reply with quote

I'm not sure what chip it uses, there is no specific module for that brand, you may want to try

Code:

modprobe pcnet_cs


I had a d-link card that was not specifically supported, but was in the generic list under pcnet_cs, however, when I did the /etc/init.d/pcmcia start it automatically loaded the correct driver for that card and started pcmcia services, but then again I used the minimal boot cd, if this is not done from a cd then I have no idea
Back to top
View user's profile Send private message
kepik_k
n00b
n00b


Joined: 27 Nov 2004
Posts: 40
Location: USA

PostPosted: Tue Feb 01, 2005 10:46 pm    Post subject: Reply with quote

speak_see_hear wrote:
Maybe I am not explaining what my problem is very well. I am trying a new installation on my laptop of Gentoo. I have a PCMCIA Nework Card a Dynex DE-E201. In order to do the installation I have to have a network connection. So when I start the installation I enter:
gentoo-nofb dopcmcia

I know that I need to do a modprobe <module name here> but I don't know what module I need to modprobe. Please help.

Thanks


dmesg and/or lspci, both will give feed back on what the LiveCD kernel recognizes it as ......
According to this post: http://www.linuxquestions.org/hcl/showproduct.php?product=1641
(granted it's not the exact same model) try using a 8139too module
Code:

modprobe 8139too
modprobe 8139

_________________
I'm still learning, so I guess that means I'm still alive
Back to top
View user's profile Send private message
ewtrowbr
Apprentice
Apprentice


Joined: 08 May 2004
Posts: 153
Location: Columbus, OH

PostPosted: Tue Apr 19, 2005 2:31 am    Post subject: Reply with quote

I just bought this card for my gentoo Inspiron 8500... It hoses up the system every 15 minutes or so. with...

Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus e3>eth2: PCI Bus error 1340.
Apr 18 14:43:24 littleboy eth2: PCI Bus error 1340.

You get the idea... It stops when I eject the card. I have tried with 8139too as a module and built in. Same result both times.

Any success stories with this card, please share...

erich
Back to top
View user's profile Send private message
lambroger
n00b
n00b


Joined: 06 Oct 2004
Posts: 19

PostPosted: Sun May 08, 2005 7:37 pm    Post subject: Reply with quote

Found these at the dynex site www.dynexproducts.com. Seems the DX-E201 is a cross between the rtl8129 and the rtl8139, hopefully these files will help to make a module you can use.

kern_compat.h
Code:
#ifndef _KERN_COMPAT_H
#define _KERN_COMPAT_H
/* kern_compat.h: Linux PCI network adapter backward compatibility code. */
/*
   $Revision: 1.3 $ $Date: 2000/04/08 01:07:02 $

   Kernel compatibility defines.
   This file provides macros to mask the difference between kernel versions.
   It is designed primarily for network device drivers.

   Written 1999-2000 Donald Becker, Scyld Computing Corporation
   This software may be used and distributed according to the terms
   of the GNU General Public License (GPL), incorporated herein by
   reference.  Drivers interacting with these functions are derivative
   works and thus are covered the GPL.  They must include an explicit
   GPL notice.

   This code provides inline scan and activate functions for PCI network
   interfaces.  It has an interface identical to pci-scan.c, but is
   intended as an include file to simplify using updated drivers with older
   kernel versions.
   This code version matches pci-scan.c:v0.05 9/16/99

   The author may be reached as becker@scyld.com, or
   Donald Becker
   Scyld Computing Corporation
   410 Severn Ave., Suite 210
   Annapolis MD 21403

   Other contributers:
   <none>
*/

#if ! defined(LINUX_VERSION_CODE)  ||  (LINUX_VERSION_CODE < 0x10000)
#include <linux/version.h>
#endif
#if LINUX_VERSION_CODE < 0x20300  &&  defined(MODVERSIONS)
#include <linux/modversions.h>
#endif

#if LINUX_VERSION_CODE < 0x20100  &&  ! defined(__alpha__)
#define ioremap(a,b)\
    (((unsigned long)(a) >= 0x100000) ? vremap(a,b) : (void*)(a))
#define iounmap(v)\
    do { if ((unsigned long)(v) >= 0x100000) vfree(v);} while (0)
#endif


#if LINUX_VERSION_CODE < 0x20115
#define MODULE_AUTHOR(name)  extern int nonesuch
#define MODULE_DESCRIPTION(string)  extern int nonesuch
#define MODULE_PARM(varname, typestring)  extern int nonesuch
#endif

#if LINUX_VERSION_CODE < 0x20123
#define hard_smp_processor_id() smp_processor_id()
#define test_and_set_bit(val, addr) set_bit(val, addr)
#define le16_to_cpu(val) (val)
#define cpu_to_le16(val) (val)
#define le16_to_cpus(val)
#define le32_to_cpu(val) (val)
#define cpu_to_le32(val) (val)
typedef long spinlock_t;
#define SPIN_LOCK_UNLOCKED 0
#define spin_lock(lock)
#define spin_unlock(lock)
#define spin_lock_irqsave(lock, flags)   save_flags(flags); cli();
#define spin_unlock_irqrestore(lock, flags) restore_flags(flags);
#endif

#if LINUX_VERSION_CODE <= 0x20139
#define   net_device_stats enet_statistics
#else
#define NETSTATS_VER2
#endif

#if LINUX_VERSION_CODE < 0x20155
#include <linux/bios32.h>
#define PCI_SUPPORT_VER1
/* A minimal version of the 2.2.* PCI support that handles configuration
   space access.
   Drivers that actually use pci_dev fields must do explicit compatibility.
   Note that the struct pci_dev * "pointer" is actually a byte mapped integer!
*/
#if LINUX_VERSION_CODE < 0x20020
struct pci_dev { int not_used; };
#endif

#define pci_find_slot(bus, devfn) (struct pci_dev*)((bus<<8) | devfn | 0xf0000)
#define bus_number(pci_dev) ((((int)(pci_dev))>>8) & 0xff)
#define devfn_number(pci_dev) (((int)(pci_dev)) & 0xff)

#ifndef CONFIG_PCI
extern inline int pci_present(void) { return 0; }
#else
#define pci_present pcibios_present
#endif

#define pci_read_config_byte(pdev, where, valp)\
   pcibios_read_config_byte(bus_number(pdev), devfn_number(pdev), where, valp)
#define pci_read_config_word(pdev, where, valp)\
   pcibios_read_config_word(bus_number(pdev), devfn_number(pdev), where, valp)
#define pci_read_config_dword(pdev, where, valp)\
   pcibios_read_config_dword(bus_number(pdev), devfn_number(pdev), where, valp)
#define pci_write_config_byte(pdev, where, val)\
   pcibios_write_config_byte(bus_number(pdev), devfn_number(pdev), where, val)
#define pci_write_config_word(pdev, where, val)\
   pcibios_write_config_word(bus_number(pdev), devfn_number(pdev), where, val)
#define pci_write_config_dword(pdev, where, val)\
   pcibios_write_config_dword(bus_number(pdev), devfn_number(pdev), where, val)
#else
#define PCI_SUPPORT_VER2
#endif

#if LINUX_VERSION_CODE < 0x20159
#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
#else
#define dev_free_skb(skb) dev_kfree_skb(skb);
#endif

#if LINUX_VERSION_CODE < 0x2030d
#define net_device device
#endif

#if ! defined(CAP_NET_ADMIN)
#define capable(CAP_XXX) (suser())
#endif
#if ! defined(HAS_NETIF_QUEUE)
#define netif_wake_queue(dev)  mark_bh(NET_BH);
#endif

#ifndef _PCI_SCAN_H
/* A few user-configurable values that may be modified when a module. */
static int min_pci_latency = 32;
extern int debug;

/* Bhahh.  We must redeclare this to work with modversion.h */
extern unsigned long get_module_symbol(char *, char *);

#if (LINUX_VERSION_CODE < 0x20100)
#define PCI_CAPABILITY_LIST   0x34   /* Offset of first capability list entry */
#define PCI_STATUS_CAP_LIST   0x10   /* Support Capability List */
#define PCI_CAP_ID_PM      0x01   /* Power Management */
#endif

enum pci_id_flags_bits {
   /* Set PCI command register bits before calling probe1(). */
   PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
   /* Read and map the single following PCI BAR. */
   PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
   PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
};

struct pci_id_info {
   const char *name;
   struct match_info {
      int   pci, pci_mask, subsystem, subsystem_mask;
      int revision, revision_mask;             /* Only 8 bits. */
   } id;
   enum pci_id_flags_bits pci_flags;
   int io_size;            /* Needed for I/O region check or ioremap(). */
   int drv_flags;            /* Driver use, intended as capability flags. */
};

enum drv_id_flags {
   PCI_HOTSWAP=1, /* Leave module loaded for Cardbus-like chips. */
};
enum drv_pwr_action {
   DRV_NOOP,         /* No action. */
   DRV_ATTACH,         /* The driver may expect power ops. */
   DRV_SUSPEND,      /* Machine suspending, next event RESUME or DETACH. */
   DRV_RESUME,         /* Resume from previous SUSPEND  */
   DRV_DETACH,         /* Card will-be/is gone. Valid from SUSPEND! */
   DRV_PWR_WakeOn,      /* Put device in e.g. Wake-On-LAN mode. */
   DRV_PWR_DOWN,      /* Go to lowest power mode. */
   DRV_PWR_UP,         /* Go to normal power mode. */
};

struct drv_id_info {
   const char *name;         /* Single-word driver name. */
   int flags;
   int pci_class;            /* Typically PCI_CLASS_NETWORK_ETHERNET<<8. */
   struct pci_id_info *pci_dev_tbl;
   void *(*probe1)(struct pci_dev *pdev, void *dev_ptr,
               long ioaddr, int irq, int table_idx, int fnd_cnt);
   /* Optional, called for suspend, resume and detach. */
   int (*pwr_event)(void *dev, int event);
#if 0
   /* Internal values. */
   struct drv_id_info *next;
   void *cb_ops;
#endif
};

enum  acpi_pwr_state {ACPI_D0, ACPI_D1, ACPI_D2, ACPI_D3};
static inline int acpi_wake(struct pci_dev *pdev);
static inline int acpi_set_pwr_state(struct pci_dev *pdev, enum acpi_pwr_state new_state);

static int (*register_cb_hook)(struct drv_id_info *did);
static void (*unregister_cb_hook)(struct drv_id_info *did);

#if LINUX_VERSION_CODE > 0x20118  &&  defined(MODULE)
MODULE_PARM(min_pci_latency, "i");
#endif

/*
  This code is not intended to support every configuration.
  It is intended to minimize duplicated code by providing the functions
  needed in almost every PCI driver.

  The "no kitchen sink" policy:
  Additional features and code will be added to this module only if more
  than half of the drivers for common hardware would benefit from the feature.
*/

/*
  Ideally we would detect and number all cards of a type (e.g. network) in
  PCI slot order.
  But that does not work with hot-swap card, CardBus cards and added drivers.
  So instead we detect just the each chip table in slot order.

  This routine takes a PCI ID table, scans the PCI bus, and calls the
  associated attach/probe1 routine with the hardware already activated and
  single I/O or memory address already mapped.

  This routine will later be supplemented with CardBus and hot-swap PCI
  support using the same table.  Thus the pci_chip_tbl[] should not be
  marked as __initdata.
*/

#if LINUX_VERSION_CODE >= 0x20200
/* The PCI code in 2.2 is harder to use, and the extra complexity serves
   no real purpose.  The resource code in 2.3 is far worse.  It is a complex
   abstaction layer with negative benefit. */
static inline int pci_drv_register(struct drv_id_info *drv_id, void *initial_device)
{
   int chip_idx, cards_found = 0;
   struct pci_dev *pdev = NULL;
   struct pci_id_info *pci_tbl = drv_id->pci_dev_tbl;
   void *newdev;

   while ((pdev = pci_find_class(drv_id->pci_class, pdev)) != 0) {
      u32 pci_id, pci_subsys_id, pci_class_rev;
      u16 pci_command, new_command;
      int pci_flags, irq;
      long pciaddr;
      long ioaddr;

      pci_read_config_dword(pdev, PCI_VENDOR_ID, &pci_id);
      pci_read_config_dword(pdev, PCI_SUBSYSTEM_ID, &pci_subsys_id);
      pci_read_config_dword(pdev, PCI_REVISION_ID, &pci_class_rev);

      for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) {
         struct pci_id_info *chip = &pci_tbl[chip_idx];
         if ((pci_id & chip->id.pci_mask) == chip->id.pci
            && (pci_subsys_id&chip->id.subsystem_mask) == chip->id.subsystem
            && (pci_class_rev&chip->id.revision_mask) == chip->id.revision)
            break;
      }
      if (pci_tbl[chip_idx].name == 0)       /* Compiled out! */
         continue;

      pci_flags = pci_tbl[chip_idx].pci_flags;
      irq = pdev->irq;
#if LINUX_VERSION_CODE >= 0x2030C
      /* Wow. A oversized, hard-to-use abstraction. Bogus.  Bad job Linus. */
      pciaddr = pdev->resource[(pci_flags >> 4) & 7].start;
#else
      pciaddr = pdev->base_address[(pci_flags >> 4) & 7];
#if defined(__alpha__)         /* Really any machine with 64 bit addressing. */
      if (pci_flags & PCI_ADDR_64BITS)
         pciaddr |= ((long)pdev->base_address[((pci_flags>>4)&7)+ 1]) << 32;
#endif
#endif
      if (debug > 2)
         printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n",
               pci_tbl[chip_idx].name, pciaddr, irq);

      if ((pciaddr & PCI_BASE_ADDRESS_SPACE_IO)) {
         ioaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK;
         if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
            continue;
      } else if ((ioaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK,
                                 pci_tbl[chip_idx].io_size)) == 0) {
         printk(KERN_INFO "Failed to map PCI address %#lx for device "
               "'%s'.\n", pciaddr, pci_tbl[chip_idx].name);
         continue;
      }

      if ( ! (pci_flags & PCI_NO_ACPI_WAKE))
         acpi_wake(pdev);
      pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
      new_command = pci_command | (pci_flags & 7);
      if (pci_command != new_command) {
         printk(KERN_INFO "  The PCI BIOS has not enabled the"
               " device at %d/%d!  Updating PCI command %4.4x->%4.4x.\n",
               pdev->bus->number, pdev->devfn, pci_command, new_command);
         pci_write_config_word(pdev, PCI_COMMAND, new_command);
      }

      newdev = drv_id->probe1(pdev, initial_device,
                        ioaddr, irq, chip_idx, cards_found);
      if (newdev  && (pci_flags & PCI_COMMAND_MASTER))
         pci_set_master(pdev);
      if (newdev  && (pci_flags & PCI_COMMAND_MASTER)  &&
         ! (pci_flags & PCI_NO_MIN_LATENCY)) {
         u8 pci_latency;
         pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
         if (pci_latency < min_pci_latency) {
            printk(KERN_INFO "  PCI latency timer (CFLT) is "
                  "unreasonably low at %d.  Setting to %d clocks.\n",
                  pci_latency, min_pci_latency);
            pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency);
         }
      }
      initial_device = 0;
      cards_found++;
   }

   if ((drv_id->flags & PCI_HOTSWAP)
      && (register_cb_hook =
         (void *)get_module_symbol(NULL, "do_cb_register")) != 0
      && (*register_cb_hook)(drv_id) == 0) {
      MOD_INC_USE_COUNT;
      return 0;
   } else
      return cards_found ? 0 : -ENODEV;
}
#else
static inline int pci_drv_register(struct drv_id_info *drv_id, void *initial_device)
{
   int pci_index, cards_found = 0;
   unsigned char pci_bus, pci_device_fn;
   struct pci_dev *pdev;
   struct pci_id_info *pci_tbl = drv_id->pci_dev_tbl;
   void *newdev;

   if ( ! pcibios_present())
      return -ENODEV;

   for (pci_index = 0; pci_index < 0xff; pci_index++) {
      u32 pci_id, subsys_id, pci_class_rev;
      u16 pci_command, new_command;
      int chip_idx, irq, pci_flags;
      long pciaddr;
      long ioaddr;
      u32 pci_busaddr;
      u8 pci_irq_line;

      if (pcibios_find_class (drv_id->pci_class, pci_index,
                        &pci_bus, &pci_device_fn)
         != PCIBIOS_SUCCESSFUL)
         break;
      pcibios_read_config_dword(pci_bus, pci_device_fn,
                          PCI_VENDOR_ID, &pci_id);
      pcibios_read_config_dword(pci_bus, pci_device_fn,
                          PCI_SUBSYSTEM_ID, &subsys_id);
      pcibios_read_config_dword(pci_bus, pci_device_fn,
                          PCI_REVISION_ID, &pci_class_rev);

      for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) {
         struct pci_id_info *chip = &pci_tbl[chip_idx];
         if ((pci_id & chip->id.pci_mask) == chip->id.pci
            && (subsys_id & chip->id.subsystem_mask) == chip->id.subsystem
            && (pci_class_rev&chip->id.revision_mask) == chip->id.revision)
            break;
      }
      if (pci_tbl[chip_idx].name == 0)       /* Compiled out! */
         continue;

      pci_flags = pci_tbl[chip_idx].pci_flags;
      pdev = pci_find_slot(pci_bus, pci_device_fn);
      pcibios_read_config_byte(pci_bus, pci_device_fn,
                         PCI_INTERRUPT_LINE, &pci_irq_line);
      irq = pci_irq_line;
      pcibios_read_config_dword(pci_bus, pci_device_fn,
                          ((pci_flags >> 2) & 0x1C) + 0x10,
                          &pci_busaddr);
      pciaddr = pci_busaddr;
#if defined(__alpha__)
      if (pci_flags & PCI_ADDR_64BITS) {
         pcibios_read_config_dword(pci_bus, pci_device_fn,
                             ((pci_flags >> 2) & 0x1C) + 0x14,
                             &pci_busaddr);
         pciaddr |= ((long)pci_busaddr)<<32;
      }
#endif

      if (debug > 2)
         printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n",
               pci_tbl[chip_idx].name, pciaddr, irq);

      if ((pciaddr & PCI_BASE_ADDRESS_SPACE_IO)) {
         ioaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK;
         if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
            continue;
      } else if ((ioaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK,
                                 pci_tbl[chip_idx].io_size)) == 0) {
         printk(KERN_INFO "Failed to map PCI address %#lx.\n",
               pciaddr);
         continue;
      }

      if ( ! (pci_flags & PCI_NO_ACPI_WAKE))
         acpi_wake(pdev);
      pcibios_read_config_word(pci_bus, pci_device_fn,
                         PCI_COMMAND, &pci_command);
      new_command = pci_command | (pci_flags & 7);
      if (pci_command != new_command) {
         printk(KERN_INFO "  The PCI BIOS has not enabled the"
               " device at %d/%d!  Updating PCI command %4.4x->%4.4x.\n",
               pci_bus, pci_device_fn, pci_command, new_command);
         pcibios_write_config_word(pci_bus, pci_device_fn,
                             PCI_COMMAND, new_command);
      }

      newdev = drv_id->probe1(pdev, initial_device,
                        ioaddr, irq, chip_idx, cards_found);

      if (newdev  && (pci_flags & PCI_COMMAND_MASTER)  &&
         ! (pci_flags & PCI_NO_MIN_LATENCY)) {
         u8 pci_latency;
         pcibios_read_config_byte(pci_bus, pci_device_fn,
                            PCI_LATENCY_TIMER, &pci_latency);
         if (pci_latency < min_pci_latency) {
            printk(KERN_INFO "  PCI latency timer (CFLT) is "
                  "unreasonably low at %d.  Setting to %d clocks.\n",
                  pci_latency, min_pci_latency);
            pcibios_write_config_byte(pci_bus, pci_device_fn,
                                PCI_LATENCY_TIMER, min_pci_latency);
         }
      }
      initial_device = 0;
      cards_found++;
   }

   if ((drv_id->flags & PCI_HOTSWAP)
      && register_cb_hook
      && (*register_cb_hook)(drv_id) == 0) {
      MOD_INC_USE_COUNT;
      return 0;
   } else
      return cards_found ? 0 : -ENODEV;
}
#endif

static inline void pci_drv_unregister(struct drv_id_info *drv_id)
{
   /* We need do something only with CardBus support. */
   if ((unregister_cb_hook =
       (void *)get_module_symbol(NULL, "do_cb_unregister")) != 0) {
      (*unregister_cb_hook)(drv_id);
      MOD_DEC_USE_COUNT;
   }
   return;
}

/*
  Search PCI configuration space for the specified capability registers.
  Return the index, or 0 on failure.
*/
static inline int pci_find_capability(struct pci_dev *pdev, int findtype)
{
   u16 pci_status, cap_type;
   u8 pci_cap_idx;
   int cap_idx;

   pci_read_config_word(pdev, PCI_STATUS, &pci_status);
   if ( ! (pci_status & PCI_STATUS_CAP_LIST))
      return 0;
   pci_read_config_byte(pdev, PCI_CAPABILITY_LIST, &pci_cap_idx);
   cap_idx = pci_cap_idx;
   for (cap_idx = pci_cap_idx; cap_idx; cap_idx = (cap_type >> 8) & 0xff) {
      pci_read_config_word(pdev, cap_idx, &cap_type);
      if ((cap_type & 0xff) == findtype)
         return cap_idx;
   }
   return 0;
}


/* Change a device from D3 (sleep) to D0 (active).
   Return the old power state.
   This is more complicated than you might first expect since most cards
   forget all PCI config info during the transition! */
static inline int acpi_wake(struct pci_dev *pdev)
{
   u32 base[5], romaddr;
   u16 pci_command, pwr_command;
   u8  pci_latency, pci_cacheline, irq;
   int i, pwr_cmd_idx = pci_find_capability(pdev, PCI_CAP_ID_PM);

   if (pwr_cmd_idx == 0)
      return 0;
   pci_read_config_word(pdev, pwr_cmd_idx + 4, &pwr_command);
   if ((pwr_command & 3) == 0)
      return 0;
   pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
   for (i = 0; i < 5; i++)
      pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + i*4,
                          &base[i]);
   pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &romaddr);
   pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &pci_latency);
   pci_read_config_byte( pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline);
   pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq);

   pci_write_config_word(pdev, pwr_cmd_idx + 4, 0x0000);
   for (i = 0; i < 5; i++)
      if (base[i])
         pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0 + i*4,
                              base[i]);
   pci_write_config_dword(pdev, PCI_ROM_ADDRESS, romaddr);
   pci_write_config_byte( pdev, PCI_INTERRUPT_LINE, irq);
   pci_write_config_byte( pdev, PCI_CACHE_LINE_SIZE, pci_cacheline);
   pci_write_config_byte( pdev, PCI_LATENCY_TIMER, pci_latency);
   pci_write_config_word( pdev, PCI_COMMAND, pci_command | 5);
   return pwr_command & 3;
}

static inline int acpi_set_pwr_state(struct pci_dev *pdev, enum acpi_pwr_state new_state)
{
   u16 pwr_command;
   int pwr_cmd_idx = pci_find_capability(pdev, PCI_CAP_ID_PM);

   if (pwr_cmd_idx == 0)
      return 0;
   pci_read_config_word(pdev, pwr_cmd_idx + 4, &pwr_command);
   if ((pwr_command & 3) == ACPI_D3  &&  new_state != ACPI_D3)
      acpi_wake(pdev);      /* The complicated sequence. */
   pci_write_config_word(pdev, pwr_cmd_idx + 4,
                       (pwr_command & ~3) | new_state);
   return pwr_command & 3;
}
#endif

/*
 * Local variables:
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 4
 * End:
 */
#endif


dxe201.c[code:1:f55f21a366]/* DXE201: */
/*
Written 1997-2000 by Donald Becker.
This software may be used and distributed according to the terms of
the GNU General Public License (GPL), incorporated herein by reference.
Drivers based on or derived from this code fall under the GPL and must
retain the authorship, copyright and license notice. This file is not
a complete program and may only be used when the entire operating
system is licensed under the GPL.

This driver is for boards based on the RTL8129 and RTL8139 PCI ethernet
chips.

The author may be reached as becker@scyld.com, or C/O
Scyld Computing Corporation
410 Severn Ave., Suite 210
Annapolis MD 21403

Support and updates available at
http://www.scyld.com/network/rtl8139.html

Twister-tuning table provided by Kinston <shangh@realtek.com.tw>.
*/

/* These identify the driver base version and may not be removed. */
static const char versionA[] =
"DXE201:v1.11a 7/14/2000 Donald Becker, becker@scyld.com.\n";
static const char versionB[] =
" http://www.scyld.com/network/rtl8139.html\n";


/* Version 1.11 is originally written by Donald Becker.
Version 1.11a is modified by Clifford Chiang, wrchiang@realtek.com.tw,
with Link Down Power Saving */



#ifndef USE_MEM_OPS
/* Note: Register access width and timing restrictions apply in MMIO mode.
This updated driver should nominally work, but I/O mode is better tested. */
#define USE_IO_OPS
#endif

/* The user-configurable values.
These may be modified when a driver module is loaded.*/
static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 20;

/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
The RTL chips use a 64 element hash table based on the Ethernet CRC. It
is efficient to update the hardware filter, but recalculating the table
for a long filter list is painful. */
static int multicast_filter_limit = 32;

/* Used to pass the full-duplex flag, etc. */
#define MAX_UNITS 8 /* More are supported, limit only on options */
static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};

/* Operational parameters that are set at compile time. */

/* Size of the in-memory receive ring. */
#define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */
#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
#define TX_BUF_SIZE 1536

/* PCI Tuning Parameters
Threshold is bytes transferred to chip before transmission starts. */
#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */

/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. */
#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */
#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */
#define TX_DMA_BURST 4 /* Calculate as 16<<val. */

/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (6*HZ)

#ifndef __KERNEL__
#define __KERNEL__
#endif
#if !defined(__OPTIMIZE__)
#warning You must compile this file with the correct options!
#warning See the last lines of the source file.
#error You must compile this driver with "-O".
#endif

#include <linux/config.h>
#if defined(CONFIG_SMP) && ! defined(__SMP__)
#define __SMP__
#endif
#if defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
#define MODVERSIONS
#endif

#include <linux/version.h>
#include <linux/module.h>
#if LINUX_VERSION_CODE < 0x20300 && defined(MODVERSIONS)
#include <linux/modversions.h>
#endif

#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>

#if LINUX_VERSION_CODE >= 0x20300
#include <linux/spinlock.h>
#elif LINUX_VERSION_CODE >= 0x20200
#include <asm/spinlock.h>
#endif

#ifdef INLINE_PCISCAN
#include "k_compat.h"
#else
// #include "pci-scan.h"
#include "kern_compat.h"
#endif

#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
char kernel_version[] = UTS_RELEASE;
#endif

/*
Theory of Operation

I. Board Compatibility

This device driver is designed for the RealTek RTL8129 series, the RealTek
Fast Ethernet controllers for PCI and CardBus. This chip is used on many
low-end boards, sometimes with custom chip labels.


II. Board-specific settings

PCI bus devices are configured by the system at boot time, so no jumpers
need to be set on the board. The system BIOS will assign the
PCI INTA signal to a (preferably otherwise unused) system IRQ line.
Note: Kernel versions earlier than 1.3.73 do not support shared PCI
interrupt lines.

III. Driver operation

IIIa. Rx Ring buffers

The receive unit uses a single linear ring buffer rather than the more
common (and more efficient) descriptor-based architecture. Incoming frames
are sequentially stored into the Rx region, and the host copies them into
skbuffs.

Comment: While it is theoretically possible to process many frames in place,
any delay in Rx processing would block the Rx ring and cause us to drop
frames. It would be difficult to design a protocol stack where the data
buffer could be recalled by the device driver.

IIIb. Tx operation

The RTL8129 uses a fixed set of four Tx descriptors in register space. Tx
frames must be 32 bit aligned. Linux aligns the IP header on word
boundaries, and 14 byte ethernet header means that almost all frames will
need to be copied to an alignment buffer. The driver statically allocates
alignment the four alignment buffers at open() time.

IVb. References

http://www.realtek.com.tw/cn/cn.html
http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html

IVc. Errata

*/


static void *rtl8139_probe1(struct pci_dev *pdev, void *init_dev,
long ioaddr, int irq, int chip_idx, int find_cnt);
static int rtl_pwr_event(void *dev_instance, int event);

enum chip_capability_flags {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02,
HAS_LNK_CHNG=0x04};
#ifdef USE_IO_OPS
#define RTL8139_IOTYPE PCI_USES_MASTER|PCI_USES_IO |PCI_ADDR0
#else
#define RTL8139_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR1
#endif
#define RTL8129_CAPS HAS_MII_XCVR
#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG

/* Note: Update the marked constant in _attach() if the RTL8139B entry moves.*/
static struct pci_id_info pci_tbl[] = {
{"RealTek RTL8129 Fast Ethernet", { 0x812910ec, 0xffffffff,},
RTL8139_IOTYPE, 0x80, RTL8129_CAPS, },
{"RealTek RTL8139 Fast Ethernet", { 0x813910ec, 0xffffffff,},
RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
{"RealTek RTL8139B PCI/CardBus", { 0x813810ec, 0xffffffff,},
RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
{"Dynex DX-E201 CardBus PC Card", { 0x13401186, 0xffffffff,},
RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
{"SMC1211TX EZCard 10/100 (RealTek RTL8139)", { 0x12111113, 0xffffffff,},
RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
{"Accton MPX5030 (RealTek RTL8139)", { 0x12111113, 0xffffffff,},
RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
{0,}, /* 0 terminated list. */
};

struct drv_id_info rtl8139_drv_id = {
"Best Buy", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_tbl,
rtl8139_probe1, rtl_pwr_event };

#ifndef USE_IO_OPS
#undef inb
#undef inw
#undef inl
#undef outb
#undef outw
#undef outl
#define inb readb
#define inw readw
#define inl readl
#define outb writeb
#define outw writew
#define outl writel
#endif

/* The rest of these values should never change. */
#define NUM_TX_DESC 4 /* Number of Tx descriptor registers. */

/* Symbolic offsets to registers. */
enum RTL8129_registers {
MAC0=0, /* Ethernet hardware address. */
MAR0=8, /* Multicast filter. */
TxStatus0=0x10, /* Transmit status (Four 32bit registers). */
TxAddr0=0x20, /* Tx descriptors (also four 32bit). */
RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
IntrMask=0x3C, IntrStatus=0x3E,
TxConfig=0x40, RxConfig=0x44,
Timer=0x48, /* A general-purpose counter. */
RxMissed=0x4C, /* 24 bits valid, write clears. */
Cfg9346=0x50, Config0=0x51, Config1=0x52,
FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B,
MultiIntr=0x5C, TxSummary=0x60,
MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,
NWayExpansion=0x6A,
/* Undocumented registers, but required for proper operation. */
FIFOTMS=0x70, /* FIFO Control and test. */
CSCR=0x74, /* Chip Status and Configuration Register. */
PARA78=0x78, PARA7c=0x7c, /* Magic transceiver parameter register. */
Config5=0xD8,
};

enum ChipCmdBits {
CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };

/* Interrupt register bits, using my own meaningful names. */
enum IntrStatusBits {
PCIErr=0x8000, PCSTimeout=0x4000,
RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,
TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,
};
enum TxStatusBits {
TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,
TxOutOfWindow=0x20000000, TxAborted=0x40000000, TxCarrierLost=0x80000000,
};
enum RxStatusBits {
RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,
RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,
RxBadAlign=0x0002, RxStatusOK=0x0001,
};

/* Twister tuning parameters from RealTek.
Completely undocumented, but required to tune bad links. */
enum CSCRBits {
CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
CSCR_LinkDownCmd=0x0f3c0,
};
#define PARA78_default 0x78fa8388
#define PARA7c_default 0xcb38de43 /* param[0][3] */
#define PARA7c_xxx 0xcb38de43
unsigned long param[4][4]={
{0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},
{0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
{0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
{0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}
};

#define PRIV_ALIGN 15 /* Desired alignment mask */
struct rtl8129_private {
struct net_device *next_module;
void *priv_addr; /* Unaligned address for kfree */
int chip_id;
int drv_flags;
struct pci_dev *pci_dev;
struct net_device_stats stats;
struct timer_list timer; /* Media selection timer. */
unsigned char *rx_ring;
unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
unsigned int rx_config;
unsigned int cur_tx, dirty_tx, tx_flag;
unsigned long tx_full; /* The Tx queue is full. */
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
struct sk_buff* tx_skbuff[NUM_TX_DESC];
unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
unsigned char *tx_bufs; /* Tx bounce buffer region. */
char phys[4]; /* MII device addresses. */
char twistie, twist_row, twist_col; /* Twister tune state. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
unsigned int duplex_lock:1;
unsigned int default_port:4; /* Last dev->if_port value. */
unsigned int media2:4; /* Secondary monitored media port. */
unsigned int medialock:1; /* Don't sense media type. */
unsigned int mediasense:1; /* Media sensing in progress. */
};

#ifdef MODULE
#if LINUX_VERSION_CODE > 0x20115
MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
MODULE_DESCRIPTION("RealTek RTL8129/8139 Fast Ethernet driver");
MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(multicast_filter_limit, "i");
MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM(debug, "i");
#endif
#endif

static int rtl8129_open(struct net_device *dev);
static int read_eeprom(long ioaddr, int location, int addr_len);
static int mdio_read(struct net_device *dev, int phy_id, int location);
static void mdio_write(struct net_device *dev, int phy_id, int location, int val);
static void rtl8129_timer(unsigned long data);
static void rtl8129_tx_timeout(struct net_device *dev);
static void rtl8129_init_ring(struct net_device *dev);
static int rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int rtl8129_rx(struct net_device *dev);
static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static int rtl8129_close(struct net_device *dev);
static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static struct net_device_stats *rtl8129_get_stats(struct net_device *dev);
static inline u32 ether_crc(int length, unsigned char *data);
static void set_rx_mode(struct net_device *dev);


/* A list of all installed RTL8129 devices, for removing the driver module. */
static struct net_device *root_rtl8129_dev = NULL;

#ifndef MODULE
int rtl8139_probe(struct net_device *dev)
{
static int did_version = 0; /* Already printed version info. */

if (debug > 0 && did_version++ == 0)
printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
return pci_drv_register(&rtl8139_drv_id, dev);
}
#endif

static void *rtl8139_probe1(struct pci_dev *pdev, void *init_dev,
long ioaddr, int irq, int chip_idx, int found_cnt)
{
struct net_device *dev;
struct rtl8129_private *np;
void *priv_mem;
int i, option = found_cnt < MAX_UNITS ? options[found_cnt] : 0;

dev = init_etherdev(init_dev, 0);

printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
dev->name, pci_tbl[chip_idx].name, ioaddr, irq);

/* Bring the chip out of low-power mode. */
outb(0x00, ioaddr + Config1);

{
int addr_len = read_eeprom(ioaddr, 0, 8) == 0x8129 ? 8 : 6;
for (i = 0; i < 3; i++)
((u16 *)(dev->dev_addr))[i] =
le16_to_cpu(read_eeprom(ioaddr, i+7, addr_len));
}

for (i = 0; i < 5; i++)
printk("%2.2x:", dev->dev_addr[i]);
printk("%2.2x.\n", dev->dev_addr[i]);

/* Make certain elements e.g. descriptor lists are aligned. */
priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
/* Check for the very unlikely case of no memory. */
if (priv_mem == NULL)
return NULL;

/* We do a request_region() to register /proc/ioports info. */
request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);

dev->base_addr = ioaddr;
dev->irq = irq;

dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
memset(np, 0, sizeof(*np));
np->priv_addr = priv_mem;

np->next_module = root_rtl8129_dev;
root_rtl8129_dev = dev;

np->pci_dev = pdev;
np->chip_id = chip_idx;
np->drv_flags = pci_tbl[chip_idx].drv_flags;

/* Find the connected MII xcvrs.
Doing this in open() would allow detecting external xcvrs later, but
takes too much time. */
if (np->drv_flags & HAS_MII_XCVR) {
int phy, phy_idx;
for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(np->phys);
phy++) {
int mii_status = mdio_read(dev, phy, 1);
if (mii_status != 0xffff && mii_status != 0x0000) {
np->phys[phy_idx++] = phy;
printk(KERN_INFO "%s: MII transceiver found at address %d.\n",
dev->name, phy);
}
}
if (phy_idx == 0) {
printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM "
"transceiver.\n",
dev->name);
np->phys[0] = -1;
}
} else
np->phys[0] = 32;

/* Put the chip into low-power mode. */
outb(0xC0, ioaddr + Cfg9346);
outb(0x03, ioaddr + Config1);
outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */

/* The lower four bits are the media type. */
if (option > 0) {
np->full_duplex = (option & 0x210) ? 1 : 0;
np->default_port = option & 0xff;
if (np->default_port)
np->medialock = 1;
}

if (found_cnt < MAX_UNITS && full_duplex[found_cnt] > 0)
np->full_duplex = full_duplex[found_cnt];

if (np->full_duplex) {
printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
/* Changing the MII-advertised media because might prevent
re-connection. */
np->duplex_lock = 1;
}
if (np->default_port) {
printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n",
(option & 0x20 ? 100 : 10),
(option & 0x10 ? "full" : "half"));
mdio_write(dev, np->phys[0], 0,
((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */
((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
}

/* The Rtl8129-specific entries in the device structure. */
dev->open = &rtl8129_open;
dev->hard_start_xmit = &rtl8129_start_xmit;
dev->stop = &rtl8129_close;
dev->get_stats = &rtl8129_get_stats;
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &mii_ioctl;

return dev;
}

/* Serial EEPROM section. */

/* EEPROM_Ctrl bits. */
#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
#define EE_CS 0x08 /* EEPROM chip select. */
#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */
#define EE_WRITE_0 0x00
#define EE_WRITE_1 0x02
#define EE_DATA_READ 0x01 /* EEPROM chip data out. */
#define EE_ENB (0x80 | EE_CS)

/* Delay between EEPROM clock transitions.
No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
*/

#define eeprom_delay() inl(ee_addr)

/* The EEPROM commands include the alway-set leading bit. */
#define EE_WRITE_CMD (5)
#define EE_READ_CMD (6)
#define EE_ERASE_CMD (7)

static int read_eeprom(long ioaddr, int location, int addr_len)
{
int i;
unsigned retval = 0;
long ee_addr = ioaddr + Cfg9346;
int read_cmd = location | (EE_READ_CMD << addr_len);

outb(EE_ENB & ~EE_CS, ee_addr);
outb(EE_ENB, ee_addr);

/* Shift the read command bits out. */
for (i = 4 + addr_len; i >= 0; i--) {
int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
outb(EE_ENB | dataval, ee_addr);
eeprom_delay();
outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
eeprom_delay();
}
outb(EE_ENB, ee_addr);
eeprom_delay();

for (i = 16; i > 0; i--) {
outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
eeprom_delay();
retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
outb(EE_ENB, ee_addr);
eeprom_delay();
}

/* Terminate the EEPROM access. */
outb(~EE_CS, ee_addr);
return retval;
}

/* MII serial management: mostly bogus for now. */
/* Read and write the MII management registers using software-generated
serial MDIO protocol.
The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
met by back-to-back PCI I/O cycles, but we insert a delay to avoid
"overclocking" issues. */
#define MDIO_DIR 0x80
#define MDIO_DATA_OUT 0x04
#define MDIO_DATA_IN 0x02
#define MDIO_CLK 0x01
#define MDIO_WRITE0 (MDIO_DIR)
#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)

#define mdio_delay() inb(mdio_addr)

static char mii_2_8139_map[8] = {MII_BMCR, MII_BMSR, 0, 0, NWayAdvert,
NWayLPAR, NWayExpansion, 0 };

/* Syncronize the MII management interface by shifting 32 one bits out. */
static void mdio_sync(long mdio_addr)
{
int i;

for (i = 32; i >= 0; i--) {
outb(MDIO_WRITE1, mdio_addr);
mdio_delay();
outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr);
mdio_delay();
}
return;
}
static int mdio_read(struct net_device *dev, int phy_id, int location)
{
long mdio_addr = dev->base_addr + MII_SMI;
int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
int retval = 0;
int i;

if (phy_id > 31) { /* Really a 8139. Use internal registers. */
return location < 8 && mii_2_8139_map[location] ?
inw(dev->base_addr + mii_2_8139_map[location]) : 0;
}
mdio_sync(mdio_addr);
/* Shift the read command bits out. */
for (i = 15; i >= 0; i--) {
int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;

outb(MDIO_DIR | dataval, mdio_addr);
mdio_delay();
outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
mdio_delay();
}

/* Read the two transition, 16 data, and wire-idle bits. */
for (i = 19; i > 0; i--) {
outb(0, mdio_addr);
mdio_delay();
retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0);
outb(MDIO_CLK, mdio_addr);
mdio_delay();
}
return (retval>>1) & 0xffff;
}

static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
{
long mdio_addr = dev->base_addr + MII_SMI;
int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
int i;

if (phy_id > 31) { /* Really a 8139. Use internal registers. */
if (location < 8 && mii_2_8139_map[location])
outw(value, dev->base_addr + mii_2_8139_map[location]);
return;
}
mdio_sync(mdio_addr);

/* Shift the command bits out. */
for (i = 31; i >= 0; i--) {
int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
outb(dataval, mdio_addr);
mdio_delay();
outb(dataval | MDIO_CLK, mdio_addr);
mdio_delay();
}
/* Clear out extra bits. */
for (i = 2; i > 0; i--) {
outb(0, mdio_addr);
mdio_delay();
outb(MDIO_CLK, mdio_addr);
mdio_delay();
}
return;
}


static int rtl8129_open(struct net_device *dev)
{
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
long ioaddr = dev->base_addr;
int i;

/* Soft reset the chip. */
outb(CmdReset, ioaddr + ChipCmd);

MOD_INC_USE_COUNT;
if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev)) {
MOD_DEC_USE_COUNT;
return -EAGAIN;
}

/* The Rx ring allocation size is 2^N + delta, which is worst-case for
the kernel binary-buddy allocation. We allocate the Tx bounce buffers
at the same time to use some of the otherwise wasted space.
The delta of +16 is required for dribble-over because the receiver does
not wrap when the packet terminates just beyond the end of the ring. */
tp->rx_ring = kmalloc(RX_BUF_LEN + 16 + (TX_BUF_SIZE * NUM_TX_DESC),
GFP_KERNEL);
if (tp->rx_ring == NULL) {
if (debug > 0)
printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n",
dev->name, RX_BUF_LEN);
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
tp->tx_bufs = tp->rx_ring + RX_BUF_LEN + 16;

rtl8129_init_ring(dev);
tp->full_duplex = tp->duplex_lock;
tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000;
tp->rx_config =
(RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8);

/* Check that the chip has finished the reset. */
for (i = 1000; i > 0; i--)
if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)
break;

outl(cpu_to_le32(*(u32*)(dev->dev_addr + 0)), ioaddr + MAC0 + 0);
outl(cpu_to_le32(*(u32*)(dev->dev_addr + 4)), ioaddr + MAC0 + 4);

/* Must enable Tx/Rx before setting transfer thresholds! */
outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
outl(tp->rx_config, ioaddr + RxConfig);
/* The manual contradicts itself describing the proper IFG setting. */
outl((TX_DMA_BURST<<8)|0x00000000, ioaddr + TxConfig);

if (tp->phys[0] >= 0 || (tp->drv_flags & HAS_MII_XCVR)) {
u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
if (mii_reg5 == 0xffff)
; /* Not there */
else if ((mii_reg5 & 0x0100) == 0x0100
|| (mii_reg5 & 0x00C0) == 0x0040)
tp->full_duplex = 1;
if (debug > 1)
printk(KERN_INFO"%s: Setting %s%s-duplex based on"
" auto-negotiated partner ability %4.4x.\n", dev->name,
mii_reg5 == 0 ? "" :
(mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
tp->full_duplex ? "full" : "half", mii_reg5);
}

outb(0xC0, ioaddr + Cfg9346);
outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
outb(0x00, ioaddr + Cfg9346);

outl(virt_to_bus(tp->rx_ring), ioaddr + RxBuf);

/* Start the chip's Tx and Rx process. */
outl(0, ioaddr + RxMissed);
set_rx_mode(dev);

outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);

dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;

/* Enable all known interrupts by setting the interrupt mask. */
outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
| TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);

if (debug > 1)
printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d"
" GP Pins %2.2x %s-duplex.\n",
dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData),
tp->full_duplex ? "full" : "half");

/* Set the timer to switch to check for link beat and perhaps switch
to an alternate media type. */
init_timer(&tp->timer);
tp->timer.expires = jiffies + 3*HZ;
tp->timer.data = (unsigned long)dev;
tp->timer.function = &rtl8129_timer;
add_timer(&tp->timer);

return 0;
}

/* Start the hardware at open or resume. */
static void rtl_hw_start(struct net_device *dev)
{
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
long ioaddr = dev->base_addr;
int i;

/* Soft reset the chip. */
outb(CmdReset, ioaddr + ChipCmd);
/* Check that the chip has finished the reset. */
for (i = 1000; i > 0; i--)
if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)
break;
/* Restore our idea of the MAC address. */
outl(cpu_to_le32(*(u32*)(dev->dev_addr + 0)), ioaddr + MAC0 + 0);
outl(cpu_to_le32(*(u32*)(dev->dev_addr + 4)), ioaddr + MAC0 + 4);

/* Hmmm, do these belong here? */
outb(0x00, ioaddr + Cfg9346);
tp->cur_rx = 0;

/* Must enable Tx/Rx before setting transfer thresholds! */
outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
outl(tp->rx_config, ioaddr + RxConfig);
/* Check this value: the documentation contradicts ifself. Is the
IFG correct with bit 28:27 zero, or with |0x03000000 ? */
outl((TX_DMA_BURST<<8), ioaddr + TxConfig);

/* check_duplex() here. */
outb(0xC0, ioaddr + Cfg9346);
outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
outb(0x00, ioaddr + Cfg9346);

outl(virt_to_bus(tp->rx_ring), ioaddr + RxBuf);
/* Start the chip's Tx and Rx process. */
outl(0, ioaddr + RxMissed);
set_rx_mode(dev);
outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
/* Enable all known interrupts by setting the interrupt mask. */
outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
| TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);

}

static void rtl8129_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
long ioaddr = dev->base_addr;
int next_tick = 60*HZ;
int mii_reg5 = mdio_read(dev, tp->phys[0], 5);

if (! tp->duplex_lock && mii_reg5 != 0xffff) {
int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
if (tp->full_duplex != duplex) {
tp->full_duplex = duplex;
printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
" partner ability of %4.4x.\n", dev->name,
tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5);
outb(0xC0, ioaddr + Cfg9346);
outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
outb(0x00, ioaddr + Cfg9346);
}
}
/* Check for bogusness. */
if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) {
int status = inw(ioaddr + IntrStatus); /* Double check */
if (status & (TxOK | RxOK) && ! dev->interrupt) {
printk(KERN_ERR "%s: DX-E201 Interrupt line blocked, status %x.\n",
dev->name, status);
rtl8129_interrupt(dev->irq, dev, 0);
}
}
if (dev->tbusy && jiffies - dev->trans_start >= 2*TX_TIMEOUT)
rtl8129_tx_timeout(dev);

#if defined(RTL_TUNE_TWISTER)
/* This is a complicated state machine to configure the "twister" for
impedance/echos based on the cable length.
All of this is magic and undocumented.
*/
if (tp->twistie) switch(tp->twistie) {
case 1: {
if (inw(ioaddr + CSCR) & CSCR_LinkOKBit) {
/* We have link beat, let us tune the twister. */
outw(CSCR_LinkDownOffCmd, ioaddr + CSCR);
tp->twistie = 2; /* Change to state 2. */
next_tick = HZ/10;
} else {
/* Just put in some reasonable defaults for when beat returns. */
outw(CSCR_LinkDownCmd, ioaddr + CSCR);
outl(0x20,ioaddr + FIFOTMS); /* Turn on cable test mode. */
outl(PARA78_default ,ioaddr + PARA78);
outl(PARA7c_default ,ioaddr + PARA7c);
tp->twistie = 0; /* Bail from future actions. */
}
} break;
case 2: {
/* Read how long it took to hear the echo. */
int linkcase = inw(ioaddr + CSCR) & CSCR_LinkStatusBits;
if (linkcase == 0x7000) tp->twist_row = 3;
else if (linkcase == 0x3000) tp->twist_row = 2;
else if (linkcase == 0x1000) tp->twist_row = 1;
else tp->twist_row = 0;
tp->twist_col = 0;
tp->twistie = 3; /* Change to state 2. */
next_tick = HZ/10;
} break;
case 3: {
/* Put out four tuning parameters, one per 100msec. */
if (tp->twist_col == 0) outw(0, ioaddr + FIFOTMS);
outl(param[(int)tp->twist_row][(int)tp->twist_col], ioaddr + PARA7c);
next_tick = HZ/10;
if (++tp->twist_col >= 4) {
/* For short cables we are done.
For long cables (row == 3) check for mistune. */
tp->twistie = (tp->twist_row == 3) ? 4 : 0;
}
} break;
case 4: {
/* Special case for long cables: check for mistune. */
if ((inw(ioaddr + CSCR) & CSCR_LinkStatusBits) == 0x7000) {
tp->twistie = 0;
break;
} else {
outl(0xfb38de03, ioaddr + PARA7c);
tp->twistie = 5;
next_tick = HZ/10;
}
} break;
case 5: {
/* Retune for shorter cable (column 2). */
outl(0x20,ioaddr + FIFOTMS);
outl(PARA78_default, ioaddr + PARA78);
outl(PARA7c_default, ioaddr + PARA7c);
outl(0x00,ioaddr + FIFOTMS);
tp->twist_row = 2;
tp->twist_col = 0;
tp->twistie = 3;
next_tick = HZ/10;
} break;
}
#endif

if (debug > 2) {
if (tp->drv_flags & HAS_MII_XCVR)
printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n",
dev->name, inb(ioaddr + GPPinData));
else
printk(KERN_DEBUG"%s: Media selection tick, Link partner %4.4x.\n",
dev->name, inw(ioaddr + NWayLPAR));
printk(KERN_DEBUG"%s: Other registers are IntMask %4.4x IntStatus %4.4x"
" RxStatus %4.4x.\n",
dev->name, inw(ioaddr + IntrMask), inw(ioaddr + IntrStatus),
inl(ioaddr + RxEarlyStatus));
printk(KERN_DEBUG"%s: Chip config %2.2x %2.2x.\n",
dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1));
}

tp->timer.expires = jiffies + next_tick;
add_timer(&tp->timer);
}

static void rtl8129_tx_timeout(struct net_device *dev)
{
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
long ioaddr = dev->base_addr;
int mii_reg, i;

if (debug > 0)
printk(KERN_ERR "%s: Transmit timeout, status %2.2x %4.4x "
"media %2.2x.\n",
dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus),
inb(ioaddr + GPPinData));

/* Disable interrupts by clearing the interrupt mask. */
outw(0x0000, ioaddr + IntrMask);
/* Emit info to figure out what went wrong. */
printk(KERN_DEBUG "%s: Tx queue start entry %d dirty entry %d%s.\n",
dev->name, tp->cur_tx, tp->dirty_tx, tp->tx_full ? ", full" : "");
for (i = 0; i < NUM_TX_DESC; i++)
printk(KERN_DEBUG "%s: Tx descriptor %d is %8.8x.%s\n",
dev->name, i, inl(ioaddr + TxStatus0 + i*4),
i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : "");
printk(KERN_DEBUG "%s: MII #%d registers are:", dev->name, tp->phys[0]);
for (mii_reg = 0; mii_reg < 8; mii_reg++)
printk(" %4.4x", mdio_read(dev, tp->phys[0], mii_reg));
printk(".\n");

/* Stop a shared interrupt from scavenging while we are. */
tp->dirty_tx = tp->cur_tx = 0;
/* Dump the unsent Tx packets. */
for (i = 0; i < NUM_TX_DESC; i++) {
if (tp->tx_skbuff[i]) {
dev_free_skb(tp->tx_skbuff[i]);
tp->tx_skbuff[i] = 0;
tp->stats.tx_dropped++;
}
}
rtl_hw_start(dev);
tp->tx_full = dev->tbusy = 0;
return;
}


/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
static void
rtl8129_init_ring(struct net_device *dev)
{
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
int i;

tp->tx_full = 0;
tp->cur_rx = 0;
tp->dirty_tx = tp->cur_tx = 0;

for (i = 0; i < NUM_TX_DESC; i++) {
tp->tx_skbuff[i] = 0;
tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE];
}
}

static int
rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
long ioaddr = dev->base_addr;
int entry;

/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
if (jiffies - dev->trans_start >= TX_TIMEOUT)
rtl8129_tx_timeout(dev);
return 1;
}

/* Calculate the next Tx descriptor entry. */
entry = tp->cur_tx % NUM_TX_DESC;

tp->tx_skbuff[entry] = skb;
if ((long)skb->data & 3) { /* Must use alignment buffer. */
memcpy(tp->tx_buf[entry], skb->data, skb->len);
outl(virt_to_bus(tp->tx_buf[entry]), ioaddr + TxAddr0 + entry*4);
} else
outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + entry*4);
/* Note: the chip doesn't have auto-pad! */
outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
ioaddr + TxStatus0 + entry*4);

/* There is a race condition here -- we might read dirty_tx, take an
interrupt that clears the Tx queue, and only then set tx_full.
So we do this in two phases. */
if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) /* Typical path */
clear_bit(0, (void*)&dev->tbusy);
else {
set_bit(0, &tp->tx_full);
if (tp->cur_tx - (volatile int)tp->dirty_tx < NUM_TX_DESC) {
clear_bit(0, (void*)&dev->tbusy);
clear_bit(0, &tp->tx_full);
}
}

dev->trans_start = jiffies;
if (debug > 4)
printk(KERN_DEBUG"%s: Queued Tx packet at %p size %d to slot %d.\n",
dev->name, skb->data, (int)skb->len, entry);

return 0;
}

/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *)dev_instance;
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
int boguscnt = max_interrupt_work;
long ioaddr = dev->base_addr;
int link_changed = 0; /* Grrr, avoid bogus "uninitialized" warning */

#if defined(__i386__)
/* A lock to prevent simultaneous entry bug on Intel SMP machines. */
if (test_and_set_bit(0, (void*)&dev->interrupt)) {
printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
dev->name);
dev->interrupt = 0; /* Avoid halting machine. */
return;
}
#else
if (dev->interrupt) {
printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
return;
}
dev->interrupt = 1;
#endif

do {
int status = inw(ioaddr + IntrStatus);
/* Acknowledge all of the current interrupt sources ASAP, but
an first get an additional status bit from CSCR. */


if ((status & RxUnderrun) && inw(ioaddr+CSCR) & CSCR_LinkChangeBit)
{ link_changed = inw(ioaddr+CSCR) & CSCR_LinkChangeBit;

/* If link OK, disable Link Down Power Saving mode.
If link OFF, enable it. This mode is avaiable only for RTL8139C */


if((inb(ioaddr+TxConfig+3) & 0x7C)==0x74)
// 0x74 is RTL8139C HW Ver.
{
if((inb(ioaddr+GPPinData) & 0x04)==0)
outb(inb(ioaddr+Config5) | 0x4, ioaddr+Config5)
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Networking & Security All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum