From 83749d6607929e6a2345d112bede06e74d077e58 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sun, 15 Oct 2006 23:34:22 +0000 Subject: Merge preliminary rdc-2.6 support (Airlink101 AR525W) git-svn-id: svn://svn.openwrt.org/openwrt/trunk@5138 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- target/linux/rdc-2.6/patches/000-rdc_fixes.patch | 861 +++++++++++++++++ .../rdc-2.6/patches/001-rdc3210_flash_map.patch | 271 ++++++ .../linux/rdc-2.6/patches/002-r6040_ethernet.patch | 1018 ++++++++++++++++++++ 3 files changed, 2150 insertions(+) create mode 100644 target/linux/rdc-2.6/patches/000-rdc_fixes.patch create mode 100644 target/linux/rdc-2.6/patches/001-rdc3210_flash_map.patch create mode 100644 target/linux/rdc-2.6/patches/002-r6040_ethernet.patch (limited to 'target/linux/rdc-2.6/patches') diff --git a/target/linux/rdc-2.6/patches/000-rdc_fixes.patch b/target/linux/rdc-2.6/patches/000-rdc_fixes.patch new file mode 100644 index 0000000000..4a75f5fca1 --- /dev/null +++ b/target/linux/rdc-2.6/patches/000-rdc_fixes.patch @@ -0,0 +1,861 @@ +diff -urN linux-2.6.17/arch/i386/Kconfig linux-2.6.17.new/arch/i386/Kconfig +--- linux-2.6.17/arch/i386/Kconfig 2006-06-18 03:49:35.000000000 +0200 ++++ linux-2.6.17.new/arch/i386/Kconfig 2006-10-07 22:33:09.000000000 +0200 +@@ -167,6 +167,14 @@ + Only choose this option if you have such a system, otherwise you + should say N here. + ++config X86_RDC ++ bool "Support for RDC 3211 boards" ++ help ++ Support for RDC 3211 sustems. Say 'Y' here if ther kernel is ++ supposed to run on an IA-32 RDC R3211 system. ++ Only choose this option if you have such as system, otherwise you ++ should say N here. ++ + endchoice + + config ACPI_SRAT +diff -urN linux-2.6.17/arch/i386/kernel/time.c linux-2.6.17.new/arch/i386/kernel/time.c +--- linux-2.6.17/arch/i386/kernel/time.c 2006-06-18 03:49:35.000000000 +0200 ++++ linux-2.6.17.new/arch/i386/kernel/time.c 2006-10-07 22:23:05.000000000 +0200 +@@ -479,7 +479,8 @@ + return; + } + #endif +- xtime.tv_sec = get_cmos_time(); ++ /* RDC board does not have CMOS */ ++ xtime.tv_sec = 0; + xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); + set_normalized_timespec(&wall_to_monotonic, + -xtime.tv_sec, -xtime.tv_nsec); +diff -urN linux-2.6.17/arch/i386/mach-rdc/led.c linux-2.6.17.new/arch/i386/mach-rdc/led.c +--- linux-2.6.17/arch/i386/mach-rdc/led.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.17.new/arch/i386/mach-rdc/led.c 2006-10-07 23:55:59.000000000 +0200 +@@ -0,0 +1,743 @@ ++/* ++ * LED interface for WP3200 ++ * ++ * Copyright (C) 2002, by Allen Hung ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "led.h" ++ ++#define BUF_LEN 30 ++ ++struct LED_DATA { ++ char sts_buf[BUF_LEN+1]; ++ unsigned long sts; ++}; ++ ++struct LED_DATA led_data[LED_DEV_NUM]; ++// sam ++unsigned long ul_ledstat = 0xffffffff; ++ ++ ++static struct timer_list blink_timer[LED_DEV_NUM]; ++// sam 01-30-2004 for watchdog ++static struct timer_list watchdog; ++// end sam ++static char cmd_buf[BUF_LEN+1]; ++ ++//------------------------------------------------------------ ++static long atoh(char *p) ++{ ++ long v = 0, c; ++ while ( (c = *p++) ) { ++ if ( c >= '0' && c <= '9' ) v = (v << 4) + c - '0'; ++ else if ( c >= 'a' && c <= 'f' ) v = (v << 4) + c - 'a' + 0xA; ++ else if ( c >= 'A' && c <= 'F' ) v = (v << 4) + c - 'A' + 0xA; ++ else break; ++ } ++ return v; ++} ++ ++static int reset_flash_default(void *data) ++{ ++ char *argv[3], *envp[1] = {NULL}; ++ int i = 0; ++ ++ int reset_default=(int) data; ++ ++ argv[i++] = "/bin/flash"; ++ argv[i++] = "default"; ++ argv[i] = NULL; ++ if(reset_default) ++ if (call_usermodehelper(argv[0], argv, envp, 1)) ++ printk("failed to Reset to default\n"); ++ machine_restart(0); ++ return 0; ++} ++ ++// sam for ps 3205U -- using CSx1 (0xb0e00000) ++// bit map as following ++// BIT 1 2 3 4 5 ++// POWER WLEN PORT1 PORT2 PORT3 ++// ++// value 0 --> led on ++// value 1 --> led off ++ ++#define _ROUTER_ ++ ++#ifdef _ROUTER_ ++ #define LED_VAL 0x8000384C // the data ofset of gpio 0~30 ++#else ++ #define LED_VAL 0x80003888 // the ofset of gpio 31~58 ++#endif ++#define GPIO_VAL 0x8000384C // the offset of gpio 0-30 ++ ++ ++ ++// sam 1-30-2004 LED status ++// bit map as following ++// BIT 4:0 Link status -->PHY Link ->1 = up, 0 = down ++#define LINK_STATUS (*(unsigned long *)0xb2000014) ++#define WATCHDOG_VAL (*(unsigned long *)0xb20000c0) ++#define WATCHDOG_PERIOD 500 // unit ms ++#define EXPIRE_TIME 300 // unit 10 ms ++#define CLEAR_TIMEER 0xffffa000l // bit 14:0 -> count up timer, write 0 to clear ++#define ENABLE_WATCHDOG 0x80000000l // bit 31 -> 1 enable , 0 disable watchdog ++#define WATCHDOG_SET_TMR_SHIFT 16 // bit 16:30 -> watchdog timer set ++// end sam ++ ++ ++//------------------------------------------------------------ ++static void turn_led(int id, int on) ++{ ++ unsigned long led_bit = 1 << (id); ++ unsigned long led_bit_val; ++ ++ // since we define we have 8 led devices and use gpio 53, 55, 57, 58 ++ // which locate at bit21~26, so we rotate left 20bit ++ ++#ifdef _ROUTER_ ++ led_bit_val = led_bit; ++#else ++ led_bit_val = led_bit << 20; ++#endif ++ ++ switch ( on ) { ++ case 0: ++ ul_ledstat|= led_bit_val; ++ outl(LED_VAL, 0xcf8); ++ outl(ul_ledstat, 0xcfc); ++ break; // LED OFF ++ case 1: ++ ul_ledstat &= ~led_bit_val; ++ outl(LED_VAL, 0xcf8); ++ outl(ul_ledstat, 0xcfc); ++ break; // LED ON ++ case 2: ++ ul_ledstat ^= led_bit_val; ++ outl(LED_VAL, 0xcf8); ++ outl(ul_ledstat, 0xcfc); ++ break; // LED inverse ++ } ++} ++ ++ ++static int led_flash[30]={20,10,100,5,5,150,100,5,5,50,20,50,50,20,60,5,20,10,30,10,5,10,50,2,5,5,5,70,10,50};//Erwin ++static unsigned int wlan_counter; //Erwin ++static void blink_wrapper(u_long id) ++{ ++ u_long sts = led_data[id].sts; ++ ++ if ( (sts & LED_BLINK_CMD) == LED_BLINK_CMD ) { ++ unsigned long period = sts & LED_BLINK_PERIOD; ++ if(period == 0xffff) // BLINK random ++ { ++ blink_timer[id].expires = jiffies + 3*led_flash[wlan_counter%30]*HZ/1000; ++ wlan_counter++; ++ } ++ else ++ blink_timer[id].expires = jiffies + (period * HZ / 1000); ++ turn_led(id, 2); ++ add_timer(&blink_timer[id]); ++ } ++ else if ( sts == LED_ON || sts == LED_OFF ) ++ turn_led(id, sts==LED_ON ? 1 : 0); ++} ++//------------------------------------------------------------ ++static void get_token_str(char *str, char token[][21], int token_num) ++{ ++ int t, i; ++ ++ for ( t = 0 ; t < token_num ; t++ ) { ++ memset(token[t], 0, 21); ++ while ( *str == ' ' ) str++; ++ for ( i = 0 ; str[i] ; i++ ) { ++ if ( str[i] == '\t' || str[i] == ' ' || str[i] == '\n' ) break; ++ if ( i < 20 ) token[t][i] = str[i]; ++ } ++ str += i; ++ } ++} ++ ++//------------------------------------------------------------ ++static void set_led_status_by_str(int id) ++{ ++ char token[3][21], *p; ++ ++ ++ get_token_str(led_data[id].sts_buf, token, 3); ++ ++ if ( strcmp(token[0], "LED") ) ++ { ++ goto set_led_off; ++ } ++ if ( !strcmp(token[1], "ON") ) ++ { ++ ++ turn_led(id, 1); ++ led_data[id].sts = LED_ON; ++ } ++ else if ( !strcmp(token[1], "OFF") ) ++ { ++ ++ goto set_led_off; ++ } ++ else if ( !strcmp(token[1], "BLINK") ) ++ { ++ unsigned int period = 0; ++ p = token[2]; ++ if ( !strcmp(p, "FAST") ) ++ period = LED_BLINK_FAST & LED_BLINK_PERIOD; ++ else if ( !strcmp(p, "SLOW") ) ++ period = LED_BLINK_SLOW & LED_BLINK_PERIOD; ++ else if ( !strcmp(p, "EXTRA_SLOW") ) ++ period = LED_BLINK_EXTRA_SLOW & LED_BLINK_PERIOD; ++ else if ( !strcmp(p, "RANDOM") ) ++ period = LED_BLINK_RANDOM & LED_BLINK_PERIOD; ++ else if ( !strcmp(p, "OFF") ) ++ goto set_led_off; ++ else if ( *p >= '0' && *p <= '9' ) ++ { ++ while ( *p >= '0' && *p <= '9' ) ++ period = period * 10 + (*p++) - '0'; ++// if ( period > 10000 ) ++// period = 10000; ++ } ++ else ++ period = LED_BLINK & LED_BLINK_PERIOD; ++ ++ if ( period == 0 ) ++ goto set_led_off; ++ ++ sprintf(led_data[id].sts_buf, "LED BLINK %d\n", period); ++ led_data[id].sts = LED_BLINK_CMD + period; ++ turn_led(id, 2); ++ // Set timer for next blink ++ del_timer(&blink_timer[id]); ++ blink_timer[id].function = blink_wrapper; ++ blink_timer[id].data = id; ++ init_timer(&blink_timer[id]); ++ ++ blink_timer[id].expires = jiffies + (1000 * HZ / 1000); ++ ++ add_timer(&blink_timer[id]); ++ } ++ else ++ { ++ goto set_led_off; ++ } ++ return; ++ set_led_off: ++ strcpy(led_data[id].sts_buf, "LED OFF\n"); ++ led_data[id].sts = LED_OFF; ++ turn_led(id, 0); ++} ++ ++//---------------------------------------------------------------------- ++static int led_read_proc(char *buf, char **start, off_t fpos, int length, int *eof, void *data) ++{ ++ int len, dev; ++ ++ for ( len = dev = 0 ; dev < LED_DEV_NUM ; dev++ ) { ++ len += sprintf(buf+len, "%d: %s", dev, led_data[dev].sts_buf); ++ } ++ len = strlen(buf) - fpos; ++ if ( len <= 0 ) { ++ *start = buf; ++ *eof = 1; ++ return 0; ++ } ++ *start = buf + fpos; ++ if ( len <= length ) *eof = 1; ++ return len < length ? len : length; ++} ++ ++//---------------------------------------------------------------------- ++static int led_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int id = (int)file->private_data; ++ ++ switch ( cmd ) { ++ case LED_ON: ++ strcpy(led_data[id].sts_buf, "LED ON\n"); ++ set_led_status_by_str(id); ++ break; ++ case LED_OFF: ++ strcpy(led_data[id].sts_buf, "LED OFF\n"); ++ set_led_status_by_str(id); ++ break; ++ default: ++ if ( (cmd & LED_BLINK_CMD) != LED_BLINK_CMD ) ++ { ++ break; ++ } ++ case LED_BLINK: ++ case LED_BLINK_FAST: ++ case LED_BLINK_SLOW: ++ case LED_BLINK_EXTRA_SLOW: ++ case LED_BLINK_RANDOM: ++ sprintf(led_data[id].sts_buf, "LED BLINK %d\n", (int)(cmd & LED_BLINK_PERIOD)); ++ set_led_status_by_str(id); ++ break; ++ } ++ return 0; ++} ++ ++static int led_open(struct inode *inode, struct file *file) ++{ ++ int led_id = MINOR(inode->i_rdev); ++// unsigned long led_bit = 1 << (led_id); ++ ++ if ( led_id >= LED_DEV_NUM ) ++ return -ENODEV; ++/* sam 12/02/2003 ++ GPIO_SEL_I_O &= ~led_bit; // 0 to GPIO ++ GPIO_O_EN |= (led_bit << 16); // 0 to Output ++*/ ++ ++ file->private_data = (void*)led_id; ++ return 0; ++} ++ ++static long led_read(struct file *file, char *buf, size_t count, loff_t *fpos) ++{ ++ int rem, len; ++ int id = (int)file->private_data; ++ char *p = led_data[id].sts_buf; ++ ++ len = strlen(p); ++ rem = len - *fpos; ++ if ( rem <= 0 ) { ++ *fpos = len; ++ return 0; ++ } ++ if ( rem > count ) rem = count; ++ memcpy(buf, p+(*fpos), rem); ++ *fpos += rem; ++ return rem; ++} ++ ++static long led_write(struct file *file, char *buf, size_t count, loff_t *fpos) ++{ ++ int len; ++ int id = (int)file->private_data; ++ char *p = id == REG_MINOR ? cmd_buf : led_data[id].sts_buf; ++ memset(p, 0, BUF_LEN); ++ ++ p += *fpos; ++ len = 0; ++ ++ ++ while ( count > 0 ) ++ { ++ ++ if ( *fpos < BUF_LEN ) ++ { ++ int c = *buf++; ++ p[len] = c>='a' && c<='z' ? c-'a'+'A' : c; ++ } ++ (*fpos)++; ++ len++; ++ count--; ++ } ++ // sam ++ set_led_status_by_str(id); ++ (*fpos) = 0; ++ // ++ ++ return len; ++} ++ ++static int led_flush(struct file *file) ++{ ++ int id = (int)file->private_data; ++ ++ if ( file->f_mode & FMODE_WRITE ) ++ { ++ set_led_status_by_str(id); ++ } ++ return 0; ++} ++ ++static struct file_operations led_fops = { ++ read: led_read, ++ write: led_write, ++ flush: led_flush, ++ ioctl: led_ioctl, ++ open: led_open, ++}; ++ ++//---------------------------------------------- ++static unsigned long *reg_addr; ++static int dump_len; ++ ++static int dump_content(char *buf) ++{ ++ return 0; ++} ++ ++static long gpio_read(struct file *file, char *buf, size_t count, loff_t *fpos) ++{ ++ int rem, len; ++ int id = (int)file->private_data; ++ char temp[80*10]; ++ unsigned long gpio_regval =0; ++ ++ outl(GPIO_VAL, 0xcf8); ++ gpio_regval = inl(0xcfc); ++ gpio_regval |= 0x40; ++ outl(gpio_regval, 0xcfc); // each in, need out 1 first ++ gpio_regval = inl(0xcfc); ++ ++ ++ // sam debug ++ //printk(KERN_ERR "gpio_id:%d, gpio_regval:%08X\n", id, gpio_regval); ++ //end sam ++ ++ if ( id < GPIO_DEV_NUM ) { ++ int gpio_bit = 1 << id; ++ ++ len = sprintf(temp, "%d\n", (gpio_regval & gpio_bit) ? 1 : 0); ++ } ++ else // REG device ++ len = dump_content(temp); ++ rem = len - *fpos; ++ if ( rem <= 0 ) { ++ *fpos = len; ++ return 0; ++ } ++ if ( rem > count ) rem = count; ++ memcpy(buf, temp+(*fpos), rem); ++ *fpos += rem; ++ return rem; ++} ++ ++static int gpio_flush(struct file *file) ++{ ++ return 0; ++} ++ ++static int gpio_open(struct inode *inode, struct file *file) ++{ ++ int id = MINOR(inode->i_rdev); ++ if ( id >= GPIO_DEV_NUM && id != REG_MINOR ) ++ return -ENODEV; ++ file->private_data = (void*)id; ++ return 0; ++} ++ ++static struct file_operations gpio_fops = { ++ read: gpio_read, ++ open: gpio_open, ++ flush: gpio_flush, ++ write: led_write, ++}; ++ ++// --------------------------------------------- ++// sam 1-30-2004 LAN_STATUS Device ++ ++//static unsigned long *reg_addr; ++//static int dump_len; ++ ++//static int lanSt_content(char *buf) ++//{ ++// int i, j, len; ++// unsigned long *p = (unsigned long *)0xb2000014; // PHY_ST ++// // j = dump_len/4 + ((dump_len&3) ? 1 : 0); ++// len = sprintf(buf, "Reg Addr = %08lX, Value = \n", (unsigned long)p); ++// // for ( i = 0 ; i < j ; i++, p++ ) ++// len += sprintf(buf+len,"%08lX\n", *p); ++ ++// return len; ++//} ++ ++#define MAC_IOBASE 0xe800 // Eth0 ++#define PHY_ADDR 1 // For Eth0 ++#define MII_STATUS_ADDR 1 ++// where "id" value means which bit of PHY reg 1 we want to check ++static long lanSt_read(struct file *file, char *buf, size_t count, loff_t *fpos) ++{ ++ int rem, len; ++// unsigned long *p = (unsigned long *)0xb2000014; // PHY_ST ++ unsigned short status; ++ unsigned int i = 0; ++ int id = (int)file->private_data; ++ char temp[80*10]; ++ ++ outw(0x2000 + MII_STATUS_ADDR + (PHY_ADDR << 8), MAC_IOBASE + 0x20); ++ do{}while( (i++ < 2048) && (inw(MAC_IOBASE+0x20) & 0x2000) ); ++ ++ status = inw(MAC_IOBASE + 0x24); ++ ++ // sam debug ++ //printk(KERN_ERR "PHY REG1 Status:%04x\n", status ); ++ // end sam ++ ++ if ( id < LAN_DEV_NUM ) { ++ unsigned long lanSt_bit = 1 << id; ++// len = lanSt_content(temp); ++ len = sprintf(temp, "%d\n",(status & lanSt_bit) ? 1 : 0); ++ } ++ else // REG device ++ { ++ len = sprintf(temp, "-1\n"); ++ } ++ rem = len - *fpos; ++ if ( rem <= 0 ) { ++ *fpos = len; ++ return 0; ++ } ++ if ( rem > count ) rem = count; ++ memcpy(buf, temp+(*fpos), rem); ++ *fpos += rem; ++ return rem; ++} ++ ++static int lanSt_flush(struct file *file) ++{ ++ return 0; ++} ++ ++static int lanSt_open(struct inode *inode, struct file *file) ++{ ++ int id = MINOR(inode->i_rdev); ++ if ( id >= LAN_DEV_NUM && id != REG_MINOR ) ++ return -ENODEV; ++ file->private_data = (void*)id; ++ return 0; ++} ++ ++static struct file_operations lanSt_fops = { ++ read: lanSt_read, ++ open: lanSt_open, ++ flush: lanSt_flush, ++ write: led_write, ++}; ++ ++//---------------------------------------------- ++static int SwResetPress = 0; ++static int SwResetCounter = 0; ++static int RebootFlag = 0; ++static void watchdog_wrapper(unsigned int period) ++{ ++ // { RexHua add for restore default, by press SwReset 5 second, 2 sec to restart ++#if 0 // ++ u_long reg; ++ ++ outl(GPIO_VAL, 0xcf8); ++ reg = inl(0xcfc); ++ reg |= 0x40; ++ outl(reg, 0xcfc); // each in, need out 1 first ++ reg = inl(0xcfc); ++ ++ if( (reg & 0x40) == 0) ++ { ++ if(SwResetPress == 0) ++ { ++ SwResetCounter=0; ++ strcpy(led_data[15].sts_buf, "LED BLINK 500\n" ); ++ set_led_status_by_str(15); ++ } ++ SwResetPress=1; ++ printk("SwReset press!\n"); ++ ++ } ++ else ++ { ++ if(SwResetPress=1) ++ { ++ strcpy(led_data[15].sts_buf, "LED ON\n" ); ++ set_led_status_by_str(15); ++ } ++ ++ SwResetPress=0; ++ if(RebootFlag == 1) ++ machine_restart(0); ++ } ++ ++ if(SwResetPress == 1) ++ { ++ if(SwResetCounter > 10) ++ { ++ turn_led(15, 0); ++// kernel_thread(reset_flash_default, 1, SIGCHLD); ++ reset_flash_default(1); ++ turn_led(15, 1); ++ } ++ else if(SwResetCounter == 3) ++ { ++ RebootFlag=1; ++ strcpy(led_data[15].sts_buf, "LED BLINK 100\n" ); ++ set_led_status_by_str(15); ++ } ++ } ++ ++ SwResetCounter++; ++#endif ++ ++ // clear timer count ++ outl(0x80003844, 0xcf8); ++ outl(0x00800080, 0xcfc); // enable watchdog and set the timeout = 1.34s ++ //printk(KERN_ERR "wdt\n" ); ++ watchdog.expires = jiffies + (period * HZ / 1000); ++ add_timer(&watchdog); ++} ++ ++//---------------------------------------------- ++static int init_status; ++ ++#define INIT_REGION 0x01 ++#define INIT_LED_REGISTER 0x02 ++#define INIT_LED_PROC_READ 0x04 ++#define INIT_GPIO_REGISTER 0x08 ++// sam 1-30-2004 LAN_STATUS ++#define INIT_LAN_STATUS_REGISTER 0x10 ++#define INIT_WATCHDOG_REGISTER 0x20 ++ ++static void led_exit(void) ++{ ++ int id; ++ for ( id = 0 ; id < LED_DEV_NUM ; id++ ) { ++ del_timer(&blink_timer[id]); ++ turn_led(id, 0); ++ } ++ if ( init_status & INIT_LED_PROC_READ ) ++ remove_proc_entry("driver/led", NULL); ++ ++ if ( init_status & INIT_LED_REGISTER ) ++ unregister_chrdev(LED_MAJOR, "led"); ++ ++ if ( init_status & INIT_GPIO_REGISTER ) ++ unregister_chrdev(GPIO_MAJOR, "gpio"); ++ // sam 1-30-2004 ++ ++ if( init_status & INIT_LAN_STATUS_REGISTER ) ++ unregister_chrdev(LAN_STATUS_MAJOR, "lanSt"); ++ ++ if( init_status & INIT_WATCHDOG_REGISTER) ++ del_timer(&watchdog); ++ ++ ++ // end sam ++ ++} ++ ++static int __init led_init(void) ++{ ++ int result, id, i, j; ++ unsigned long reg; ++ init_status = 0; ++ ++ //----- register device (LED)------------------------- ++ ++ ++ result = register_chrdev(LED_MAJOR, "led", &led_fops); ++ if ( result < 0 ) { ++ printk(KERN_ERR "led: can't register char device\n" ); ++ led_exit(); ++ return result; ++ } ++ init_status |= INIT_LED_REGISTER; ++ //----- register device (GPIO)------------------------- ++ result = register_chrdev(GPIO_MAJOR, "gpio", &gpio_fops); ++ if ( result < 0 ) { ++ printk(KERN_ERR "gpio: can't register char device\n" ); ++ led_exit(); ++ return result; ++ } ++ init_status |= INIT_GPIO_REGISTER; ++ ++ // sam 1-30-2004 LAN Status ++ // ----- register device (LAN_STATUS)------------------- ++ ++ //--> sam 5-1802995 ++ ++ result = register_chrdev(LAN_STATUS_MAJOR, "lanSt", &lanSt_fops); ++ if ( result < 0 ) { ++ printk(KERN_ERR "lanSt: can't register char device\n" ); ++ led_exit(); ++ return result; ++ } ++ init_status |= INIT_LAN_STATUS_REGISTER; ++ ++ // <-- end sam ++ ++ // -----------init watchdog timer------------------------- ++ //del_timer(&blink_timer[id]); ++ ++ outl(0x80003840, 0xcf8); ++ reg = inl(0xcfc); ++ reg |= 0x1600; // ensable SRC bit ++ outl(reg, 0xcfc); ++#ifdef _ROUTER_ ++ outl(0x80003848, 0xcf8); ++ reg = inl(0xcfc); ++ reg |= 0x18040; // enable GPIO, PowerLED:15, WLAN_LED0:16, SwReset:6 ++ outl(reg, 0xcfc); ++ ++ outl(0x8000384c, 0xcf8); ++ reg = inl(0xcfc); ++ reg |= 0x40; // output SwReset:6 1, Set SwReset as Input ++ outl(reg, 0xcfc); ++#endif ++ // sam debug ++ //reg = inl(0xcfc); ++ //printk(KERN_ERR "REG40:%08X\n", reg); ++ // end sam ++ outl(0x80003844, 0xcf8); ++ outl(0x00800080, 0xcfc); // enable watchdog and set the timeout = 1.34s ++ ++ watchdog.function = watchdog_wrapper; ++ watchdog.data = WATCHDOG_PERIOD; ++ init_timer(&watchdog); ++ watchdog.expires = jiffies + (WATCHDOG_PERIOD * HZ / 1000); ++ add_timer(&watchdog); ++ init_status |= INIT_WATCHDOG_REGISTER; ++ ++ // end sam ++ //------ read proc ------------------- ++ if ( !create_proc_read_entry("driver/led", 0, 0, led_read_proc, NULL) ) { ++ printk(KERN_ERR "led: can't create /proc/driver/led\n"); ++ led_exit(); ++ return -ENOMEM; ++ } ++ init_status |= INIT_LED_PROC_READ; ++ //------------------------------ ++// reg_addr = (unsigned long *)0xB4000000; ++// dump_len = 4; ++ ++ for ( id = 0 ; id < LED_DEV_NUM ; id++ ) { ++ strcpy(led_data[id].sts_buf, "LED ON\n" ); ++ set_led_status_by_str(id); ++ } ++ ++// for (i = 0; i < 0xffff; i++) ++// for (j = 0; j < 0x6000; j++); ++ ++/* sam 5-18-2005 remark ++ for ( id = 0 ; id < LED_DEV_NUM ; id++ ) { ++ strcpy(led_data[id].sts_buf, "LED ON\n" ); ++ set_led_status_by_str(id); ++ } ++*/ ++ printk(KERN_INFO "LED & GPIO & LAN Status Driver LED_VERSION \n"); ++ return 0; ++} ++ ++module_init(led_init); ++module_exit(led_exit); ++EXPORT_NO_SYMBOLS; +diff -urN linux-2.6.17/arch/i386/mach-rdc/led.h linux-2.6.17.new/arch/i386/mach-rdc/led.h +--- linux-2.6.17/arch/i386/mach-rdc/led.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.17.new/arch/i386/mach-rdc/led.h 2006-10-07 22:28:32.000000000 +0200 +@@ -0,0 +1,32 @@ ++#ifndef _LED_H_INCLUDED ++#define _LED_H_INCLUDED ++ ++#include ++ ++#define LED_VERSION "v1.0" ++#define LED_MAJOR 166 ++#define LED_DEV_NUM 32 ++#define LED_GPIO_START 1 ++#define GPIO_MAJOR 167 ++#define GPIO_DEV_NUM 32 ++#define REG_MINOR 128 ++// sam 1-30-2004 for LAN_STATUS ++#define LAN_STATUS_MAJOR 168 ++#define LAN_DEV_NUM 5 ++// end sam ++ ++//#define GPIO_IO_BASE 0xB4002480 ++//#define GPIO_IO_BASE ((unsigned long)0xb20000b8) ++//#define GPIO_IO_EXTENT 0x40 ++ ++#define LED_ON 0x010000 ++#define LED_OFF 0x020000 ++#define LED_BLINK_CMD 0x030000 ++#define LED_BLINK_PERIOD 0x00FFFF ++#define LED_BLINK (LED_BLINK_CMD|1000) ++#define LED_BLINK_FAST (LED_BLINK_CMD|250) ++#define LED_BLINK_SLOW (LED_BLINK_CMD|500) ++#define LED_BLINK_EXTRA_SLOW (LED_BLINK_CMD|2000) ++#define LED_BLINK_RANDOM (LED_BLINK_CMD|0xffff) ++ ++#endif +diff -urN linux-2.6.17/arch/i386/mach-rdc/Makefile linux-2.6.17.new/arch/i386/mach-rdc/Makefile +--- linux-2.6.17/arch/i386/mach-rdc/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.17.new/arch/i386/mach-rdc/Makefile 2006-10-07 22:31:19.000000000 +0200 +@@ -0,0 +1,5 @@ ++# ++# Makefile for the linux kernel. ++# ++ ++obj-$(CONFIG_X86_RDC) := led.o +diff -urN linux-2.6.17/arch/i386/Makefile linux-2.6.17.new/arch/i386/Makefile +--- linux-2.6.17/arch/i386/Makefile 2006-06-18 03:49:35.000000000 +0200 ++++ linux-2.6.17.new/arch/i386/Makefile 2006-10-07 23:56:13.000000000 +0200 +@@ -80,6 +80,10 @@ + mflags-$(CONFIG_X86_ES7000) := -Iinclude/asm-i386/mach-es7000 + mcore-$(CONFIG_X86_ES7000) := mach-default + core-$(CONFIG_X86_ES7000) := arch/i386/mach-es7000/ ++# RDC subarch support ++mflags-$(CONFIG_X86_RDC) := -Iinclude/asm-i386/mach-generic ++mcore-$(CONFIG_X86_RDC) := mach-default ++core-$(CONFIG_X86_RDC) := arch/i386/mach-rdc/ + + # default subarch .h files + mflags-y += -Iinclude/asm-i386/mach-default +diff -urN linux-2.6.17/arch/i386/mm/fault.c linux-2.6.17.new/arch/i386/mm/fault.c +--- linux-2.6.17/arch/i386/mm/fault.c 2006-06-18 03:49:35.000000000 +0200 ++++ linux-2.6.17.new/arch/i386/mm/fault.c 2006-10-07 22:24:15.000000000 +0200 +@@ -551,6 +551,7 @@ + tsk->thread.cr2 = address; + tsk->thread.trap_no = 14; + tsk->thread.error_code = error_code; ++ machine_restart(NULL); /* Added for RDC */ + die("Oops", regs, error_code); + bust_spinlocks(0); + do_exit(SIGKILL); +@@ -566,6 +567,12 @@ + down_read(&mm->mmap_sem); + goto survive; + } ++ /* RDC : Forcing processes to be niced */ ++ if (tsk->prio < 0) { ++ printk("VM: niced process %s\n", tsk->comm); ++ yield(); ++ goto survive; ++ } + printk("VM: killing process %s\n", tsk->comm); + if (error_code & 4) + do_exit(SIGKILL); diff --git a/target/linux/rdc-2.6/patches/001-rdc3210_flash_map.patch b/target/linux/rdc-2.6/patches/001-rdc3210_flash_map.patch new file mode 100644 index 0000000000..5e1a2fb0e5 --- /dev/null +++ b/target/linux/rdc-2.6/patches/001-rdc3210_flash_map.patch @@ -0,0 +1,271 @@ +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 +@@ -76,6 +76,12 @@ + PNC-2000 is the name of Network Camera product from PHOTRON + Ltd. in Japan. It uses CFI-compliant flash. + ++config MTD_RDC3210 ++ tristate "CFI Flash devcie mapped on RDC3210" ++ depends on X86 && MTD_CFI && MTD_PARTITIONS ++ help ++ RDC-3210 is the flash device we find on Ralink reference board ++ + config MTD_SC520CDP + tristate "CFI Flash device mapped on AMD SC520 CDP" + depends on X86 && MTD_CFI +diff -urN linux-2.6.17/drivers/mtd/maps/Makefile linux-2.6.17.new/drivers/mtd/maps/Makefile +--- linux-2.6.17/drivers/mtd/maps/Makefile 2006-06-18 03:49:35.000000000 +0200 ++++ linux-2.6.17.new/drivers/mtd/maps/Makefile 2006-09-24 20:26:10.000000000 +0200 +@@ -28,6 +28,7 @@ + obj-$(CONFIG_MTD_PHYSMAP) += physmap.o + obj-$(CONFIG_MTD_PNC2000) += pnc2000.o + obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o ++obj-$(CONFIG_MTD_RDC3210) += rdc3210.o + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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"); ++ diff --git a/target/linux/rdc-2.6/patches/002-r6040_ethernet.patch b/target/linux/rdc-2.6/patches/002-r6040_ethernet.patch new file mode 100644 index 0000000000..88a9ea17ea --- /dev/null +++ b/target/linux/rdc-2.6/patches/002-r6040_ethernet.patch @@ -0,0 +1,1018 @@ +diff -urN linux-2.6.17/drivers/net/Kconfig linux-2.6.17.new/drivers/net/Kconfig +--- linux-2.6.17/drivers/net/Kconfig 2006-06-18 03:49:35.000000000 +0200 ++++ linux-2.6.17.new/drivers/net/Kconfig 2006-09-25 13:14:27.000000000 +0200 +@@ -1358,6 +1358,19 @@ + . The module will be + called apricot. + ++config R6040 ++ tristate "RDC Fast-Ethernet support (EXPERIMENTAL)" ++ depends on NET_PCI && EXPERIMENTAL ++ select MII ++ help ++ If you have a network (Ethernet) controller of this type, say Y and ++ read the Ethernet-HOWTO, available from ++ . ++ ++ To compile this driver as a module, choose M here and read ++ . The module will be ++ called r6040. ++ + config B44 + tristate "Broadcom 4400 ethernet support (EXPERIMENTAL)" + depends on NET_PCI && PCI && EXPERIMENTAL +diff -urN linux-2.6.17/drivers/net/Makefile linux-2.6.17.new/drivers/net/Makefile +--- linux-2.6.17/drivers/net/Makefile 2006-06-18 03:49:35.000000000 +0200 ++++ linux-2.6.17.new/drivers/net/Makefile 2006-09-25 13:14:45.000000000 +0200 +@@ -106,6 +106,7 @@ + obj-$(CONFIG_NE3210) += ne3210.o 8390.o + obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o + obj-$(CONFIG_B44) += b44.o ++obj-$(CONFIG_R6040) += r6040.o + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* for udelay() */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Sten Wang "); ++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, struct pt_regs *regs); ++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(" 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(" 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 pt_regs *regs) ++{ ++ 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; (imc_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(" Link Change %x \n", inw(ioaddr)); ++ } ++ ++ /* Debug */ ++// printk(" 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 */ -- cgit v1.2.3