Split up drivers and specific files, update flash map driver

SVN-Revision: 6765
lede-17.01
Florian Fainelli 2007-03-30 21:56:07 +00:00
parent 263d62cf19
commit ed5e0b9431
5 changed files with 1249 additions and 1228 deletions

View File

@ -0,0 +1,25 @@
#ifndef GT_IMGHDR_H
#define GT_IMGHDR_H
#define GTIMG_MAGIC "GMTK"
/* Product ID */
#define PID_RTL_AIRGO 1
#define PID_RTL_RALINK 2
#define PID_RDC_AIRGO 3
#define PID_RDC_RALINK 5 /* White Lable */
/* Gemtek */
typedef struct
{
UINT8 magic[4]; /* ASICII: GMTK */
UINT32 checksum; /* CRC32 */
UINT32 version; /* x.x.x.x */
UINT32 kernelsz; /* The size of the kernel image */
UINT32 imagesz; /* The length of this image file ( kernel + romfs + this header) */
UINT32 pid; /* Product ID */
UINT32 fastcksum; /* Partial CRC32 on (First(256), medium(256), last(512)) */
UINT32 reserved;
}gt_imghdr_t;
#endif

View File

@ -0,0 +1,244 @@
/*******************************************************************
* Simple Flash mapping for RDC3210 *
* *
* 2005.03.23 *
* Dante Su (dante_su@gemtek.com.tw) *
* Copyright (C) 2005 Gemtek Corporation *
*******************************************************************/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/config.h>
#ifndef RDC3210_STATIC_MAP
#define RDC3210_STATIC_MAP 0
#endif
#ifndef RDC3210_NO_FACTORY_DFLT
#define RDC3210_NO_FACTORY_DFLT 1
#endif
#ifndef RDC3210_USING_JFFS2
#define RDC3210_USING_JFFS2 1
#endif
#define WINDOW_ADDR 0xFFC00000
#define WINDOW_SIZE 0x00400000
#define BUSWIDTH 2
/* Dante: linked from linux-2.4.x/drivers/mtd/chips/flashdrv.c */
extern int flashdrv_get_size(void);
extern int flashdrv_get_sector(int addr);
extern int flashdrv_get_sector_addr(int sector);
extern int flashdrv_get_sector_size(int sector);
static struct mtd_info *rdc3210_mtd;
__u8 rdc3210_map_read8(struct map_info *map, unsigned long ofs)
{
return *(__u8 *)(map->map_priv_1 + ofs);
}
__u16 rdc3210_map_read16(struct map_info *map, unsigned long ofs)
{
return *(__u16 *)(map->map_priv_1 + ofs);
}
__u32 rdc3210_map_read32(struct map_info *map, unsigned long ofs)
{
return *(__u32 *)(map->map_priv_1 + ofs);
}
void rdc3210_map_write8(struct map_info *map, __u8 d, unsigned long adr)
{
*(__u8 *)(map->map_priv_1 + adr) = d;
}
void rdc3210_map_write16(struct map_info *map, __u16 d, unsigned long adr)
{
*(__u16 *)(map->map_priv_1 + adr) = d;
}
void rdc3210_map_write32(struct map_info *map, __u32 d, unsigned long adr)
{
*(__u32 *)(map->map_priv_1 + adr) = d;
}
void rdc3210_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
int i;
u16 *dst = (u16 *)(to);
u16 *src = (u16 *)(map->map_priv_1 + from);
for(i = 0; i < (len / 2); ++i)
dst[i] = src[i];
if(len & 1)
{
printk("# WARNNING!!! rdc3210_map_copy_from has odd length\n");
//dst[len - 1] = B0(src[i]);
}
}
void rdc3210_map_copy_to(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
int i;
u16 *dst = (u16 *)(map->map_priv_1 + to);
u16 *src = (u16 *)(from);
for(i = 0; i < (len / 2); ++i)
dst[i] = src[i];
if(len & 1)
{
printk("# WARNNING!!! rdc3210_map_copy_from has odd length\n");
//dst[len - 1] = B0(src[i]);
}
}
struct map_info rdc3210_map =
{
name: "RDC3210 Flash",
size: WINDOW_SIZE,
buswidth: BUSWIDTH,
read8: rdc3210_map_read8,
read16: rdc3210_map_read16,
read32: rdc3210_map_read32,
copy_from: rdc3210_map_copy_from,
write8: rdc3210_map_write8,
write16: rdc3210_map_write16,
write32: rdc3210_map_write32,
copy_to: rdc3210_map_copy_to,
};
/* Dante: This is the default static mapping, however this is nothing but a hint. (Say dynamic mapping) */
static struct mtd_partition rdc3210_parts[] =
{
{ name: "linux", offset: 0, size: 0x003C0000 }, /* 3840 KB = (Kernel + ROMFS) = (768 KB + 3072 KB) */
{ name: "romfs", offset: 0x000C0000, size: 0x00300000 }, /* 3072 KB */
{ name: "nvram", offset: 0x003C0000, size: 0x00010000 }, /* 64 KB */
#if RDC3210_STATIC_MAP || !RDC3210_NO_FACTORY_DFLT
{ name: "factory", offset: 0x003D0000, size: 0x00010000 }, /* 64 KB */
#endif
{ name: "bootldr", offset: 0x003E0000, size: 0x00020000 }, /* 128 KB */
};
#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
#define init_rdc3210_map init_module
#define cleanup_rdc3210_map cleanup_module
#endif
mod_init_t init_rdc3210_map(void)
{
printk(KERN_NOTICE "flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
rdc3210_map.map_priv_1 = ioremap(WINDOW_ADDR, WINDOW_SIZE);
if (!rdc3210_map.map_priv_1)
{
printk("Failed to ioremap\n");
return -EIO;
}
rdc3210_mtd = do_map_probe("cfi_probe", &rdc3210_map);
#if RDC3210_STATIC_MAP /* Dante: This is for fixed map */
if (rdc3210_mtd)
{
rdc3210_mtd->module = THIS_MODULE;
add_mtd_partitions(rdc3210_mtd, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
return 0;
}
#else /* Dante: This is for dynamic mapping */
#include <gemtek/sysdep.h>
#include <gemtek/imghdr.h>
if (rdc3210_mtd)
{ // Dante
#if RDC3210_USING_JFFS2
unsigned int tmp, tmp2 = rdc3210_mtd->erasesize;
#else
unsigned int tmp, tmp2 = 32;
#endif
gt_imghdr_t *hdr;
hdr = (gt_imghdr_t *)(rdc3210_map.map_priv_1);
if(memcmp(hdr->magic, GTIMG_MAGIC, 4))
{
printk("Invalid MAGIC for Firmware Image!!!\n");
return -EIO;
}
/* 1. Adjust Redboot */
tmp = flashdrv_get_size() - rdc3210_parts[4].size;
rdc3210_parts[4].offset = flashdrv_get_sector_addr(flashdrv_get_sector(tmp));
rdc3210_parts[4].size = flashdrv_get_size() - rdc3210_parts[4].offset;
/* 2. Adjust NVRAM */
tmp -= rdc3210_parts[3].size;
rdc3210_parts[3].offset = flashdrv_get_sector_addr(flashdrv_get_sector(tmp));
rdc3210_parts[3].size = rdc3210_parts[4].offset - rdc3210_parts[3].offset;
/* 3. Adjust Factory Default */
tmp -= rdc3210_parts[2].size;
rdc3210_parts[2].offset = flashdrv_get_sector_addr(flashdrv_get_sector(tmp));
rdc3210_parts[2].size = rdc3210_parts[3].offset - rdc3210_parts[2].offset;
/* 4. Adjust Linux (Kernel + ROMFS) */
rdc3210_parts[0].size = rdc3210_parts[2].offset - rdc3210_parts[0].offset;
/* 5. Adjust ROMFS */
tmp = hdr->kernelsz + sizeof(gt_imghdr_t);
rdc3210_parts[1].offset = rdc3210_parts[0].offset + (((tmp / tmp2) + ((tmp % tmp2) ? 1 : 0)) * tmp2);
rdc3210_parts[1].size = rdc3210_parts[2].offset - rdc3210_parts[1].offset;
#if RDC3210_NO_FACTORY_DFLT
/* 1. Adjust Redboot */
tmp = flashdrv_get_size() - rdc3210_parts[3].size;
rdc3210_parts[3].offset = flashdrv_get_sector_addr(flashdrv_get_sector(tmp));
rdc3210_parts[3].size = flashdrv_get_size() - rdc3210_parts[3].offset;
/* 2. Adjust NVRAM */
tmp -= rdc3210_parts[2].size;
rdc3210_parts[2].offset = flashdrv_get_sector_addr(flashdrv_get_sector(tmp));
rdc3210_parts[2].size = rdc3210_parts[3].offset - rdc3210_parts[2].offset;
/* 4. Adjust Linux (Kernel + ROMFS) */
rdc3210_parts[0].size = rdc3210_parts[2].offset - rdc3210_parts[0].offset;
/* 5. Adjust ROMFS */
tmp = hdr->kernelsz + sizeof(gt_imghdr_t);
rdc3210_parts[1].offset = rdc3210_parts[0].offset + (((tmp / tmp2) + ((tmp % tmp2) ? 1 : 0)) * tmp2);
rdc3210_parts[1].size = rdc3210_parts[2].offset - rdc3210_parts[1].offset;
#endif
rdc3210_mtd->module = THIS_MODULE;
add_mtd_partitions(rdc3210_mtd, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
return 0;
}
#endif
iounmap((void *)rdc3210_map.map_priv_1);
return -ENXIO;
}
mod_exit_t cleanup_rdc3210_map(void)
{
if (rdc3210_mtd)
{
del_mtd_partitions(rdc3210_mtd);
map_destroy(rdc3210_mtd);
}
if (rdc3210_map.map_priv_1)
{
iounmap((void *)rdc3210_map.map_priv_1);
rdc3210_map.map_priv_1 = NULL;
}
}
module_init(init_rdc3210_map);
module_exit(cleanup_rdc3210_map);

View File

@ -0,0 +1,980 @@
/* rdc.c: A RDC FastEthernet driver for linux. */
/*
Re-written 2004 by Sten Wang.
Copyright 1994-2000 by Donald Becker.
Copyright 1993 United States Government as represented by the
Director, National Security Agency. This software may be used and
distributed according to the terms of the GNU General Public License,
incorporated herein by reference.
This driver is for RDC FastEthernet MAC series.
For kernel version after 2.4.22
Modification List
---------- ------------------------------------------------
12-22-2004 Sten Init MAC MBCR register=0x012A
PHY_CAP = 0x01E1
*/
#define FORICPLUS /* Supports ICPlus IP175C switch chip */
#define BOOSTRDC /* Accelerate Ethernet performance */
#define DRV_NAME "rdc"
#define DRV_VERSION "0.6"
#define DRV_RELDATE "9July2004"
/* PHY CHIP Address */
#define PHY1_ADDR 1 /* For MAC1 */
#define PHY2_ADDR 2 /* For MAC2 */
#define PHY_MODE 0x3100 /* PHY CHIP Register 0 */
#define PHY_CAP 0x01E1 /* PHY CHIP Register 4 */
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (400 * HZ / 1000)
#define TIMER_WUT (jiffies + HZ * 1)/* timer wakeup time : 1 second */
/* RDC MAC ID */
#define RDC_MAC_ID 0x6040
/* RDC MAC I/O Size */
#define R6040_IO_SIZE 256
/* RDC Chip PCI Command */
#define R6040_PCI_CMD 0x0005 /* IO, Master */
/* MAX RDC MAC */
#define MAX_MAC 2
/* MAC setting */
#ifdef BOOSTRDC
#define TX_DCNT 32 /* TX descriptor count */
#define RX_DCNT 32 /* RX descriptor count */
#else
#define TX_DCNT 0x8 /* TX descriptor count */
#define RX_DCNT 0x8 /* RX descriptor count */
#endif
#define MAX_BUF_SIZE 0x600
#define ALLOC_DESC_SIZE ((TX_DCNT+RX_DCNT)*sizeof(struct rdc_descriptor)+0x10)
#define MBCR_DEFAULT 0x012A /* MAC Control Register */
/* Debug enable or not */
#define RDC_DEBUG 0
#if RDC_DEBUG > 1
#define RDC_DBUG(msg, value) printk("%s %x\n", msg, value);
#else
#define RDC_DBUG(msg, value)
#endif
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/delay.h> /* for udelay() */
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/crc32.h>
#include <linux/spinlock.h>
#include <asm/processor.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
MODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>");
MODULE_DESCRIPTION("RDC R6040 PCI FastEthernet Driver");
MODULE_LICENSE("GPL");
//MODULE_PARM(adr_table, "2-4i");
MODULE_PARM_DESC(adr_table, "MAC Address (assigned)");
struct rdc_descriptor {
u16 status, len; /* 0-3 */
u32 buf; /* 4-7 */
u32 ndesc; /* 8-B */
u32 rev1; /* C-F */
char *vbufp; /* 10-13 */
struct rdc_descriptor *vndescp; /* 14-17 */
struct sk_buff *skb_ptr; /* 18-1B */
u32 rev2; /* 1C-1F */
} __attribute__(( aligned(32) ));
struct rdc_private {
struct net_device_stats stats;
spinlock_t lock;
struct timer_list timer;
struct pci_dev *pdev;
struct rdc_descriptor *rx_insert_ptr;
struct rdc_descriptor *rx_remove_ptr;
struct rdc_descriptor *tx_insert_ptr;
struct rdc_descriptor *tx_remove_ptr;
u16 tx_free_desc, rx_free_desc, phy_addr, phy_mode;
u16 mcr0, mcr1;
dma_addr_t desc_dma;
char *desc_pool;
};
struct rdc_chip_info {
const char *name;
u16 pci_flags;
int io_size;
int drv_flags;
};
static int __devinitdata printed_version;
static char version[] __devinitdata =
KERN_INFO DRV_NAME ": RDC R6040 net driver, version "
DRV_VERSION " (" DRV_RELDATE ")\n";
static struct rdc_chip_info rdc_chip_info[] __devinitdata =
{
{ "RDC R6040 Knight", R6040_PCI_CMD, R6040_IO_SIZE, 0}
};
static int phy_table[] = { 0x1, 0x2};
static u8 adr_table[2][8] = {{0x00, 0x00, 0x60, 0x00, 0x00, 0x01}, {0x00, 0x00, 0x60, 0x00, 0x00, 0x02}};
static int rdc_open(struct net_device *dev);
static int rdc_start_xmit(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t rdc_interrupt(int irq, void *dev_id);
static struct net_device_stats *rdc_get_stats(struct net_device *dev);
static int rdc_close(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static struct ethtool_ops netdev_ethtool_ops;
static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
static void rdc_down(struct net_device *dev);
static void rdc_up(struct net_device *dev);
static void rdc_tx_timeout (struct net_device *dev);
static void rdc_timer(unsigned long);
static int phy_mode_chk(struct net_device *dev);
static int phy_read(int ioaddr, int phy_adr, int reg_idx);
static void phy_write(int ioaddr, int phy_adr, int reg_idx, int dat);
#ifdef BOOSTRDC
#define rx_buf_alloc(lp) \
do { \
struct rdc_descriptor *descptr; \
descptr = lp->rx_insert_ptr; \
while(lp->rx_free_desc < RX_DCNT){ \
descptr->skb_ptr = dev_alloc_skb(MAX_BUF_SIZE); \
if (!descptr->skb_ptr) break; \
descptr->buf = cpu_to_le32(pci_map_single(lp->pdev, descptr->skb_ptr->tail, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE)); \
descptr->status = 0x8000; \
descptr = descptr->vndescp; \
lp->rx_free_desc++; \
} \
lp->rx_insert_ptr = descptr; \
} while(0)
#else
static void rx_buf_alloc(struct rdc_private *lp);
#endif
#ifdef FORICPLUS
static void process_ioctl(struct net_device*, unsigned long* );
#endif
static int __devinit rdc_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct net_device *dev;
struct rdc_private *lp;
int ioaddr, io_size, err;
static int card_idx = -1;
int chip_id = (int)ent->driver_data;
RDC_DBUG("rdc_init_one()", 0);
if (printed_version++)
printk(version);
if ((err = pci_enable_device (pdev)))
return err;
/* this should always be supported */
if (pci_set_dma_mask(pdev, 0xffffffff)) {
printk(KERN_ERR DRV_NAME "32-bit PCI DMA addresses not supported by the card!?\n");
return -ENODEV;
}
/* IO Size check */
io_size = rdc_chip_info[chip_id].io_size;
if (pci_resource_len (pdev, 0) < io_size) {
return -ENODEV;
}
ioaddr = pci_resource_start (pdev, 0); /* IO map base address */
pci_set_master(pdev);
dev = alloc_etherdev(sizeof(struct rdc_private));
if (dev == NULL)
return -ENOMEM;
SET_MODULE_OWNER(dev);
if (pci_request_regions(pdev, DRV_NAME)) {
printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n");
err = -ENODEV;
goto err_out_disable;
}
/* Init system & device */
lp = dev->priv;
dev->base_addr = ioaddr;
dev->irq = pdev->irq;
spin_lock_init(&lp->lock);
pci_set_drvdata(pdev, dev);
/* Set MAC address */
card_idx++;
memcpy(dev->dev_addr, (u8 *)&adr_table[card_idx][0], 6);
/* Link new device into rdc_root_dev */
lp->pdev = pdev;
/* Init RDC private data */
lp->mcr0 = 0x1002;
lp->phy_addr = phy_table[card_idx];
/* The RDC-specific entries in the device structure. */
dev->open = &rdc_open;
dev->hard_start_xmit = &rdc_start_xmit;
dev->stop = &rdc_close;
dev->get_stats = &rdc_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->do_ioctl = &netdev_ioctl;
dev->ethtool_ops = &netdev_ethtool_ops;
dev->tx_timeout = &rdc_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
/* Register net device. After this dev->name assign */
if ((err = register_netdev(dev))) {
printk(KERN_ERR DRV_NAME ": Failed to register net device\n");
goto err_out_res;
}
netif_carrier_on(dev);
return 0;
err_out_res:
pci_release_regions(pdev);
err_out_disable:
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
kfree(dev);
return err;
}
static void __devexit rdc_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
unregister_netdev(dev);
pci_release_regions(pdev);
kfree(dev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
static int
rdc_open(struct net_device *dev)
{
struct rdc_private *lp = dev->priv;
int i;
RDC_DBUG("rdc_open()", 0);
/* Request IRQ and Register interrupt handler */
i = request_irq(dev->irq, &rdc_interrupt, SA_SHIRQ, dev->name, dev);
if (i) return i;
/* Allocate Descriptor memory */
lp->desc_pool = pci_alloc_consistent(lp->pdev, ALLOC_DESC_SIZE, &lp->desc_dma);
if (!lp->desc_pool) return -ENOMEM;
rdc_up(dev);
netif_start_queue(dev);
#ifndef FORICPLUS
/* set and active a timer process */
init_timer(&lp->timer);
lp->timer.expires = TIMER_WUT;
lp->timer.data = (unsigned long)dev;
lp->timer.function = &rdc_timer;
add_timer(&lp->timer);
#endif
return 0;
}
static void
rdc_tx_timeout (struct net_device *dev)
{
struct rdc_private *lp = dev->priv;
//int ioaddr = dev->base_addr;
//struct rdc_descriptor *descptr = lp->tx_remove_ptr;
RDC_DBUG("rdc_tx_timeout()", 0);
/* Transmitter timeout, serious problems. */
/* Sten: Nothing need to do so far. */
printk(KERN_ERR DRV_NAME ": Big Trobule, transmit timeout/n");
lp->stats.tx_errors++;
netif_stop_queue(dev);
//printk("<RDC> XMT timedout: CR0 %x, CR40 %x, CR3C %x, CR2C %x, CR30 %x, CR34 %x, CR38 %x\n", inw(ioaddr), inw(ioaddr+0x40), inw(ioaddr+0x3c), inw(ioaddr+0x2c), inw(ioaddr+0x30), inw(ioaddr+0x34), inw(ioaddr+0x38));
//printk("<RDC> XMT_TO: %08lx:%04x %04x %08lx %08lx %08lx %08lx\n", descptr, descptr->status, descptr->len, descptr->buf, descptr->skb_ptr, descptr->ndesc, descptr->vndescp);
}
static int
rdc_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct rdc_private *lp = dev->priv;
struct rdc_descriptor *descptr;
int ioaddr = dev->base_addr;
unsigned long flags;
RDC_DBUG("rdc_start_xmit()", 0);
if (skb == NULL) /* NULL skb directly return */
return 0;
if (skb->len >= MAX_BUF_SIZE) { /* Packet too long, drop it */
dev_kfree_skb(skb);
return 0;
}
/* Critical Section */
spin_lock_irqsave(&lp->lock, flags);
/* TX resource check */
if (!lp->tx_free_desc) {
spin_unlock_irqrestore(&lp->lock, flags);
printk(KERN_ERR DRV_NAME ": NO TX DESC ");
return 1;
}
/* Statistic Counter */
lp->stats.tx_packets++;
lp->stats.tx_bytes += skb->len;
/* Set TX descriptor & Transmit it */
lp->tx_free_desc--;
descptr = lp->tx_insert_ptr;
if (skb->len < 0x3c) descptr->len = 0x3c;
else descptr->len = skb->len;
descptr->skb_ptr = skb;
descptr->buf = cpu_to_le32(pci_map_single(lp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE));
descptr->status = 0x8000;
outw(0x01, ioaddr + 0x14);
lp->tx_insert_ptr = descptr->vndescp;
#if RDC_DEBUG
printk("Xmit(): %08lx:%04x %04x %08lx %08lx %08lx %08lx\n", descptr, descptr->status, descptr->len, descptr->buf, descptr->skb_ptr, descptr->ndesc, descptr->vndescp);
#endif
/* If no tx resource, stop */
if (!lp->tx_free_desc)
netif_stop_queue(dev);
dev->trans_start = jiffies;
spin_unlock_irqrestore(&lp->lock, flags);
return 0;
}
/* The RDC interrupt handler. */
static irqreturn_t
rdc_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct rdc_private *lp;
struct rdc_descriptor *descptr;
struct sk_buff *skb_ptr;
int ioaddr, status;
unsigned long flags;
int handled = 0;
RDC_DBUG("rdc_interrupt()", 0);
if (dev == NULL) {
printk (KERN_ERR DRV_NAME ": INT() unknown device.\n");
return IRQ_RETVAL(handled);
}
lp = (struct rdc_private *)dev->priv;
spin_lock_irqsave(&lp->lock, flags);
/* Check MAC Interrupt status */
ioaddr = dev->base_addr;
outw(0x0, ioaddr + 0x40); /* Mask Off RDC MAC interrupt */
status = inw(ioaddr + 0x3c); /* Read INTR status and clear */
/* TX interrupt request */
if (status & 0x10) {
handled = 1;
descptr = lp->tx_remove_ptr;
while(lp->tx_free_desc < TX_DCNT) {
if (descptr->status & 0x8000) break; /* Not complte */
skb_ptr = descptr->skb_ptr;
pci_unmap_single(lp->pdev, descptr->buf, skb_ptr->len, PCI_DMA_TODEVICE);
dev_kfree_skb_irq(skb_ptr); /* Free buffer */
descptr->skb_ptr = 0;
descptr = descptr->vndescp; /* To next descriptor */
lp->tx_free_desc++;
}
lp->tx_remove_ptr = descptr;
if (lp->tx_free_desc) netif_wake_queue(dev);
}
/* RX interrupt request */
if (status & 0x01) {
handled = 1;
descptr = lp->rx_remove_ptr;
while(lp->rx_free_desc) {
if (descptr->status & 0x8000) break; /* No Rx packet */
skb_ptr = descptr->skb_ptr;
descptr->skb_ptr = 0;
skb_ptr->dev = dev;
skb_put(skb_ptr, descptr->len - 4);
pci_unmap_single(lp->pdev, descptr->buf, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
skb_ptr->protocol = eth_type_trans(skb_ptr, dev);
netif_rx(skb_ptr); /* Send to upper layer */
lp->stats.rx_packets++;
lp->stats.rx_bytes += descptr->len;
descptr = descptr->vndescp; /* To next descriptor */
lp->rx_free_desc--;
}
lp->rx_remove_ptr = descptr;
}
/* Allocate new RX buffer */
if (lp->rx_free_desc < RX_DCNT) rx_buf_alloc(lp);
outw(0x0011, ioaddr + 0x40); /* TX/RX interrupt enable */
spin_unlock_irqrestore(&lp->lock, flags);
return IRQ_RETVAL(handled);
}
static struct net_device_stats *
rdc_get_stats(struct net_device *dev)
{
struct rdc_private *lp = dev->priv;
RDC_DBUG("rdc_get_stats()", 0);
return &lp->stats;
}
/*
* Set or clear the multicast filter for this adaptor.
*/
static void
set_multicast_list(struct net_device *dev)
{
struct rdc_private *lp = dev->priv;
struct dev_mc_list *mcptr;
int ioaddr = dev->base_addr;
u16 *adrp, i;
unsigned long flags;
RDC_DBUG("set_multicast_list()", 0);
/* MAC Address */
ioaddr += 0x68;
adrp = (u16 *) dev->dev_addr;
outw(adrp[0], ioaddr); ioaddr += 2;
outw(adrp[1], ioaddr); ioaddr += 2;
outw(adrp[2], ioaddr); ioaddr += 2;
#if RDC_DEBUG
printk("MAC ADDR: %04x %04x %04x\n", adrp[0], adrp[1], adrp[2]);
#endif
/* Promiscous Mode */
spin_lock_irqsave(lp->lock, flags);
i = inw(ioaddr) & ~0x0120; /* Clear AMCP & PROM */
if (dev->flags & IFF_PROMISC) i |= 0x0020;
if (dev->mc_count > 4) i |= 0x0100; /* Too many multicast address */
outw(i, ioaddr);
spin_unlock_irqrestore(lp->lock, flags);
/* Multicast Address */
if (dev->mc_count > 4) /* Wait to do: Hash Table for multicast */
return;
/* Multicast Address 1~4 case */
for (i = 0, mcptr = dev->mc_list; (i<dev->mc_count) && (i<4); i++) {
adrp = (u16 *)mcptr->dmi_addr;
outw(adrp[0], ioaddr); ioaddr += 2;
outw(adrp[1], ioaddr); ioaddr += 2;
outw(adrp[2], ioaddr); ioaddr += 2;
mcptr = mcptr->next;
#if RDC_DEBUG
printk("M_ADDR: %04x %04x %04x\n", adrp[0], adrp[1], adrp[2]);
#endif
}
for (i = dev->mc_count; i < 4; i++) {
outw(0xffff, ioaddr); ioaddr += 2;
outw(0xffff, ioaddr); ioaddr += 2;
outw(0xffff, ioaddr); ioaddr += 2;
}
}
static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
{
struct rdc_private *rp = dev->priv;
strcpy (info->driver, DRV_NAME);
strcpy (info->version, DRV_VERSION);
strcpy (info->bus_info, pci_name(rp->pdev));
}
static struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
};
static int
rdc_close(struct net_device *dev)
{
struct rdc_private *lp = dev->priv;
RDC_DBUG("rdc_close()", 0);
/* deleted timer */
del_timer_sync(&lp->timer);
spin_lock_irq(&lp->lock);
netif_stop_queue(dev);
rdc_down(dev);
spin_unlock_irq(&lp->lock);
return 0;
}
/**
*/
static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
{
RDC_DBUG("netdev_ioctl()", 0);
#ifdef FORICPLUS
switch(cmd)
{
case SIOCDEVPRIVATE:
//printk(KERN_INFO"Ethernet IOCTL: cmd SIOCDEVPRIVATE\n");
{
unsigned long *data;
unsigned long args[4];
data = (unsigned long *)rq->ifr_data;
if (copy_from_user(args, data, 4*sizeof(unsigned long)))
return -EFAULT;
process_ioctl(dev, args);
}
break;
default:
break;
}
#endif
return 0;
}
/**
Stop RDC MAC and Free the allocated resource
*/
static void rdc_down(struct net_device *dev)
{
struct rdc_private *lp = dev->priv;
int i;
int ioaddr = dev->base_addr;
RDC_DBUG("rdc_down()", 0);
/* Stop MAC */
outw(0x0000, ioaddr + 0x40); /* Mask Off Interrupt */
outw(0x0001, ioaddr + 0x04); /* Reset RDC MAC */
i = 0;
do{}while((i++ < 2048) && (inw(ioaddr + 0x04) & 0x1));
free_irq(dev->irq, dev);
/* Free RX buffer */
for (i = 0; i < RX_DCNT; i++) {
if (lp->rx_insert_ptr->skb_ptr) {
pci_unmap_single(lp->pdev, lp->rx_insert_ptr->buf, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
dev_kfree_skb(lp->rx_insert_ptr->skb_ptr);
lp->rx_insert_ptr->skb_ptr = 0;
}
lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp;
}
/* Free TX buffer */
for (i = 0; i < TX_DCNT; i++) {
if (lp->tx_insert_ptr->skb_ptr) {
pci_unmap_single(lp->pdev, lp->tx_insert_ptr->buf, MAX_BUF_SIZE, PCI_DMA_TODEVICE);
dev_kfree_skb(lp->tx_insert_ptr->skb_ptr);
lp->rx_insert_ptr->skb_ptr = 0;
}
lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp;
}
/* Free Descriptor memory */
pci_free_consistent(lp->pdev, ALLOC_DESC_SIZE, lp->desc_pool, lp->desc_dma);
}
/* Init RDC MAC */
static void rdc_up(struct net_device *dev)
{
struct rdc_private *lp = dev->priv;
struct rdc_descriptor *descptr;
int i;
int ioaddr = dev->base_addr;
u32 tmp_addr;
dma_addr_t desc_dma, start_dma;
RDC_DBUG("rdc_up()", 0);
/* Initilize */
lp->tx_free_desc = TX_DCNT;
lp->rx_free_desc = 0;
/* Init descriptor */
memset(lp->desc_pool, 0, ALLOC_DESC_SIZE); /* Let all descriptor = 0 */
lp->tx_insert_ptr = (struct rdc_descriptor *)lp->desc_pool;
lp->tx_remove_ptr = lp->tx_insert_ptr;
lp->rx_insert_ptr = (struct rdc_descriptor *)lp->tx_insert_ptr+TX_DCNT;
lp->rx_remove_ptr = lp->rx_insert_ptr;
/* Init TX descriptor */
descptr = lp->tx_insert_ptr;
desc_dma = lp->desc_dma;
start_dma = desc_dma;
for (i = 0; i < TX_DCNT; i++) {
descptr->ndesc = cpu_to_le32(desc_dma + sizeof(struct rdc_descriptor));
descptr->vndescp = (descptr + 1);
descptr = (descptr + 1);
desc_dma += sizeof(struct rdc_descriptor);
}
(descptr - 1)->ndesc = cpu_to_le32(start_dma);
(descptr - 1)->vndescp = lp->tx_insert_ptr;
/* Init RX descriptor */
start_dma = desc_dma;
descptr = lp->rx_insert_ptr;
for (i = 0; i < RX_DCNT; i++) {
descptr->ndesc = cpu_to_le32(desc_dma + sizeof(struct rdc_descriptor));
descptr->vndescp = (descptr + 1);
descptr = (descptr + 1);
desc_dma += sizeof(struct rdc_descriptor);
}
(descptr - 1)->ndesc = cpu_to_le32(start_dma);
(descptr - 1)->vndescp = lp->rx_insert_ptr;
/* Allocate buffer for RX descriptor */
rx_buf_alloc(lp);
#if RDC_DEBUG
descptr = lp->tx_insert_ptr;
for (i = 0; i < TX_DCNT; i++) {
printk("%08lx:%04x %04x %08lx %08lx %08lx %08lx\n", descptr, descptr->status, descptr->len, descptr->buf, descptr->skb_ptr, descptr->ndesc, descptr->vndescp);
descptr = descptr->vndescp;
}
descptr = lp->rx_insert_ptr;
for (i = 0; i < RX_DCNT; i++) {
printk("%08lx:%04x %04x %08lx %08lx %08lx %08lx\n", descptr, descptr->status, descptr->len, descptr->buf, descptr->skb_ptr, descptr->ndesc, descptr->vndescp);
descptr = descptr->vndescp;
}
#endif
/* MAC operation register */
outw(0x01, ioaddr); /* Reset MAC */
outw(2 , ioaddr+0xAC);
outw(0 , ioaddr+0xAC);
udelay(5000);
/* TX and RX descriptor start Register */
tmp_addr = cpu_to_le32(lp->tx_insert_ptr);
//timc
tmp_addr = virt_to_bus((volatile void *)tmp_addr);
outw((u16) tmp_addr, ioaddr+0x2c);
outw(tmp_addr >> 16, ioaddr+0x30);
tmp_addr = cpu_to_le32(lp->rx_insert_ptr);
//timc
tmp_addr = virt_to_bus((volatile void *)tmp_addr);
outw((u16) tmp_addr, ioaddr+0x34);
outw(tmp_addr >> 16, ioaddr+0x38);
/* Buffer Size Register */
outw(MAX_BUF_SIZE, ioaddr+0x18);
#ifdef FORICPLUS
if(phy_read(ioaddr, 0, 2) == 0x0243) // ICPlus IP175C Signature
{
phy_write(ioaddr, 29,31, 0x175C); //Enable registers
}
lp->phy_mode = 0x8000;
#else
/* PHY Mode Check */
phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP);
phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE);
if (PHY_MODE == 0x3100)
lp->phy_mode = phy_mode_chk(dev);
else lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
#endif
/* MAC Bus Control Register */
outw(MBCR_DEFAULT, ioaddr+0x8);
/* MAC TX/RX Enable */
lp->mcr0 |= lp->phy_mode;
// Dante
// BIT15 | BIT12 | BIT5 | BIT1
lp->mcr0 |= 0x0020;
//Xavier, only set promiscuous mode with eth1 (LAN i/f)
//This is a very bad hard code...
//if(ioaddr == 0xe900)lp->mcr0 |= 0x0020;
outw(lp->mcr0, ioaddr);
#ifdef BOOSTRDC
/* set interrupt waiting time and packet numbers */
outw(0x0802, ioaddr + 0x0C);
outw(0x0802, ioaddr + 0x10);
#ifdef FORICPLUS
/* upgrade performance (by RDC guys) */
phy_write(ioaddr,30,17,(phy_read(ioaddr,30,17)|0x4000)); //bit 14=1
phy_write(ioaddr,30,17,~((~phy_read(ioaddr,30,17))|0x2000)); //bit 13=0
phy_write(ioaddr,0,19,0x0000);
phy_write(ioaddr,0,30,0x01F0);
#endif
#endif
/* Interrupt Mask Register */
outw(0x0011, ioaddr + 0x40);
}
/*
A periodic timer routine
Polling PHY Chip Link Status
*/
static void rdc_timer(unsigned long data)
{
struct net_device *dev=(struct net_device *)data;
struct rdc_private *lp = dev->priv;
u16 ioaddr = dev->base_addr, phy_mode;
RDC_DBUG("rdc_timer()", 0);
/* Polling PHY Chip Status */
if (PHY_MODE == 0x3100)
phy_mode = phy_mode_chk(dev);
else phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
if (phy_mode != lp->phy_mode) {
lp->phy_mode = phy_mode;
lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode;
outw(lp->mcr0, ioaddr);
printk("<RDC> Link Change %x \n", inw(ioaddr));
}
/* Debug */
// printk("<RDC> Timer: CR0 %x CR40 %x CR3C %x\n", inw(ioaddr), inw(ioaddr+0x40), inw(ioaddr+0x3c));
/* Timer active again */
lp->timer.expires = TIMER_WUT;
add_timer(&lp->timer);
}
#ifndef BOOSTRDC
/* Allocate skb buffer for rx descriptor */
static void rx_buf_alloc(struct rdc_private *lp)
{
struct rdc_descriptor *descptr;
RDC_DBUG("rx_buf_alloc()", 0);
descptr = lp->rx_insert_ptr;
while(lp->rx_free_desc < RX_DCNT){
descptr->skb_ptr = dev_alloc_skb(MAX_BUF_SIZE);
if (!descptr->skb_ptr) break;
descptr->buf = cpu_to_le32(pci_map_single(lp->pdev, descptr->skb_ptr->tail, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE));
descptr->status = 0x8000;
descptr = descptr->vndescp;
lp->rx_free_desc++;
}
lp->rx_insert_ptr = descptr;
}
#endif
/* Status of PHY CHIP */
static int phy_mode_chk(struct net_device *dev)
{
struct rdc_private *lp = dev->priv;
int ioaddr = dev->base_addr, phy_dat;
RDC_DBUG("phy_mode_chk()", 0);
/* PHY Link Status Check */
phy_dat = phy_read(ioaddr, lp->phy_addr, 1);
if (!(phy_dat & 0x4)) return 0x8000; /* Link Failed, full duplex */
/* PHY Chip Auto-Negotiation Status */
phy_dat = phy_read(ioaddr, lp->phy_addr, 1);
if (phy_dat & 0x0020) {
/* Auto Negotiation Mode */
phy_dat = phy_read(ioaddr, lp->phy_addr, 5);
phy_dat &= phy_read(ioaddr, lp->phy_addr, 4);
if (phy_dat & 0x140) phy_dat = 0x8000;
else phy_dat = 0;
} else {
/* Force Mode */
phy_dat = phy_read(ioaddr, lp->phy_addr, 0);
if (phy_dat & 0x100) phy_dat = 0x8000;
else phy_dat = 0x0000;
}
return phy_dat;
};
/* Read a word data from PHY Chip */
static int phy_read(int ioaddr, int phy_addr, int reg_idx)
{
int i = 0;
RDC_DBUG("phy_read()", 0);
outw(0x2000 + reg_idx + (phy_addr << 8), ioaddr + 0x20);
do{}while( (i++ < 2048) && (inw(ioaddr + 0x20) & 0x2000) );
return inw(ioaddr + 0x24);
}
/* Write a word data from PHY Chip */
static void phy_write(int ioaddr, int phy_addr, int reg_idx, int dat)
{
int i = 0;
RDC_DBUG("phy_write()", 0);
outw(dat, ioaddr + 0x28);
outw(0x4000 + reg_idx + (phy_addr << 8), ioaddr + 0x20);
do{}while( (i++ < 2048) && (inw(ioaddr + 0x20) & 0x4000) );
}
enum {
RDC_6040 = 0
};
static struct pci_device_id rdc_pci_tbl[] = {
{0x17F3, 0x6040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RDC_6040},
//{0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RDC_6040},
{0,} /* terminate list */
};
MODULE_DEVICE_TABLE(pci, rdc_pci_tbl);
static struct pci_driver rdc_driver = {
.name = "r6040",
.id_table = rdc_pci_tbl,
.probe = rdc_init_one,
.remove = __devexit_p(rdc_remove_one),
};
static int __init rdc_init (void)
{
RDC_DBUG("rdc_init()", 0);
printk(version);
printed_version = 1;
return pci_module_init (&rdc_driver);
}
static void __exit rdc_cleanup (void)
{
RDC_DBUG("rdc_cleanup()", 0);
pci_unregister_driver (&rdc_driver);
}
module_init(rdc_init);
module_exit(rdc_cleanup);
/*
* Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c rdc.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
* End:
*/
#ifdef FORICPLUS
#define DMZ_GPIO 1
#define RDC3210_CFGREG_ADDR 0x0CF8
#define RDC3210_CFGREG_DATA 0x0CFC
static void process_ioctl(struct net_device *dev, unsigned long* args)
{
int ioaddr = dev->base_addr;
/* port priority */
if(args[0]&(1<<31))phy_write(ioaddr,29,19,(phy_read(ioaddr,29,19)|0x2000)); /* port 0 */
if(args[0]&(1<<29))phy_write(ioaddr,29,19,(phy_read(ioaddr,29,19)|0x0020)); /* port 1 */
if(args[0]&(1<<27))phy_write(ioaddr,29,20,(phy_read(ioaddr,29,20)|0x2000)); /* port 2 */
if(args[0]&(1<<25))phy_write(ioaddr,29,20,(phy_read(ioaddr,29,20)|0x0020)); /* port 3 */
/* DMZ LED */
{
unsigned int val;
val = 0x80000000 | (7 << 11) | ((0x48));
outl(val, RDC3210_CFGREG_ADDR);
udelay(10);
val = inl(RDC3210_CFGREG_DATA);
val |= (0x1 << DMZ_GPIO);
outl(val, RDC3210_CFGREG_DATA);
udelay(10);
val = 0x80000000 | (7 << 11) | ((0x4C));
outl(val, RDC3210_CFGREG_ADDR);
udelay(10);
val = inl(RDC3210_CFGREG_DATA);
if(args[0]&(1<<23)) /* DMZ enabled */
val &= ~(0x1 << DMZ_GPIO); /* low activated */
else val |= (0x1 << DMZ_GPIO);
outl(val, RDC3210_CFGREG_DATA);
udelay(10);
}
}
#endif /* FORICPLUS */

View File

@ -1,32 +1,3 @@
diff -urN linux-2.6.17/drivers/mtd/maps/imghdr.h linux-2.6.17.new/drivers/mtd/maps/imghdr.h
--- linux-2.6.17/drivers/mtd/maps/imghdr.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17.new/drivers/mtd/maps/imghdr.h 2006-09-24 20:29:20.000000000 +0200
@@ -0,0 +1,25 @@
+#ifndef GT_IMGHDR_H
+#define GT_IMGHDR_H
+
+#define GTIMG_MAGIC "GMTK"
+
+/* Product ID */
+#define PID_RTL_AIRGO 1
+#define PID_RTL_RALINK 2
+#define PID_RDC_AIRGO 3
+#define PID_RDC_RALINK 5 /* White Lable */
+
+/* Gemtek */
+typedef struct
+{
+ UINT8 magic[4]; /* ASICII: GMTK */
+ UINT32 checksum; /* CRC32 */
+ UINT32 version; /* x.x.x.x */
+ UINT32 kernelsz; /* The size of the kernel image */
+ UINT32 imagesz; /* The length of this image file ( kernel + romfs + this header) */
+ UINT32 pid; /* Product ID */
+ UINT32 fastcksum; /* Partial CRC32 on (First(256), medium(256), last(512)) */
+ UINT32 reserved;
+}gt_imghdr_t;
+
+#endif
diff -urN linux-2.6.17/drivers/mtd/maps/Kconfig linux-2.6.17.new/drivers/mtd/maps/Kconfig
--- linux-2.6.17/drivers/mtd/maps/Kconfig 2006-06-18 03:49:35.000000000 +0200
+++ linux-2.6.17.new/drivers/mtd/maps/Kconfig 2006-09-24 20:28:11.000000000 +0200
@ -54,218 +25,3 @@ diff -urN linux-2.6.17/drivers/mtd/maps/Makefile linux-2.6.17.new/drivers/mtd/ma
obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
diff -urN linux-2.6.17/drivers/mtd/maps/rdc3210.c linux-2.6.17.new/drivers/mtd/maps/rdc3210.c
--- linux-2.6.17/drivers/mtd/maps/rdc3210.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17.new/drivers/mtd/maps/rdc3210.c 2006-09-24 22:55:20.000000000 +0200
@@ -0,0 +1,211 @@
+/*******************************************************************
+ * Simple Flash mapping for RDC3210 *
+ * *
+ * 2005.03.23 *
+ * Dante Su (dante_su@gemtek.com.tw) *
+ * Copyright (C) 2005 Gemtek Corporation *
+ *******************************************************************/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/autoconf.h>
+
+#define WINDOW_ADDR 0xFFC00000
+#define WINDOW_SIZE 0x00400000
+
+#define BUSWIDTH 2
+
+static struct mtd_info *rdc3210_mtd_info;
+
+__u8 rdc3210_map_read8(struct map_info *map, unsigned long ofs)
+{
+ return *(__u8 *)(map->map_priv_1 + ofs);
+}
+
+__u16 rdc3210_map_read16(struct map_info *map, unsigned long ofs)
+{
+ return *(__u16 *)(map->map_priv_1 + ofs);
+}
+
+__u32 rdc3210_map_read32(struct map_info *map, unsigned long ofs)
+{
+ return *(__u32 *)(map->map_priv_1 + ofs);
+}
+
+void rdc3210_map_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ *(__u8 *)(map->map_priv_1 + adr) = d;
+}
+
+void rdc3210_map_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ *(__u16 *)(map->map_priv_1 + adr) = d;
+}
+
+void rdc3210_map_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ *(__u32 *)(map->map_priv_1 + adr) = d;
+}
+
+void rdc3210_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ int i;
+ u16 *dst = (u16 *)(to);
+ u16 *src = (u16 *)(map->map_priv_1 + from);
+
+ for(i = 0; i < (len / 2); ++i)
+ dst[i] = src[i];
+
+ if(len & 1)
+ {
+ printk("# WARNNING!!! rdc3210_map_copy_from has odd length\n");
+ //dst[len - 1] = B0(src[i]);
+ }
+}
+
+void rdc3210_map_copy_to(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ int i;
+ u16 *dst = (u16 *)(map->map_priv_1 + to);
+ u16 *src = (u16 *)(from);
+
+ for(i = 0; i < (len / 2); ++i)
+ dst[i] = src[i];
+
+ if(len & 1)
+ {
+ printk("# WARNNING!!! rdc3210_map_copy_from has odd length\n");
+ //dst[len - 1] = B0(src[i]);
+ }
+}
+
+static struct map_info rdc3210_map =
+{
+ .name = "RDC3210 Flash",
+ .size = WINDOW_SIZE,
+ .bankwidth = BUSWIDTH,
+ .phys = WINDOW_ADDR,
+};
+
+/* Dante: This is the default static mapping, however this is nothing but a hint. (Say dynamic mapping) */
+static struct mtd_partition rdc3210_parts[] =
+{
+ { .name = "linux", .offset = 0, .size = 0x003C0000 }, /* 3840 KB = (Kernel + ROMFS) = (768 KB + 3072 KB) */
+ { .name = "romfs", .offset = 0x000C0000, .size = 0x00300000 }, /* 3072 KB */
+ { .name = "nvram", .offset = 0x003C0000, .size = 0x00010000 }, /* 64 KB */
+ { .name = "factory", .offset = 0x003D0000, .size = 0x00010000 }, /* 64 KB */
+ { .name = "bootldr", .offset = 0x003E0000, .size = 0x00020000 }, /* 128 KB */
+};
+
+static int __init rdc3210_mtd_init(void)
+{
+ printk(KERN_NOTICE "flash device: 0x%x at 0x%x\n", WINDOW_SIZE, WINDOW_ADDR);
+
+ rdc3210_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
+
+ if (!rdc3210_map.virt)
+ {
+ printk("Failed to ioremap\n");
+ return -EIO;
+ }
+
+ simple_map_init(&rdc3210_map);
+
+ rdc3210_mtd_info = do_map_probe("cfi_probe", &rdc3210_map);
+ /* Dante: This is for fixed map */
+ if (rdc3210_mtd_info)
+ {
+ rdc3210_mtd_info->owner = THIS_MODULE;
+ add_mtd_partitions(rdc3210_mtd_info, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
+ return 0;
+ }
+ /* Dante: This is for dynamic mapping */
+#if 0
+ if (rdc3210_mtd_info)
+ { // Dante
+ unsigned int tmp;
+ gt_imghdr_t *hdr;
+
+ hdr = (gt_imghdr_t *)(rdc3210_map.virt);
+
+ if(memcmp(hdr->magic, GTIMG_MAGIC, 4))
+ {
+ printk("Invalid MAGIC for Firmware Image!!!\n");
+ return -EIO;
+ }
+
+ /* 1. Adjust Redboot */
+ tmp = flashdrv_get_size() - rdc3210_parts[4].size;
+ rdc3210_parts[4].offset = flashdrv_get_sector_addr(flashdrv_get_sector(tmp));
+ rdc3210_parts[4].size = flashdrv_get_size() - rdc3210_parts[4].offset;
+
+ /* 2. Adjust NVRAM */
+ tmp -= rdc3210_parts[3].size;
+ rdc3210_parts[3].offset = flashdrv_get_sector_addr(flashdrv_get_sector(tmp));
+ rdc3210_parts[3].size = rdc3210_parts[4].offset - rdc3210_parts[3].offset;
+
+ /* 3. Adjust Factory Default */
+ tmp -= rdc3210_parts[2].size;
+ rdc3210_parts[2].offset = flashdrv_get_sector_addr(flashdrv_get_sector(tmp));
+ rdc3210_parts[2].size = rdc3210_parts[3].offset - rdc3210_parts[2].offset;
+
+ /* 4. Adjust Linux (Kernel + ROMFS) */
+ rdc3210_parts[0].size = rdc3210_parts[2].offset - rdc3210_parts[0].offset;
+
+ /* 5. Adjust ROMFS */
+ tmp = hdr->kernelsz + sizeof(gt_imghdr_t);
+ rdc3210_parts[1].offset = rdc3210_parts[0].offset + (((tmp / 32) + ((tmp % 32) ? 1 : 0)) * 32);
+ rdc3210_parts[1].size = rdc3210_parts[2].offset - rdc3210_parts[1].offset;
+
+ /* 1. Adjust Redboot */
+ tmp = flashdrv_get_size() - rdc3210_parts[3].size;
+ rdc3210_parts[3].offset = flashdrv_get_sector_addr(flashdrv_get_sector(tmp));
+ rdc3210_parts[3].size = flashdrv_get_size() - rdc3210_parts[3].offset;
+
+ /* 2. Adjust NVRAM */
+ tmp -= rdc3210_parts[2].size;
+ rdc3210_parts[2].offset = flashdrv_get_sector_addr(flashdrv_get_sector(tmp));
+ rdc3210_parts[2].size = rdc3210_parts[3].offset - rdc3210_parts[2].offset;
+
+ /* 4. Adjust Linux (Kernel + ROMFS) */
+ rdc3210_parts[0].size = rdc3210_parts[2].offset - rdc3210_parts[0].offset;
+
+ /* 5. Adjust ROMFS */
+ tmp = hdr->kernelsz + sizeof(gt_imghdr_t);
+ rdc3210_parts[1].offset = rdc3210_parts[0].offset + (((tmp / 32) + ((tmp % 32) ? 1 : 0)) * 32);
+ rdc3210_parts[1].size = rdc3210_parts[2].offset - rdc3210_parts[1].offset;
+
+ rdc3210_mtd_info->owner = THIS_MODULE;
+ add_mtd_partitions(rdc3210_mtd_info, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
+ return 0;
+ }
+#endif
+ iounmap((void *)rdc3210_map.virt);
+ return -ENXIO;
+}
+
+static void __exit rdc3210_mtd_exit(void)
+{
+ if (rdc3210_mtd_info)
+ {
+ del_mtd_partitions(rdc3210_mtd_info);
+ map_destroy(rdc3210_mtd_info);
+ }
+
+ if (rdc3210_map.virt)
+ {
+ iounmap(rdc3210_map.virt);
+ rdc3210_map.virt = 0;
+ }
+}
+
+module_init(rdc3210_mtd_init);
+module_exit(rdc3210_mtd_exit);
+MODULE_LICENSE("GPL");
+

View File

@ -32,987 +32,3 @@ diff -urN linux-2.6.17/drivers/net/Makefile linux-2.6.17.new/drivers/net/Makefil
obj-$(CONFIG_FORCEDETH) += forcedeth.o
obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
diff -urN linux-2.6.17/drivers/net/r6040.c linux-2.6.17.new/drivers/net/r6040.c
--- linux-2.6.17/drivers/net/r6040.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17.new/drivers/net/r6040.c 2006-09-25 13:12:41.000000000 +0200
@@ -0,0 +1,980 @@
+/* rdc.c: A RDC FastEthernet driver for linux. */
+/*
+ Re-written 2004 by Sten Wang.
+
+ Copyright 1994-2000 by Donald Becker.
+ Copyright 1993 United States Government as represented by the
+ Director, National Security Agency. This software may be used and
+ distributed according to the terms of the GNU General Public License,
+ incorporated herein by reference.
+
+ This driver is for RDC FastEthernet MAC series.
+ For kernel version after 2.4.22
+
+ Modification List
+ ---------- ------------------------------------------------
+ 12-22-2004 Sten Init MAC MBCR register=0x012A
+ PHY_CAP = 0x01E1
+*/
+
+#define FORICPLUS /* Supports ICPlus IP175C switch chip */
+#define BOOSTRDC /* Accelerate Ethernet performance */
+
+#define DRV_NAME "rdc"
+#define DRV_VERSION "0.6"
+#define DRV_RELDATE "9July2004"
+
+/* PHY CHIP Address */
+#define PHY1_ADDR 1 /* For MAC1 */
+#define PHY2_ADDR 2 /* For MAC2 */
+#define PHY_MODE 0x3100 /* PHY CHIP Register 0 */
+#define PHY_CAP 0x01E1 /* PHY CHIP Register 4 */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (400 * HZ / 1000)
+#define TIMER_WUT (jiffies + HZ * 1)/* timer wakeup time : 1 second */
+
+/* RDC MAC ID */
+#define RDC_MAC_ID 0x6040
+
+/* RDC MAC I/O Size */
+#define R6040_IO_SIZE 256
+
+/* RDC Chip PCI Command */
+#define R6040_PCI_CMD 0x0005 /* IO, Master */
+
+/* MAX RDC MAC */
+#define MAX_MAC 2
+
+/* MAC setting */
+#ifdef BOOSTRDC
+#define TX_DCNT 32 /* TX descriptor count */
+#define RX_DCNT 32 /* RX descriptor count */
+#else
+#define TX_DCNT 0x8 /* TX descriptor count */
+#define RX_DCNT 0x8 /* RX descriptor count */
+#endif
+#define MAX_BUF_SIZE 0x600
+#define ALLOC_DESC_SIZE ((TX_DCNT+RX_DCNT)*sizeof(struct rdc_descriptor)+0x10)
+#define MBCR_DEFAULT 0x012A /* MAC Control Register */
+
+/* Debug enable or not */
+#define RDC_DEBUG 0
+
+#if RDC_DEBUG > 1
+#define RDC_DBUG(msg, value) printk("%s %x\n", msg, value);
+#else
+#define RDC_DBUG(msg, value)
+#endif
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/delay.h> /* for udelay() */
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/crc32.h>
+#include <linux/spinlock.h>
+
+#include <asm/processor.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+MODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>");
+MODULE_DESCRIPTION("RDC R6040 PCI FastEthernet Driver");
+MODULE_LICENSE("GPL");
+
+//MODULE_PARM(adr_table, "2-4i");
+MODULE_PARM_DESC(adr_table, "MAC Address (assigned)");
+
+struct rdc_descriptor {
+ u16 status, len; /* 0-3 */
+ u32 buf; /* 4-7 */
+ u32 ndesc; /* 8-B */
+ u32 rev1; /* C-F */
+ char *vbufp; /* 10-13 */
+ struct rdc_descriptor *vndescp; /* 14-17 */
+ struct sk_buff *skb_ptr; /* 18-1B */
+ u32 rev2; /* 1C-1F */
+} __attribute__(( aligned(32) ));
+
+struct rdc_private {
+ struct net_device_stats stats;
+ spinlock_t lock;
+ struct timer_list timer;
+ struct pci_dev *pdev;
+
+ struct rdc_descriptor *rx_insert_ptr;
+ struct rdc_descriptor *rx_remove_ptr;
+ struct rdc_descriptor *tx_insert_ptr;
+ struct rdc_descriptor *tx_remove_ptr;
+ u16 tx_free_desc, rx_free_desc, phy_addr, phy_mode;
+ u16 mcr0, mcr1;
+ dma_addr_t desc_dma;
+ char *desc_pool;
+};
+
+struct rdc_chip_info {
+ const char *name;
+ u16 pci_flags;
+ int io_size;
+ int drv_flags;
+};
+
+static int __devinitdata printed_version;
+static char version[] __devinitdata =
+ KERN_INFO DRV_NAME ": RDC R6040 net driver, version "
+ DRV_VERSION " (" DRV_RELDATE ")\n";
+
+static struct rdc_chip_info rdc_chip_info[] __devinitdata =
+{
+ { "RDC R6040 Knight", R6040_PCI_CMD, R6040_IO_SIZE, 0}
+};
+
+static int phy_table[] = { 0x1, 0x2};
+static u8 adr_table[2][8] = {{0x00, 0x00, 0x60, 0x00, 0x00, 0x01}, {0x00, 0x00, 0x60, 0x00, 0x00, 0x02}};
+
+static int rdc_open(struct net_device *dev);
+static int rdc_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t rdc_interrupt(int irq, void *dev_id);
+static struct net_device_stats *rdc_get_stats(struct net_device *dev);
+static int rdc_close(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static struct ethtool_ops netdev_ethtool_ops;
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static void rdc_down(struct net_device *dev);
+static void rdc_up(struct net_device *dev);
+static void rdc_tx_timeout (struct net_device *dev);
+static void rdc_timer(unsigned long);
+
+static int phy_mode_chk(struct net_device *dev);
+static int phy_read(int ioaddr, int phy_adr, int reg_idx);
+static void phy_write(int ioaddr, int phy_adr, int reg_idx, int dat);
+
+#ifdef BOOSTRDC
+#define rx_buf_alloc(lp) \
+ do { \
+ struct rdc_descriptor *descptr; \
+ descptr = lp->rx_insert_ptr; \
+ while(lp->rx_free_desc < RX_DCNT){ \
+ descptr->skb_ptr = dev_alloc_skb(MAX_BUF_SIZE); \
+ if (!descptr->skb_ptr) break; \
+ descptr->buf = cpu_to_le32(pci_map_single(lp->pdev, descptr->skb_ptr->tail, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE)); \
+ descptr->status = 0x8000; \
+ descptr = descptr->vndescp; \
+ lp->rx_free_desc++; \
+ } \
+ lp->rx_insert_ptr = descptr; \
+ } while(0)
+
+#else
+static void rx_buf_alloc(struct rdc_private *lp);
+#endif
+
+#ifdef FORICPLUS
+static void process_ioctl(struct net_device*, unsigned long* );
+#endif
+
+static int __devinit rdc_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *dev;
+ struct rdc_private *lp;
+ int ioaddr, io_size, err;
+ static int card_idx = -1;
+ int chip_id = (int)ent->driver_data;
+
+ RDC_DBUG("rdc_init_one()", 0);
+
+ if (printed_version++)
+ printk(version);
+
+ if ((err = pci_enable_device (pdev)))
+ return err;
+
+ /* this should always be supported */
+ if (pci_set_dma_mask(pdev, 0xffffffff)) {
+ printk(KERN_ERR DRV_NAME "32-bit PCI DMA addresses not supported by the card!?\n");
+ return -ENODEV;
+ }
+
+ /* IO Size check */
+ io_size = rdc_chip_info[chip_id].io_size;
+ if (pci_resource_len (pdev, 0) < io_size) {
+ return -ENODEV;
+ }
+
+ ioaddr = pci_resource_start (pdev, 0); /* IO map base address */
+ pci_set_master(pdev);
+
+ dev = alloc_etherdev(sizeof(struct rdc_private));
+ if (dev == NULL)
+ return -ENOMEM;
+ SET_MODULE_OWNER(dev);
+
+ if (pci_request_regions(pdev, DRV_NAME)) {
+ printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n");
+ err = -ENODEV;
+ goto err_out_disable;
+ }
+
+ /* Init system & device */
+ lp = dev->priv;
+ dev->base_addr = ioaddr;
+ dev->irq = pdev->irq;
+
+ spin_lock_init(&lp->lock);
+ pci_set_drvdata(pdev, dev);
+
+ /* Set MAC address */
+ card_idx++;
+ memcpy(dev->dev_addr, (u8 *)&adr_table[card_idx][0], 6);
+
+ /* Link new device into rdc_root_dev */
+ lp->pdev = pdev;
+
+ /* Init RDC private data */
+ lp->mcr0 = 0x1002;
+ lp->phy_addr = phy_table[card_idx];
+
+ /* The RDC-specific entries in the device structure. */
+ dev->open = &rdc_open;
+ dev->hard_start_xmit = &rdc_start_xmit;
+ dev->stop = &rdc_close;
+ dev->get_stats = &rdc_get_stats;
+ dev->set_multicast_list = &set_multicast_list;
+ dev->do_ioctl = &netdev_ioctl;
+ dev->ethtool_ops = &netdev_ethtool_ops;
+ dev->tx_timeout = &rdc_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ /* Register net device. After this dev->name assign */
+ if ((err = register_netdev(dev))) {
+ printk(KERN_ERR DRV_NAME ": Failed to register net device\n");
+ goto err_out_res;
+ }
+
+ netif_carrier_on(dev);
+ return 0;
+
+err_out_res:
+ pci_release_regions(pdev);
+err_out_disable:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ kfree(dev);
+
+ return err;
+}
+
+static void __devexit rdc_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ unregister_netdev(dev);
+ pci_release_regions(pdev);
+ kfree(dev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+static int
+rdc_open(struct net_device *dev)
+{
+ struct rdc_private *lp = dev->priv;
+ int i;
+
+ RDC_DBUG("rdc_open()", 0);
+
+ /* Request IRQ and Register interrupt handler */
+ i = request_irq(dev->irq, &rdc_interrupt, SA_SHIRQ, dev->name, dev);
+ if (i) return i;
+
+ /* Allocate Descriptor memory */
+ lp->desc_pool = pci_alloc_consistent(lp->pdev, ALLOC_DESC_SIZE, &lp->desc_dma);
+ if (!lp->desc_pool) return -ENOMEM;
+
+ rdc_up(dev);
+
+ netif_start_queue(dev);
+
+#ifndef FORICPLUS
+ /* set and active a timer process */
+ init_timer(&lp->timer);
+ lp->timer.expires = TIMER_WUT;
+ lp->timer.data = (unsigned long)dev;
+ lp->timer.function = &rdc_timer;
+ add_timer(&lp->timer);
+#endif
+
+ return 0;
+}
+
+static void
+rdc_tx_timeout (struct net_device *dev)
+{
+ struct rdc_private *lp = dev->priv;
+ //int ioaddr = dev->base_addr;
+ //struct rdc_descriptor *descptr = lp->tx_remove_ptr;
+
+ RDC_DBUG("rdc_tx_timeout()", 0);
+
+ /* Transmitter timeout, serious problems. */
+ /* Sten: Nothing need to do so far. */
+ printk(KERN_ERR DRV_NAME ": Big Trobule, transmit timeout/n");
+ lp->stats.tx_errors++;
+ netif_stop_queue(dev);
+
+//printk("<RDC> XMT timedout: CR0 %x, CR40 %x, CR3C %x, CR2C %x, CR30 %x, CR34 %x, CR38 %x\n", inw(ioaddr), inw(ioaddr+0x40), inw(ioaddr+0x3c), inw(ioaddr+0x2c), inw(ioaddr+0x30), inw(ioaddr+0x34), inw(ioaddr+0x38));
+
+//printk("<RDC> XMT_TO: %08lx:%04x %04x %08lx %08lx %08lx %08lx\n", descptr, descptr->status, descptr->len, descptr->buf, descptr->skb_ptr, descptr->ndesc, descptr->vndescp);
+}
+
+
+static int
+rdc_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct rdc_private *lp = dev->priv;
+ struct rdc_descriptor *descptr;
+ int ioaddr = dev->base_addr;
+ unsigned long flags;
+
+ RDC_DBUG("rdc_start_xmit()", 0);
+
+ if (skb == NULL) /* NULL skb directly return */
+ return 0;
+ if (skb->len >= MAX_BUF_SIZE) { /* Packet too long, drop it */
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ /* Critical Section */
+ spin_lock_irqsave(&lp->lock, flags);
+
+ /* TX resource check */
+ if (!lp->tx_free_desc) {
+ spin_unlock_irqrestore(&lp->lock, flags);
+ printk(KERN_ERR DRV_NAME ": NO TX DESC ");
+ return 1;
+ }
+
+ /* Statistic Counter */
+ lp->stats.tx_packets++;
+ lp->stats.tx_bytes += skb->len;
+
+ /* Set TX descriptor & Transmit it */
+ lp->tx_free_desc--;
+ descptr = lp->tx_insert_ptr;
+ if (skb->len < 0x3c) descptr->len = 0x3c;
+ else descptr->len = skb->len;
+ descptr->skb_ptr = skb;
+ descptr->buf = cpu_to_le32(pci_map_single(lp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE));
+ descptr->status = 0x8000;
+ outw(0x01, ioaddr + 0x14);
+ lp->tx_insert_ptr = descptr->vndescp;
+
+#if RDC_DEBUG
+ printk("Xmit(): %08lx:%04x %04x %08lx %08lx %08lx %08lx\n", descptr, descptr->status, descptr->len, descptr->buf, descptr->skb_ptr, descptr->ndesc, descptr->vndescp);
+#endif
+
+ /* If no tx resource, stop */
+ if (!lp->tx_free_desc)
+ netif_stop_queue(dev);
+
+ dev->trans_start = jiffies;
+ spin_unlock_irqrestore(&lp->lock, flags);
+ return 0;
+}
+
+/* The RDC interrupt handler. */
+static irqreturn_t
+rdc_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct rdc_private *lp;
+ struct rdc_descriptor *descptr;
+ struct sk_buff *skb_ptr;
+ int ioaddr, status;
+ unsigned long flags;
+ int handled = 0;
+
+ RDC_DBUG("rdc_interrupt()", 0);
+ if (dev == NULL) {
+ printk (KERN_ERR DRV_NAME ": INT() unknown device.\n");
+ return IRQ_RETVAL(handled);
+ }
+
+ lp = (struct rdc_private *)dev->priv;
+ spin_lock_irqsave(&lp->lock, flags);
+
+ /* Check MAC Interrupt status */
+ ioaddr = dev->base_addr;
+ outw(0x0, ioaddr + 0x40); /* Mask Off RDC MAC interrupt */
+ status = inw(ioaddr + 0x3c); /* Read INTR status and clear */
+
+ /* TX interrupt request */
+ if (status & 0x10) {
+ handled = 1;
+ descptr = lp->tx_remove_ptr;
+ while(lp->tx_free_desc < TX_DCNT) {
+ if (descptr->status & 0x8000) break; /* Not complte */
+ skb_ptr = descptr->skb_ptr;
+ pci_unmap_single(lp->pdev, descptr->buf, skb_ptr->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(skb_ptr); /* Free buffer */
+ descptr->skb_ptr = 0;
+ descptr = descptr->vndescp; /* To next descriptor */
+ lp->tx_free_desc++;
+ }
+ lp->tx_remove_ptr = descptr;
+ if (lp->tx_free_desc) netif_wake_queue(dev);
+ }
+
+ /* RX interrupt request */
+ if (status & 0x01) {
+ handled = 1;
+ descptr = lp->rx_remove_ptr;
+ while(lp->rx_free_desc) {
+ if (descptr->status & 0x8000) break; /* No Rx packet */
+ skb_ptr = descptr->skb_ptr;
+ descptr->skb_ptr = 0;
+ skb_ptr->dev = dev;
+ skb_put(skb_ptr, descptr->len - 4);
+ pci_unmap_single(lp->pdev, descptr->buf, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ skb_ptr->protocol = eth_type_trans(skb_ptr, dev);
+ netif_rx(skb_ptr); /* Send to upper layer */
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes += descptr->len;
+ descptr = descptr->vndescp; /* To next descriptor */
+ lp->rx_free_desc--;
+ }
+ lp->rx_remove_ptr = descptr;
+ }
+
+ /* Allocate new RX buffer */
+ if (lp->rx_free_desc < RX_DCNT) rx_buf_alloc(lp);
+
+ outw(0x0011, ioaddr + 0x40); /* TX/RX interrupt enable */
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
+
+static struct net_device_stats *
+rdc_get_stats(struct net_device *dev)
+{
+ struct rdc_private *lp = dev->priv;
+
+ RDC_DBUG("rdc_get_stats()", 0);
+ return &lp->stats;
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+static void
+set_multicast_list(struct net_device *dev)
+{
+ struct rdc_private *lp = dev->priv;
+ struct dev_mc_list *mcptr;
+ int ioaddr = dev->base_addr;
+ u16 *adrp, i;
+ unsigned long flags;
+
+ RDC_DBUG("set_multicast_list()", 0);
+
+ /* MAC Address */
+ ioaddr += 0x68;
+ adrp = (u16 *) dev->dev_addr;
+ outw(adrp[0], ioaddr); ioaddr += 2;
+ outw(adrp[1], ioaddr); ioaddr += 2;
+ outw(adrp[2], ioaddr); ioaddr += 2;
+
+#if RDC_DEBUG
+ printk("MAC ADDR: %04x %04x %04x\n", adrp[0], adrp[1], adrp[2]);
+#endif
+
+ /* Promiscous Mode */
+ spin_lock_irqsave(lp->lock, flags);
+ i = inw(ioaddr) & ~0x0120; /* Clear AMCP & PROM */
+ if (dev->flags & IFF_PROMISC) i |= 0x0020;
+ if (dev->mc_count > 4) i |= 0x0100; /* Too many multicast address */
+ outw(i, ioaddr);
+ spin_unlock_irqrestore(lp->lock, flags);
+
+ /* Multicast Address */
+ if (dev->mc_count > 4) /* Wait to do: Hash Table for multicast */
+ return;
+
+ /* Multicast Address 1~4 case */
+ for (i = 0, mcptr = dev->mc_list; (i<dev->mc_count) && (i<4); i++) {
+ adrp = (u16 *)mcptr->dmi_addr;
+ outw(adrp[0], ioaddr); ioaddr += 2;
+ outw(adrp[1], ioaddr); ioaddr += 2;
+ outw(adrp[2], ioaddr); ioaddr += 2;
+ mcptr = mcptr->next;
+#if RDC_DEBUG
+ printk("M_ADDR: %04x %04x %04x\n", adrp[0], adrp[1], adrp[2]);
+#endif
+ }
+ for (i = dev->mc_count; i < 4; i++) {
+ outw(0xffff, ioaddr); ioaddr += 2;
+ outw(0xffff, ioaddr); ioaddr += 2;
+ outw(0xffff, ioaddr); ioaddr += 2;
+ }
+}
+
+static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ struct rdc_private *rp = dev->priv;
+
+ strcpy (info->driver, DRV_NAME);
+ strcpy (info->version, DRV_VERSION);
+ strcpy (info->bus_info, pci_name(rp->pdev));
+}
+
+static struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+};
+
+static int
+rdc_close(struct net_device *dev)
+{
+ struct rdc_private *lp = dev->priv;
+
+ RDC_DBUG("rdc_close()", 0);
+
+ /* deleted timer */
+ del_timer_sync(&lp->timer);
+
+ spin_lock_irq(&lp->lock);
+
+ netif_stop_queue(dev);
+
+ rdc_down(dev);
+
+ spin_unlock_irq(&lp->lock);
+
+ return 0;
+}
+
+/**
+ */
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ RDC_DBUG("netdev_ioctl()", 0);
+
+#ifdef FORICPLUS
+ switch(cmd)
+ {
+ case SIOCDEVPRIVATE:
+
+ //printk(KERN_INFO"Ethernet IOCTL: cmd SIOCDEVPRIVATE\n");
+ {
+ unsigned long *data;
+ unsigned long args[4];
+
+ data = (unsigned long *)rq->ifr_data;
+ if (copy_from_user(args, data, 4*sizeof(unsigned long)))
+ return -EFAULT;
+
+ process_ioctl(dev, args);
+ }
+ break;
+
+ default:
+ break;
+ }
+#endif
+ return 0;
+}
+
+/**
+ Stop RDC MAC and Free the allocated resource
+ */
+static void rdc_down(struct net_device *dev)
+{
+ struct rdc_private *lp = dev->priv;
+ int i;
+ int ioaddr = dev->base_addr;
+
+ RDC_DBUG("rdc_down()", 0);
+
+ /* Stop MAC */
+ outw(0x0000, ioaddr + 0x40); /* Mask Off Interrupt */
+ outw(0x0001, ioaddr + 0x04); /* Reset RDC MAC */
+ i = 0;
+ do{}while((i++ < 2048) && (inw(ioaddr + 0x04) & 0x1));
+
+ free_irq(dev->irq, dev);
+
+ /* Free RX buffer */
+ for (i = 0; i < RX_DCNT; i++) {
+ if (lp->rx_insert_ptr->skb_ptr) {
+ pci_unmap_single(lp->pdev, lp->rx_insert_ptr->buf, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(lp->rx_insert_ptr->skb_ptr);
+ lp->rx_insert_ptr->skb_ptr = 0;
+ }
+ lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp;
+ }
+
+ /* Free TX buffer */
+ for (i = 0; i < TX_DCNT; i++) {
+ if (lp->tx_insert_ptr->skb_ptr) {
+ pci_unmap_single(lp->pdev, lp->tx_insert_ptr->buf, MAX_BUF_SIZE, PCI_DMA_TODEVICE);
+ dev_kfree_skb(lp->tx_insert_ptr->skb_ptr);
+ lp->rx_insert_ptr->skb_ptr = 0;
+ }
+ lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp;
+ }
+
+ /* Free Descriptor memory */
+ pci_free_consistent(lp->pdev, ALLOC_DESC_SIZE, lp->desc_pool, lp->desc_dma);
+}
+
+/* Init RDC MAC */
+static void rdc_up(struct net_device *dev)
+{
+ struct rdc_private *lp = dev->priv;
+ struct rdc_descriptor *descptr;
+ int i;
+ int ioaddr = dev->base_addr;
+ u32 tmp_addr;
+ dma_addr_t desc_dma, start_dma;
+
+ RDC_DBUG("rdc_up()", 0);
+
+ /* Initilize */
+ lp->tx_free_desc = TX_DCNT;
+ lp->rx_free_desc = 0;
+
+ /* Init descriptor */
+ memset(lp->desc_pool, 0, ALLOC_DESC_SIZE); /* Let all descriptor = 0 */
+ lp->tx_insert_ptr = (struct rdc_descriptor *)lp->desc_pool;
+ lp->tx_remove_ptr = lp->tx_insert_ptr;
+ lp->rx_insert_ptr = (struct rdc_descriptor *)lp->tx_insert_ptr+TX_DCNT;
+ lp->rx_remove_ptr = lp->rx_insert_ptr;
+
+ /* Init TX descriptor */
+ descptr = lp->tx_insert_ptr;
+ desc_dma = lp->desc_dma;
+ start_dma = desc_dma;
+ for (i = 0; i < TX_DCNT; i++) {
+ descptr->ndesc = cpu_to_le32(desc_dma + sizeof(struct rdc_descriptor));
+ descptr->vndescp = (descptr + 1);
+ descptr = (descptr + 1);
+ desc_dma += sizeof(struct rdc_descriptor);
+ }
+ (descptr - 1)->ndesc = cpu_to_le32(start_dma);
+ (descptr - 1)->vndescp = lp->tx_insert_ptr;
+
+ /* Init RX descriptor */
+ start_dma = desc_dma;
+ descptr = lp->rx_insert_ptr;
+ for (i = 0; i < RX_DCNT; i++) {
+ descptr->ndesc = cpu_to_le32(desc_dma + sizeof(struct rdc_descriptor));
+ descptr->vndescp = (descptr + 1);
+ descptr = (descptr + 1);
+ desc_dma += sizeof(struct rdc_descriptor);
+ }
+ (descptr - 1)->ndesc = cpu_to_le32(start_dma);
+ (descptr - 1)->vndescp = lp->rx_insert_ptr;
+
+ /* Allocate buffer for RX descriptor */
+ rx_buf_alloc(lp);
+
+#if RDC_DEBUG
+descptr = lp->tx_insert_ptr;
+for (i = 0; i < TX_DCNT; i++) {
+ printk("%08lx:%04x %04x %08lx %08lx %08lx %08lx\n", descptr, descptr->status, descptr->len, descptr->buf, descptr->skb_ptr, descptr->ndesc, descptr->vndescp);
+ descptr = descptr->vndescp;
+}
+descptr = lp->rx_insert_ptr;
+for (i = 0; i < RX_DCNT; i++) {
+ printk("%08lx:%04x %04x %08lx %08lx %08lx %08lx\n", descptr, descptr->status, descptr->len, descptr->buf, descptr->skb_ptr, descptr->ndesc, descptr->vndescp);
+ descptr = descptr->vndescp;
+}
+#endif
+
+ /* MAC operation register */
+ outw(0x01, ioaddr); /* Reset MAC */
+ outw(2 , ioaddr+0xAC);
+ outw(0 , ioaddr+0xAC);
+ udelay(5000);
+
+ /* TX and RX descriptor start Register */
+ tmp_addr = cpu_to_le32(lp->tx_insert_ptr);
+ //timc
+ tmp_addr = virt_to_bus((volatile void *)tmp_addr);
+ outw((u16) tmp_addr, ioaddr+0x2c);
+ outw(tmp_addr >> 16, ioaddr+0x30);
+ tmp_addr = cpu_to_le32(lp->rx_insert_ptr);
+ //timc
+ tmp_addr = virt_to_bus((volatile void *)tmp_addr);
+ outw((u16) tmp_addr, ioaddr+0x34);
+ outw(tmp_addr >> 16, ioaddr+0x38);
+
+ /* Buffer Size Register */
+ outw(MAX_BUF_SIZE, ioaddr+0x18);
+
+#ifdef FORICPLUS
+
+ if(phy_read(ioaddr, 0, 2) == 0x0243) // ICPlus IP175C Signature
+ {
+ phy_write(ioaddr, 29,31, 0x175C); //Enable registers
+ }
+ lp->phy_mode = 0x8000;
+
+#else
+ /* PHY Mode Check */
+ phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP);
+ phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE);
+
+ if (PHY_MODE == 0x3100)
+ lp->phy_mode = phy_mode_chk(dev);
+ else lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
+#endif
+ /* MAC Bus Control Register */
+ outw(MBCR_DEFAULT, ioaddr+0x8);
+
+ /* MAC TX/RX Enable */
+ lp->mcr0 |= lp->phy_mode;
+
+ // Dante
+ // BIT15 | BIT12 | BIT5 | BIT1
+ lp->mcr0 |= 0x0020;
+ //Xavier, only set promiscuous mode with eth1 (LAN i/f)
+ //This is a very bad hard code...
+ //if(ioaddr == 0xe900)lp->mcr0 |= 0x0020;
+
+ outw(lp->mcr0, ioaddr);
+
+#ifdef BOOSTRDC
+ /* set interrupt waiting time and packet numbers */
+ outw(0x0802, ioaddr + 0x0C);
+ outw(0x0802, ioaddr + 0x10);
+
+#ifdef FORICPLUS
+ /* upgrade performance (by RDC guys) */
+ phy_write(ioaddr,30,17,(phy_read(ioaddr,30,17)|0x4000)); //bit 14=1
+ phy_write(ioaddr,30,17,~((~phy_read(ioaddr,30,17))|0x2000)); //bit 13=0
+ phy_write(ioaddr,0,19,0x0000);
+ phy_write(ioaddr,0,30,0x01F0);
+#endif
+#endif
+
+ /* Interrupt Mask Register */
+ outw(0x0011, ioaddr + 0x40);
+}
+
+/*
+ A periodic timer routine
+ Polling PHY Chip Link Status
+*/
+static void rdc_timer(unsigned long data)
+{
+ struct net_device *dev=(struct net_device *)data;
+ struct rdc_private *lp = dev->priv;
+ u16 ioaddr = dev->base_addr, phy_mode;
+
+ RDC_DBUG("rdc_timer()", 0);
+
+ /* Polling PHY Chip Status */
+ if (PHY_MODE == 0x3100)
+ phy_mode = phy_mode_chk(dev);
+ else phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
+
+ if (phy_mode != lp->phy_mode) {
+ lp->phy_mode = phy_mode;
+ lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode;
+ outw(lp->mcr0, ioaddr);
+ printk("<RDC> Link Change %x \n", inw(ioaddr));
+ }
+
+ /* Debug */
+// printk("<RDC> Timer: CR0 %x CR40 %x CR3C %x\n", inw(ioaddr), inw(ioaddr+0x40), inw(ioaddr+0x3c));
+
+ /* Timer active again */
+ lp->timer.expires = TIMER_WUT;
+ add_timer(&lp->timer);
+}
+
+#ifndef BOOSTRDC
+/* Allocate skb buffer for rx descriptor */
+static void rx_buf_alloc(struct rdc_private *lp)
+{
+ struct rdc_descriptor *descptr;
+
+ RDC_DBUG("rx_buf_alloc()", 0);
+ descptr = lp->rx_insert_ptr;
+ while(lp->rx_free_desc < RX_DCNT){
+ descptr->skb_ptr = dev_alloc_skb(MAX_BUF_SIZE);
+ if (!descptr->skb_ptr) break;
+ descptr->buf = cpu_to_le32(pci_map_single(lp->pdev, descptr->skb_ptr->tail, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE));
+ descptr->status = 0x8000;
+ descptr = descptr->vndescp;
+ lp->rx_free_desc++;
+ }
+ lp->rx_insert_ptr = descptr;
+}
+#endif
+
+/* Status of PHY CHIP */
+static int phy_mode_chk(struct net_device *dev)
+{
+
+ struct rdc_private *lp = dev->priv;
+ int ioaddr = dev->base_addr, phy_dat;
+
+ RDC_DBUG("phy_mode_chk()", 0);
+
+ /* PHY Link Status Check */
+ phy_dat = phy_read(ioaddr, lp->phy_addr, 1);
+ if (!(phy_dat & 0x4)) return 0x8000; /* Link Failed, full duplex */
+
+ /* PHY Chip Auto-Negotiation Status */
+ phy_dat = phy_read(ioaddr, lp->phy_addr, 1);
+ if (phy_dat & 0x0020) {
+ /* Auto Negotiation Mode */
+ phy_dat = phy_read(ioaddr, lp->phy_addr, 5);
+ phy_dat &= phy_read(ioaddr, lp->phy_addr, 4);
+ if (phy_dat & 0x140) phy_dat = 0x8000;
+ else phy_dat = 0;
+ } else {
+ /* Force Mode */
+ phy_dat = phy_read(ioaddr, lp->phy_addr, 0);
+ if (phy_dat & 0x100) phy_dat = 0x8000;
+ else phy_dat = 0x0000;
+ }
+
+ return phy_dat;
+
+};
+
+/* Read a word data from PHY Chip */
+static int phy_read(int ioaddr, int phy_addr, int reg_idx)
+{
+ int i = 0;
+
+ RDC_DBUG("phy_read()", 0);
+ outw(0x2000 + reg_idx + (phy_addr << 8), ioaddr + 0x20);
+ do{}while( (i++ < 2048) && (inw(ioaddr + 0x20) & 0x2000) );
+
+ return inw(ioaddr + 0x24);
+}
+
+/* Write a word data from PHY Chip */
+static void phy_write(int ioaddr, int phy_addr, int reg_idx, int dat)
+{
+ int i = 0;
+
+ RDC_DBUG("phy_write()", 0);
+ outw(dat, ioaddr + 0x28);
+ outw(0x4000 + reg_idx + (phy_addr << 8), ioaddr + 0x20);
+ do{}while( (i++ < 2048) && (inw(ioaddr + 0x20) & 0x4000) );
+}
+
+enum {
+ RDC_6040 = 0
+};
+
+static struct pci_device_id rdc_pci_tbl[] = {
+ {0x17F3, 0x6040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RDC_6040},
+ //{0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RDC_6040},
+ {0,} /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, rdc_pci_tbl);
+
+static struct pci_driver rdc_driver = {
+ .name = "r6040",
+ .id_table = rdc_pci_tbl,
+ .probe = rdc_init_one,
+ .remove = __devexit_p(rdc_remove_one),
+};
+
+
+static int __init rdc_init (void)
+{
+ RDC_DBUG("rdc_init()", 0);
+
+ printk(version);
+ printed_version = 1;
+
+ return pci_module_init (&rdc_driver);
+}
+
+
+static void __exit rdc_cleanup (void)
+{
+ RDC_DBUG("rdc_cleanup()", 0);
+ pci_unregister_driver (&rdc_driver);
+}
+
+module_init(rdc_init);
+module_exit(rdc_cleanup);
+
+
+/*
+ * Local variables:
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c rdc.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
+
+#ifdef FORICPLUS
+#define DMZ_GPIO 1
+#define RDC3210_CFGREG_ADDR 0x0CF8
+#define RDC3210_CFGREG_DATA 0x0CFC
+static void process_ioctl(struct net_device *dev, unsigned long* args)
+{
+ int ioaddr = dev->base_addr;
+
+ /* port priority */
+ if(args[0]&(1<<31))phy_write(ioaddr,29,19,(phy_read(ioaddr,29,19)|0x2000)); /* port 0 */
+ if(args[0]&(1<<29))phy_write(ioaddr,29,19,(phy_read(ioaddr,29,19)|0x0020)); /* port 1 */
+ if(args[0]&(1<<27))phy_write(ioaddr,29,20,(phy_read(ioaddr,29,20)|0x2000)); /* port 2 */
+ if(args[0]&(1<<25))phy_write(ioaddr,29,20,(phy_read(ioaddr,29,20)|0x0020)); /* port 3 */
+
+ /* DMZ LED */
+
+ {
+ unsigned int val;
+
+ val = 0x80000000 | (7 << 11) | ((0x48));
+ outl(val, RDC3210_CFGREG_ADDR);
+ udelay(10);
+ val = inl(RDC3210_CFGREG_DATA);
+
+ val |= (0x1 << DMZ_GPIO);
+ outl(val, RDC3210_CFGREG_DATA);
+ udelay(10);
+
+ val = 0x80000000 | (7 << 11) | ((0x4C));
+ outl(val, RDC3210_CFGREG_ADDR);
+ udelay(10);
+ val = inl(RDC3210_CFGREG_DATA);
+ if(args[0]&(1<<23)) /* DMZ enabled */
+ val &= ~(0x1 << DMZ_GPIO); /* low activated */
+ else val |= (0x1 << DMZ_GPIO);
+ outl(val, RDC3210_CFGREG_DATA);
+ udelay(10);
+ }
+
+
+}
+#endif /* FORICPLUS */