S: San Jose, California 95131
S: USA
+N: Kumar Gala
+E: kumar.gala@motorola.com
+D: AltiVec PowerPC support
+
N: Nigel Gamble
E: nigel@nrg.org
E: nigel@sgi.com
E: benh@mipsys.com
D: PowerMac booter (BootX)
D: Additional PowerBook support
+D: Apple "Core99" machines support (ibook,g4,...)
S: 22, rue des Marguettes
S: 75012 Paris
S: France
E: ken@halcyon.com
D: CDROM driver "sonycd535" (Sony CDU-535/531)
+N: Matt Porter
+E: mporter@phx.mcd.mot.com
+D: Motorola PowerPC PReP support
+S: 2900 S. Diable Way
+S: Tempe, Arizona 85282
+S: USA
+
N: Frederic Potter
E: Frederic.Potter@masi.ibp.fr
D: Some PCI kernel support
VERSION = 2
PATCHLEVEL = 2
SUBLEVEL = 17
-EXTRAVERSION = pre4
+EXTRAVERSION = pre5
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
zvmlinux.initrd: zvmlinux
$(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
- --add-section=initrd=ramdisk.image.gz \
+ --add-section=initrd=../coffboot/ramdisk.image.gz \
--add-section=image=../coffboot/vmlinux.gz \
zvmlinux.initrd.tmp zvmlinux.initrd
$(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd initrd` \
-c -o misc.o misc.c
$(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
- --add-section=initrd=ramdisk.image.gz \
+ --add-section=initrd=../coffboot/ramdisk.image.gz \
--add-section=image=../coffboot/vmlinux.gz \
zvmlinux.initrd.tmp $@
rm zvmlinux.initrd.tmp
#define get_32be(x) (*(unsigned *)(x))
#define RAM_START 0x00000000
-#define RAM_END (8<<20)
+#define RAM_END (64<<20)
-#define RAM_FREE ((unsigned long)(_end+0x1000)&~0xFFF)
+#define BOOT_START ((unsigned long)_start)
+#define BOOT_END ((unsigned long)(_end + 0xFFF) & ~0xFFF)
#define PROG_START 0x00010000
char *avail_ram;
char *end_avail;
-extern char _end[];
+extern char _start[], _end[];
extern char image_data[];
extern int image_len;
extern char initrd_data[];
initrd_start = (RAM_END - initrd_size) & ~0xFFF;
a1 = initrd_start;
a2 = initrd_size;
- printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n\r", initrd_start,
- initrd_data,initrd_size);
+ claim(initrd_start, RAM_END - initrd_start, 0);
+ printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n",
+ initrd_start, initrd_data, initrd_size);
memcpy((char *)initrd_start, initrd_data, initrd_size);
- end_avail = (char *)initrd_start;
- } else
- end_avail = (char *) RAM_END;
+ }
im = image_data;
len = image_len;
+ /* try and claim our text/data in case of OF bugs */
+ claim(BOOT_START, BOOT_END - BOOT_START, 0);
+ /* claim 4MB starting at PROG_START */
+ claim(PROG_START, (4<<20) - PROG_START, 0);
dst = (void *) PROG_START;
if (im[0] == 0x1f && im[1] == 0x8b) {
- avail_ram = (char *)RAM_FREE;
+ /* claim 512kB for scratch space */
+ avail_ram = (char *) claim(0, 512 << 10, 0x10);
+ end_avail = avail_ram + (512 << 10);
+ printf("avail_ram = %x\n", avail_ram);
printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
gunzip(dst, 0x400000, im, &len);
printf("done %u bytes\n\r", len);
.text
/*
- * Use the BAT0 registers to map the 1st 8MB of RAM to 0x90000000.
+ * Use the BAT0 registers to map the 1st 8 or 64MB of RAM to 0x90000000.
*/
.globl setup_bats
setup_bats:
ori 4,4,4 /* set up BAT registers for 601 */
li 5,0x7f
b 5f
-4: ori 4,4,0xff /* set up BAT registers for 604 */
+4: ori 4,4,0x7ff /* set up BAT registers for 604 */
li 5,2
mtdbatu 3,4
mtdbatl 3,5
return args.phandle;
}
+void *
+claim(unsigned int virt, unsigned int size, unsigned int align)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ unsigned int virt;
+ unsigned int size;
+ unsigned int align;
+ void *ret;
+ } args;
+
+ args.service = "claim";
+ args.nargs = 3;
+ args.nret = 1;
+ args.virt = virt;
+ args.size = size;
+ args.align = align;
+ (*prom)(&args);
+ return args.ret;
+}
+
int
getprop(void *phandle, const char *name, void *buf, int buflen)
{
micoffboot: dummy.o
$(LD) -o $@ $(COFF_LD_ARGS) dummy.o $(LIBS)
-miboot.image: micoffboot hack-coff
+miboot.image: micoffboot hack-coff vmlinux.gz
$(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz micoffboot $@
./hack-coff $@
-miboot.image.initrd: micoffboot hack-coff
+miboot.image.initrd: micoffboot hack-coff vmlinux.gz ramdisk.image.gz
$(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz \
--add-section=initrd=ramdisk.image.gz micoffboot $@
./hack-coff $@
--- /dev/null
+int main(void)
+{
+ return 0;
+}
if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE
fi
+tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE
bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP
$(TOPDIR)/include/asm/ptrace.h
$(CC) ${CFLAGS} -S mk_defs.c
cp ppc_defs.head ppc_defs.h
- grep '^#define' mk_defs.s >>ppc_defs.h
+ chmod 755 ppc_defs.h
+ grep '^#define' mk_defs.s >> ppc_defs.h
rm mk_defs.s
find_name : find_name.c
while ( *s )
call_rtas( "display-character", 1, 1, NULL, *s++ );
}
+
+void chrp_indicator(int x)
+{
+ call_rtas("set-indicator", 3, 1, NULL, 6, 0, x);
+}
stw r0,20(r1)
lis r4,rtas_data@ha
lwz r4,rtas_data@l(r4)
- addis r4,r4,-KERNELBASE@h
lis r6,1f@ha /* physical return address for rtas */
addi r6,r6,1f@l
addis r6,r6,-KERNELBASE@h
#undef SHOW_GATWICK_IRQS
+void pmac_time_init(void);
unsigned long pmac_get_rtc_time(void);
int pmac_set_rtc_time(unsigned long nowtime);
void pmac_read_rtc_time(void);
find_via_cuda();
find_via_pmu();
+ pmac_nvram_init();
+
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
pmac_init2(void))
{
adb_init();
- pmac_nvram_init();
media_bay_init();
}
ppc_md.power_off = pmac_power_off;
ppc_md.halt = pmac_halt;
- ppc_md.time_init = NULL;
+ ppc_md.time_init = pmac_time_init;
ppc_md.set_rtc_time = pmac_set_rtc_time;
ppc_md.get_rtc_time = pmac_get_rtc_time;
ppc_md.calibrate_decr = pmac_calibrate_decr;
#undef DEBUG
-/*
- * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
- */
-static int nvram_naddrs;
-static volatile unsigned char *nvram_addr;
-static volatile unsigned char *nvram_data;
-static int nvram_mult, is_core_99;
-static char* nvram_image;
-static int core99_bank = 0;
-
-extern int pmac_newworld;
-
#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */
#define CORE99_SIGNATURE 0x5a
#define CORE99_FLASH_CMD_RESET 0xff
#define CORE99_FLASH_CMD_WRITE_SETUP 0x40
-
/* CHRP NVRAM header */
struct chrp_header {
u8 signature;
u32 reserved[2];
};
+/*
+ * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
+ */
+static int nvram_naddrs;
+static volatile unsigned char *nvram_addr;
+static volatile unsigned char *nvram_data;
+static int nvram_mult, is_core_99;
+static int core99_bank = 0;
static int nvram_partitions[3];
+/* FIXME: kmalloc fails to allocate the image now that I had to move it
+ * before time_init(). For now, I allocate a static buffer here
+ * but it's a waste of space on all but core99 machines
+ */
+#if 0
+static char* nvram_image;
+#else
+__pmac static char nvram_image[NVRAM_SIZE];
+#endif
+
+extern int pmac_newworld;
+
+
static u8
chrp_checksum(struct chrp_header* hdr)
{
printk(KERN_ERR "nvram: no address\n");
return;
}
+#if 0
nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
if (!nvram_image) {
printk(KERN_ERR "nvram: can't allocate image\n");
return;
}
+#endif
nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
#ifdef DEBUG
printk("nvram: Checking bank 0...\n");
return req.reply[1];
case 1:
if (is_core_99)
- return nvram_image[addr];
+ return nvram_image ? nvram_image[addr] : 0;
return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
case 2:
*nvram_addr = addr >> 5;
break;
case 1:
if (is_core_99) {
+ if (!nvram_image)
+ return;
nvram_image[addr] = val;
break;
}
#include <asm/system.h>
#include <asm/io.h>
#include <asm/pgtable.h>
+#include <asm/nvram.h>
#include "time.h"
/* Bits in IFR and IER */
#define T1_INT 0x40 /* Timer 1 interrupt */
-__pmac
+extern struct timezone sys_tz;
+
+__init
+void pmac_time_init(void)
+{
+ s32 delta = 0;
+ int dst;
+ int i;
+ char tmp[1024];
+ char *p = tmp;
+
+ delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
+ delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
+ delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
+ if (delta & 0x00800000UL)
+ delta |= 0xFF000000UL;
+ dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
+ printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
+ dst ? "on" : "off");
+ sys_tz.tz_minuteswest = -delta/60;
+ /* I _suppose_ this is 0:off, 1:on */
+ sys_tz.tz_dsttime = dst;
+}
+__pmac
unsigned long pmac_get_rtc_time(void)
{
struct adb_request req;
+ int offset = sys_tz.tz_minuteswest * 60;
/* Get the time from the RTC */
if (adb_controller == 0)
printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
req.reply_len);
return (req.reply[3] << 24) + (req.reply[4] << 16)
- + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
+ + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET + offset;
case ADB_VIAPMU:
if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) {
printk("pmac_read_rtc_time: pmu_request failed\n");
printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
req.reply_len);
return (req.reply[1] << 24) + (req.reply[2] << 16)
- + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET;
+ + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET + offset;
default:
return 0;
}
int pmac_set_rtc_time(unsigned long nowtime)
{
- return 0;
+ struct adb_request req;
+
+ nowtime += RTC_OFFSET - sys_tz.tz_minuteswest * 60;
+
+ /* Set the time in the RTC */
+ if (adb_controller == 0)
+ return 0;
+ /* adb_controller->kind, not adb_hardware, since that doesn't
+ get set until we call adb_init - paulus. */
+ switch (adb_controller->kind) {
+ case ADB_VIACUDA:
+ if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
+ nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+ return 0;
+ while (!req.complete)
+ cuda_poll();
+// if (req.reply_len != 7)
+ printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+ req.reply_len);
+ return 1;
+ case ADB_VIAPMU:
+ if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
+ nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+ return 0;
+ while (!req.complete)
+ pmu_poll();
+ if (req.reply_len != 5)
+ printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+ req.reply_len);
+ return 1;
+ default:
+ return 0;
+ }
}
/*
#include <asm/spinlock.h>
#include <asm/dma.h>
#include <asm/machdep.h>
+#include <asm/nvram.h>
/* Tell string.h we don't want memcpy etc. as cpp defines */
#define EXPORT_SYMTAB_STROPS
extern atomic_t ppc_n_lost_interrupts;
extern void do_lost_interrupts(unsigned long);
extern int do_signal(sigset_t *, struct pt_regs *);
+extern unsigned long mktime(unsigned int, unsigned int, unsigned int,
+ unsigned int, unsigned int, unsigned int);
+extern void to_tm(int tim, struct rtc_time * tm);
long long __ashrdi3(long long, int);
long long __ashldi3(long long, int);
/*#ifdef CONFIG_PMAC */
EXPORT_SYMBOL(nvram_read_byte);
EXPORT_SYMBOL(nvram_write_byte);
+EXPORT_SYMBOL(pmac_xpram_read);
+EXPORT_SYMBOL(pmac_xpram_write);
/*#endif*/ /* CONFIG_PMAC */
+#ifdef CONFIG_PPC_RTC
+EXPORT_SYMBOL(mktime);
+EXPORT_SYMBOL(to_tm);
+#endif
EXPORT_SYMBOL(abs);
char *bootpath = 0;
char *bootdevice = 0;
-unsigned int rtas_data = 0; /* virtual pointer */
+unsigned int rtas_data = 0; /* physical pointer */
unsigned int rtas_entry = 0; /* physical pointer */
unsigned int rtas_size = 0;
unsigned int old_rtas = 0;
void drawchar(char c);
void drawstring(const char *c);
-static void drawhex(unsigned long v);
+void drawhex(unsigned long v);
static void scrollscreen(void);
static void draw_byte(unsigned char c, long locX, long locY);
}
}
+void
+prom_print_hex(unsigned int v)
+{
+ char buf[16];
+ int i, c;
+
+ for (i = 0; i < 8; ++i) {
+ c = (v >> ((7-i)*4)) & 0xf;
+ c += (c >= 10)? ('a' - 10): '0';
+ buf[i] = c;
+ }
+ buf[i] = ' ';
+ buf[i+1] = 0;
+ prom_print(buf);
+}
+
unsigned long smp_ibm_chrp_hack __initdata = 0;
/*
RELOC(bootdevice) = PTRUNRELOC(d);
mem = ALIGN(mem + strlen(d) + 1);
}
-
- mem = check_display(mem);
-
- prom_print(RELOC("copying OF device tree..."));
- mem = copy_device_tree(mem, mem + (1<<20));
- prom_print(RELOC("done\n"));
-
-
- RELOC(klimit) = (char *) (mem - offset);
prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas"));
if (prom_rtas != (void *) -1) {
RELOC(rtas_data) = 0;
} else {
/*
- * We do _not_ want the rtas_data inside the klimit
- * boundry since it'll be squashed when we do the
- * relocate of the kernel on chrp right after prom_init()
- * in head.S. So, we just pick a spot in memory.
- * -- Cort
+ * Ask OF for some space for RTAS.
*/
-#if 0
- mem = (mem + 4095) & -4096;
- RELOC(rtas_data) = mem + KERNELBASE;
- mem += RELOC(rtas_size);
-#endif
- RELOC(rtas_data) = (6<<20) + KERNELBASE;
+ RELOC(rtas_data) = (unsigned int)
+ call_prom(RELOC("claim"), 3, 1, 0,
+ RELOC(rtas_size), 0x1000);
+ prom_print(RELOC("rtas at "));
+ prom_print_hex(RELOC(rtas_data));
+ prom_print(RELOC("\n"));
}
prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas"));
{
prom_args.nret = 2;
prom_args.args[0] = RELOC("instantiate-rtas");
prom_args.args[1] = prom_rtas;
- prom_args.args[2] = ((void *)(RELOC(rtas_data)-KERNELBASE));
+ prom_args.args[2] = (void *) RELOC(rtas_data);
RELOC(prom)(&prom_args);
if (prom_args.args[nargs] != 0)
i = 0;
prom_print(RELOC(" done\n"));
}
+ mem = check_display(mem);
+
+ prom_print(RELOC("copying OF device tree..."));
+ /* N.B. do this *after* any claims */
+ mem = copy_device_tree(mem, mem + (1<<20));
+ prom_print(RELOC("done\n"));
+
+ RELOC(klimit) = (char *) (mem - offset);
+
/* If we are already running at 0xc0000000, we assume we were loaded by
* an OF bootloader which did set a BAT for us. This breaks OF translate
* so we force phys to be 0
}
#ifdef CONFIG_BOOTX_TEXT
- if (!chrp && RELOC(prom_disp_node) != 0)
+ if (RELOC(prom_disp_node) != 0)
setup_disp_fake_bi(RELOC(prom_disp_node));
#endif
RELOC(prom_stdout) = 0;
clearscreen();
prom_welcome(PTRRELOC(RELOC(disp_bi)), phys);
- prom_print(RELOC("booting...\n"));
}
#endif
+ prom_print(RELOC("booting...\n"));
return phys;
}
if (RELOC(prom_disp_node) == 0)
RELOC(prom_disp_node) = node;
-
+
/* Setup a useable color table when the appropriate
* method is available. Should update this to set-colors */
for (i = 0; i < 32; i++)
prom_print(RELOC("Failed to get pitch\n"));
return;
}
+ if (pitch == 1)
+ pitch = 0x1000;
address = len = 0;
+ len = 0xfa000000;
call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len));
address = len;
if (address == 0) {
/* kludge for valkyrie */
if (strcmp(dp->name, "valkyrie") == 0)
address += 0x1000;
- }
#endif
- RELOC(disp_bi) = &fake_bi;
- bi = PTRRELOC((&fake_bi));
- RELOC(g_loc_X) = 0;
- RELOC(g_loc_Y) = 0;
- RELOC(g_max_loc_X) = width / 8;
- RELOC(g_max_loc_Y) = height / 16;
- bi->logicalDisplayBase = (unsigned char *)address;
- bi->dispDeviceBase = (unsigned char *)address;
- bi->dispDeviceRowBytes = pitch;
- bi->dispDeviceDepth = depth;
- bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
- bi->dispDeviceRect[2] = width;
- bi->dispDeviceRect[3] = height;
+ RELOC(disp_bi) = &fake_bi;
+ bi = PTRRELOC((&fake_bi));
+ RELOC(g_loc_X) = 0;
+ RELOC(g_loc_Y) = 0;
+ RELOC(g_max_loc_X) = width / 8;
+ RELOC(g_max_loc_Y) = height / 16;
+ bi->logicalDisplayBase = (unsigned char *)address;
+ bi->dispDeviceBase = (unsigned char *)address;
+ bi->dispDeviceRowBytes = pitch;
+ bi->dispDeviceDepth = depth;
+ bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
+ bi->dispDeviceRect[2] = width;
+ bi->dispDeviceRect[3] = height;
}
#endif
finish_device_tree(void)
{
unsigned long mem = (unsigned long) klimit;
-#if 0
- char* model;
-
- /* Here, we decide if we'll use the interrupt-tree (new Core99 code) or not.
- * This code was only tested with Core99 machines so far, but should be easily
- * adapted to older newworld machines (iMac, B&W G3, Lombard).
- */
- model = get_property(allnodes, "model", 0);
- if ((boot_infos == 0) && model && (
- strcmp(model, "PowerBook2,1") == 0 ||
- strcmp(model, "PowerBook3,1") == 0 ||
- strcmp(model, "PowerMac2,1") == 0 ||
- strcmp(model, "PowerMac3,1") == 0))
- use_of_interrupt_tree = 1;
-#endif
- /* All newworld machines now use the interrupt tree */
+
+ /* All newworld machines and CHRP now use the interrupt tree */
struct device_node *np = allnodes;
- while(np) {
+ while(np && (_machine == _MACH_Pmac)) {
if (get_property(np, "interrupt-parent", 0)) {
pmac_newworld = 1;
break;
}
np = np->allnext;
}
- if (boot_infos == 0 && pmac_newworld)
+ if ((_machine == _MACH_chrp) || (boot_infos == 0 && pmac_newworld))
use_of_interrupt_tree = 1;
mem = finish_node(allnodes, mem, NULL);
for (j=2; j<isize; j++)
interrupts++;
}
+ /*
+ * On the CHRP LongTrail, ISA interrupts are cascaded through
+ * the OpenPIC. For compatibility reasons, ISA interrupts are
+ * numbered 0-15 and OpenPIC interrupts start at 16.
+ * Hence we have to fixup the interrupt numbers for sources
+ * that are attached to the OpenPIC and thus have an
+ * interrupt-controller named `open-pic'.
+ *
+ * FIXME: The name of the interrupt-controller node for the
+ * `ide' node has no name, although its parent is
+ * correctly specified in interrupt-map, so we check
+ * for a NULL name as well.
+ */
+ if (_machine == _MACH_chrp &&
+ ((node->name && !strcmp(node->name, "open-pic")) ||
+ !node->name)) {
+ for (i = 0; i < np->n_intrs; ++i)
+ np->intrs[i].line = openpic_to_irq(np->intrs[i].line);
+ }
return mem_start;
}
/* We lookup for an interrupt-map. This code can only handle one interrupt
}
}
+void
+here(int n)
+{
+ chrp_indicator(n);
+ if (n == 1)
+ clearscreen();
+ showvalue("here ", n);
+}
+
__pmac
void
drawstring(const char *c)
}
__pmac
-static void
+void
drawhex(unsigned long v)
{
static char hex_table[] = "0123456789abcdef";
if ( !smp_processor_id() )
{
do_timer(regs);
+#if 0
+ /* -- BenH -- I'm removing this for now since it can cause various
+ * troubles with local-time RTCs. Now that we have a
+ * /dev/rtc that uses ppc_md.set_rtc_time() on mac, it
+ * should be possible to program the RTC from userland
+ * in all cases.
+ */
/*
* update the rtc when needed
*/
/* do it again in 60 s */
last_rtc_update = xtime.tv_sec;
}
+#endif
}
}
#ifdef __SMP__
/* On the powerpc, no user access
forces R/W kernel access */
f |= _PAGE_USER;
+ map_page(v, p, f);
+ v += PAGE_SIZE;
+ p += PAGE_SIZE;
+ }
+ }
+
#else /* CONFIG_8xx */
- for (i = 0; i < phys_mem.n_regions; ++i) {
- v = (ulong)__va(phys_mem.regions[i].address);
- p = phys_mem.regions[i].address;
- for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
+ for (i = 0; i < phys_mem.n_regions; ++i) {
+ v = (ulong)__va(phys_mem.regions[i].address);
+ p = phys_mem.regions[i].address;
+ for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
/* On the MPC8xx, we want the page shared so we
* don't get ASID compares on kernel space.
*/
- f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED;
+ f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED;
/* I don't really need the rest of this code, but
* I grabbed it because I think the line:
* the MPC8xx, the PAGE_DIRTY takes care of that
* for us (along with the RW software state).
*/
- if ((char *) v < _stext || (char *) v >= etext)
- f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
-#endif /* CONFIG_8xx */
+ if ((char *) v < _stext || (char *) v >= etext)
+ f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
map_page(v, p, f);
v += PAGE_SIZE;
p += PAGE_SIZE;
}
- }
+ }
+#endif /* CONFIG_8xx */
}
/* This can get called from ioremap, so don't make it an initfunc, OK? */
#endif /* CONFIG_GEMINI */
else /* prep */
end_of_DRAM = prep_find_end_of_memory();
-*(unsigned long *)(KERNELBASE) = 0xdeadbeef;
hash_init();
_SDR1 = __pa(Hash) | (Hash_mask >> 10);
ioremap_base = 0xf8000000;
#endif /* CONFIG_BLK_DEV_INITRD */
#ifndef CONFIG_8xx
if ( !rtas_data ||
- addr < (rtas_data & PAGE_MASK) ||
- addr >= (rtas_data+rtas_size))
+ addr < (rtas_data + KERNELBASE) ||
+ addr >= (rtas_data + KERNELBASE + rtas_size))
#endif /* CONFIG_8xx */
free_page(addr);
}
return ret;
}
#endif /* CONFIG_MBX */
+
#ifndef CONFIG_8xx
/*
* On systems with Open Firmware, collect information about
if (boot_infos == 0) {
/* record which bits the prom is using */
get_mem_prop("available", &phys_avail);
+ remove_mem_piece(&phys_avail, __max_memory, ~0U, 0);
prom_mem = phys_mem;
for (i = 0; i < phys_avail.n_regions; ++i)
remove_mem_piece(&prom_mem,
-/* $Id: sys_sparc32.c,v 1.107.2.8 2000/02/28 04:09:49 davem Exp $
+/* $Id: sys_sparc32.c,v 1.107.2.9 2000/06/20 17:12:25 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* the cmsg_len for MSG_TRUNC cases, we need not check that case either.
*/
ucmsg = (struct cmsghdr *) orig_cmsg_uptr;
- while(((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) {
+ while(((unsigned long)ucmsg) <=
+ (((unsigned long)kmsg->msg_control) - sizeof(struct cmsghdr))) {
struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp;
int clen64, clen32;
err = nfs_getfh32_trans(karg, arg32);
break;
case NFSCTL_LOCKD:
- /* No arguments, no translations... */
- err = 0;
+ /* We still have to copy over the version
+ * because nfsctl still checks that.
+ */
+ err = get_user(karg->ca_version, &arg32->ca32_version);
break;
default:
err = -EINVAL;
(void) pci_write_config_byte(dev, 0x58, 0x3f);
(void) pci_write_config_byte(dev, 0x5b, 0x3f);
+#ifdef CONFIG_PPC
+ (void) pci_write_config_byte(dev, 0x73, 0xf0);
+#endif /* CONFIG_PPC */
+
hwif->dmaproc = &cmd646_dmaproc;
}
/* ... more stuff */
};
+static inline void mac_fix_string(char *stg, int len)
+{
+ int i;
+
+ for (i = len - 1; i >= 0 && stg[i] == ' '; i--)
+ stg[i] = 0;
+}
+
static int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec)
{
struct buffer_head *bh;
*/
if (_machine == _MACH_Pmac) {
int goodness = 0;
+
+ mac_fix_string(part->processor, 16);
+ mac_fix_string(part->name, 32);
+ mac_fix_string(part->type, 32);
if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
&& strcasecmp(part->processor, "powerpc") == 0)
goodness++;
- if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0) {
+ if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
+ || strcasecmp(part->type, "Linux_PPC") == 0) {
+ int i, l;
+
goodness++;
- if ((strcmp(part->name, "/") == 0) ||
- (strstr(part->name, "root") != 0)) {
+ l = strlen(part->name);
+ if (strcmp(part->name, "/") == 0)
goodness++;
+ for (i = 0; i <= l - 4; ++i) {
+ if (strnicmp(part->name + i, "root",
+ 4) == 0) {
+ goodness += 2;
+ break;
+ }
}
- if (strncmp(part->name, "swap", 4) == 0)
+ if (strnicmp(part->name, "swap", 4) == 0)
goodness--;
}
if (stat)
toc->capacity = 0x1fffff;
+ HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9);
+ drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
+
/* Remember that we've read this stuff. */
CDROM_STATE_FLAGS (drive)->toc_valid = 1;
*((unsigned short *) &gcw) = id->config;
+#ifdef CONFIG_PPC
+ /* kludge for Apple PowerBook internal zip */
+ if ((gcw.device_type == 5) && !strstr(id->model, "CD-ROM")
+ && strstr(id->model, "ZIP"))
+ gcw.device_type = 0;
+#endif
+
#if IDEFLOPPY_DEBUG_INFO
printk (KERN_INFO "Dumping ATAPI Identify Device floppy parameters\n");
switch (gcw.protocol) {
*
* Copyright (C) 1998 Paul Mackerras.
*
+ * Bits from Benjamin Herrenschmidt
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
#include "ide.h"
#include "ide_modes.h"
-ide_ioreg_t pmac_ide_regbase[MAX_HWIFS];
-int pmac_ide_irq[MAX_HWIFS];
-int pmac_ide_count;
-struct device_node *pmac_ide_node[MAX_HWIFS];
+#undef IDE_PMAC_DEBUG
+
+#define IDE_SYSCLK_NS 30
+#define IDE_SYSCLK_ULTRA_PS 0x1d4c /* (15 * 1000 / 2)*/
+
+struct pmac_ide_hwif {
+ ide_ioreg_t regbase;
+ int irq;
+ int kind;
+ int aapl_bus_id;
+ struct device_node* node;
+ u32 timings[2];
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+ volatile struct dbdma_regs* dma_regs;
+ struct dbdma_cmd* dma_table;
+#endif
+
+} pmac_ide[MAX_HWIFS];
+
+static int pmac_ide_count;
+
+enum {
+ controller_ohare, /* OHare based */
+ controller_heathrow, /* Heathrow/Paddington */
+ controller_kl_ata3, /* KeyLargo ATA-3 */
+ controller_kl_ata4 /* KeyLargo ATA-4 */
+};
+
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+
+typedef struct {
+ int accessTime;
+ int cycleTime;
+} pmac_ide_timing;
+
+/* Multiword DMA timings */
+static pmac_ide_timing mdma_timings[] =
+{
+ { 215, 480 }, /* Mode 0 */
+ { 80, 150 }, /* 1 */
+ { 70, 120 } /* 2 */
+};
+
+/* Ultra DMA timings (for use when I know how to calculate them */
+static pmac_ide_timing udma_timings[] =
+{
+ { 0, 114 }, /* Mode 0 */
+ { 0, 75 }, /* 1 */
+ { 0, 55 }, /* 2 */
+ { 100, 45 }, /* 3 */
+ { 100, 25 } /* 4 */
+};
+
+/* allow up to 256 DBDMA commands per xfer */
+#define MAX_DCMDS 256
+/* Wait 1.5s for disk to answer on IDE bus after
+ * enable operation.
+ * NOTE: There is at least one case I know of a disk that needs about 10sec
+ * before anwering on the bus. I beleive we could add a kernel command
+ * line arg to override this delay for such cases.
+ */
+#define IDE_WAKEUP_DELAY_MS 1500
#define MAX_DCMDS 256 /* allow up to 256 DBDMA commands per xfer */
-static void pmac_ide_setup_dma(struct device_node *np, ide_hwif_t *hwif);
+static void pmac_ide_setup_dma(struct device_node *np, int ix);
static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
-static int pmac_ide_build_dmatable(ide_drive_t *drive, int wr);
+static int pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr);
+static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio);
+static void pmac_ide_selectproc(ide_drive_t *drive);
+
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
#ifdef CONFIG_PMAC_PBOOK
-static int idepmac_notify(struct pmu_sleep_notifier *self, int when);
+static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when);
struct pmu_sleep_notifier idepmac_sleep_notifier = {
- idepmac_notify, SLEEP_LEVEL_BLOCK,
+ idepmac_notify_sleep, SLEEP_LEVEL_BLOCK,
};
#endif /* CONFIG_PMAC_PBOOK */
+static int
+pmac_ide_find(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ ide_ioreg_t base;
+ int i;
+
+ for (i=0; i<pmac_ide_count; i++) {
+ base = pmac_ide[i].regbase;
+ if (base && base == hwif->io_ports[0])
+ return i;
+ }
+ return -1;
+}
+
/*
* N.B. this can't be an initfunc, because the media-bay task can
* call ide_[un]register at any time.
return;
for (ix = 0; ix < MAX_HWIFS; ++ix)
- if (base == pmac_ide_regbase[ix])
+ if (base == pmac_ide[ix].regbase)
break;
if (ix >= MAX_HWIFS) {
return;
}
- /* we check only for -EINVAL meaning that we have found a matching
- bay but with the wrong device type */
-
- i = check_media_bay_by_base(base, MB_CD);
- if (i == -EINVAL)
- return;
-
for (i = 0; i < 8; ++i)
*p++ = base + i * 0x10;
*p = base + 0x160;
if (irq != NULL)
- *irq = pmac_ide_irq[ix];
+ *irq = pmac_ide[ix].irq;
+
+ ide_hwifs[ix].tuneproc = pmac_ide_tuneproc;
+ ide_hwifs[ix].selectproc = pmac_ide_selectproc;
+ if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table) {
+ ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
+#ifdef CONFIG_PMAC_IDEDMA_AUTO
+ ide_hwifs[ix].autodma = 1;
+#endif
+ }
}
-void pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
+#if 0
+/* This one could be later extended to handle CMD IDE and be used by some kind
+ * of /proc interface. I want to be able to get the devicetree path of a block
+ * device for yaboot configuration
+ */
+struct device_node*
+pmac_ide_get_devnode(ide_drive_t *drive)
{
- ide_pio_data_t d;
+ int i = pmac_ide_find(drive);
+ if (i < 0)
+ return NULL;
+ return pmac_ide[i].node;
+}
+#endif
- if (_machine != _MACH_Pmac)
+/* Setup timings for the selected drive (master/slave). I still need to verify if this
+ * is enough, I beleive selectproc will be called whenever an IDE command is started,
+ * but... */
+static void
+pmac_ide_selectproc(ide_drive_t *drive)
+{
+ int i = pmac_ide_find(drive);
+ if (i < 0)
return;
+
+ if (drive->select.all & 0x10)
+ out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[1]);
+ else
+ out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[0]);
+}
+
+/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
+#define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
+#define SYSCLK_TICKS_UDMA(t) (((t) + IDE_SYSCLK_ULTRA_PS - 1) / IDE_SYSCLK_ULTRA_PS)
+
+/* Calculate PIO timings */
+static void
+pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
+{
+ ide_pio_data_t d;
+ int i;
+ u32 *timings;
+ int accessTicks, recTicks;
+
+ i = pmac_ide_find(drive);
+ if (i < 0)
+ return;
+
pio = ide_get_best_pio_mode(drive, pio, 4, &d);
- switch (pio) {
- case 4:
- out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x211025);
- break;
- default:
- out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x2f8526);
- break;
+ if (drive->select.all & 0x10)
+ timings = &pmac_ide[i].timings[1];
+ else
+ timings = &pmac_ide[i].timings[0];
+
+ if (pmac_ide[i].kind == controller_kl_ata4) {
+ /* The "ata-4" IDE controller of Core99 machines */
+ accessTicks = SYSCLK_TICKS_UDMA(ide_pio_timings[pio].active_time * 1000);
+ recTicks = SYSCLK_TICKS_UDMA(d.cycle_time * 1000) - accessTicks;
+
+ *timings = ((*timings) & 0x1FFFFFC00) | accessTicks | (recTicks << 5);
+ } else {
+ /* The old "ata-3" IDE controller */
+ accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time);
+ if (accessTicks < 4)
+ accessTicks = 4;
+ recTicks = SYSCLK_TICKS(d.cycle_time) - accessTicks - 4;
+ if (recTicks < 1)
+ recTicks = 1;
+
+ *timings = ((*timings) & 0xFFFFFF800) | accessTicks | (recTicks << 5);
}
+
+#ifdef IDE_PMAC_DEBUG
+ printk("ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
+ pio, *timings);
+#endif
+
+ if (drive->select.all == IN_BYTE(IDE_SELECT_REG))
+ pmac_ide_selectproc(drive);
+}
+
+ide_ioreg_t
+pmac_ide_get_base(int index)
+{
+ return pmac_ide[index].regbase;
+}
+
+static int ide_majors[] = { 3, 22, 33, 34, 56, 57 };
+
+__initfunc(kdev_t pmac_find_ide_boot(char *bootdevice, int n))
+{
+ int i;
+
+ /*
+ * Look through the list of IDE interfaces for this one.
+ */
+ for (i = 0; i < pmac_ide_count; ++i) {
+ char *name;
+ if (!pmac_ide[i].node || !pmac_ide[i].node->full_name)
+ continue;
+ name = pmac_ide[i].node->full_name;
+ if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
+ /* XXX should cope with the 2nd drive as well... */
+ return MKDEV(ide_majors[i], 0);
+ }
+ }
+
+ return 0;
}
__initfunc(void
struct device_node *atas;
struct device_node *p, **pp, *removables, **rp;
unsigned long base;
- int irq;
+ int irq, big_delay;
ide_hwif_t *hwif;
if (_machine != _MACH_Pmac)
}
*rp = NULL;
*pp = removables;
+ big_delay = 0;
for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
struct device_node *tp;
+ int *bidp;
/*
* If this node is not under a mac-io or dbdma node,
} else {
irq = np->intrs[0].line;
}
- pmac_ide_regbase[i] = base;
- pmac_ide_irq[i] = irq;
- pmac_ide_node[i] = np;
+ pmac_ide[i].regbase = base;
+ pmac_ide[i].irq = irq;
+ pmac_ide[i].node = np;
+ if (device_is_compatible(np, "keylargo-ata")) {
+ if (strcmp(np->name, "ata-4") == 0)
+ pmac_ide[i].kind = controller_kl_ata4;
+ else
+ pmac_ide[i].kind = controller_kl_ata3;
+ } else if (device_is_compatible(np, "heathrow-ata"))
+ pmac_ide[i].kind = controller_heathrow;
+ else
+ pmac_ide[i].kind = controller_ohare;
+
+ bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
+ pmac_ide[i].aapl_bus_id = bidp ? *bidp : 0;
if (np->parent && np->parent->name
&& strcasecmp(np->parent->name, "media-bay") == 0) {
media_bay_set_ide_infos(np->parent,base,irq,i);
- } else
- feature_set(np, FEATURE_IDE_enable);
-
+ } else if (pmac_ide[i].kind == controller_ohare) {
+ /* The code below is having trouble on some ohare machines
+ * (timing related ?). Until I can put my hand on one of these
+ * units, I keep the old way
+ */
+ feature_set(np, FEATURE_IDE0_enable);
+ feature_set(np, FEATURE_IOBUS_enable);
+ } else {
+ /* This is necessary to enable IDE when net-booting */
+ printk("pmac_ide: enabling IDE bus ID %d\n", pmac_ide[i].aapl_bus_id);
+ switch(pmac_ide[i].aapl_bus_id) {
+ case 0:
+ feature_set(np, FEATURE_IDE0_reset);
+ feature_set(np, FEATURE_IOBUS_enable);
+ mdelay(10);
+ feature_set(np, FEATURE_IDE0_enable);
+ mdelay(10);
+ feature_clear(np, FEATURE_IDE0_reset);
+ break;
+ case 1:
+ feature_set(np, FEATURE_IDE1_reset);
+ feature_set(np, FEATURE_IOBUS_enable);
+ mdelay(10);
+ feature_set(np, FEATURE_IDE1_enable);
+ mdelay(10);
+ feature_clear(np, FEATURE_IDE1_reset);
+ break;
+ case 2:
+ /* This one exists only for KL, I don't know
+ about any enable bit */
+ feature_set(np, FEATURE_IDE2_reset);
+ mdelay(10);
+ feature_clear(np, FEATURE_IDE2_reset);
+ break;
+ }
+ big_delay = 1;
+ }
hwif = &ide_hwifs[i];
pmac_ide_init_hwif_ports(hwif->io_ports, base, &hwif->irq);
- hwif->chipset = ide_generic;
- hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
- hwif->tuneproc = pmac_ide_tuneproc;
+ hwif->chipset = ide_pmac;
+ hwif->noprobe = (check_media_bay_by_base(base, MB_CD) == -EINVAL);
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
if (np->n_addrs >= 2) {
/* has a DBDMA controller channel */
- pmac_ide_setup_dma(np, hwif);
+ pmac_ide_setup_dma(np, i);
}
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
++i;
}
pmac_ide_count = i;
+ if (big_delay)
+ mdelay(IDE_WAKEUP_DELAY_MS);
#ifdef CONFIG_PMAC_PBOOK
pmu_register_sleep_notifier(&idepmac_sleep_notifier);
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
__initfunc(static void
-pmac_ide_setup_dma(struct device_node *np, ide_hwif_t *hwif))
+pmac_ide_setup_dma(struct device_node *np, int ix))
{
- hwif->dma_base = (unsigned long) ioremap(np->addrs[1].address, 0x200);
+ pmac_ide[ix].dma_regs =
+ (volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);
/*
* Allocate space for the DBDMA commands.
* The +2 is +1 for the stop command and +1 to allow for
* aligning the start address to a multiple of 16 bytes.
*/
- hwif->dmatable = (unsigned long *)
- kmalloc((MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), GFP_KERNEL);
- if (hwif->dmatable == 0) {
+ pmac_ide[ix].dma_table = (struct dbdma_cmd*)
+ kmalloc((MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), GFP_KERNEL);
+ if (pmac_ide[ix].dma_table == 0) {
printk(KERN_ERR "%s: unable to allocate DMA command list\n",
- hwif->name);
+ ide_hwifs[ix].name);
return;
}
- hwif->dmaproc = &pmac_ide_dmaproc;
+ ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
#ifdef CONFIG_PMAC_IDEDMA_AUTO
- hwif->autodma = 1;
+ ide_hwifs[ix].autodma = 1;
#endif
}
* for a transfer and sets the DBDMA channel to point to it.
*/
static int
-pmac_ide_build_dmatable(ide_drive_t *drive, int wr)
+pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr)
{
- ide_hwif_t *hwif = HWIF(drive);
struct dbdma_cmd *table, *tstart;
int count = 0;
struct request *rq = HWGROUP(drive)->rq;
struct buffer_head *bh = rq->bh;
unsigned int size, addr;
- volatile struct dbdma_regs *dma
- = (volatile struct dbdma_regs *) hwif->dma_base;
+ volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs;
- table = tstart = (struct dbdma_cmd *) DBDMA_ALIGN(hwif->dmatable);
+ table = tstart = (struct dbdma_cmd *) DBDMA_ALIGN(pmac_ide[ix].dma_table);
out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
+ /* Should this be dma->control like in macserial.c ? */
+ while (in_le32(&dma->status) & RUN)
+ udelay(1);
do {
/*
return 1;
}
+
+/* This is fun. -DaveM */
+#define IDE_SETXFER 0x03
+#define IDE_SETFEATURE 0xef
+#define IDE_DMA2_ENABLE 0x22
+#define IDE_DMA1_ENABLE 0x21
+#define IDE_DMA0_ENABLE 0x20
+#define IDE_UDMA4_ENABLE 0x44
+#define IDE_UDMA3_ENABLE 0x43
+#define IDE_UDMA2_ENABLE 0x42
+#define IDE_UDMA1_ENABLE 0x41
+#define IDE_UDMA0_ENABLE 0x40
+
+static __inline__ unsigned char
+dma_bits_to_command(unsigned char bits)
+{
+ if(bits & 0x04)
+ return IDE_DMA2_ENABLE;
+ if(bits & 0x02)
+ return IDE_DMA1_ENABLE;
+ return IDE_DMA0_ENABLE;
+}
+
+static __inline__ unsigned char
+udma_bits_to_command(unsigned char bits)
+{
+ if(bits & 0x10)
+ return IDE_UDMA4_ENABLE;
+ if(bits & 0x08)
+ return IDE_UDMA3_ENABLE;
+ if(bits & 0x04)
+ return IDE_UDMA2_ENABLE;
+ if(bits & 0x02)
+ return IDE_UDMA1_ENABLE;
+ if(bits & 0x01)
+ return IDE_UDMA0_ENABLE;
+ return 0;
+}
+
+static __inline__ int
+wait_for_ready(ide_drive_t *drive)
+{
+ /* Timeout bumped for some powerbooks */
+ int timeout = 2000;
+ byte stat;
+
+ while(--timeout) {
+ stat = GET_STAT();
+ if(!(stat & BUSY_STAT)) {
+ if (drive->ready_stat == 0)
+ break;
+ else if((stat & drive->ready_stat) || (stat & ERR_STAT))
+ break;
+ }
+ mdelay(1);
+ }
+ if((stat & ERR_STAT) || timeout <= 0) {
+ if (stat & ERR_STAT) {
+ printk("ide_pmace: wait_for_ready, error status: %x\n", stat);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int
+pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
+{
+ unsigned long flags;
+ byte old_select;
+ int result = 1;
+
+ save_flags(flags);
+ cli();
+ old_select = IN_BYTE(IDE_SELECT_REG);
+ OUT_BYTE(drive->select.all, IDE_SELECT_REG);
+ udelay(10);
+ OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG);
+ OUT_BYTE(command, IDE_NSECTOR_REG);
+ if(wait_for_ready(drive)) {
+ printk("pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
+ goto out;
+ }
+ OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG);
+ result = wait_for_ready(drive);
+ if (result)
+ printk("pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
+out:
+ OUT_BYTE(old_select, IDE_SELECT_REG);
+ restore_flags(flags);
+
+ return result;
+}
+
+/* Calculate MultiWord DMA timings */
+static int
+pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
+{
+ byte bits = drive->id->dma_mword & 0x07;
+ byte feature = dma_bits_to_command(bits);
+ u32 *timings;
+ int cycleTime, accessTime;
+ int accessTicks, recTicks;
+ struct hd_driveid *id = drive->id;
+
+ /* Set feature on drive */
+ printk("%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
+ if (pmac_ide_do_setfeature(drive, feature)) {
+ printk("%s: Failed !\n", drive->name);
+ return 0;
+ }
+
+ /* which drive is it ? */
+ if (drive->select.all & 0x10)
+ timings = &pmac_ide[idx].timings[1];
+ else
+ timings = &pmac_ide[idx].timings[0];
+
+ /* Calculate accesstime and cycle time */
+ cycleTime = mdma_timings[feature & 0xf].cycleTime;
+ accessTime = mdma_timings[feature & 0xf].accessTime;
+ if ((id->field_valid & 2) && (id->eide_dma_time))
+ cycleTime = id->eide_dma_time;
+ if ((pmac_ide[idx].kind == controller_ohare) && (cycleTime < 150))
+ cycleTime = 150;
+
+ /* For ata-4 controller, we don't know the calculation */
+ if (pmac_ide[idx].kind == controller_kl_ata4) {
+ accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
+ recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks;
+ *timings = ((*timings) & 0xffe003ff) |
+ (accessTicks | (recTicks << 5)) << 10;
+ } else {
+ int halfTick = 0;
+ int origAccessTime = accessTime;
+ int origCycleTime = cycleTime;
+
+ accessTicks = SYSCLK_TICKS(accessTime);
+ if (accessTicks < 1)
+ accessTicks = 1;
+ accessTime = accessTicks * IDE_SYSCLK_NS;
+ recTicks = SYSCLK_TICKS(cycleTime - accessTime) - 1;
+ if (recTicks < 1)
+ recTicks = 1;
+ cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS;
+
+ /* KeyLargo ata-3 don't support the half-tick stuff */
+ if ((pmac_ide[idx].kind != controller_kl_ata3) &&
+ (accessTicks > 1) &&
+ ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
+ ((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) {
+ halfTick = 1;
+ accessTicks--;
+ }
+ *timings = ((*timings) & 0x7FF) |
+ (accessTicks | (recTicks << 5) | (halfTick << 10)) << 11;
+ }
+#ifdef IDE_PMAC_DEBUG
+ printk("ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
+ feature & 0xf, *timings);
+#endif
+ return 1;
+}
+
+/* Calculate Ultra DMA timings */
+static int
+pmac_ide_udma_enable(ide_drive_t *drive, int idx)
+{
+ byte bits = drive->id->dma_ultra & 0x1f;
+ byte feature = udma_bits_to_command(bits);
+ int cycleTime, accessTime;
+ int rdyToPauseTicks, cycleTicks;
+ u32 *timings;
+
+ /* Set feature on drive */
+ printk("%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
+ if (pmac_ide_do_setfeature(drive, feature)) {
+ printk("%s: Failed !\n", drive->name);
+ return 0;
+ }
+
+ /* which drive is it ? */
+ if (drive->select.all & 0x10)
+ timings = &pmac_ide[idx].timings[1];
+ else
+ timings = &pmac_ide[idx].timings[0];
+
+
+ cycleTime = udma_timings[feature & 0xf].cycleTime;
+ accessTime = udma_timings[feature & 0xf].accessTime;
+
+ rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
+ cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000);
+
+ *timings = ((*timings) & 0xe00fffff) |
+ ((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20;
+ return 1;
+}
+
+static int
+pmac_ide_dma_onoff(ide_drive_t *drive, int enable)
+{
+ int ata4, udma, idx;
+ struct hd_driveid *id = drive->id;
+
+ drive->using_dma = 0;
+
+ idx = pmac_ide_find(drive);
+ if (idx < 0)
+ return 0;
+
+ if (drive->media == ide_floppy)
+ enable = 0;
+ if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE))
+ enable = 0;
+ if (check_drive_lists(drive, BAD_DMA_DRIVE))
+ enable = 0;
+
+ udma = 0;
+ ata4 = (pmac_ide[idx].kind == controller_kl_ata4);
+
+ if(enable) {
+ if (ata4 && (drive->media == ide_disk) &&
+ (id->field_valid & 0x0004) && (id->dma_ultra & 0x17)) {
+ /* UltraDMA modes. */
+ drive->using_dma = pmac_ide_udma_enable(drive, idx);
+ }
+ if (!drive->using_dma && (id->dma_mword & 0x0007)) {
+ /* Normal MultiWord DMA modes. */
+ drive->using_dma = pmac_ide_mdma_enable(drive, idx);
+ }
+ /* Without this, strange things will happen on Keylargo-based
+ * machines
+ */
+ OUT_BYTE(0, IDE_CONTROL_REG);
+ if (drive->select.all == IN_BYTE(IDE_SELECT_REG))
+ pmac_ide_selectproc(drive);
+ }
+ return 0;
+}
+
int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
- volatile struct dbdma_regs *dma
- = (volatile struct dbdma_regs *) hwif->dma_base;
- int dstat;
+ int ix, dstat;
+ volatile struct dbdma_regs *dma;
+
+ /* Can we stuff a pointer to our intf structure in config_data
+ * or select_data in hwif ?
+ */
+ ix = pmac_ide_find(drive);
+ if (ix < 0)
+ return 0;
+ dma = pmac_ide[ix].dma_regs;
switch (func) {
case ide_dma_on:
- /* ide-floppy DMA doesn't work yet... */
- drive->using_dma = drive->media != ide_floppy;
- break;
case ide_dma_off:
- printk(KERN_INFO "%s: DMA disabled\n", drive->name);
case ide_dma_off_quietly:
- drive->using_dma = 0;
+ pmac_ide_dma_onoff(drive, (func == ide_dma_on));
break;
case ide_dma_check:
- /* ide-floppy DMA doesn't work yet... */
- drive->using_dma = hwif->autodma && drive->media != ide_floppy;
+ if (hwif->autodma)
+ pmac_ide_dma_onoff(drive, 1);
break;
case ide_dma_read:
case ide_dma_write:
- if (!pmac_ide_build_dmatable(drive, func==ide_dma_write))
+ if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write))
return 1;
drive->waiting_for_dma = 1;
if (drive->media != ide_disk)
#ifdef CONFIG_PMAC_PBOOK
static void idepmac_sleep_disk(int i, unsigned long base)
{
+ struct device_node* np = pmac_ide[i].node;
int j;
- /* Reset to PIO 0 */
- out_le32((unsigned *)(base + 0x200 + _IO_BASE), 0x2f8526);
-
/* FIXME: We only handle the master IDE */
if (ide_hwifs[i].drives[0].media == ide_disk) {
/* Spin down the drive */
break;
}
}
+ feature_set(np, FEATURE_IDE0_reset);
+ feature_clear(np, FEATURE_IDE0_enable);
+ switch(pmac_ide[i].aapl_bus_id) {
+ case 0:
+ feature_set(np, FEATURE_IDE0_reset);
+ feature_clear(np, FEATURE_IDE0_enable);
+ break;
+ case 1:
+ feature_set(np, FEATURE_IDE1_reset);
+ feature_clear(np, FEATURE_IDE1_enable);
+ break;
+ case 2:
+ feature_set(np, FEATURE_IDE2_reset);
+ break;
+ }
+ pmac_ide[i].timings[0] = 0;
+ pmac_ide[i].timings[1] = 0;
}
static void idepmac_wake_disk(int i, unsigned long base)
{
+ struct device_node* np = pmac_ide[i].node;
int j;
/* Revive IDE disk and controller */
- feature_set(pmac_ide_node[i], FEATURE_IDE_enable);
- mdelay(1);
- feature_set(pmac_ide_node[i], FEATURE_IDE_DiskPower);
- mdelay(100);
- feature_set(pmac_ide_node[i], FEATURE_IDE_Reset);
- mdelay(1);
- /* Make sure we are still PIO0 */
- out_le32((unsigned *)(base + 0x200 + _IO_BASE), 0x2f8526);
- mdelay(100);
+ switch(pmac_ide[i].aapl_bus_id) {
+ case 0:
+ feature_set(np, FEATURE_IDE0_reset);
+ feature_set(np, FEATURE_IOBUS_enable);
+ mdelay(10);
+ feature_set(np, FEATURE_IDE0_enable);
+ mdelay(10);
+ feature_clear(np, FEATURE_IDE0_reset);
+ break;
+ case 1:
+ feature_set(np, FEATURE_IDE1_reset);
+ feature_set(np, FEATURE_IOBUS_enable);
+ mdelay(10);
+ feature_set(np, FEATURE_IDE1_enable);
+ mdelay(10);
+ feature_clear(np, FEATURE_IDE1_reset);
+ break;
+ case 2:
+ /* This one exists only for KL, I don't know
+ about any enable bit */
+ feature_set(np, FEATURE_IDE2_reset);
+ mdelay(10);
+ feature_clear(np, FEATURE_IDE2_reset);
+ break;
+ }
+ mdelay(IDE_WAKEUP_DELAY_MS);
+
+ /* Reset timings */
+ pmac_ide_selectproc(&ide_hwifs[i].drives[0]);
+ mdelay(10);
/* Wait up to 10 seconds (enough for recent drives) */
for (j = 0; j < 100; j++) {
{
int timeout;
- timeout = 5000;
+ /* Reset timings */
+ pmac_ide_selectproc(&ide_hwifs[i].drives[0]);
+ mdelay(10);
+
+ timeout = 10000;
while ((inb(base + 0x70) & BUSY_STAT) && timeout) {
mdelay(1);
--timeout;
}
}
-static int idepmac_notify(struct pmu_sleep_notifier *self, int when)
+/* Note: We support only master drives for now. This will have to be
+ * improved if we want to handle sleep on the iMacDV where the CD-ROM
+ * is a slave
+ */
+static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
{
int i, ret;
unsigned long base;
break;
case PBOOK_SLEEP_NOW:
for (i = 0; i < pmac_ide_count; ++i) {
- if ((base = pmac_ide_regbase[i]) == 0)
+ if ((base = pmac_ide[i].regbase) == 0)
continue;
/* Disable irq during sleep */
- disable_irq(pmac_ide_irq[i]);
+ disable_irq(pmac_ide[i].irq);
ret = check_media_bay_by_base(base, MB_CD);
- if (ret == -ENODEV)
+ if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)
/* not media bay - put the disk to sleep */
idepmac_sleep_disk(i, base);
}
break;
case PBOOK_WAKE:
for (i = 0; i < pmac_ide_count; ++i) {
- if ((base = pmac_ide_regbase[i]) == 0)
+ ide_hwif_t *hwif;
+ if ((base = pmac_ide[i].regbase) == 0)
continue;
+ hwif = &ide_hwifs[i];
/* We don't handle media bay devices this way */
ret = check_media_bay_by_base(base, MB_CD);
- if (ret == -ENODEV)
+ if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)
idepmac_wake_disk(i, base);
else if (ret == 0)
idepmac_wake_bay(i, base);
- enable_irq(pmac_ide_irq[i]);
+ enable_irq(pmac_ide[i].irq);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+ if (hwif->drives[0].present && hwif->drives[0].using_dma)
+ pmac_ide_dma_onoff(&hwif->drives[0], 1);
+#endif
}
break;
}
}
type = ide_cdrom; /* Early cdrom models used zero */
case ide_cdrom:
- printk ("CDROM");
drive->removable = 1;
+#ifdef CONFIG_PPC
+ /* kludge for Apple PowerBook internal zip */
+ if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) {
+ printk ("FLOPPY");
+ type = ide_floppy;
+ break;
+ }
+#endif
+ printk ("CDROM");
break;
case ide_tape:
printk ("TAPE");
case ide_rz1000: name = "rz1000"; break;
case ide_trm290: name = "trm290"; break;
case ide_4drives: name = "4drives"; break;
+ case ide_pmac: name = "mac-io"; break;
default: name = "(unknown)"; break;
}
len = sprintf(page, "%s\n", name);
ide_cmd640, ide_dtc2278, ide_ali14xx,
ide_qd6580, ide_umc8672, ide_ht6560b,
ide_pdc4030, ide_rz1000, ide_trm290,
- ide_cmd646, ide_4drives
+ ide_cmd646, ide_4drives, ide_pmac
} hwif_chipset_t;
typedef struct ide_pci_devid_s {
set_fs(fs);
}
+#ifdef CONFIG_MAC_FLOPPY
+int swim3_fd_eject(int devnum);
+#endif
__initfunc(static void rd_load_disk(int n))
{
if (rd_prompt) {
#ifdef CONFIG_BLK_DEV_FD
floppy_eject();
+#endif
+#ifdef CONFIG_MAC_FLOPPY
+ if(MAJOR(ROOT_DEV) == FLOPPY_MAJOR)
+ swim3_fd_eject(MINOR(ROOT_DEV));
+ else if(MAJOR(real_root_dev) == FLOPPY_MAJOR)
+ swim3_fd_eject(MINOR(real_root_dev));
#endif
printk(KERN_NOTICE
"VFS: Insert root floppy disk to be loaded into RAM disk and press ENTER\n");
return err;
}
+int swim3_fd_eject(int devnum)
+{
+ if (devnum >= floppy_count)
+ return -ENODEV;
+ /* Do not check this - this function should ONLY be called early
+ * in the boot process! */
+ /* if (floppy_states[devnum].ref_count != 1) return -EBUSY; */
+ return fd_eject(&floppy_states[devnum]);
+}
+
static struct floppy_struct floppy_type =
{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */
endif
endif
+ifeq ($(CONFIG_PPC_RTC),y)
+ L_OBJS += rtc.o
+else
+ ifeq ($(CONFIG_PPC_RTC),m)
+ M_OBJS += rtc.o
+ endif
+endif
+
ifdef CONFIG_MAC_KEYBOARD
L_OBJS += mac_keyb.o
endif
--- /dev/null
+/*
+ * Linux/PowerPC Real Time Clock Driver
+ *
+ * heavily based on:
+ * Linux/SPARC Real Time Clock Driver
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
+ *
+ * This is a little driver that lets a user-level program access
+ * the PPC clocks chip. It is no use unless you
+ * use the modified clock utility.
+ *
+ * Get the modified clock utility from:
+ * ftp://vger.rutgers.edu/pub/linux/Sparc/userland/clock.c
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/mc146818rtc.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+
+/* in kernel/time.c, these prototypes shouldn't be here */
+extern unsigned long mktime(unsigned int, unsigned int, unsigned int,
+ unsigned int, unsigned int, unsigned int);
+extern void to_tm(int tim, struct rtc_time * tm);
+
+static int rtc_busy = 0;
+
+/* Retrieve the current date and time from the real time clock. */
+void get_rtc_time(struct rtc_time *t)
+{
+ unsigned long nowtime;
+
+ nowtime = (ppc_md.get_rtc_time)();
+
+ to_tm(nowtime, t);
+
+ t->tm_year -= 1900;
+ t->tm_mon -= 1;
+ t->tm_wday -= 1;
+}
+
+/* Set the current date and time inthe real time clock. */
+void set_rtc_time(struct rtc_time *t)
+{
+ unsigned long nowtime;
+
+ printk(KERN_INFO "rtc.c:set_rtc_time: %04d-%02d-%02d %02d:%02d:%02d.\n", t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+
+ nowtime = mktime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+
+ printk(KERN_INFO "rtc.c:set_rtc_time: set rtc time to %d seconds.\n", nowtime);
+
+ (ppc_md.set_rtc_time)(nowtime);
+}
+
+static long long rtc_lseek(struct file *file, long long offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct rtc_time rtc_tm;
+
+ switch (cmd)
+ {
+ case RTC_RD_TIME:
+ if (ppc_md.get_rtc_time)
+ {
+ get_rtc_time(&rtc_tm);
+
+ copy_to_user_ret((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time), -EFAULT);
+
+ return 0;
+ }
+ else
+ return -EINVAL;
+
+ case RTC_SET_TIME:
+ if (!capable(CAP_SYS_TIME))
+ return -EPERM;
+
+ if (ppc_md.set_rtc_time)
+ {
+ copy_from_user_ret(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time), -EFAULT);
+
+ set_rtc_time(&rtc_tm);
+
+ return 0;
+ }
+ else
+ return -EINVAL;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+ if (rtc_busy)
+ return -EBUSY;
+
+ rtc_busy = 1;
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+ MOD_DEC_USE_COUNT;
+ rtc_busy = 0;
+ return 0;
+}
+
+static struct file_operations rtc_fops = {
+ rtc_lseek,
+ NULL, /* rtc_read */
+ NULL, /* rtc_write */
+ NULL, /* rtc_readdir */
+ NULL, /* rtc_poll */
+ rtc_ioctl,
+ NULL, /* rtc_mmap */
+ rtc_open,
+ NULL, /* flush */
+ rtc_release
+};
+
+static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops };
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int rtc_init(void))
+#endif
+{
+ int error;
+
+ error = misc_register(&rtc_dev);
+ if (error) {
+ printk(KERN_ERR "rtc: unable to get misc minor\n");
+ return error;
+ }
+
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ misc_deregister(&rtc_dev);
+}
+#endif
- In vortex_error, do_tx_reset and vortex_tx_timeout(Vortex): clear
tbusy and force a BH rerun to better recover from errors.
+ 12Jun00 <2.2.16> andrewm
+ - Better handling of shared interrupts
+ - Reset the transmitter in vortex_error() on both maxcollisions and Tx reclaim error
+
- See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.2 for more details.
*/
static char *version =
-"3c59x.c:v0.99H 27May00 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+"3c59x.c:v0.99H 12Jun00 Donald Becker and others http://www.scyld.com/network/vortex.html\n";
/* "Knobs" that adjust features and parameters. */
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
if (tx_status & 0x14) vp->stats.tx_fifo_errors++;
if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
outb(0, ioaddr + TxStatus);
- if (tx_status & 0x30)
- do_tx_reset = 1;
+ if (tx_status & 0x3a) /* TxReset after 16 collisions, despite what the manual says */
+ do_tx_reset = 1; /* Also reset on reclaim errors */
else /* Merely re-enable the transmitter. */
outw(TxEnable, ioaddr + EL3_CMD);
}
struct device *dev = dev_id;
struct vortex_private *vp = (struct vortex_private *)dev->priv;
long ioaddr;
- int latency, status;
+ int status;
int work_done = max_interrupt_work;
- spin_lock(&vp->lock);
-
ioaddr = dev->base_addr;
- latency = inb(ioaddr + Timer);
+ spin_lock(&vp->lock);
status = inw(ioaddr + EL3_STATUS);
+ if ((status & IntLatch) == 0)
+ goto no_int; /* Happens during shared interrupts */
if (status & IntReq) {
status |= vp->deferred;
if (vortex_debug > 4)
printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
- dev->name, status, latency);
+ dev->name, status, inb(ioaddr + Timer));
+
do {
if (vortex_debug > 5)
printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n",
printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
dev->name, status);
+no_int:
spin_unlock(&vp->lock);
- return;
}
static int vortex_rx(struct device *dev)
#define DMFE_AUTO 8
#define DMFE_TIMER_WUT jiffies+(HZ*2)/2 /* timer wakeup time : 1 second */
-#define DMFE_TX_TIMEOUT HZ*1.5 /* tx packet time-out time 1.5 s" */
+#define DMFE_TX_TIMEOUT ((HZ*3)/2) /* tx packet time-out time 1.5 s" */
#define DMFE_DBUG(dbug_now, msg, vaule) if (dmfe_debug || dbug_now) printk("DBUG: %s %x\n", msg, vaule)
#ifndef MODULE
static int version_printed=0;
#endif
-static const char* version = "HDLC support routines revision: 1.0-pre9";
+static const char* version = "HDLC support routines revision: 1.0-pre10";
#define CISCO_MULTICAST 0x8f /* Cisco multicast address */
#endif
case CISCO_KEEPALIVE:
- if (skb->len != sizeof(cisco_packet)) {
+ if (skb->len != CISCO_PACKET_LEN &&
+ skb->len != CISCO_BIG_PACKET_LEN) {
printk(KERN_INFO "%s: Invalid length of Cisco "
- "control packet\n", hdlc->name);
+ "control packet (%d bytes)\n", hdlc->name,
+ skb->len);
goto rx_error;
}
ifeq ($(CONFIG_LANMEDIA),y)
O_TARGET := lmc.o
- O_OBJS = lmc_debug.o lmc_media.o lmc_main.o
+ O_OBJS = lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o
else
ifeq ($(CONFIG_LANMEDIA),m)
MOD_LIST_NAME := NET_MODULES
M_OBJS := lmc.o
O_TARGET := lmc.o
- O_OBJS = lmc_debug.o lmc_media.o lmc_main.o
+ O_OBJS = lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o
endif
endif
/*
* prototypes for everyone
*/
-int lmc_probe(struct device * dev);
+int lmc_probe(struct net_device * dev);
unsigned lmc_mii_readreg(lmc_softc_t * const sc, unsigned
devaddr, unsigned regno);
void lmc_mii_writereg(lmc_softc_t * const sc, unsigned devaddr,
void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits);
void lmc_gpio_mkoutput(lmc_softc_t * const sc, u_int32_t bits);
+int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
extern lmc_media_t lmc_ds3_media;
extern lmc_media_t lmc_ssi_media;
extern lmc_media_t lmc_t1_media;
#include <linux/types.h>
#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/version.h>
+#include "lmc_ver.h"
#include "lmc_debug.h"
/*
#endif
}
-#ifdef DEBUG
-u_int32_t lmcEventLogIndex = 0;
-u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS];
-#endif
+inline void lmc_trace(struct net_device *dev, char *msg){
+#ifdef LMC_TRACE
+ unsigned long j = jiffies + 3; /* Wait for 50 ms */
-void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3)
-{
-#ifdef DEBUG
- lmcEventLogBuf[lmcEventLogIndex++] = EventNum;
- lmcEventLogBuf[lmcEventLogIndex++] = arg2;
- lmcEventLogBuf[lmcEventLogIndex++] = arg3;
- lmcEventLogBuf[lmcEventLogIndex++] = jiffies;
-
- lmcEventLogIndex &= (LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS) - 1;
+ if(in_interrupt()){
+ printk("%s: * %s\n", dev->name, msg);
+// while(jiffies < j+10)
+// ;
+ }
+ else {
+ printk("%s: %s\n", dev->name, msg);
+ while(jiffies < j)
+ schedule();
+ }
#endif
}
#define LMC_CONSOLE_LOG(x,y,z)
#endif
-
-
-/* Debug --- Event log definitions --- */
-/* EVENTLOGSIZE*EVENTLOGARGS needs to be a power of 2 */
-#define LMC_EVENTLOGSIZE 512 /* number of events in eventlog */
-#define LMC_EVENTLOGARGS 4 /* number of args for each event */
-
-/* event indicators */
-#define LMC_EVENT_XMT 1
-#define LMC_EVENT_XMTEND 2
-#define LMC_EVENT_XMTINT 3
-#define LMC_EVENT_RCVINT 4
-#define LMC_EVENT_RCVEND 5
-#define LMC_EVENT_INT 6
-#define LMC_EVENT_XMTINTTMO 7
-#define LMC_EVENT_XMTPRCTMO 8
-#define LMC_EVENT_INTEND 9
-#define LMC_EVENT_RESET1 10
-#define LMC_EVENT_RESET2 11
-#define LMC_EVENT_FORCEDRESET 12
-#define LMC_EVENT_WATCHDOG 13
-#define LMC_EVENT_BADPKTSURGE 14
-
-
-#ifdef DEBUG
-extern u_int32_t lmcEventLogIndex;
-extern u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS];
-#define LMC_EVENT_LOG(x, y, z) lmcEventLog((x), (y), (z))
-#else
-#define LMC_EVENT_LOG(x,y,z)
-#endif /* end ifdef _DBG_EVENTLOG */
-
-
void lmcConsoleLog(char *type, unsigned char *ucData, int iLen);
-void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3);
+inline void lmc_trace(struct net_device *dev, char *msg);
#endif
#ifndef _LMC_IOCTL_H_
#define _LMC_IOCTL_H_
-/* $Id: lmc_ioctl.h,v 1.9 2000/01/21 13:29:47 asj Exp $ */
+/* $Id: lmc_ioctl.h,v 1.18 2000/06/06 08:32:12 asj Exp $ */
/*
* Copyright (c) 1997-2000 LAN Media Corporation (LMC)
* of the GNU Public License version 2, incorporated herein by reference.
*/
-#define LMCIOCGINFO SIOCDEVPRIVATE+3 /* get current state */
-#define LMCIOCSINFO SIOCDEVPRIVATE+4 /* set state to user values */
-#define LMCIOCSKEEPALIVE SIOCDEVPRIVATE+5 /* Turn keepalives on/off */
-#ifdef LMC_DEBUG_FILE
-#define LMCIOCLEARSTATS LMCIOCSINFO + 1 /* Clear debug stats */
-#endif
-#define LMCIOCGETLMCSTATS LMCIOCSINFO + 3
-#define LMCIOCCLEARLMCSTATS LMCIOCSINFO + 4
-#define LMCIOCDUMPEVENTLOG LMCIOCSINFO + 5
-#define LMCIOCGETXINFO LMCIOCSINFO + 6
-#define LMCIOCSETCIRCUIT LMCIOCSINFO + 7
-#define LMCIOCUNUSEDATM LMCIOCSINFO + 8
-#define LMCIOCRESET LMCIOCSINFO + 9
-#define LMCIOCT1CONTROL LMCIOCSINFO + 10
-
-#define LMC_CARDTYPE_UNKNOWN -1
+#define LMCIOCGINFO SIOCDEVPRIVATE+3 /* get current state */
+#define LMCIOCSINFO SIOCDEVPRIVATE+4 /* set state to user values */
+#define LMCIOCGETLMCSTATS SIOCDEVPRIVATE+5
+#define LMCIOCCLEARLMCSTATS SIOCDEVPRIVATE+6
+#define LMCIOCDUMPEVENTLOG SIOCDEVPRIVATE+7
+#define LMCIOCGETXINFO SIOCDEVPRIVATE+8
+#define LMCIOCSETCIRCUIT SIOCDEVPRIVATE+9
+#define LMCIOCUNUSEDATM SIOCDEVPRIVATE+10
+#define LMCIOCRESET SIOCDEVPRIVATE+11
+#define LMCIOCMEDIA SIOCDEVPRIVATE+12
+#define LMCIOCIFTYPE SIOCDEVPRIVATE+13
+#define LMCIOCXILINX SIOCDEVPRIVATE+14
+
+#define LMC_CARDTYPE_UNKNOWN -1
#define LMC_CARDTYPE_HSSI 1 /* probed card is a HSSI card */
#define LMC_CARDTYPE_DS3 2 /* probed card is a DS3 card */
#define LMC_CARDTYPE_SSI 3 /* probed card is a SSI card */
#define LMC_CTL_CIRCUIT_TYPE_E1 0
#define LMC_CTL_CIRCUIT_TYPE_T1 1
+/*
+ * IFTYPE defines
+ */
+#define LMC_PPP 1 /* use sppp interface */
+#define LMC_NET 2 /* use direct net interface */
+#define LMC_RAW 3 /* use direct net interface */
+
/*
* These are not in the least IOCTL related, but I want them common.
*/
*/
#define LMC_GEP_INIT 0x01 /* 0: */
#define LMC_GEP_RESET 0x02 /* 1: */
-#define LMC_GEP_LOAD 0x10 /* 4: */
+#define LMC_GEP_MODE 0x10 /* 4: */
#define LMC_GEP_DP 0x20 /* 5: */
-#define LMC_GEP_SERIAL 0x40 /* 6: serial out */
-#define LMC_GEP_SERIALCLK 0x80 /* 7: serial clock */
+#define LMC_GEP_DATA 0x40 /* 6: serial out */
+#define LMC_GEP_CLK 0x80 /* 7: serial clock */
/*
* HSSI GPIO assignments
#define LMC_GEP_HSSI_CLOCK 0x08 /* 3: clock source */
/*
- * T1 GPIO assignments
+ * SSI GPIO assignments
*/
#define LMC_GEP_SSI_GENERATOR 0x04 /* 2: enable prog freq gen serial i/f */
#define LMC_GEP_SSI_TXCLOCK 0x08 /* 3: provide clock on TXCLOCK output */
+/*
+ * T1 GPIO assigments
+ */
+#define LMC_GEP_T1_INT 0x08 /* 3: Interupt enable */
+
/*
* Common MII16 bits
*/
#define LMC_MII16_DS3_DLOS 0x0040
#define LMC_MII16_DS3_CRC 0x1000
#define LMC_MII16_DS3_SCRAM 0x2000
+#define LMC_MII16_DS3_SCRAM_LARS 0x4000
/* Note: 2 pairs of LEDs where swapped by mistake
* in Xilinx code for DS3 & DS1 adapters */
/*
* And T1, LMC1200
*/
-#define LMC_MII16_T1_UNUSED1 0x0003
+#define LMC_MII16_T1_UNUSED1 0x0001
+#define LMC_MII16_T1_INVERT 0x0002
#define LMC_MII16_T1_XOE 0x0004
#define LMC_MII16_T1_RST 0x0008 /* T1 chip reset - RW */
#define LMC_MII16_T1_Z 0x0010 /* output impedance T1=1, E1=0 output - RW */
#define LMC_T1F_WRITE 0
#define LMC_T1F_READ 1
+enum lmc_st1f_cmd {
+ lmc_st1f_write = 1,
+ lmc_st1f_read = 2,
+ lmc_st1f_inv = 3,
+ lmc_st1f_amisf = 4,
+ lmc_st1f_frac = 5,
+ lmc_st1f_loopt = 6,
+};
+
typedef struct lmc_st1f_control {
int command;
int address;
char *data;
} lmc_t1f_control;
+
+
+enum lmc_xilinx_c {
+ lmc_xilinx_reset = 1,
+ lmc_xilinx_load_prom = 2,
+ lmc_xilinx_load = 3
+};
+
+struct lmc_xilinx_control {
+ enum lmc_xilinx_c command;
+ int len;
+ char *data;
+};
+
/* ------------------ end T1 defs ------------------- */
#define LMC_MII_LedMask 0x0780
#define LMC_MII_LedBitPos 7
-#endif
\ No newline at end of file
+#endif
* With Help By:
* David Boggs
* Ron Crane
- * Allan Cox
+ * Alan Cox
*
* This software may be used and distributed according to the terms
* of the GNU Public License version 2, incorporated herein by reference.
*
*/
-/* $Id: lmc_main.c,v 1.24 2000/01/21 13:29:48 asj Exp $ */
+/* $Id: lmc_main.c,v 1.44 2000/06/19 16:53:59 asj Exp $ */
-#include <linux/version.h>
#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/delay.h>
#include <asm/segment.h>
-#include <asm/smp.h>
-
-#if LINUX_VERSION_CODE < 0x20155
-#include <linux/bios32.h>
-#endif
+#include <linux/init.h>
#include <linux/in.h>
#include <linux/if_arp.h>
#if LINUX_VERSION_CODE >= 0x20200
#include <asm/uaccess.h>
-#include <asm/spinlock.h>
-#endif
-
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
-#include <linux/module.h>
-#include <linux/version.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
+//#include <asm/spinlock.h>
+#else /* 2.0 kernel */
+#define ARPHRD_HDLC 513
#endif
#define DRIVER_MAJOR_VERSION 1
-#define DRIVER_MINOR_VERSION 33
-#define DRIVER_SUB_VERSION 1
+#define DRIVER_MINOR_VERSION 34
+#define DRIVER_SUB_VERSION 7
#define DRIVER_VERSION ((DRIVER_MAJOR_VERSION << 8) + DRIVER_MINOR_VERSION)
-#include "lmc.h"
#include "lmc_ver.h"
+#include "lmc.h"
#include "lmc_var.h"
#include "lmc_ioctl.h"
#include "lmc_debug.h"
+#include "lmc_proto.h"
+
static int Lmc_Count = 0;
-static struct device *Lmc_root_dev = NULL;
+static struct net_device *Lmc_root_dev = NULL;
static u8 cards_found = 0;
static int lmc_first_load = 0;
-int lmc_probe_fake(struct device *dev);
-static struct device *lmc_probe1(struct device *dev, int ioaddr, int irq,
- int chip_id, int subdevice, int board_idx);
-static int lmc_start_xmit(struct sk_buff *skb, struct device *dev);
-static int lmc_rx(struct device *dev);
-static int lmc_open(struct device *dev);
-static int lmc_close(struct device *dev);
-static struct enet_statistics *lmc_get_stats(struct device *dev);
+int LMC_PKT_BUF_SZ = 1542;
+
+#if LINUX_VERSION_CODE >= 0x20363
+#ifdef MODULE
+static struct pci_device_id lmc_pci_tbl[] __devinitdata = {
+ { 0x1011, 0x009, 0x1376, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, lmc_pci_tbl);
+#endif
+#endif
+
+
+int lmc_probe_fake(struct net_device *dev);
+static struct net_device *lmc_probe1(struct net_device *dev, unsigned long ioaddr, unsigned int irq,
+ int chip_id, int subdevice, int board_idx, void *pci_dev);
+static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int lmc_rx (struct net_device *dev);
+static int lmc_open(struct net_device *dev);
+static int lmc_close(struct net_device *dev);
+static struct enet_statistics *lmc_get_stats(struct net_device *dev);
static void lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-static int lmc_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-static int lmc_set_config(struct device *dev, struct ifmap *map);
-static void lmc_initcsrs(lmc_softc_t * const, u32, size_t);
+static int lmc_set_config(struct net_device *dev, struct ifmap *map);
+static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size);
static void lmc_softreset(lmc_softc_t * const);
-static void lmc_running_reset(struct device *dev);
-static int lmc_ifdown(struct device * const);
+static void lmc_running_reset(struct net_device *dev);
+static int lmc_ifdown(struct net_device * const);
static void lmc_watchdog(unsigned long data);
-static int lmc_init(struct device * const);
+static int lmc_init(struct net_device * const);
static void lmc_reset(lmc_softc_t * const sc);
static void lmc_dec_reset(lmc_softc_t * const sc);
-static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base,size_t csr_size);
+#if LINUX_VERSION_CODE >= 0x20363
+static void lmc_driver_timeout(struct net_device *dev);
+int lmc_setup(void);
+#endif
+
/*
* linux reserves 16 device specific IOCTLs. We call them
* LMCIOC* to control various bits of our world.
*/
-static int lmc_ioctl (struct device *dev, struct ifreq *ifr, int cmd) /*fold00*/
+int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
{
lmc_softc_t *sc;
lmc_ctl_t ctl;
sc = dev->priv;
+ lmc_trace(dev, "lmc_ioctl in");
+
/*
* Most functions mess with the structure
* Disable interupts while we do the polling
*/
- spin_lock_irqsave(&sc->lmc_lock, flags);
+ LMC_SPIN_LOCK_IRQSAVE(sc);
switch (cmd) {
/*
* Return current driver state. Since we keep this up
* To date internally, just copy this out to the user.
*/
- case LMCIOCGINFO:
+ case LMCIOCGINFO: /*fold01*/
LMC_COPY_TO_USER(ifr->ifr_data, &sc->ictl, sizeof (lmc_ctl_t));
ret = 0;
break;
- case LMCIOCSINFO:
+ case LMCIOCSINFO: /*fold01*/
sp = &((struct ppp_device *) dev)->sppp;
if (!suser ()) {
ret = -EPERM;
if(ctl.crc_length != sc->ictl.crc_length) {
sc->lmc_media->set_crc_length(sc, ctl.crc_length);
+ if (sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16)
+ sc->TxDescriptControlInit |= LMC_TDES_ADD_CRC_DISABLE;
+ else
+ sc->TxDescriptControlInit &= ~LMC_TDES_ADD_CRC_DISABLE;
}
if (ctl.keepalive_onoff == LMC_CTL_OFF)
ret = 0;
break;
- case LMCIOCGETXINFO:
+
+ case LMCIOCIFTYPE: /*fold01*/
+ {
+ u_int16_t old_type = sc->if_type;
+ u_int16_t new_type;
+
+ if (!suser ()) {
+ ret = -EPERM;
+ break;
+ }
+
+ LMC_COPY_FROM_USER(&new_type, ifr->ifr_data, sizeof(u_int16_t));
+
+
+ if (new_type == old_type)
+ {
+ ret = 0 ;
+ break; /* no change */
+ }
+
+ lmc_proto_close(sc);
+ lmc_proto_detach(sc);
+
+ sc->if_type = new_type;
+// lmc_proto_init(sc);
+ lmc_proto_attach(sc);
+ lmc_proto_open(sc);
+
+ ret = 0 ;
+ break ;
+ }
+
+ case LMCIOCGETXINFO: /*fold01*/
sc->lmc_xinfo.Magic0 = 0xBEEFCAFE;
sc->lmc_xinfo.PciCardType = sc->lmc_cardtype;
sc->lmc_xinfo.DriverSubVersion = DRIVER_SUB_VERSION;
sc->lmc_xinfo.XilinxRevisionNumber =
lmc_mii_readreg (sc, 0, 3) & 0xf;
- sc->lmc_xinfo.MaxFrameSize = PKT_BUF_SZ;
+ sc->lmc_xinfo.MaxFrameSize = LMC_PKT_BUF_SZ;
sc->lmc_xinfo.link_status = sc->lmc_media->get_link_status (sc);
sc->lmc_xinfo.mii_reg16 = lmc_mii_readreg (sc, 0, 16);
break;
- case LMCIOCGETLMCSTATS:
+ case LMCIOCGETLMCSTATS: /*fold01*/
if (sc->lmc_cardtype == LMC_CARDTYPE_T1){
lmc_mii_writereg (sc, 0, 17, T1FRAMER_FERR_LSB);
sc->stats.framingBitErrorCount +=
ret = 0;
break;
- case LMCIOCCLEARLMCSTATS:
+ case LMCIOCCLEARLMCSTATS: /*fold01*/
if (!suser ()){
ret = -EPERM;
break;
ret = 0;
break;
- case LMCIOCSETCIRCUIT:
+ case LMCIOCSETCIRCUIT: /*fold01*/
if (!suser ()){
ret = -EPERM;
break;
break;
- case LMCIOCRESET:
+ case LMCIOCRESET: /*fold01*/
if (!suser ()){
ret = -EPERM;
break;
lmc_running_reset (dev);
printk (" REG16 after reset +%04x\n", lmc_mii_readreg (sc, 0, 16));
- LMC_EVENT_LOG(LMC_EVENT_FORCEDRESET, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16));
-
ret = 0;
break;
+ case LMCIOCMEDIA: /*fold01*/
+ ret = sc->lmc_media->ioctl(sc, ifr->ifr_data);
+ break;
+ case LMCIOCXILINX: /*fold01*/
+ {
+ struct lmc_xilinx_control xc; /*fold02*/
-#ifdef DEBUG
- case LMCIOCDUMPEVENTLOG:
- LMC_COPY_TO_USER(ifr->ifr_data, &lmcEventLogIndex, sizeof (u32));
- LMC_COPY_TO_USER(ifr->ifr_data + sizeof (u32), lmcEventLogBuf, sizeof (lmcEventLogBuf));
+ if (!suser ()){
+ ret = -EPERM;
+ break;
+ }
+
+ /*
+ * Stop the xwitter whlie we restart the hardware
+ */
+ LMC_XMITTER_BUSY(dev);
+
+ LMC_COPY_FROM_USER(&xc, ifr->ifr_data, sizeof (struct lmc_xilinx_control));
+ switch(xc.command){
+ case lmc_xilinx_reset: /*fold02*/
+ {
+ u16 mii;
+ mii = lmc_mii_readreg (sc, 0, 16);
+
+ /*
+ * Make all of them 0 and make input
+ */
+ lmc_gpio_mkinput(sc, 0xff);
+
+ /*
+ * make the reset output
+ */
+ lmc_gpio_mkoutput(sc, LMC_GEP_RESET);
+
+ /*
+ * RESET low to force configuration. This also forces
+ * the transmitter clock to be internal, but we expect to reset
+ * that later anyway.
+ */
+
+ sc->lmc_gpio &= ~LMC_GEP_RESET;
+ LMC_CSR_WRITE(sc, csr_gp, cpu_to_le32(sc->lmc_gpio));
+
+
+ /*
+ * hold for more than 10 microseconds
+ */
+ udelay(50);
+
+ sc->lmc_gpio |= LMC_GEP_RESET;
+ LMC_CSR_WRITE(sc, csr_gp, cpu_to_le32(sc->lmc_gpio));
+
+
+ /*
+ * stop driving Xilinx-related signals
+ */
+ lmc_gpio_mkinput(sc, 0xff);
+
+ /* Reset the frammer hardware */
+ sc->lmc_media->set_link_status (sc, 1);
+ sc->lmc_media->set_status (sc, NULL);
+// lmc_softreset(sc);
+
+ {
+ int i;
+ for(i = 0; i < 5; i++){
+ lmc_led_on(sc, LMC_DS3_LED0);
+ mdelay(100);
+ lmc_led_off(sc, LMC_DS3_LED0);
+ lmc_led_on(sc, LMC_DS3_LED1);
+ mdelay(100);
+ lmc_led_off(sc, LMC_DS3_LED1);
+ lmc_led_on(sc, LMC_DS3_LED3);
+ mdelay(100);
+ lmc_led_off(sc, LMC_DS3_LED3);
+ lmc_led_on(sc, LMC_DS3_LED2);
+ mdelay(100);
+ lmc_led_off(sc, LMC_DS3_LED2);
+ }
+ }
+
+
+
+ ret = 0x0;
+
+ }
+
+ break;
+ case lmc_xilinx_load_prom: /*fold02*/
+ {
+ u16 mii;
+ int timeout = 500000;
+ mii = lmc_mii_readreg (sc, 0, 16);
+
+ /*
+ * Make all of them 0 and make input
+ */
+ lmc_gpio_mkinput(sc, 0xff);
+
+ /*
+ * make the reset output
+ */
+ lmc_gpio_mkoutput(sc, LMC_GEP_DP | LMC_GEP_RESET);
+
+ /*
+ * RESET low to force configuration. This also forces
+ * the transmitter clock to be internal, but we expect to reset
+ * that later anyway.
+ */
+
+ sc->lmc_gpio &= ~(LMC_GEP_RESET | LMC_GEP_DP);
+ LMC_CSR_WRITE(sc, csr_gp, cpu_to_le32(sc->lmc_gpio));
+
+
+ /*
+ * hold for more than 10 microseconds
+ */
+ udelay(50);
+
+ sc->lmc_gpio |= LMC_GEP_DP | LMC_GEP_RESET;
+ LMC_CSR_WRITE(sc, csr_gp, cpu_to_le32(sc->lmc_gpio));
+
+ /*
+ * busy wait for the chip to reset
+ */
+ while( (le32_to_cpu(LMC_CSR_READ(sc, csr_gp)) & LMC_GEP_INIT) == 0 &&
+ (timeout-- > 0))
+ ;
+
+ /*
+ * stop driving Xilinx-related signals
+ */
+ lmc_gpio_mkinput(sc, 0xff);
+ ret = 0x0;
+ break;
+
+ }
+
+ case lmc_xilinx_load: /*fold02*/
+ {
+ char *data;
+ int pos;
+ int timeout = 500000;
+
+ if(xc.data == 0x0){
+ ret = -EINVAL;
+ break;
+ }
+
+ data = kmalloc(xc.len, GFP_KERNEL);
+ if(data == 0x0){
+ printk(KERN_WARNING "%s: Failed to allocate memory for copy\n", dev->name);
+ ret = -ENOMEM;
+ break;
+ }
+
+ LMC_COPY_FROM_USER(data, xc.data, xc.len);
+
+ printk("%s: Starting load of data Len: %d at 0x%p == 0x%p\n", dev->name, xc.len, xc.data, data);
+
+ lmc_gpio_mkinput(sc, 0xff);
+
+ /*
+ * Clear the Xilinx and start prgramming from the DEC
+ */
+
+ /*
+ * Set ouput as:
+ * Reset: 0 (active)
+ * DP: 0 (active)
+ * Mode: 1
+ *
+ */
+ sc->lmc_gpio = 0x00;
+ sc->lmc_gpio &= ~LMC_GEP_DP;
+ sc->lmc_gpio &= ~LMC_GEP_RESET;
+ sc->lmc_gpio |= LMC_GEP_MODE;
+ LMC_CSR_WRITE(sc, csr_gp, cpu_to_le32(sc->lmc_gpio));
+
+ lmc_gpio_mkoutput(sc, LMC_GEP_MODE | LMC_GEP_DP | LMC_GEP_RESET);
+
+ /*
+ * Wait at least 10 us 20 to be safe
+ */
+ udelay(50);
+
+ /*
+ * Clear reset and activate programing lines
+ * Reset: Input
+ * DP: Input
+ * Clock: Output
+ * Data: Output
+ * Mode: Output
+ */
+ lmc_gpio_mkinput(sc, LMC_GEP_DP | LMC_GEP_RESET);
+
+ /*
+ * Set LOAD, DATA, Clock to 1
+ */
+ sc->lmc_gpio = 0x00;
+ sc->lmc_gpio |= LMC_GEP_MODE;
+ sc->lmc_gpio |= LMC_GEP_DATA;
+ sc->lmc_gpio |= LMC_GEP_CLK;
+ LMC_CSR_WRITE(sc, csr_gp, cpu_to_le32(sc->lmc_gpio));
+
+ lmc_gpio_mkoutput(sc, LMC_GEP_DATA | LMC_GEP_CLK | LMC_GEP_MODE );
+
+ /*
+ * busy wait for the chip to reset
+ */
+ while( (le32_to_cpu(LMC_CSR_READ(sc, csr_gp)) & LMC_GEP_INIT) == 0 &&
+ (timeout-- > 0))
+ ;
+
+ printk(KERN_DEBUG "%s: Waited %d for the Xilinx to clear it's memory\n", dev->name, 500000-timeout);
+
+ for(pos = 0; pos < xc.len; pos++){
+ switch(data[pos]){
+ case 0:
+ sc->lmc_gpio &= ~LMC_GEP_DATA; /* Data is 0 */
+ break;
+ case 1:
+ sc->lmc_gpio |= LMC_GEP_DATA; /* Data is 1 */
+ break;
+ default:
+ printk(KERN_WARNING "%s Bad data in xilinx programing data at %d, got %d wanted 0 or 1\n", dev->name, pos, data[pos]);
+ sc->lmc_gpio |= LMC_GEP_DATA; /* Assume it's 1 */
+ }
+ sc->lmc_gpio &= ~LMC_GEP_CLK; /* Clock to zero */
+ sc->lmc_gpio |= LMC_GEP_MODE;
+ LMC_CSR_WRITE(sc, csr_gp, cpu_to_le32(sc->lmc_gpio));
+ udelay(1);
+
+ sc->lmc_gpio |= LMC_GEP_CLK; /* Put the clack back to one */
+ sc->lmc_gpio |= LMC_GEP_MODE;
+ LMC_CSR_WRITE(sc, csr_gp, cpu_to_le32(sc->lmc_gpio));
+ udelay(1);
+ }
+ if((le32_to_cpu(LMC_CSR_READ(sc, csr_gp)) & LMC_GEP_INIT) == 0){
+ printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (corrupted data)\n", dev->name);
+ }
+ else if((le32_to_cpu(LMC_CSR_READ(sc, csr_gp)) & LMC_GEP_DP) == 0){
+ printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (done)\n", dev->name);
+ }
+ else {
+ printk(KERN_DEBUG "%s: Done reprograming Xilinx, %d bits, good luck!\n", dev->name, pos);
+ }
+
+ lmc_gpio_mkinput(sc, 0xff);
+
+ sc->lmc_miireg16 |= LMC_MII16_FIFO_RESET;
+ lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+
+ sc->lmc_miireg16 &= ~LMC_MII16_FIFO_RESET;
+ lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+
+ kfree(data);
+
+ ret = 0;
+
+ break;
+ }
+ default: /*fold02*/
+ ret = -EBADE;
+ break;
+ }
+
+ LMC_XMITTER_FREE(dev);
+ sc->lmc_txfull = 0;
- ret = 0;
- break;
-#endif /* end ifdef _DBG_EVENTLOG */
- case LMCIOCT1CONTROL:
- if (sc->lmc_cardtype != LMC_CARDTYPE_T1){
- ret = -EOPNOTSUPP;
- break;
}
break;
- default:
- /* If we don't know what to do, give syncppp a shot. */
- ret = sppp_do_ioctl (dev, ifr, cmd);
+ default: /*fold01*/
+ /* If we don't know what to do, give the protocol a shot. */
+ ret = lmc_proto_ioctl (sc, ifr, cmd);
+ break;
}
- spin_unlock_irqrestore(&sc->lmc_lock, flags);
+ LMC_SPIN_UNLOCK_IRQRESTORE(sc); /*fold01*/
+
+ lmc_trace(dev, "lmc_ioctl out");
return ret;
}
/* the watchdog process that cruises around */
static void lmc_watchdog (unsigned long data) /*fold00*/
{
- struct device *dev = (struct device *) data;
+ struct net_device *dev = (struct net_device *) data;
lmc_softc_t *sc;
int link_status;
u_int32_t ticks;
- LMC_SPIN_FLAGS
+ LMC_SPIN_FLAGS;
sc = dev->priv;
- spin_lock_irqsave(&sc->lmc_lock, flags);
+ lmc_trace(dev, "lmc_watchdog in");
+
+ LMC_SPIN_LOCK_IRQSAVE(sc);
+
+ if(sc->check != 0xBEAFCAFE){
+ printk("LMC: Corrupt net_device stuct, breaking out\n");
+ return;
+ }
+
/* Make sure the tx jabber and rx watchdog are off,
* and the transmit and recieve processes are running.
*/
- LMC_CSR_WRITE (sc, csr_15, 0x00000011);
+ LMC_CSR_WRITE (sc, csr_15, cpu_to_le32(0x00000011));
sc->lmc_cmdmode |= TULIP_CMD_TXRUN | TULIP_CMD_RXRUN;
- LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+ LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(sc->lmc_cmdmode));
if (sc->lmc_ok == 0)
goto kick_timer;
- LMC_EVENT_LOG(LMC_EVENT_WATCHDOG, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16));
-
/* --- begin time out check -----------------------------------
* check for a transmit interrupt timeout
* Has the packet xmt vs xmt serviced threshold been exceeded */
sc->tx_TimeoutInd)
{
- LMC_EVENT_LOG(LMC_EVENT_XMTINTTMO, LMC_CSR_READ (sc, csr_status), 0);
-
sc->tx_TimeoutDisplay = 1;
sc->stats.tx_TimeoutCnt++;
/* DEC chip is stuck, hit it with a RESET!!!! */
lmc_running_reset (dev);
-
- /* look at receive & transmit process state to make sure they are running */
- LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
-
- /* look at: DSR - 02 for Reg 16
- * CTS - 08
- * DCD - 10
- * RI - 20
- * for Reg 17
- */
- LMC_EVENT_LOG(LMC_EVENT_RESET2, lmc_mii_readreg (sc, 0, 16), lmc_mii_readreg (sc, 0, 17));
-
/* reset the transmit timeout detection flag */
sc->tx_TimeoutInd = 0;
sc->lastlmc_taint_tx = sc->lmc_taint_tx;
* Mark it as down.
*/
if ((link_status == 0) && (sc->last_link_status != 0)) {
- printk(KERN_WARNING "%s: link down\n", dev->name);
+ printk(KERN_WARNING "%s: hardware/physical link down\n", dev->name);
sc->last_link_status = 0;
/* lmc_reset (sc); Why reset??? The link can go down ok */
* Bring it back up again.
*/
if (link_status != 0 && sc->last_link_status == 0) {
- printk(KERN_WARNING "%s: link up\n", dev->name);
+ printk(KERN_WARNING "%s: hardware/physical link up\n", dev->name);
sc->last_link_status = 1;
/* lmc_reset (sc); Again why reset??? */
* --bbraun
*/
- sppp_reopen (dev);
+ lmc_proto_reopen(sc);
}
* Poke the transmitter to make sure it
* never stops, even if we run out of mem
*/
- LMC_CSR_WRITE(sc, csr_rxpoll, 0);
+ LMC_CSR_WRITE(sc, csr_rxpoll, cpu_to_le32(0));
+
+ /*
+ * Check for code that failed
+ * and try and fix it as appropriate
+ */
+ if(sc->failed_ring == 1){
+ /*
+ * Failed to setup the recv/xmit rin
+ * Try again
+ */
+ sc->failed_ring = 0;
+ lmc_softreset(sc);
+ }
+ if(sc->failed_recv_alloc == 1){
+ /*
+ * We failed to alloc mem in the
+ * interupt halder, go through the rings
+ * and rebuild them
+ */
+ sc->failed_recv_alloc = 0;
+ lmc_softreset(sc);
+ }
/*
*/
kick_timer:
- ticks = LMC_CSR_READ (sc, csr_gp_timer);
- LMC_CSR_WRITE (sc, csr_gp_timer, 0xffffffffUL);
+ ticks = le32_to_cpu(LMC_CSR_READ (sc, csr_gp_timer));
+ LMC_CSR_WRITE (sc, csr_gp_timer, cpu_to_le32(0xffffffffUL));
sc->ictl.ticks = 0x0000ffff - (ticks & 0x0000ffff);
/*
sc->timer.expires = jiffies + (HZ);
add_timer (&sc->timer);
- spin_unlock_irqrestore(&sc->lmc_lock, flags);
+ LMC_SPIN_UNLOCK_IRQRESTORE(sc);
+
+ lmc_trace(dev, "lmc_watchdog out");
}
-static int lmc_init(struct device * const dev) /*fold00*/
+static int lmc_init(struct net_device * const dev) /*fold00*/
{
+ lmc_trace(dev, "lmc_init in");
+ lmc_trace(dev, "lmc_init out");
+
return 0;
}
/* This initializes each card from lmc_probe() */
-static struct device *lmc_probe1 (struct device *dev, int ioaddr, int irq, /*fold00*/
- int chip_id, int subdevice, int board_idx)
+static struct net_device *lmc_probe1 (struct net_device *dev, unsigned long ioaddr, unsigned int irq, /*FOLD00*/
+ int chip_id, int subdevice, int board_idx, void *pci_dev)
{
lmc_softc_t *sc = NULL;
u_int16_t AdapModelNum;
-
+#if LINUX_VERSION_CODE >= 0x20363
+ struct pci_dev *pdev = pci_dev;
+ dma_addr_t dma_handle;
+#endif
/*
* Allocate our own device structure
*/
-
+
+#if LINUX_VERSION_CODE < 0x20210 /* Changed in 2.2.16 */
dev = kmalloc (sizeof (struct ppp_device)+8, GFP_KERNEL);
+#else
+ dev = kmalloc (sizeof (struct net_device)+8, GFP_KERNEL);
+#endif
if (dev == NULL){
printk (KERN_ERR "lmc: kmalloc for device failed\n");
return NULL;
}
- memset (dev, 0, sizeof (struct ppp_device));
+ memset (dev, 0, sizeof (struct net_device));
- /*
- * Switch to common hdlc%d naming. We name by type not by vendor
- */
- dev->name = (char *) (((u32) (dev)) + sizeof (struct ppp_device));
+#ifndef GCOM
+ /*
+ * Switch to common hdlc%d naming. We name by type not by vendor
+ */
+#if LINUX_VERSION_CODE < 0x20210
+ dev->name = ((char *) (dev)) + sizeof (struct ppp_device);
+#elif LINUX_VERSION_CODE < 0x20363
+ dev->name = ((char *) (dev)) + sizeof (struct net_device);
+#endif
+
+#if LINUX_VERSION_CODE >= 0x20200
dev_alloc_name(dev, "hdlc%d");
+#else
+ sprintf(dev->name, "hdlc%d", Lmc_Count);
+#endif
+
+#else
+ /*
+ * GCOM uses LMC vendor name so that clients can know which card
+ * to attach to.
+ */
+ dev->name = ((char *) (dev)) + sizeof (struct ppp_device);
+ dev_alloc_name(dev, "lmc%d");
+#endif
+ lmc_trace(dev, "lmc_probe1 in");
+
Lmc_Count++;
if(lmc_first_load == 0){
printk(KERN_INFO "Lan Media Corporation WAN Driver Version %d.%d.%d\n",DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION,DRIVER_SUB_VERSION);
-#ifndef MODULE
- sync_ppp_init();
-#endif
lmc_first_load = 1;
}
-
-
- /* Initialize the sppp layer */
- sppp_attach ((struct ppp_device *) dev);
-
+
/*
* Allocate space for the private data structure
*/
-
+#if LINUX_VERSION_CODE >= 0x20363
+ sc = pci_alloc_consistent(pdev, sizeof (lmc_softc_t), &dma_handle);
+#else
sc = kmalloc (sizeof (lmc_softc_t), GFP_KERNEL);
+#endif
if (sc == NULL) {
printk (KERN_WARNING "%s: Cannot allocate memory for device state\n",
dev->name);
dev->priv = sc;
sc->lmc_device = dev;
sc->name = dev->name;
-
+ sc->if_type = LMC_PPP;
+ sc->check = 0xBEAFCAFE;
+#if LINUX_VERSION_CODE >= 0x20363
+ sc->pdev = pdev;
+ sc->sc_dma_handle = dma_handle;
+ sc->sc_dma = (lmc_softc_t *) dma_handle;
+#endif
+
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+ /*
+ * This will get the protocol layer ready and do any 1 time init's
+ * Must have a valid sc and dev structure
+ */
+ lmc_proto_init(sc);
+ lmc_proto_attach(sc);
/* Just fill in the entries for the device */
dev->init = lmc_init;
+ dev->type = ARPHRD_HDLC;
dev->hard_start_xmit = lmc_start_xmit;
dev->open = lmc_open;
dev->stop = lmc_close;
dev->get_stats = lmc_get_stats;
dev->do_ioctl = lmc_ioctl;
dev->set_config = lmc_set_config;
+#if LINUX_VERSION_CODE >= 0x20363
+ dev->tx_timeout = lmc_driver_timeout;
+ dev->watchdog_timeo = (HZ); /* 1 second */
+#endif
+
/*
* Why were we changing this???
dev->tx_queue_len = 100;
/* Init the spin lock so can call it latter */
- spin_lock_init(&sc->lmc_lock);
+ LMC_SPIN_LOCK_INIT(sc);
LMC_SETUP_20_DEV;
-
- printk ("%s: detected at %#3x, irq %d\n", dev->name, ioaddr, irq);
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
+
+ printk ("%s: detected at %lx, irq %d\n", dev->name, ioaddr, dev->irq);
if (register_netdev (dev) != 0) {
printk (KERN_ERR "%s: register_netdev failed.\n", dev->name);
- sppp_detach (dev);
+ lmc_proto_detach(sc);
kfree (dev->priv);
kfree (dev);
return NULL;
}
else {
- printk ("%s: Model number (%d) miscompare for PCI Subsystem ID = 0x%04x\n",
+ /* Print a warning but not a major failure case */
+ printk (KERN_WARNING "%s: Model number (%d) miscompare for PCI Subsystem ID = 0x%04x\n",
dev->name, AdapModelNum, subdevice);
- return (NULL);
}
/*
* reset clock
*/
- LMC_CSR_WRITE (sc, csr_gp_timer, 0xFFFFFFFFUL);
+ LMC_CSR_WRITE (sc, csr_gp_timer, cpu_to_le32(0xFFFFFFFFUL));
sc->board_idx = board_idx;
sc->lmc_ok = 0;
sc->last_link_status = 0;
+ lmc_trace(dev, "lmc_probe1 out");
+
return dev;
}
/* This is the entry point. This is what is called immediatly. */
/* This goes out and finds the card */
-int lmc_probe_fake(struct device *dev)
+int lmc_probe_fake(struct net_device *dev) /*fold00*/
{
lmc_probe(NULL);
/* Return 1 to unloaded bogus device */
return 1;
}
-int lmc_probe (struct device *dev) /*fold00*/
+int lmc_probe (struct net_device *dev) /*fold00*/
{
int pci_index = 0;
+#if LINUX_VERSION_CODE >= 0x20155
+ unsigned long pci_ioaddr;
+ unsigned int pci_irq_line;
+ struct pci_dev *pdev;
+#if LINUX_VERSION_CODE < 0x20363
+ unsigned short pci_command;
+#endif
+#else
unsigned char pci_irq_line;
+ u32 pci_ioaddr;
+#endif
u16 vendor, subvendor, device, subdevice;
- u32 pci_ioaddr, foundaddr = 0;
+ u32 foundaddr = 0;
unsigned char pci_bus, pci_device_fn;
u8 intcf = 0;
/* Read the info we need to determine if this is
* our card or not
*/
-#if LINUX_VERSION_CODE >= 0x20155
- vendor = pci_find_slot (pci_bus, pci_device_fn)->vendor;
- device = pci_find_slot (pci_bus, pci_device_fn)->device;
- pci_irq_line = pci_find_slot (pci_bus, pci_device_fn)->irq;
- pci_ioaddr = pci_find_slot (pci_bus, pci_device_fn)->base_address[0];
- pci_read_config_word (pci_find_slot (pci_bus, pci_device_fn),
- PCI_SUBSYSTEM_VENDOR_ID, &subvendor);
- pci_read_config_word (pci_find_slot (pci_bus, pci_device_fn),
- PCI_SUBSYSTEM_ID, &subdevice);
-#else
+#if LINUX_VERSION_CODE >= 0x20155 /* 2.2, 2.4 */
+ pdev = pci_find_slot (pci_bus, pci_device_fn);
+
+ if (!pdev)
+ break;
+
+#if LINUX_VERSION_CODE >= 0x20363
+ if(pci_enable_device(pdev)){
+ break;
+ }
+#endif
+
+ vendor = pdev->vendor;
+ device = pdev->device;
+ pci_irq_line = pdev->irq;
+#if LINUX_VERSION_CODE < 0x20363 /* 2.2 */
+ pci_ioaddr = pdev->base_address[0];
+ pci_read_config_word (pdev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor);
+ pci_read_config_word (pdev, PCI_SUBSYSTEM_ID, &subdevice);
+#else /* 2.4 */
+ pci_ioaddr = pci_resource_start (pdev, 0);
+ subvendor = pdev->subsystem_vendor;
+ subdevice = pdev->subsystem_device;
+#endif
+#else /* 2.0 */
pcibios_read_config_word (pci_bus, pci_device_fn,
PCI_VENDOR_ID, &vendor);
pcibios_read_config_word (pci_bus, pci_device_fn,
(vendor == CORRECT_VENDOR_ID) &&
(device == CORRECT_DEV_ID) &&
((subvendor == PCI_VENDOR_LMC) || (subdevice == PCI_VENDOR_LMC))){
- struct device *cur, *prev = NULL;
+ struct net_device *cur, *prev = NULL;
/* Fix the error, exchange the two values */
if(subdevice == PCI_VENDOR_LMC){
subvendor = PCI_VENDOR_LMC ;
}
+ /* Set the bus master bit */
+#if LINUX_VERSION_CODE < 0x20363
+#if LINUX_VERSION_CODE > 0x20155
+ pci_read_config_word(pdev, PCI_COMMAND,
+ &pci_command);
+ pci_command |= PCI_COMMAND_MASTER;
+ pci_write_config_word(pdev, PCI_COMMAND,
+ pci_command);
+#endif
+ /* Make the call to actually setup this card */
+ dev = lmc_probe1 (dev, pci_ioaddr, pci_irq_line,
+ device, subdevice, cards_found, 0x0);
+
+#else
+ pci_set_master (pdev);
/* Make the call to actually setup this card */
dev = lmc_probe1 (dev, pci_ioaddr, pci_irq_line,
- device, subdevice, cards_found);
+ device, subdevice, cards_found, pdev);
+
+#endif
+
if (dev == NULL) {
printk ("lmc_probe: lmc_probe1 failed\n");
goto lmc_probe_next_card;
/* After this is called, packets can be sent.
* Does not initialize the addresses
*/
-static int lmc_open (struct device *dev) /*fold00*/
+static int lmc_open (struct net_device *dev) /*fold00*/
{
lmc_softc_t *sc = dev->priv;
- int err;
- lmc_dec_reset (sc);
- lmc_reset (sc);
+ lmc_trace(dev, "lmc_open in");
- LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
- LMC_EVENT_LOG(LMC_EVENT_RESET2,
- lmc_mii_readreg (sc, 0, 16),
- lmc_mii_readreg (sc, 0, 17));
+ lmc_led_on(sc, LMC_DS3_LED0);
+ lmc_dec_reset (sc);
+ lmc_reset (sc);
- if (sc->lmc_ok)
+ if (sc->lmc_ok){
+ lmc_trace(dev, "lmc_open lmc_ok out");
return (0);
+ }
lmc_softreset (sc);
/* Since we have to use PCI bus, this should work on x86,alpha,ppc */
if (request_irq (dev->irq, &lmc_interrupt, SA_SHIRQ, dev->name, dev)){
printk(KERN_WARNING "%s: could not get irq: %d\n", dev->name, dev->irq);
+ lmc_trace(dev, "lmc_open irq failed out");
return -EAGAIN;
}
sc->got_irq = 1;
/* disable 32 bit CRC generated by ASIC */
sc->TxDescriptControlInit |= LMC_TDES_ADD_CRC_DISABLE;
}
+ sc->lmc_media->set_crc_length(sc, sc->ictl.crc_length);
/* Acknoledge the Terminal Active and light LEDs */
/* dev->flags |= IFF_UP; */
- err = sppp_open (dev);
- if (err){
- return err;
- }
+ lmc_proto_open(sc);
+
dev->do_ioctl = lmc_ioctl;
- dev->tbusy = 0;
+
+
+ LMC_XMITTER_INIT(dev);
+
+#if LINUX_VERSION_CODE < 0x20363
dev->start = 1;
+#endif
+
+ sc->stats.tx_tbusy0++ ;
MOD_INC_USE_COUNT;
| TULIP_STS_TXSTOPPED
| TULIP_STS_TXUNDERFLOW
| TULIP_STS_RXSTOPPED
+ | TULIP_STS_RXNOBUF
);
- LMC_CSR_WRITE (sc, csr_intr, sc->lmc_intrmask);
+ LMC_CSR_WRITE (sc, csr_intr, cpu_to_le32(sc->lmc_intrmask));
sc->lmc_cmdmode |= TULIP_CMD_TXRUN;
sc->lmc_cmdmode |= TULIP_CMD_RXRUN;
- LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+ LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(sc->lmc_cmdmode));
sc->lmc_ok = 1; /* Run watchdog */
sc->timer.function = &lmc_watchdog;
add_timer (&sc->timer);
+ lmc_trace(dev, "lmc_open out");
+
return (0);
}
* under heavy load
*/
-static void lmc_running_reset (struct device *dev) /*fold00*/
+static void lmc_running_reset (struct net_device *dev) /*fold00*/
{
lmc_softc_t *sc = (lmc_softc_t *) dev->priv;
+ lmc_trace(dev, "lmc_runnig_reset in");
+
/* stop interrupts */
/* Clear the interrupt mask */
- LMC_CSR_WRITE (sc, csr_intr, 0x00000000);
+ LMC_CSR_WRITE (sc, csr_intr, cpu_to_le32(0x00000000));
lmc_dec_reset (sc);
lmc_reset (sc);
sc->lmc_media->set_link_status (sc, 1);
sc->lmc_media->set_status (sc, NULL);
- dev->flags |= IFF_RUNNING;
- dev->tbusy = 0;
+ //dev->flags |= IFF_RUNNING;
+
+ LMC_XMITTER_FREE(dev);
+
sc->lmc_txfull = 0;
+ sc->stats.tx_tbusy0++ ;
sc->lmc_intrmask = TULIP_DEFAULT_INTR_MASK;
- LMC_CSR_WRITE (sc, csr_intr, sc->lmc_intrmask);
+ LMC_CSR_WRITE (sc, csr_intr, cpu_to_le32(sc->lmc_intrmask));
sc->lmc_cmdmode |= (TULIP_CMD_TXRUN | TULIP_CMD_RXRUN);
- LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+ LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(sc->lmc_cmdmode));
+
+ lmc_trace(dev, "lmc_runnin_reset_out");
}
* This disables the timer for the watchdog and keepalives,
* and disables the irq for dev.
*/
-static int lmc_close (struct device *dev) /*fold00*/
+static int lmc_close (struct net_device *dev) /*fold00*/
{
/* not calling release_region() as we should */
- lmc_softc_t *sc;
+ lmc_softc_t *sc = dev->priv;
+ lmc_trace(dev, "lmc_close in");
+
sc = dev->priv;
sc->lmc_ok = 0;
sc->lmc_media->set_link_status (sc, 0);
del_timer (&sc->timer);
- sppp_close (dev);
+ lmc_proto_close(sc);
lmc_ifdown (dev);
+#if LINUX_VERSION_CODE < 0x20363
+ dev->start = 0;
+#endif
+
+
+ /*
+ * Let's make sure all the leds are off
+ * when not configured
+ */
+ lmc_led_off(sc, LMC_DS3_LED0);
+ lmc_led_off(sc, LMC_DS3_LED1);
+ lmc_led_off(sc, LMC_DS3_LED2);
+ lmc_led_off(sc, LMC_DS3_LED3);
+
+ lmc_trace(dev, "lmc_close out");
+
return 0;
}
/* Ends the transfer of packets */
/* When the interface goes down, this is called */
-static int lmc_ifdown (struct device *dev) /*fold00*/
+static int lmc_ifdown (struct net_device *dev) /*fold00*/
{
lmc_softc_t *sc = dev->priv;
u32 csr6;
int i;
+ lmc_trace(dev, "lmc_ifdown in");
+
/* Don't let anything else go on right now */
- dev->start = 0;
- dev->tbusy = 1;
+ // dev->start = 0;
+ LMC_XMITTER_BUSY(dev);
+ sc->stats.tx_tbusy1++ ;
/* stop interrupts */
/* Clear the interrupt mask */
- LMC_CSR_WRITE (sc, csr_intr, 0x00000000);
+ LMC_CSR_WRITE (sc, csr_intr, cpu_to_le32(0x00000000));
/* Stop Tx and Rx on the chip */
- csr6 = LMC_CSR_READ (sc, csr_command);
+ csr6 = le32_to_cpu(LMC_CSR_READ (sc, csr_command));
csr6 &= ~LMC_DEC_ST; /* Turn off the Transmission bit */
csr6 &= ~LMC_DEC_SR; /* Turn off the Recieve bit */
- LMC_CSR_WRITE (sc, csr_command, csr6);
+ LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(csr6));
dev->flags &= ~IFF_RUNNING;
sc->stats.rx_missed_errors +=
- LMC_CSR_READ (sc, csr_missed_frames) & 0xffff;
+ le32_to_cpu(LMC_CSR_READ (sc, csr_missed_frames)) & 0xffff;
/* release the interrupt */
if(sc->got_irq == 1){
lmc_led_off (sc, LMC_MII16_LED_ALL);
- dev->tbusy = 0;
+ LMC_XMITTER_FREE(dev);
+ sc->stats.tx_tbusy0++ ;
+
+ lmc_trace(dev, "lmc_ifdown out");
MOD_DEC_USE_COUNT;
return 0;
*/
static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/
{
- struct device *dev = (struct device *) dev_instance;
- lmc_softc_t *sc;
+ struct net_device *dev = (struct net_device *) dev_instance;
+ lmc_softc_t *sc = dev->priv;
u32 csr;
int i;
s32 stat;
unsigned int badtx;
u32 firstcsr;
+ int max_work = LMC_RXDESCS;
+ unsigned long flags;
- sc = dev->priv;
+ lmc_trace(dev, "lmc_interrupt in");
- spin_lock(&sc->lmc_lock);
- if (test_and_set_bit (0, (void *) &dev->interrupt)) {
- goto lmc_int_fail_out;
- }
+ LMC_SPIN_LOCK_IRQSAVE(sc);
/*
* Read the csr to find what interupts we have (if any)
*/
- csr = LMC_CSR_READ (sc, csr_status);
+ csr = le32_to_cpu(LMC_CSR_READ (sc, csr_status));
/*
* Make sure this is our interrupt
*/
if ( ! (csr & sc->lmc_intrmask)) {
+ /*
+ * If it's not make sure it's not a media interupt first
+ */
+ sc->lmc_media->got_interupt(sc);
goto lmc_int_fail_out;
}
/* always go through this loop at least once */
while (csr & sc->lmc_intrmask) {
-
/*
* Clear interupt bits, we handle all case below
*/
- LMC_CSR_WRITE (sc, csr_status, csr);
+ LMC_CSR_WRITE (sc, csr_status, cpu_to_le32(csr));
/*
* One of
lmc_running_reset (dev);
break;
}
-
- if (csr & (TULIP_STS_RXINTR | TULIP_STS_RXNOBUF)) {
- lmc_rx (dev);
+ if (csr & TULIP_STS_RXINTR){
+ lmc_trace(dev, "rx interupt");
+ lmc_rx (dev);
+
}
-
if (csr & (TULIP_STS_TXINTR | TULIP_STS_TXNOBUF | TULIP_STS_TXSTOPPED)) {
+ int n_compl = 0 ;
/* reset the transmit timeout detection flag -baz */
sc->stats.tx_NoCompleteCnt = 0;
i = badtx % LMC_TXDESCS;
while ((badtx < sc->lmc_next_tx)) {
- stat = sc->lmc_txring[i].status;
+ stat = le32_to_cpu(sc->lmc_txring[i].status);
- LMC_EVENT_LOG (LMC_EVENT_XMTINT, stat, 0);
/*
* If bit 31 is 1 the tulip owns it break out of the loop
*/
- if (stat < 0)
+ if (stat & 0x80000000)
break;
+ n_compl++ ; /* i.e., have an empty slot in ring */
/*
* If we have no skbuff or have cleared it
* Already continue to the next buffer
else {
#if LINUX_VERSION_CODE >= 0x20200
- sc->stats.tx_bytes += sc->lmc_txring[i].length & 0x7ff;
+ sc->stats.tx_bytes += le32_to_cpu(sc->lmc_txring[i].length) & 0x7ff;
#endif
sc->stats.tx_packets++;
}
-
- LMC_DEV_KFREE_SKB (sc->lmc_txq[i]);
+
+#if LINUX_VERSION_CODE >= 0x20363 /* 2.4 */
+ pci_unmap_single(sc->pdev, sc->lmc_txring[i].buffer1, sc->lmc_txq[i]->len, PCI_DMA_TODEVICE);
+#endif
+ dev_kfree_skb_irq(sc->lmc_txq[i]);
sc->lmc_txq[i] = 0;
badtx++;
badtx += LMC_TXDESCS;
}
sc->lmc_txfull = 0;
- dev->tbusy = 0;
- mark_bh (NET_BH); /* Tell Linux to give me more packets */
-
-#ifdef DEBUG
- sc->stats.dirtyTx = badtx;
- sc->stats.lmc_next_tx = sc->lmc_next_tx;
- sc->stats.lmc_txfull = sc->lmc_txfull;
- sc->stats.tbusy = dev->tbusy;
+ LMC_XMITTER_FREE(dev);
+ sc->stats.tx_tbusy0++ ;
+#if LINUX_VERSION_CODE < 0x20363
+ mark_bh (NET_BH); /* Tell Linux to give me more packets */
#endif
sc->lmc_taint_tx = badtx;
- /*
- * Why was there a break here???
- */
} /* end handle transmit interrupt */
if (csr & TULIP_STS_SYSERROR) {
}
lmc_dec_reset (sc);
lmc_reset (sc);
- LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
- LMC_EVENT_LOG(LMC_EVENT_RESET2,
- lmc_mii_readreg (sc, 0, 16),
- lmc_mii_readreg (sc, 0, 17));
}
+
+
+ if(max_work-- <= 0)
+ break;
+
/*
* Get current csr status to make sure
* we've cleared all interupts
*/
- csr = LMC_CSR_READ (sc, csr_status);
+ csr = le32_to_cpu(LMC_CSR_READ (sc, csr_status));
} /* end interrupt loop */
- LMC_EVENT_LOG(LMC_EVENT_INT, firstcsr, csr);
-
- dev->interrupt = 0;
lmc_int_fail_out:
- spin_unlock(&sc->lmc_lock);
+ LMC_SPIN_UNLOCK_IRQRESTORE(sc);
+
+ lmc_trace(dev, "lmc_interrupt out");
+
return;
}
-static int lmc_start_xmit (struct sk_buff *skb, struct device *dev) /*fold00*/
+static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/
{
lmc_softc_t *sc;
u32 flag;
int ret = 0;
LMC_SPIN_FLAGS;
- sc = dev->priv;
+ lmc_trace(dev, "lmc_start_xmit in");
- /* the interface better be up */
- if ( ! (dev->flags & IFF_UP))
- return 1;
+ sc = dev->priv;
- spin_lock_irqsave(&sc->lmc_lock, flags);
+ LMC_SPIN_LOCK_IRQSAVE(sc);
/*
* If the transmitter is busy
* Poke the chip and try to get it running
*
*/
- if (dev->tbusy) {
+#if LINUX_VERSION_CODE < 0x20363
+ if(dev->tbusy != 0){
u32 csr6;
+ printk("%s: Xmitter busy|\n", dev->name);
+
+ sc->stats.tx_tbusy_calls++ ;
if (jiffies - dev->trans_start < TX_TIMEOUT) {
ret = 1;
goto lmc_start_xmit_bug_out;
* table and starts from scartch
*/
- LMC_EVENT_LOG(LMC_EVENT_XMTPRCTMO,
- LMC_CSR_READ (sc, csr_status),
- sc->stats.tx_ProcTimeout);
-
lmc_running_reset (dev);
- LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
- LMC_EVENT_LOG(LMC_EVENT_RESET2,
- lmc_mii_readreg (sc, 0, 16),
- lmc_mii_readreg (sc, 0, 17));
-
/* restart the tx processes */
- csr6 = LMC_CSR_READ (sc, csr_command);
- LMC_CSR_WRITE (sc, csr_command, csr6 | 0x0002);
- LMC_CSR_WRITE (sc, csr_command, csr6 | 0x2002);
+ csr6 = le32_to_cpu(LMC_CSR_READ (sc, csr_command));
+ LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(csr6 | 0x0002));
+ LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(csr6 | 0x2002));
/* immediate transmit */
- LMC_CSR_WRITE (sc, csr_txpoll, 0);
+ LMC_CSR_WRITE (sc, csr_txpoll, cpu_to_le32(0));
sc->stats.tx_errors++;
sc->stats.tx_ProcTimeout++; /* -baz */
ret = 1;
goto lmc_start_xmit_bug_out;
}
- /* normal path */
+#endif
+ /* normal path, tbusy known to be zero */
entry = sc->lmc_next_tx % LMC_TXDESCS;
sc->lmc_txq[entry] = skb;
+#if LINUX_VERSION_CODE >= 0x20363
+ sc->lmc_txring[entry].buffer1 = pci_map_single (sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+#else
sc->lmc_txring[entry].buffer1 = virt_to_bus (skb->data);
+#endif
LMC_CONSOLE_LOG("xmit", skb->data, skb->len);
+#ifndef GCOM
/* If the queue is less than half full, don't interrupt */
if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS / 2)
{
/* Do not interrupt on completion of this packet */
flag = 0x60000000;
- dev->tbusy = 0;
+ LMC_XMITTER_FREE(dev);
}
else if (sc->lmc_next_tx - sc->lmc_taint_tx == LMC_TXDESCS / 2)
{
/* This generates an interrupt on completion of this packet */
flag = 0xe0000000;
- dev->tbusy = 0;
+ LMC_XMITTER_FREE(dev);
}
else if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS - 1)
{
/* Do not interrupt on completion of this packet */
flag = 0x60000000;
- dev->tbusy = 0;
+ LMC_XMITTER_FREE(dev);
}
else
{
/* This generates an interrupt on completion of this packet */
flag = 0xe0000000;
sc->lmc_txfull = 1;
- dev->tbusy = 1;
+ LMC_XMITTER_BUSY(dev);
}
+#else
+ flag = LMC_TDES_INTERRUPT_ON_COMPLETION;
- if ((entry == LMC_TXDESCS - 1))
- {
- flag |= 0xe2000000;
- dev->tbusy = 1;
+ if (sc->lmc_next_tx - sc->lmc_taint_tx >= LMC_TXDESCS - 1)
+ { /* ring full, go busy */
+ sc->lmc_txfull = 1;
+ LMC_XMITTER_BUSY(dev);
+ sc->stats.tx_tbusy1++ ;
+ LMC_EVENT_LOG(LMC_EVENT_TBUSY1, entry, 0);
}
- /* don't pad small packets either */
- sc->lmc_txring[entry].length = (skb->len) | flag | sc->TxDescriptControlInit;
+#endif
- /* Done above through TxDescControlInit */
- /*
- sc->lmc_txring[entry].length = (skb->len) | flag | 0x00800000;
- if(sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16){
- sc->lmc_txring[entry].length |= 0x04000000;
- }
- */
+
+ if (entry == LMC_TXDESCS - 1) /* last descriptor in ring */
+ flag |= LMC_TDES_END_OF_RING; /* flag as such for Tulip */
+
+ /* don't pad small packets either */
+ flag = sc->lmc_txring[entry].length = cpu_to_le32((skb->len) | flag |
+ sc->TxDescriptControlInit);
/* set the transmit timeout flag to be checked in
* the watchdog timer handler. -baz
sc->stats.tx_NoCompleteCnt++;
sc->lmc_next_tx++;
- /* give ownership to the chip */
- sc->lmc_txring[entry].status = 0x80000000;
+ sc->lmc_txring[entry].status = cpu_to_le32(0x80000000);
/* send now! */
- LMC_CSR_WRITE (sc, csr_txpoll, 0);
+ LMC_CSR_WRITE (sc, csr_txpoll, cpu_to_le32(0));
dev->trans_start = jiffies;
+#if LINUX_VERSION_CODE < 0x20363
lmc_start_xmit_bug_out:
+#endif
+
+ LMC_SPIN_UNLOCK_IRQRESTORE(sc);
- spin_unlock_irqrestore(&sc->lmc_lock, flags);
+ lmc_trace(dev, "lmc_start_xmit_out");
return ret;
}
-static int lmc_rx (struct device *dev) /*fold00*/
+static int lmc_rx (struct net_device *dev) /*fold00*/
{
lmc_softc_t *sc;
int i;
struct sk_buff *skb, *nsb;
u16 len;
- sc = dev->priv;
+ lmc_trace(dev, "lmc_rx in");
- if ( ! (dev->flags & IFF_UP))
- return 1;
+ sc = dev->priv;
- rxIntLoopCnt = 0; /* debug -baz */
+ rxIntLoopCnt = 0;
i = sc->lmc_next_rx % LMC_RXDESCS;
next_rx = sc->lmc_next_rx;
- while (((stat = sc->lmc_rxring[i].status) & LMC_RDES_OWN_BIT) != DESC_OWNED_BY_DC21X4)
+ while (((stat = le32_to_cpu(sc->lmc_rxring[i].status)) & LMC_RDES_OWN_BIT) != DESC_OWNED_BY_DC21X4)
{
rxIntLoopCnt++; /* debug -baz */
- LMC_EVENT_LOG(LMC_EVENT_RCVINT, stat, 0);
-
+ len = ((stat & LMC_RDES_FRAME_LENGTH) >> RDES_FRAME_LENGTH_BIT_NUMBER);
if ((stat & 0x0300) != 0x0300) { /* Check first segment and last segment */
if ((stat & 0x0000ffff) != 0x7fff) {
/* Oversized frame */
sc->stats.rx_length_errors++;
+ sc->stats.rx_errors++;
goto skip_packet;
}
}
- if(stat & 0x00000008){ /* Catch a dribbling bit error */
+ if(stat & 0x00000004){ /* Catch a dribbling bit error */
sc->stats.rx_errors++;
sc->stats.rx_frame_errors++;
goto skip_packet;
}
- if(stat & 0x00000004){ /* Catch a CRC error by the Xilinx */
+ if(stat & 0x00000008){ /* Catch a CRC error by the Xilinx */
sc->stats.rx_errors++;
sc->stats.rx_crc_errors++;
goto skip_packet;
}
- len = ((stat & LMC_RDES_FRAME_LENGTH) >> RDES_FRAME_LENGTH_BIT_NUMBER);
- if (len > PKT_BUF_SZ){
+ if (len > LMC_PKT_BUF_SZ){
+ sc->stats.rx_errors++;
sc->stats.rx_length_errors++;
localLengthErrCnt++;
goto skip_packet;
if (len < sc->lmc_crcSize + 2) {
sc->stats.rx_length_errors++;
sc->stats.rx_SmallPktCnt++;
+ sc->stats.rx_errors++;
localLengthErrCnt++;
goto skip_packet;
}
*/
if(skb == 0x0){
- nsb = dev_alloc_skb (PKT_BUF_SZ + 2);
+ nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
if (nsb) {
LMC_SKB_FREE(nsb, 1);
sc->lmc_rxq[i] = nsb;
nsb->dev = dev;
+#if LINUX_VERSION_CODE >= 0x20363
+ sc->lmc_rxring[i].buffer1 = pci_map_single(sc->pdev, nsb->tail, LMC_PKT_BUF_SZ+2, PCI_DMA_FROMDEVICE);
+#else
sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
+#endif
}
+ sc->failed_recv_alloc = 1;
goto skip_packet;
}
dev->last_rx = jiffies;
sc->stats.rx_packets++;
+#if LINUX_VERSION_CODE >= 0x20363
+#ifdef LMC_PACKET_LOG
+ pci_dma_sync_single(sc->pdev, sc->lmc_rxring[i].buffer1, len, PCI_DMA_FROMDEVICE);
+#endif
+#endif
LMC_CONSOLE_LOG("recv", skb->data, len);
/*
* them into a new buffer??
*/
- if(len > (3*LMC_MTU)/4){
+ if(len > (LMC_MTU - (LMC_MTU>>2))){ /* len > LMC_MTU * 0.75 */
/*
* If it's a large packet don't copy it just hand it up
*/
give_it_anyways:
sc->lmc_rxq[i] = 0x0;
- sc->lmc_rxring[i].buffer1 = 0x0;
+ sc->lmc_rxring[i].buffer1 = cpu_to_le32(0x0);
skb_put (skb, len);
- skb->protocol=htons(ETH_P_WAN_PPP);
+ skb->protocol = lmc_proto_type(sc, skb);
+ skb->protocol = htons(ETH_P_WAN_PPP);
skb->mac.raw = skb->data;
- skb->nh.raw = skb->data;
+// skb->nh.raw = skb->data;
skb->dev = dev;
- netif_rx(skb);
+#if LINUX_VERSION_CODE >= 0x20363 /* 2.4 */
+ pci_unmap_single(sc->pdev, sc->lmc_rxring[i].buffer1, len, PCI_DMA_FROMDEVICE);
+#endif
+ lmc_proto_netif(sc, skb);
/*
* This skb will be destroyed by the upper layers, make a new one
*/
- nsb = dev_alloc_skb (PKT_BUF_SZ + 2);
+ nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
if (nsb) {
LMC_SKB_FREE(nsb, 1);
sc->lmc_rxq[i] = nsb;
nsb->dev = dev;
+#if LINUX_VERSION_CODE >= 0x20363
+ sc->lmc_rxring[i].buffer1 = pci_map_single(sc->pdev, nsb->tail, LMC_PKT_BUF_SZ+2, PCI_DMA_FROMDEVICE);
+#else
sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
+#endif
/* Transfered to 21140 below */
}
else {
* again. (once a second)
*/
sc->stats.rx_BuffAllocErr++;
+ sc->failed_recv_alloc = 1;
goto skip_out_of_mem;
-
}
-
}
else {
nsb = dev_alloc_skb(len);
goto give_it_anyways;
}
memcpy(skb_put(nsb, len), skb->data, len);
- nsb->protocol=htons(ETH_P_WAN_PPP);
+
+ nsb->protocol = lmc_proto_type(sc, skb);
nsb->mac.raw = nsb->data;
- nsb->nh.raw = nsb->data;
+ // nsb->nh.raw = nsb->data;
nsb->dev = dev;
- netif_rx(nsb);
+#if LINUX_VERSION_CODE >= 0x20363 /* 2.4 */
+ pci_unmap_single(sc->pdev, sc->lmc_rxring[i].buffer1, len, PCI_DMA_FROMDEVICE);
+#endif
+ lmc_proto_netif(sc, nsb);
}
skip_packet:
- sc->lmc_rxring[i].status = DESC_OWNED_BY_DC21X4;
+ sc->lmc_rxring[i].status = cpu_to_le32(DESC_OWNED_BY_DC21X4);
sc->lmc_next_rx++;
i = sc->lmc_next_rx % LMC_RXDESCS;
break;
}
- /* detect condition for LMC1000 where DSU cable attaches and fills
- * descriptors with bogus packets
- */
- if (localLengthErrCnt > LMC_RXDESCS - 3) {
- sc->stats.rx_BadPktSurgeCnt++;
- LMC_EVENT_LOG(LMC_EVENT_BADPKTSURGE,
- localLengthErrCnt,
- sc->stats.rx_BadPktSurgeCnt);
- }
-
/* save max count of receive descriptors serviced */
if (rxIntLoopCnt > sc->stats.rxIntLoopCnt) {
sc->stats.rxIntLoopCnt = rxIntLoopCnt; /* debug -baz */
}
-#ifdef DEBUG
- if (rxIntLoopCnt == 0)
- {
- for (i = 0; i < LMC_RXDESCS; i++)
- {
- if ((sc->lmc_rxring[i].status & LMC_RDES_OWN_BIT)
- != DESC_OWNED_BY_DC21X4)
- {
- rxIntLoopCnt++;
- }
- }
- LMC_EVENT_LOG(LMC_EVENT_RCVEND, rxIntLoopCnt, 0);
- }
-#endif
-
skip_out_of_mem:
+ lmc_trace(dev, "lmc_rx out");
+
return 0;
}
-static struct enet_statistics *lmc_get_stats (struct device *dev) /*fold00*/
+static struct enet_statistics *lmc_get_stats (struct net_device *dev) /*fold00*/
{
lmc_softc_t *sc;
LMC_SPIN_FLAGS;
+ lmc_trace(dev, "lmc_get_stats in");
+
sc = dev->priv;
- spin_lock_irqsave(&sc->lmc_lock, flags);
+ LMC_SPIN_LOCK_IRQSAVE(sc);
+
+ sc->stats.rx_missed_errors += le32_to_cpu(LMC_CSR_READ (sc, csr_missed_frames)) & 0xffff;
- if (dev->start)
- sc->stats.rx_missed_errors += LMC_CSR_READ (sc, csr_missed_frames) & 0xffff;
+ LMC_SPIN_UNLOCK_IRQRESTORE(sc);
- spin_unlock_irqrestore(&sc->lmc_lock, flags);
+ lmc_trace(dev, "lmc_get_stats out");
return (struct enet_statistics *) &sc->stats;
}
void cleanup_module (void) /*fold00*/
{
- struct device *dev, *next;
+ struct net_device *dev, *next;
+ lmc_softc_t *sc;
/* we have no pointer to our devices, since they are all dynamically
* allocated. So, here we loop through all the network devices
/* close the syncppp stuff, and release irq. Close is run on unreg net */
lmc_close (dev);
- sppp_detach (dev);
+
+ sc = dev->priv;
+
+ printk ("%s: detaching from protocol...\n", dev->name);
+ if (sc != NULL)
+ lmc_proto_detach(sc);
- /* Remove the device from the linked list */
unregister_netdev (dev);
/* Let go of the io region */;
release_region (dev->base_addr, LMC_REG_RANGE);
/* free our allocated structures. */
+#if LINUX_VERSION_CODE >= 0x20363
+ pci_free_consistent(sc->pdev, sizeof(lmc_softc_t), sc, sc->sc_dma_handle);
+#else
kfree (dev->priv);
+#endif
dev->priv = NULL;
- kfree ((struct ppp_device *) dev);
+ kfree (dev);
dev = NULL;
}
int command = (0xf6 << 10) | (devaddr << 5) | regno;
int retval = 0;
+ lmc_trace(sc->lmc_device, "lmc_mii_readreg in");
+
LMC_MII_SYNC (sc);
+ lmc_trace(sc->lmc_device, "lmc_mii_readreg: done sync");
+
for (i = 15; i >= 0; i--)
{
int dataval = (command & (1 << i)) ? 0x20000 : 0;
- LMC_CSR_WRITE (sc, csr_9, dataval);
+ LMC_CSR_WRITE (sc, csr_9, cpu_to_le32(dataval));
lmc_delay ();
/* __SLOW_DOWN_IO; */
- LMC_CSR_WRITE (sc, csr_9, dataval | 0x10000);
+ LMC_CSR_WRITE (sc, csr_9, cpu_to_le32(dataval | 0x10000));
lmc_delay ();
/* __SLOW_DOWN_IO; */
}
+ lmc_trace(sc->lmc_device, "lmc_mii_readreg: done1");
+
for (i = 19; i > 0; i--)
{
- LMC_CSR_WRITE (sc, csr_9, 0x40000);
+ LMC_CSR_WRITE (sc, csr_9, cpu_to_le32(0x40000));
lmc_delay ();
/* __SLOW_DOWN_IO; */
- retval = (retval << 1) | ((LMC_CSR_READ (sc, csr_9) & 0x80000) ? 1 : 0);
- LMC_CSR_WRITE (sc, csr_9, 0x40000 | 0x10000);
+ retval = (retval << 1) | (le32_to_cpu((LMC_CSR_READ(sc, csr_9)) & 0x80000) ? 1 : 0);
+ LMC_CSR_WRITE (sc, csr_9, cpu_to_le32(0x40000 | 0x10000));
lmc_delay ();
/* __SLOW_DOWN_IO; */
}
+ lmc_trace(sc->lmc_device, "lmc_mii_readreg out");
+
return (retval >> 1) & 0xffff;
}
-void lmc_mii_writereg (lmc_softc_t * const sc, unsigned devaddr, /*fold00*/
- unsigned regno, unsigned data)
+void lmc_mii_writereg (lmc_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data) /*fold00*/
{
int i = 32;
int command = (0x5002 << 16) | (devaddr << 23) | (regno << 18) | data;
+ lmc_trace(sc->lmc_device, "lmc_mii_writereg in");
+
LMC_MII_SYNC (sc);
i = 31;
else
datav = 0x00000;
- LMC_CSR_WRITE (sc, csr_9, datav);
+ LMC_CSR_WRITE (sc, csr_9, cpu_to_le32(datav));
lmc_delay ();
/* __SLOW_DOWN_IO; */
- LMC_CSR_WRITE (sc, csr_9, (datav | 0x10000));
+ LMC_CSR_WRITE (sc, csr_9, cpu_to_le32(datav | 0x10000));
lmc_delay ();
/* __SLOW_DOWN_IO; */
i--;
i = 2;
while (i > 0)
{
- LMC_CSR_WRITE (sc, csr_9, 0x40000);
+ LMC_CSR_WRITE (sc, csr_9, cpu_to_le32(0x40000));
lmc_delay ();
/* __SLOW_DOWN_IO; */
- LMC_CSR_WRITE (sc, csr_9, 0x50000);
+ LMC_CSR_WRITE (sc, csr_9, cpu_to_le32(0x50000));
lmc_delay ();
/* __SLOW_DOWN_IO; */
i--;
}
+
+ lmc_trace(sc->lmc_device, "lmc_mii_writereg out");
}
static void lmc_softreset (lmc_softc_t * const sc) /*fold00*/
{
int i;
+ lmc_trace(sc->lmc_device, "lmc_softreset in");
+
/* Initialize the recieve rings and buffers. */
sc->lmc_txfull = 0;
sc->lmc_next_rx = 0;
if (sc->lmc_rxq[i] == NULL)
{
- skb = dev_alloc_skb (PKT_BUF_SZ + 2);
- sc->lmc_rxq[i] = skb;
+ skb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
+ if(skb == NULL){
+ printk(KERN_WARNING "%s: Failed to allocate receiver ring, will try again\n", sc->name);
+ sc->failed_ring = 1;
+ break;
+ }
+ else{
+ sc->lmc_rxq[i] = skb;
+ }
}
else
{
LMC_SKB_FREE(skb, 1);
/* owned by 21140 */
- sc->lmc_rxring[i].status = 0x80000000;
+ sc->lmc_rxring[i].status = cpu_to_le32(0x80000000);
/* used to be PKT_BUF_SZ now uses skb since we loose some to head room */
- sc->lmc_rxring[i].length = skb->end - skb->data;
+ sc->lmc_rxring[i].length = cpu_to_le32(skb->end - skb->data);
/* use to be tail which is dumb since you're thinking why write
* to the end of the packj,et but since there's nothing there tail == data
*/
+#if LINUX_VERSION_CODE >= 0x20363
+ sc->lmc_rxring[i].buffer1 = pci_map_single(sc->pdev, skb->data, sc->lmc_rxring[i].length, PCI_DMA_FROMDEVICE);
+ sc->lmc_rxring[i].buffer2 = (u32) &(sc->sc_dma->lmc_rxring[i + 1]);
+#else
sc->lmc_rxring[i].buffer1 = virt_to_bus (skb->data);
+ sc->lmc_rxring[i].buffer2 = virt_to_bus (&sc->lmc_rxring[i+1]);
- /* This is fair since the structure is static and we have the next address */
- sc->lmc_rxring[i].buffer2 = virt_to_bus (&sc->lmc_rxring[i + 1]);
+#endif
}
/*
* Sets end of ring
*/
- sc->lmc_rxring[i - 1].length |= 0x02000000; /* Set end of buffers flag */
+ sc->lmc_rxring[i - 1].length |= cpu_to_le32(0x02000000); /* Set end of buffers flag */
+#if LINUX_VERSION_CODE >= 0x20363
+ sc->lmc_rxring[i - 1].buffer2 = (u32) &sc->sc_dma->lmc_rxring[0]; /* Point back to the start */
+ LMC_CSR_WRITE (sc, csr_rxlist, (u32) &sc->sc_dma->lmc_rxring); /* write base address */
+#else
sc->lmc_rxring[i - 1].buffer2 = virt_to_bus (&sc->lmc_rxring[0]); /* Point back to the start */
LMC_CSR_WRITE (sc, csr_rxlist, virt_to_bus (sc->lmc_rxring)); /* write base address */
+#endif
/* Initialize the transmit rings and buffers */
for (i = 0; i < LMC_TXDESCS; i++)
{
+ if (sc->lmc_txq[i] != NULL){ /* have buffer */
+#if LINUX_VERSION_CODE >= 0x20363 /* 2.4 */
+ pci_unmap_single(sc->pdev, sc->lmc_txring[i].buffer1, sc->lmc_txq[i]->len, PCI_DMA_TODEVICE);
+#endif
+ LMC_DEV_KFREE_SKB(sc->lmc_txq[i]); /* free it */
+ sc->stats.tx_dropped++; /* We just dropped a packet */
+ }
sc->lmc_txq[i] = 0;
- sc->lmc_txring[i].status = 0x00000000;
+ sc->lmc_txring[i].status = cpu_to_le32(0x00000000);
+#if LINUX_VERSION_CODE >= 0x20363
+ sc->lmc_txring[i].buffer2 = (u32) &(sc->sc_dma->lmc_txring[i + 1]);
+#else
sc->lmc_txring[i].buffer2 = virt_to_bus (&sc->lmc_txring[i + 1]);
+#endif
}
+
+#if LINUX_VERSION_CODE >= 0x20363
+ sc->lmc_txring[i - 1].buffer2 = (u32) &sc->sc_dma->lmc_txring[0]; /* Point back to the start */
+ LMC_CSR_WRITE (sc, csr_txlist, (u32) &sc->sc_dma->lmc_txring); /* write base address */
+#else
sc->lmc_txring[i - 1].buffer2 = virt_to_bus (&sc->lmc_txring[0]);
LMC_CSR_WRITE (sc, csr_txlist, virt_to_bus (sc->lmc_txring));
+#endif
+
+ lmc_trace(sc->lmc_device, "lmc_softreset out");
}
-static int lmc_set_config(struct device *dev, struct ifmap *map) /*fold00*/
+static int lmc_set_config(struct net_device *dev, struct ifmap *map) /*fold00*/
{
+ lmc_trace(dev, "lmc_set_config in");
+ lmc_trace(dev, "lmc_set_config out");
return -EOPNOTSUPP;
}
-void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits)
+void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits) /*fold00*/
{
+ lmc_trace(sc->lmc_device, "lmc_gpio_mkinput in");
sc->lmc_gpio_io &= ~bits;
- LMC_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET | (sc->lmc_gpio_io));
+ LMC_CSR_WRITE(sc, csr_gp, cpu_to_le32(TULIP_GP_PINSET | (sc->lmc_gpio_io)));
+ lmc_trace(sc->lmc_device, "lmc_gpio_mkinput out");
}
-void lmc_gpio_mkoutput(lmc_softc_t * const sc, u_int32_t bits)
+void lmc_gpio_mkoutput(lmc_softc_t * const sc, u_int32_t bits) /*fold00*/
{
+ lmc_trace(sc->lmc_device, "lmc_gpio_mkoutput in");
sc->lmc_gpio_io |= bits;
- LMC_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET | (sc->lmc_gpio_io));
+ LMC_CSR_WRITE(sc, csr_gp, cpu_to_le32(TULIP_GP_PINSET | (sc->lmc_gpio_io)));
+ lmc_trace(sc->lmc_device, "lmc_gpio_mkoutput out");
}
-void lmc_led_on(lmc_softc_t * const sc, u_int32_t led)
+void lmc_led_on(lmc_softc_t * const sc, u_int32_t led) /*fold00*/
{
- if((~sc->lmc_miireg16) & led) /* Already on! */
+ lmc_trace(sc->lmc_device, "lmc_led_on in");
+ if((~sc->lmc_miireg16) & led){ /* Already on! */
+ lmc_trace(sc->lmc_device, "lmc_led_on aon out");
return;
+ }
sc->lmc_miireg16 &= ~led;
lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+ lmc_trace(sc->lmc_device, "lmc_led_on out");
}
-void lmc_led_off(lmc_softc_t * const sc, u_int32_t led)
+void lmc_led_off(lmc_softc_t * const sc, u_int32_t led) /*fold00*/
{
- if(sc->lmc_miireg16 & led) /* Already set don't do anything */
+ lmc_trace(sc->lmc_device, "lmc_led_off in");
+ if(sc->lmc_miireg16 & led){ /* Already set don't do anything */
+ lmc_trace(sc->lmc_device, "lmc_led_off aoff out");
return;
+ }
sc->lmc_miireg16 |= led;
lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+ lmc_trace(sc->lmc_device, "lmc_led_off out");
}
-static void lmc_reset(lmc_softc_t * const sc)
+static void lmc_reset(lmc_softc_t * const sc) /*fold00*/
{
+ lmc_trace(sc->lmc_device, "lmc_reset in");
sc->lmc_miireg16 |= LMC_MII16_FIFO_RESET;
lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
/*
* make some of the GPIO pins be outputs
*/
- lmc_gpio_mkoutput(sc, LMC_GEP_DP | LMC_GEP_RESET);
+ lmc_gpio_mkoutput(sc, LMC_GEP_RESET);
/*
- * drive DP and RESET low to force configuration. This also forces
+ * RESET low to force state reset. This also forces
* the transmitter clock to be internal, but we expect to reset
* that later anyway.
*/
- sc->lmc_gpio &= ~(LMC_GEP_DP | LMC_GEP_RESET);
- LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+ sc->lmc_gpio &= ~(LMC_GEP_RESET);
+ LMC_CSR_WRITE(sc, csr_gp, cpu_to_le32(sc->lmc_gpio));
/*
* hold for more than 10 microseconds
/*
* stop driving Xilinx-related signals
*/
- lmc_gpio_mkinput(sc, LMC_GEP_DP | LMC_GEP_RESET);
-
- /*
- * busy wait for the chip to reset
- */
- while ((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_DP) == 0)
- ;
+ lmc_gpio_mkinput(sc, LMC_GEP_RESET);
/*
* Call media specific init routine
sc->lmc_media->init(sc);
sc->stats.resetCount++;
+ lmc_trace(sc->lmc_device, "lmc_reset out");
}
-static void lmc_dec_reset(lmc_softc_t * const sc)
+static void lmc_dec_reset(lmc_softc_t * const sc) /*fold00*/
{
u_int32_t val;
+ lmc_trace(sc->lmc_device, "lmc_dec_reset in");
/*
* disable all interrupts
*/
sc->lmc_intrmask = 0;
- LMC_CSR_WRITE(sc, csr_intr, sc->lmc_intrmask);
+ LMC_CSR_WRITE(sc, csr_intr, cpu_to_le32(sc->lmc_intrmask));
/*
* Reset the chip with a software reset command.
* 33MHz that comes to two microseconds but wait a
* bit longer anyways)
*/
- LMC_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
+ LMC_CSR_WRITE(sc, csr_busmode, cpu_to_le32(TULIP_BUSMODE_SWRESET));
udelay(25);
- sc->lmc_cmdmode = LMC_CSR_READ(sc, csr_command);
+#ifdef __sparc__
+ sc->lmc_busmode = LMC_CSR_READ(sc, cpu_to_le32(csr_busmode));
+ sc->lmc_busmode = 0x00000000;
+ //sc->lmc_busmode = 0x00100000;
+ sc->lmc_busmode &= ~TULIP_BUSMODE_SWRESET;
+ LMC_CSR_WRITE(sc, csr_busmode, cpu_to_le32(sc->lmc_busmode));
+#endif
+ sc->lmc_cmdmode = le32_to_cpu(LMC_CSR_READ(sc, csr_command));
/*
* We want:
| TULIP_CMD_TXTHRSHLDCTL
);
- LMC_CSR_WRITE(sc, csr_command, sc->lmc_cmdmode);
+ LMC_CSR_WRITE(sc, csr_command, cpu_to_le32(sc->lmc_cmdmode));
/*
* disable receiver watchdog and transmit jabber
*/
- val = LMC_CSR_READ(sc, csr_sia_general);
+ val = le32_to_cpu(LMC_CSR_READ(sc, csr_sia_general));
val |= (TULIP_WATCHDOG_TXDISABLE | TULIP_WATCHDOG_RXDISABLE);
- LMC_CSR_WRITE(sc, csr_sia_general, val);
+ LMC_CSR_WRITE(sc, csr_sia_general, cpu_to_le32(val));
+ lmc_trace(sc->lmc_device, "lmc_dec_reset out");
}
-static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base,
+static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, /*fold00*/
size_t csr_size)
{
+ lmc_trace(sc->lmc_device, "lmc_initcsrs in");
sc->lmc_csrs.csr_busmode = csr_base + 0 * csr_size;
sc->lmc_csrs.csr_txpoll = csr_base + 1 * csr_size;
sc->lmc_csrs.csr_rxpoll = csr_base + 2 * csr_size;
sc->lmc_csrs.csr_13 = csr_base + 13 * csr_size;
sc->lmc_csrs.csr_14 = csr_base + 14 * csr_size;
sc->lmc_csrs.csr_15 = csr_base + 15 * csr_size;
+ lmc_trace(sc->lmc_device, "lmc_initcsrs out");
+}
+
+#if LINUX_VERSION_CODE >= 0x20363
+static void lmc_driver_timeout(struct net_device *dev) { /*fold00*/
+ lmc_softc_t *sc;
+ u32 csr6;
+ LMC_SPIN_FLAGS;
+
+ lmc_trace(dev, "lmc_driver_timeout in");
+
+ sc = dev->priv;
+
+ LMC_SPIN_LOCK_IRQSAVE(sc);
+
+ printk("%s: Xmitter busy|\n", dev->name);
+
+ sc->stats.tx_tbusy_calls++ ;
+ if (jiffies - dev->trans_start < TX_TIMEOUT) {
+ goto bug_out;
+ }
+
+ /*
+ * Chip seems to have locked up
+ * Reset it
+ * This whips out all our decriptor
+ * table and starts from scartch
+ */
+
+ lmc_running_reset (dev);
+
+ /* restart the tx processes */
+ csr6 = le32_to_cpu(LMC_CSR_READ (sc, csr_command));
+ LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(csr6 | 0x0002));
+ LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(csr6 | 0x2002));
+
+ /* immediate transmit */
+ LMC_CSR_WRITE (sc, csr_txpoll, cpu_to_le32(0));
+
+ sc->stats.tx_errors++;
+ sc->stats.tx_ProcTimeout++; /* -baz */
+
+ dev->trans_start = jiffies;
+
+bug_out:
+
+ LMC_SPIN_UNLOCK_IRQRESTORE(sc);
+
+ lmc_trace(dev, "lmc_driver_timout out");
+
+
}
+int lmc_setup(void) { /*fold00*/
+ return lmc_probe(NULL);
+}
+
+#endif
-/* $Id: lmc_media.c,v 1.9 2000/01/21 13:29:49 asj Exp $ */
+/* $Id: lmc_media.c,v 1.16 2000/06/06 08:32:14 asj Exp $ */
#include <linux/version.h>
#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <asm/segment.h>
-#include <asm/smp.h>
+//#include <asm/smp.h>
#if LINUX_VERSION_CODE < 0x20155
#include <linux/bios32.h>
#if LINUX_VERSION_CODE >= 0x20200
#include <asm/uaccess.h>
-#include <asm/spinlock.h>
+//#include <asm/spinlock.h>
#endif
-#include "lmc.h"
#include "lmc_ver.h"
+#include "lmc.h"
#include "lmc_var.h"
#include "lmc_ioctl.h"
+#include "lmc_debug.h"
#define CONFIG_LMC_IGNORE_HARDWARE_HANDSHAKE 1
*/
/*
- * For lack of a better place, put the T1 cable stuff here.
+ * For lack of a better place, put the SSI cable stuff here.
*/
char *lmc_t1_cables[] = {
"V.10/RS423", "EIA530A", "reserved", "X.21", "V.35",
static void lmc_t1_set_crc_length (lmc_softc_t * const, int);
static void lmc_t1_set_clock (lmc_softc_t * const, int);
static void lmc_t1_watchdog (lmc_softc_t * const);
+static int lmc_t1_ioctl (lmc_softc_t * const, void *);
+static int lmc_t1_got_interupt (lmc_softc_t * const);
static void lmc_dummy_set_1 (lmc_softc_t * const, int);
static void lmc_dummy_set2_1 (lmc_softc_t * const, lmc_ctl_t *);
+static int lmc_dummy_ioctl (lmc_softc_t * const, void *);
+static int lmc_dummy_got_interupt (lmc_softc_t * const);
static inline void write_av9110_bit (lmc_softc_t *, int);
-static void write_av9110 (lmc_softc_t *, u_int32_t, u_int32_t, u_int32_t,
+static void write_av9110 (lmc_softc_t *, u_int32_t, u_int32_t, u_int32_t, /*fold00*/
u_int32_t, u_int32_t);
lmc_media_t lmc_ds3_media = {
lmc_dummy_set_1, /* set link status */
lmc_ds3_set_crc_length, /* set CRC length */
lmc_dummy_set_1, /* set T1 or E1 circuit type */
- lmc_ds3_watchdog
+ lmc_ds3_watchdog,
+ lmc_dummy_ioctl,
+ lmc_dummy_got_interupt,
};
lmc_media_t lmc_hssi_media = {
lmc_hssi_set_link_status, /* set link status */
lmc_hssi_set_crc_length, /* set CRC length */
lmc_dummy_set_1, /* set T1 or E1 circuit type */
- lmc_hssi_watchdog
+ lmc_hssi_watchdog,
+ lmc_dummy_ioctl,
+ lmc_dummy_got_interupt,
+
};
lmc_media_t lmc_ssi_media = { lmc_ssi_init, /* special media init stuff */
lmc_ssi_set_link_status, /* set link status */
lmc_ssi_set_crc_length, /* set CRC length */
lmc_dummy_set_1, /* set T1 or E1 circuit type */
- lmc_ssi_watchdog
+ lmc_ssi_watchdog,
+ lmc_dummy_ioctl,
+ lmc_dummy_got_interupt,
+
};
lmc_media_t lmc_t1_media = {
lmc_dummy_set_1, /* set link status */
lmc_t1_set_crc_length, /* set CRC length */
lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */
- lmc_t1_watchdog
+ lmc_t1_watchdog,
+ lmc_t1_ioctl,
+ lmc_t1_got_interupt,
+
};
-static void
-lmc_dummy_set_1 (lmc_softc_t * const sc, int a)
+static void lmc_dummy_set_1 (lmc_softc_t * const sc, int a) /*fold00*/
{
}
-static void
-lmc_dummy_set2_1 (lmc_softc_t * const sc, lmc_ctl_t * a)
+static void lmc_dummy_set2_1 (lmc_softc_t * const sc, lmc_ctl_t * a) /*fold00*/
{
}
+static int lmc_dummy_ioctl (lmc_softc_t * const sc, void *d) /*fold00*/
+{
+ return -ENOSYS;
+}
+
+static int lmc_dummy_got_interupt (lmc_softc_t * const sc) /*fold00*/
+{
+ return -ENOSYS;
+}
+
+
+
/*
* HSSI methods
*/
static void
-lmc_hssi_init (lmc_softc_t * const sc)
+lmc_hssi_init (lmc_softc_t * const sc) /*fold00*/
{
sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC5200;
}
static void
-lmc_hssi_default (lmc_softc_t * const sc)
+lmc_hssi_default (lmc_softc_t * const sc) /*fold00*/
{
sc->lmc_miireg16 = LMC_MII16_LED_ALL;
* always reset the card if needed.
*/
static void
-lmc_hssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+lmc_hssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) /*fold00*/
{
if (ctl == NULL)
{
* 1 == internal, 0 == external
*/
static void
-lmc_hssi_set_clock (lmc_softc_t * const sc, int ie)
+lmc_hssi_set_clock (lmc_softc_t * const sc, int ie) /*fold00*/
{
+ int old;
+ old = sc->ictl.clock_source;
if (ie == LMC_CTL_CLOCK_SOURCE_EXT)
{
sc->lmc_gpio |= LMC_GEP_HSSI_CLOCK;
LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT;
- printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS);
+ if(old != ie)
+ printk (KERN_INFO "%s: clock external\n", sc->name);
}
else
{
sc->lmc_gpio &= ~(LMC_GEP_HSSI_CLOCK);
LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
- printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
+ if(old != ie)
+ printk (KERN_INFO "%s: clock internal\n", sc->name);
}
}
* 0 == link is down, 1 == link is up.
*/
static int
-lmc_hssi_get_link_status (lmc_softc_t * const sc)
+lmc_hssi_get_link_status (lmc_softc_t * const sc) /*fold00*/
{
/*
* We're using the same code as SSI since
}
static void
-lmc_hssi_set_link_status (lmc_softc_t * const sc, int state)
+lmc_hssi_set_link_status (lmc_softc_t * const sc, int state) /*fold00*/
{
if (state == LMC_LINK_UP)
sc->lmc_miireg16 |= LMC_MII16_HSSI_TA;
* 0 == 16bit, 1 == 32bit
*/
static void
-lmc_hssi_set_crc_length (lmc_softc_t * const sc, int state)
+lmc_hssi_set_crc_length (lmc_softc_t * const sc, int state) /*FOLD00*/
{
if (state == LMC_CTL_CRC_LENGTH_32)
{
/* 32 bit */
sc->lmc_miireg16 |= LMC_MII16_HSSI_CRC;
sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32;
+ sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_4;
}
else
{
/* 16 bit */
sc->lmc_miireg16 &= ~LMC_MII16_HSSI_CRC;
sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16;
+ sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_2;
}
lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
}
static void
-lmc_hssi_watchdog (lmc_softc_t * const sc)
+lmc_hssi_watchdog (lmc_softc_t * const sc) /*fold00*/
{
/* HSSI is blank */
}
* Set cable length
*/
static void
-lmc_ds3_set_100ft (lmc_softc_t * const sc, int ie)
+lmc_ds3_set_100ft (lmc_softc_t * const sc, int ie) /*fold00*/
{
if (ie == LMC_CTL_CABLE_LENGTH_GT_100FT)
{
}
static void
-lmc_ds3_default (lmc_softc_t * const sc)
+lmc_ds3_default (lmc_softc_t * const sc) /*fold00*/
{
sc->lmc_miireg16 = LMC_MII16_LED_ALL;
* always reset the card if needed.
*/
static void
-lmc_ds3_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+lmc_ds3_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) /*fold00*/
{
if (ctl == NULL)
{
}
static void
-lmc_ds3_init (lmc_softc_t * const sc)
+lmc_ds3_init (lmc_softc_t * const sc) /*fold00*/
{
int i;
* 1 == DS3 payload scrambled, 0 == not scrambled
*/
static void
-lmc_ds3_set_scram (lmc_softc_t * const sc, int ie)
+lmc_ds3_set_scram (lmc_softc_t * const sc, int ie) /*fold00*/
{
if (ie == LMC_CTL_ON)
{
* 0 == link is down, 1 == link is up.
*/
static int
-lmc_ds3_get_link_status (lmc_softc_t * const sc)
+lmc_ds3_get_link_status (lmc_softc_t * const sc) /*fold00*/
{
u_int16_t link_status, link_status_11;
int ret = 1;
* 0 == 16bit, 1 == 32bit
*/
static void
-lmc_ds3_set_crc_length (lmc_softc_t * const sc, int state)
+lmc_ds3_set_crc_length (lmc_softc_t * const sc, int state) /*FOLD00*/
{
if (state == LMC_CTL_CRC_LENGTH_32)
{
/* 32 bit */
sc->lmc_miireg16 |= LMC_MII16_DS3_CRC;
sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32;
+ sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_4;
}
else
{
/* 16 bit */
sc->lmc_miireg16 &= ~LMC_MII16_DS3_CRC;
sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16;
+ sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_2;
}
lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
}
static void
-lmc_ds3_watchdog (lmc_softc_t * const sc)
+lmc_ds3_watchdog (lmc_softc_t * const sc) /*fold00*/
{
- sc->lmc_miireg16 = lmc_mii_readreg (sc, 0, 16);
- if (sc->lmc_miireg16 & 0x0018) {
- printk ("%s: AIS Recieved\n", sc->name);
- lmc_led_on (sc, LMC_DS3_LED1 | LMC_DS3_LED2);
- }
- else{
- }
+
}
*/
static void
-lmc_ssi_init (lmc_softc_t * const sc)
+lmc_ssi_init (lmc_softc_t * const sc) /*fold00*/
{
u_int16_t mii17;
int cable;
}
static void
-lmc_ssi_default (lmc_softc_t * const sc)
+lmc_ssi_default (lmc_softc_t * const sc) /*fold00*/
{
sc->lmc_miireg16 = LMC_MII16_LED_ALL;
* always reset the card if needed.
*/
static void
-lmc_ssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+lmc_ssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) /*fold00*/
{
if (ctl == NULL)
{
* 1 == internal, 0 == external
*/
static void
-lmc_ssi_set_clock (lmc_softc_t * const sc, int ie)
+lmc_ssi_set_clock (lmc_softc_t * const sc, int ie) /*fold00*/
{
+ int old;
+ old = ie;
if (ie == LMC_CTL_CLOCK_SOURCE_EXT)
{
sc->lmc_gpio &= ~(LMC_GEP_SSI_TXCLOCK);
LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT;
- printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS);
+ if(ie != old)
+ printk (KERN_INFO "%s: clock external\n", sc->name);
}
else
{
sc->lmc_gpio |= LMC_GEP_SSI_TXCLOCK;
LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
- printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
+ if(ie != old)
+ printk (KERN_INFO "%s: clock internal\n", sc->name);
}
}
static void
-lmc_ssi_set_speed (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+lmc_ssi_set_speed (lmc_softc_t * const sc, lmc_ctl_t * ctl) /*fold00*/
{
lmc_ctl_t *ictl = &sc->ictl;
lmc_av9110_t *av;
* 0 == link is down, 1 == link is up.
*/
static int
-lmc_ssi_get_link_status (lmc_softc_t * const sc)
+lmc_ssi_get_link_status (lmc_softc_t * const sc) /*fold00*/
{
u_int16_t link_status;
u_int32_t ticks;
ret = 0;
if(sc->last_led_err[3] != 1){
sc->stats.tx_lossOfClockCnt++;
- printk(KERN_WARNING "%s: Lost Clock Card Down\n", sc->name);
+ printk(KERN_WARNING "%s: Lost Clock, Link Down\n", sc->name);
}
sc->last_led_err[3] = 1;
lmc_led_on (sc, LMC_MII16_LED3); /* turn ON red LED */
if(hw_hdsk == 0){
if(sc->last_led_err[1] != 1)
- printk(KERN_WARNING "%s: DSR no asserted\n", sc->name);
+ printk(KERN_WARNING "%s: DSR not asserted\n", sc->name);
sc->last_led_err[1] = 1;
lmc_led_off(sc, LMC_MII16_LED1);
}
}
static void
-lmc_ssi_set_link_status (lmc_softc_t * const sc, int state)
+lmc_ssi_set_link_status (lmc_softc_t * const sc, int state) /*fold00*/
{
if (state == LMC_LINK_UP)
{
sc->lmc_miireg16 |= (LMC_MII16_SSI_DTR | LMC_MII16_SSI_RTS);
- printk (LMC_PRINTF_FMT ": asserting DTR and RTS\n", LMC_PRINTF_ARGS);
+// printk (LMC_PRINTF_FMT ": asserting DTR and RTS\n", LMC_PRINTF_ARGS);
}
else
{
sc->lmc_miireg16 &= ~(LMC_MII16_SSI_DTR | LMC_MII16_SSI_RTS);
- printk (LMC_PRINTF_FMT ": deasserting DTR and RTS\n", LMC_PRINTF_ARGS);
+// printk (LMC_PRINTF_FMT ": deasserting DTR and RTS\n", LMC_PRINTF_ARGS);
}
lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
* 0 == 16bit, 1 == 32bit
*/
static void
-lmc_ssi_set_crc_length (lmc_softc_t * const sc, int state)
+lmc_ssi_set_crc_length (lmc_softc_t * const sc, int state) /*FOLD00*/
{
if (state == LMC_CTL_CRC_LENGTH_32)
{
* These are bits to program the ssi frequency generator
*/
static inline void
-write_av9110_bit (lmc_softc_t * sc, int c)
+write_av9110_bit (lmc_softc_t * sc, int c) /*fold00*/
{
/*
* set the data bit as we need it.
*/
- sc->lmc_gpio &= ~(LMC_GEP_SERIALCLK);
+ sc->lmc_gpio &= ~(LMC_GEP_CLK);
if (c & 0x01)
- sc->lmc_gpio |= LMC_GEP_SERIAL;
+ sc->lmc_gpio |= LMC_GEP_DATA;
else
- sc->lmc_gpio &= ~(LMC_GEP_SERIAL);
+ sc->lmc_gpio &= ~(LMC_GEP_DATA);
LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
/*
* set the clock to high
*/
- sc->lmc_gpio |= LMC_GEP_SERIALCLK;
+ sc->lmc_gpio |= LMC_GEP_CLK;
LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
/*
* set the clock to low again.
*/
- sc->lmc_gpio &= ~(LMC_GEP_SERIALCLK);
+ sc->lmc_gpio &= ~(LMC_GEP_CLK);
LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
}
static void
-write_av9110 (lmc_softc_t * sc, u_int32_t n, u_int32_t m, u_int32_t v,
+write_av9110 (lmc_softc_t * sc, u_int32_t n, u_int32_t m, u_int32_t v, /*fold00*/
u_int32_t x, u_int32_t r)
{
int i;
-#if 0
- printk (LMC_PRINTF_FMT ": speed %u, %d %d %d %d %d\n",
- LMC_PRINTF_ARGS, sc->ictl.clock_rate, n, m, v, x, r);
-#endif
-
sc->lmc_gpio |= LMC_GEP_SSI_GENERATOR;
- sc->lmc_gpio &= ~(LMC_GEP_SERIAL | LMC_GEP_SERIALCLK);
+ sc->lmc_gpio &= ~(LMC_GEP_DATA | LMC_GEP_CLK);
LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
/*
* Set the TXCLOCK, GENERATOR, SERIAL, and SERIALCLK
* as outputs.
*/
- lmc_gpio_mkoutput (sc, (LMC_GEP_SERIAL | LMC_GEP_SERIALCLK
+ lmc_gpio_mkoutput (sc, (LMC_GEP_DATA | LMC_GEP_CLK
| LMC_GEP_SSI_GENERATOR));
sc->lmc_gpio &= ~(LMC_GEP_SSI_GENERATOR);
* stop driving serial-related signals
*/
lmc_gpio_mkinput (sc,
- (LMC_GEP_SERIAL | LMC_GEP_SERIALCLK
+ (LMC_GEP_DATA | LMC_GEP_CLK
| LMC_GEP_SSI_GENERATOR));
}
static void
-lmc_ssi_watchdog (lmc_softc_t * const sc)
+lmc_ssi_watchdog (lmc_softc_t * const sc) /*fold00*/
{
u_int16_t mii17;
struct ssicsr2
* The framer regs are multiplexed through MII regs 17 & 18
* write the register address to MII reg 17 and the * data to MII reg 18. */
static void
-lmc_t1_write (lmc_softc_t * const sc, int a, int d)
+lmc_t1_write (lmc_softc_t * const sc, int a, int d) /*fold00*/
{
lmc_mii_writereg (sc, 0, 17, a);
lmc_mii_writereg (sc, 0, 18, d);
}
-/* Save a warning
+
static int
-lmc_t1_read (lmc_softc_t * const sc, int a)
+lmc_t1_read (lmc_softc_t * const sc, int a) /*fold00*/
{
lmc_mii_writereg (sc, 0, 17, a);
return lmc_mii_readreg (sc, 0, 18);
}
-*/
+
static void
-lmc_t1_init (lmc_softc_t * const sc)
+lmc_t1_init (lmc_softc_t * const sc) /*fold00*/
{
u_int16_t mii16;
int i;
sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC1200;
mii16 = lmc_mii_readreg (sc, 0, 16);
+ mii16 &= ~LMC_MII16_T1_XOE;
+ lmc_mii_writereg (sc, 0, 16, mii16);
+ sc->lmc_miireg16 = mii16;
+
/* reset 8370 */
mii16 &= ~LMC_MII16_T1_RST;
lmc_mii_writereg (sc, 0, 16, mii16 | LMC_MII16_T1_RST);
lmc_t1_set_circuit_type(sc, LMC_CTL_CIRCUIT_TYPE_T1);
mii16 = sc->lmc_miireg16;
- lmc_t1_write (sc, 0x01, 0x1B); /* CR0 - primary control */
- lmc_t1_write (sc, 0x02, 0x42); /* JAT_CR - jitter atten config */
- lmc_t1_write (sc, 0x14, 0x00); /* LOOP - loopback config */
- lmc_t1_write (sc, 0x15, 0x00); /* DL3_TS - external data link timeslot */
+ /* Clear "foreced alarm" bis */
+ sc->yellow_alarm = 0;
+ sc->red_alarm = 0;
+ sc->blue_alarm = 0;
+
+ /*
+ * CR0
+ * - Set framing too ESF + Force CRC
+ * - Set T1
+ */
+
+ lmc_t1_write (sc, 0x01, 0x1b);
+ /*
+ * JAT_CR
+ * - set Free Running JCLK and CLAD0
+ * - Reset Elastic store to center
+ * - 64 bit elastic store
+ */
+ lmc_t1_write (sc, 0x02, 0x4b);
+
+ /*
+ * JAT_CR
+ * - Release Elastic store reset
+ */
+ lmc_t1_write (sc, 0x02, 0x43);
+
+ /*
+ * Disable all interupts
+ * Except: BOP receive
+ */
+
+ lmc_t1_write (sc, 0x0C, 0x00);
+ lmc_t1_write (sc, 0x0D, 0x00);
+ lmc_t1_write (sc, 0x0E, 0x00);
+ lmc_t1_write (sc, 0x0F, 0x00);
+ lmc_t1_write (sc, 0x10, 0x00);
+ lmc_t1_write (sc, 0x11, 0x00);
+ lmc_t1_write (sc, 0x12, 0x80);
+ lmc_t1_write (sc, 0x13, 0x00);
+
+ /*
+ * LOOP
+ * - No loopbacks set
+ */
+ lmc_t1_write (sc, 0x14, 0x00);
+
+ /*
+ * DL3_TS
+ * - Disabled
+ */
+ lmc_t1_write (sc, 0x15, 0x00);
+
+ /*
+ * PIO
+ * - ONESEC_IO, RDL_IO, TDL_IO, INDY_IO, RFSYNC_IO, RMSYNC_IO
+ * TFSNYC_IO, TMSYNC_IO: Set for output
+ */
lmc_t1_write (sc, 0x18, 0xFF); /* PIO - programmable I/O */
+
+ /*
+ * POE
+ * TDL_OE, RDL_OE: tri state output capable enable
+ * Rest: 2 level output
+ */
lmc_t1_write (sc, 0x19, 0x30); /* POE - programmable OE */
+
+ /*
+ * CMUX - Clock Input Mux
+ * RSBCKLI: Normal RSB timebase
+ * TSBCKI: Normal TSB timebase
+ * CLADI: CLAD slaved to transmit
+ * TCKI: Internal CLAD
+ */
lmc_t1_write (sc, 0x1A, 0x0F); /* CMUX - clock input mux */
+
+ /*
+ * LIU_CR
+ * RST_LIU: Reset LIU
+ * SQUELCH: Enable squelch
+ * Must be 1: Set to 1
+ */
+ lmc_t1_write (sc, 0x20, 0xC1); /* LIU_CR - RX LIU config */
lmc_t1_write (sc, 0x20, 0x41); /* LIU_CR - RX LIU config */
- lmc_t1_write (sc, 0x22, 0x76); /* RLIU_CR - RX LIU config */
+ /*
+ * RLIU_CR
+ * WHAT IS GOING ON HERE? USED TO BE 0x76
+ * FRZ_SHORT: don't update on strong signals
+ * AGC: 0x11 normal op
+ * LONG_EYE: normal
+ */
+ lmc_t1_write (sc, 0x22, 0xB1); /* RLIU_CR - RX LIU config */
+
+ /*
+ * VGA_MAX
+ * Setting of -20db sesitivity
+ */
+ lmc_t1_write (sc, 0x24, 0x21);
+
+ /*
+ * PRE_EQ
+ * Force off the pre-equilizer
+ * Load 0x26 in VTHRESH
+ */
+ lmc_t1_write (sc, 0x2A, 0xA6);
+
+ /*
+ * GAIN
+ * Equilizer Gain threshholds
+ * Number taken straight from David test code
+ */
+ lmc_t1_write (sc, 0x38, 0x24); /* RX_TH0 - RX gain threshold 0 */
+ lmc_t1_write (sc, 0x39, 0x28); /* RX_TH1 - RX gain threshold 0 */
+ lmc_t1_write (sc, 0x3A, 0x2C); /* RX_TH2 - RX gain threshold 0 */
+ lmc_t1_write (sc, 0x3B, 0x30); /* RX_TH3 - RX gain threshold 0 */
+ lmc_t1_write (sc, 0x3C, 0x34); /* RX_TH4 - RX gain threshold 0 */
+
+ /*
+ * LIU_CR
+ * Reset the LIU so it'll load the new constants
+ */
+ lmc_t1_write (sc, 0x20, 0x81); /* LIU_CR - RX LIU config (reset RLIU) */
+ lmc_t1_write (sc, 0x20, 0x01); /* LIU_CR - RX LIU config (clear reset) */
+
+ /*
+ * RCR0
+ * Receive B8ZS and 2 out of 4 F-bit errors for reframe
+ */
lmc_t1_write (sc, 0x40, 0x03); /* RCR0 - RX config */
- lmc_t1_write (sc, 0x45, 0x00); /* RALM - RX alarm config */
- lmc_t1_write (sc, 0x46, 0x05); /* LATCH - RX alarm/err/cntr latch */
- lmc_t1_write (sc, 0x68, 0x40); /* TLIU_CR - TX LIU config */
- lmc_t1_write (sc, 0x70, 0x0D); /* TCR0 - TX framer config */
- lmc_t1_write (sc, 0x71, 0x05); /* TCR1 - TX config */
- lmc_t1_write (sc, 0x72, 0x0B); /* TFRM - TX frame format */
- lmc_t1_write (sc, 0x73, 0x00); /* TERROR - TX error insert */
- lmc_t1_write (sc, 0x74, 0x00); /* TMAN - TX manual Sa/FEBE config */
- lmc_t1_write (sc, 0x75, 0x00); /* TALM - TX alarm signal config */
- lmc_t1_write (sc, 0x76, 0x00); /* TPATT - TX test pattern config */
- lmc_t1_write (sc, 0x77, 0x00); /* TLB - TX inband loopback config */
- lmc_t1_write (sc, 0x90, 0x05); /* CLAD_CR - clock rate adapter config */
+
+ /*
+ * RPATT
+ * Zero the test pattern generator
+ */
+ lmc_t1_write (sc, 0x41, 0x00);
+
+ /*
+ * RLB
+ * Loop back code detector
+ * DN_LEN: Down length is 8 bits
+ * UP_LEN: 5 bits
+ */
+ lmc_t1_write (sc, 0x42, 0x09);
+
+ /*
+ * LBA: Loopback activate
+ * LBA[6]: 1
+ * Loopback activate code
+ */
+ lmc_t1_write (sc, 0x43, 0x08);
+
+ /*
+ * LBD: Loopback deactivate
+ *
+ * Loopback deactivate code
+ */
+ lmc_t1_write (sc, 0x44, 0x24);
+
+ /*
+ * RALM: Receive Alarm Signal Configuration
+ *
+ * Set 0 which seems to be narmal alarms
+ */
+ lmc_t1_write (sc, 0x45, 0x00);
+
+ /*
+ * LATCH: Alarm/Error/Cournetr Latch register
+ *
+ * STOP_CNT: Stop error counters durring RLOF/RLOS/RAIS
+ */
+ lmc_t1_write (sc, 0x46, 0x08);
+
+ /*
+ * TLIU_CR: Transmit LIU Control Register
+ *
+ * TERM: External Transmit termination
+ * LBO: No line buildout
+ * Pulse shape from N8370DSE: 3-66
+ * // PULSE: 000 = 0 - 133ft 100 ohm twisted pair T1 DSX
+ * PULSE: 111 = Long Haul FCC Part 68 100 ohm twisted T1 CSU/NCTE
+ */
+
+ lmc_t1_write (sc, 0x68, 0x4E);
+
+ /*
+ * TCR0: Transmit Framer Configuration
+ *
+ * TFRAME: 1101 == ESF + Froce CRC
+ */
+ lmc_t1_write (sc, 0x70, 0x0D);
+
+ /*
+ * TCR1: Transmit Configuration Registers
+ *
+ * TLOFA: 2 out of 4 bit errors = LOF
+ * TZCS: 000VB0VB Table 3-20 page 3-72
+ */
+ lmc_t1_write (sc, 0x71, 0x05);
+
+ /*
+ * TFRM: Transmit Frame Format
+ *
+ * INS_MF: Insert Multiframe aligement
+ * INS_CRC: Insert CRC
+ * INS_FBIT: Insert Framing
+ */
+ lmc_t1_write (sc, 0x72, 0x0B);
+
+ /*
+ * TERROR
+ *
+ * Don't xmit any errors
+ */
+ lmc_t1_write (sc, 0x73, 0x00);
+
+ /*
+ * TMAN: Tranimit Mahual Sa-byte/FEBE configuration
+ */
+ lmc_t1_write (sc, 0x74, 0x00);
+
+
+ /*
+ * TALM: Transmit Alarm Signal Configuration
+ *
+ * Don't use any of these auto alarms
+ */
+ lmc_t1_write (sc, 0x75, 0x00);
+
+
+ /*
+ * TPATT: Transmit Pattern Canfiguration
+ *
+ * No special test patterns
+ */
+ lmc_t1_write (sc, 0x76, 0x00);
+
+ /*
+ * TLB: Transmit Inband Loopback Codhe Configuration
+ *
+ * Not enabled
+ */
+ lmc_t1_write (sc, 0x77, 0x00);
+
+ /*
+ * CLAD_CR: Clack Rate Adapter Configuration
+ *
+ * LFGAIN: Loop filter gain 1/2^6
+ */
+ lmc_t1_write (sc, 0x90, 0x06); /* CLAD_CR - clock rate adapter config */
+
+ /*
+ * CSEL: CLAD Frequency Select
+ *
+ * CLADV: 0000 - 1024 kHz
+ * CLADO: 0101 - 1544 kHz
+ */
lmc_t1_write (sc, 0x91, 0x05); /* CSEL - clad freq sel */
- lmc_t1_write (sc, 0xA6, 0x00); /* DL1_CTL - DL1 control */
+
+ /*
+ * CPHASE: CLAD Phase detector
+ */
+ lmc_t1_write (sc, 0x92, 0x00);
+
+ /*
+ * CTEST: Clad Test
+ *
+ * No tests
+ */
+ lmc_t1_write (sc, 0x93, 0x00);
+
+ /*
+ * BOP: Bop receiver
+ *
+ * Enable, 25 messages receive, 25 send, BOP has priority over FDL
+ */
+ lmc_t1_write (sc, 0xA0, 0xea); /* BOP - Bit oriented protocol xcvr */
+
+ /*
+ * Setup required to activae BOP.
+ * See table: 3-22 page 3-87
+ * See at the end
+ */
+ lmc_t1_write (sc, 0xA4, 0x40); /* DL1_TS - DL1 time slot enable */
+ lmc_t1_write (sc, 0xA5, 0x00); /* DL1_BIT - DL1 bit enable */
+ lmc_t1_write (sc, 0xA6, 0x03); /* DL1_CTL - DL1 control */
+ lmc_t1_write (sc, 0xA7, 0x00); /* RDL1_FFC - DL1 FIFO Size */
+ lmc_t1_write (sc, 0xAB, 0x00); /* TDL1_FFC - DL1 Empty Control*/
+
+ /*
+ * PRM: FDL PRM Messages
+ *
+ * Disable all automatic FDL messages
+ */
+
+ lmc_t1_write (sc, 0xAA, 0x00); /* PRM - performance report message */
+
+ /*
+ * DLC2 Control
+ *
+ * TDL2_EN: Disable transmit
+ * RDL2_EN: Disable receive
+ */
lmc_t1_write (sc, 0xB1, 0x00); /* DL2_CTL - DL2 control */
+ /*
+ * SBI_CR: System Bus Interface Configuration
+ *
+ * SBI_OE: Enable system bus
+ * SBI: T1 at 1544 with 24+fbit Page 3-113
+ */
lmc_t1_write (sc, 0xD0, 0x47); /* SBI_CR - sys bus iface config */
- lmc_t1_write (sc, 0xD1, 0x70); /* RSB_CR - RX sys bus config */
+ /*
+ * RSB_CR: Receive System Bus Coniguration
+ *
+ * SIG_OFF: RPCMO signalling off
+ * RPCM_NEG: Output on falling edge
+ * RSYN_NEG: Output sync an negative edge of clock
+ *
+ */
+ lmc_t1_write (sc, 0xD1, 0x70);
+
+ /*
+ * TSB_CR: Transmit System Bus Configuration
+ *
+ * TPCM_NEG: Tranimettr multiframe follows TSB
+ * TSYN_NEG: TFSYNC or TMSYNC on falling edge output
+ */
lmc_t1_write (sc, 0xD4, 0x30); /* TSB_CR - TX sys bus config */
+
for (i = 0; i < 32; i++)
{
lmc_t1_write (sc, 0x0E0 + i, 0x00); /* SBCn - sys bus per-channel ctl */
lmc_t1_write (sc, 0x100 + i, 0x00); /* TPCn - TX per-channel ctl */
lmc_t1_write (sc, 0x180 + i, 0x00); /* RPCn - RX per-channel ctl */
}
+ for (i=1; i<25; i++)
+ lmc_t1_write (sc, 0x0E0 + i, 0x01); /* SBCn - sys bus per-channel ctl */
for (i = 1; i < 25; i++)
{
lmc_t1_write (sc, 0x0E0 + i, 0x0D); /* SBCn - sys bus per-channel ctl */
}
+ /*
+ * Seems to get lost sometimes
+ */
+ lmc_t1_write (sc, 0xA4, 0x40); /* DL1_TS - DL1 time slot enable */
+ lmc_t1_write (sc, 0xA5, 0x00); /* DL1_BIT - DL1 bit enable */
+ lmc_t1_write (sc, 0xA6, 0x03); /* DL1_CTL - DL1 control */
+ lmc_t1_write (sc, 0xA7, 0x00); /* RDL1_FFC - DL1 FIFO Size */
+ lmc_t1_write (sc, 0xAB, 0x00); /* TDL1_FFC - DL1 Empty Control*/
+
+ /*
+ * Basic setup is done, now setup modes like SF AMI, and
+ * Fractional T1.
+ */
+
+ if(sc->t1_amisf != 0){
+ /*
+ * Set ami line codeing
+ */
+ lmc_t1_write (sc, 0x40, 0x83);
+ lmc_t1_write (sc, 0x71, 0x07); // 0x03 is ami
+
+ /*
+ * Set SF framing
+ */
+ lmc_t1_write (sc, 0x70, 0x04);
+ lmc_t1_write (sc, 0x72, 0x09);
+ lmc_t1_write (sc, 0x01, 0x09);
+
+ lmc_t1_write (sc, 0x46,0x00);
+ lmc_t1_write (sc, 0xa6,0x00);
+ lmc_t1_write (sc, 0xa0,0x00);
+
+ /* Setup Loopback */
+ lmc_t1_write (sc, 0x0d, 0xc0);
+ lmc_t1_write (sc, 0x42, 0x09);
+ lmc_t1_write (sc, 0x43, 0x08);
+ lmc_t1_write (sc, 0x44, 0x24);
+
+
+ if(sc->t1_amisf == 2 && sc->t1_frac_mask == 0){
+ sc->t1_frac_mask = 0xfffffffe;
+ }
+ }
+
+ if(sc->t1_frac_mask){
+ u32 mask = sc->t1_frac_mask;
+ int i;
+ int onoff;
+ for(i = 24; i >= 1; i--){
+ onoff = mask & 0x1;
+ mask >>= 1;
+ if(onoff == 0){
+ lmc_t1_write(sc, 0x0e0+i,0x01);
+ lmc_t1_write(sc, 0x100+i,0x20);
+ lmc_t1_write(sc, 0x140+i,0x7f);
+ }
+ else{
+ lmc_t1_write(sc, 0x0e0+i,0x0D);
+ lmc_t1_write(sc, 0x100+i,0x00);
+ lmc_t1_write(sc, 0x140+i,0x00);
+ }
+ }
+ mii16 |= LMC_MII16_T1_INVERT;
+ lmc_mii_writereg (sc, 0, 16, mii16);
+ }
+ else {
+ mii16 &= ~LMC_MII16_T1_INVERT; /* Unless we're on AMI SF don't invert */
+ }
+
+ if(sc->t1_loop_time){
+ lmc_t1_write(sc, 0x02, 0xa3);
+ }
+
+ lmc_gpio_mkoutput(sc, LMC_GEP_T1_INT);
+ sc->lmc_gpio |= LMC_GEP_T1_INT;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
mii16 |= LMC_MII16_T1_XOE;
lmc_mii_writereg (sc, 0, 16, mii16);
sc->lmc_miireg16 = mii16;
}
static void
-lmc_t1_default (lmc_softc_t * const sc)
+lmc_t1_default (lmc_softc_t * const sc) /*fold00*/
{
sc->lmc_miireg16 = LMC_MII16_LED_ALL;
sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN);
/* * Given a user provided state, set ourselves up to match it. This will * always reset the card if needed.
*/
static void
-lmc_t1_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+lmc_t1_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) /*fold00*/
{
if (ctl == NULL)
{
* return hardware link status.
* 0 == link is down, 1 == link is up.
*/ static int
-lmc_t1_get_link_status (lmc_softc_t * const sc)
+lmc_t1_get_link_status (lmc_softc_t * const sc) /*fold00*/
{
u_int16_t link_status;
int ret = 1;
* led3 red = Loss of Signal (LOS) or out of frame (OOF)
* conditions detected on T3 receive signal
*/
-
+ lmc_trace(sc->lmc_device, "lmc_t1_get_link_status in");
lmc_led_on(sc, LMC_DS3_LED2);
lmc_mii_writereg (sc, 0, 17, T1FRAMER_ALARM1_STATUS);
link_status = lmc_mii_readreg (sc, 0, 18);
- if (link_status & T1F_RAIS) { /* turn on blue LED */
+ if ((link_status & T1F_RAIS) || sc->blue_alarm) { /* turn on blue LED */
ret = 0;
if(sc->last_led_err[1] != 1){
printk(KERN_WARNING "%s: Receive AIS/Blue Alarm. Far end in RED alarm\n", sc->name);
}
+ if(sc->blue_alarm != 0){
+ sc->blue_alarm--;
+ }
lmc_led_on(sc, LMC_DS3_LED1);
+
sc->last_led_err[1] = 1;
}
else {
}
/*
- * Yellow Alarm is nasty evil stuff, looks at data patterns
+ * AMI: Yellow Alarm is nasty evil stuff, looks at data patterns
* inside the channel and confuses it with HDLC framing
* ignore all yellow alarms.
*
+ * B8ZS: RAI/Yellow alarm is implemented via a continous BOP
+ * message.
+ *
* Do listen to MultiFrame Yellow alarm which while implemented
* different ways isn't in the channel and hence somewhat
* more reliable
*/
- if (link_status & T1F_RMYEL) {
+ if ((link_status & T1F_RMYEL) || sc->yellow_alarm) {
ret = 0;
if(sc->last_led_err[0] != 1){
printk(KERN_WARNING "%s: Receive Yellow AIS Alarm\n", sc->name);
}
+ if(sc->yellow_alarm > 0){
+ sc->yellow_alarm--;
+ }
lmc_led_on(sc, LMC_DS3_LED0);
sc->last_led_err[0] = 1;
}
* Loss of signal and los of frame
* Use the green bit to identify which one lit the led
*/
- if(link_status & T1F_RLOF){
+ if((link_status & T1F_RLOF) || sc->red_alarm){
ret = 0;
if(sc->last_led_err[3] != 1){
- printk(KERN_WARNING "%s: Local Red Alarm: Loss of Framing\n", sc->name);
+ printk(KERN_WARNING "%s: Local Red Alarm: Loss of Framing (LOF)\n", sc->name);
+ /*
+ * Send AIS/Yellow
+ * So send continuous AIS/Yellom BOP messages
+ */
+ if(!sc->t1_amisf){
+ lmc_t1_write (sc, 0xA0, 0xee); /* Cont BOP */
+ lmc_t1_write (sc, 0xA1, 0x00); /* 0x00 is AIS/yellow BOP */
+ }
+ }
+ if(sc->red_alarm != 0){
+ sc->red_alarm--;
}
lmc_led_on(sc, LMC_DS3_LED3);
sc->last_led_err[3] = 1;
else {
if(sc->last_led_err[3] != 0){
printk(KERN_WARNING "%s: End Red Alarm (LOF)\n", sc->name);
+ /*
+ * Stop sending continuous BOP
+ * hence end yellow alarm
+ */
+ if(!sc->t1_amisf){
+ lmc_t1_write (sc, 0xA0, 0xea); /* Normal 25 BOP */
+ }
}
if( ! (link_status & T1F_RLOS))
lmc_led_off(sc, LMC_DS3_LED3);
sc->last_led_err[3] = 0;
}
- if(link_status & T1F_RLOS){
+ if((link_status & T1F_RLOS) || sc->red_alarm){
ret = 0;
if(sc->last_led_err[2] != 1){
- printk(KERN_WARNING "%s: Local Red Alarm: Loss of Signal\n", sc->name);
+ printk(KERN_WARNING "%s: Local Red Alarm: Loss of Signal (LOS)\n", sc->name);
+ /*
+ * Send AIS/Yellow
+ * So send continuous AIS/Yellom BOP messages
+ */
+ if(!sc->t1_amisf){
+ lmc_t1_write (sc, 0xA0, 0xee); /* Cont BOP */
+ lmc_t1_write (sc, 0xA1, 0x00); /* 0x00 is AIS/yellow BOP */
+ }
+ }
+ if(sc->red_alarm != 0){
+ sc->red_alarm--;
}
lmc_led_on(sc, LMC_DS3_LED3);
sc->last_led_err[2] = 1;
else {
if(sc->last_led_err[2] != 0){
printk(KERN_WARNING "%s: End Red Alarm (LOS)\n", sc->name);
+ /*
+ * Stop sending continuous BOP
+ * hence end yellow alarm
+ */
+ if(!sc->t1_amisf){
+ lmc_t1_write (sc, 0xA0, 0xea); /* Normal 25 BOP */
+ }
+
}
if( ! (link_status & T1F_RLOF))
lmc_led_off(sc, LMC_DS3_LED3);
lmc_mii_writereg (sc, 0, 17, T1FRAMER_ALARM2_STATUS);
sc->lmc_xinfo.t1_alarm2_status = lmc_mii_readreg (sc, 0, 18);
+
+ lmc_trace(sc->lmc_device, "lmc_t1_get_link_status out");
+
return ret;
}
* 1 == T1 Circuit Type , 0 == E1 Circuit Type
*/
static void
-lmc_t1_set_circuit_type (lmc_softc_t * const sc, int ie)
+lmc_t1_set_circuit_type (lmc_softc_t * const sc, int ie) /*fold00*/
{
+ int old;
+ old = sc->ictl.circuit_type;
if (ie == LMC_CTL_CIRCUIT_TYPE_T1) {
- sc->lmc_miireg16 |= LMC_MII16_T1_Z;
sc->ictl.circuit_type = LMC_CTL_CIRCUIT_TYPE_T1;
- printk(KERN_INFO "%s: In T1 Mode\n", sc->name);
+ if(old != sc->ictl.circuit_type)
+ printk(KERN_INFO "%s: In T1 Mode\n", sc->name);
}
else {
- sc->lmc_miireg16 &= ~LMC_MII16_T1_Z;
sc->ictl.circuit_type = LMC_CTL_CIRCUIT_TYPE_E1;
- printk(KERN_INFO "%s: In E1 Mode\n", sc->name);
+ if(old != sc->ictl.circuit_type)
+ printk(KERN_INFO "%s: In E1 Mode (non functional)\n", sc->name);
}
lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
/*
* 0 == 16bit, 1 == 32bit */
static void
-lmc_t1_set_crc_length (lmc_softc_t * const sc, int state)
+lmc_t1_set_crc_length (lmc_softc_t * const sc, int state) /*fold00*/
{
if (state == LMC_CTL_CRC_LENGTH_32)
{
* 1 == internal, 0 == external
*/
static void
-lmc_t1_set_clock (lmc_softc_t * const sc, int ie)
+lmc_t1_set_clock (lmc_softc_t * const sc, int ie) /*fold00*/
{
- if (ie == LMC_CTL_CLOCK_SOURCE_EXT)
- {
- sc->lmc_gpio &= ~(LMC_GEP_SSI_TXCLOCK);
- LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
- sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT;
- printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS);
- }
- else
- {
- sc->lmc_gpio |= LMC_GEP_SSI_TXCLOCK;
- LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
- sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
- printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
- }
+ /*
+ * Not set this way, done through T1 specific IOCTL
+ */
}
-static void
-lmc_t1_watchdog (lmc_softc_t * const sc)
+static void lmc_t1_watchdog (lmc_softc_t * const sc) /*fold00*/
{
+ if(sc->loop_timer != 0){
+ sc->loop_timer--;
+ if(sc->loop_timer == 0){
+ if(lmc_t1_read(sc, 0x014) != 0x00){
+ printk(KERN_DEBUG "%s: Timeout: Loop down\n", sc->name);
+ lmc_t1_write(sc, 0x014, 0x00);
+ /*
+ * If we're not loop timed
+ * go back to intelnal clack
+ */
+ if(! sc->t1_loop_time){
+ lmc_t1_write(sc, 0x02, 0x4b);
+ }
+ }
+ }
+ }
+ /*
+ * Check for BOP messages on A2 rev boards
+ */
+ lmc_t1_got_interupt (sc);
}
-static void
-lmc_set_protocol (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+static int lmc_t1_ioctl (lmc_softc_t * const sc, void *d) /*fold00*/
+{
+ struct lmc_st1f_control ctl;
+ int ret;
+
+ LMC_COPY_FROM_USER(&ctl, d, sizeof (struct lmc_st1f_control));
+
+ switch(ctl.command){
+ case lmc_st1f_write:
+ lmc_t1_write(sc, ctl.address, ctl.value);
+ ret = 0;
+ break;
+ case lmc_st1f_read:
+ ctl.value = lmc_t1_read(sc, ctl.address) & 0xff;
+ LMC_COPY_TO_USER(d, &ctl, sizeof (struct lmc_st1f_control));
+ ret = 0;
+ break;
+ case lmc_st1f_inv:
+ if(ctl.value == 1){
+ sc->lmc_miireg16 |= LMC_MII16_T1_INVERT;
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+ printk("%s: Request to invert data\n", sc->name);
+ }
+ else {
+ sc->lmc_miireg16 &= ~LMC_MII16_T1_INVERT;
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+ printk("%s: Request to non-invert data\n", sc->name);
+ }
+ ret = 0;
+ break;
+ case lmc_st1f_amisf:
+ sc->t1_amisf = ctl.value;
+ if(sc->lmc_ok){
+ lmc_t1_init(sc);
+ }
+ ret = 0;
+ break;
+ case lmc_st1f_frac:
+ LMC_COPY_FROM_USER(&sc->t1_frac_mask, ctl.data, sizeof (u32));
+ if(sc->lmc_ok){
+ lmc_t1_init(sc);
+ }
+ ret = 0;
+ break;
+ case lmc_st1f_loopt:
+ sc->t1_loop_time = ctl.value;
+ if(sc->lmc_ok){
+ lmc_t1_init(sc);
+ }
+ ret = 0;
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ return ret;
+}
+
+static int lmc_t1_got_interupt (lmc_softc_t * const sc) /*fold00*/
+{
+ u8 reg;
+
+ /* And it with the mask in case we're polling
+ * and we have want the int disabsled
+ */
+ reg = lmc_t1_read(sc, 0x00a) & lmc_t1_read(sc, 0x12);
+
+ if(reg & 0x80){
+// printk(KERN_DEBUG "%s: Got Inbound BOP message 0x%02x\n", sc->name, lmc_t1_read(sc, 0x0a2) & 0x3f);
+ switch(lmc_t1_read(sc, 0x0a2) & 0x3f) {
+ case 0x00: /* Yellow Alarm */
+ sc->yellow_alarm = 5; /* Start Yellow Alarm for 3 seconds */
+ break;
+
+ case 0x07: /* Loop up */
+ printk(KERN_DEBUG "%s: BOP: Loop up\n", sc->name);
+ sc->loop_timer = 305;
+ lmc_t1_write(sc, 0x002, 0xa3); /* Enter loop timeing */
+ lmc_t1_write(sc, 0x014, 0x04); /* Loop towards net */
+ break;
+
+ case 0x0b: /* Pay load loop back */
+ printk(KERN_DEBUG "%s: BOP: Payload Loop up\n", sc->name);
+ sc->loop_timer = 305;
+ lmc_t1_write(sc, 0x014, 0x08);
+ break;
+
+ case 0x1a:
+ case 0x1c: /* Loop down T1.409, etc */
+ case 0x1d: /* Loop down T1.403 */
+ printk(KERN_DEBUG "%s: BOP: Loop down\n", sc->name);
+ lmc_t1_write(sc, 0x014, 0x00); /* Loop down */
+ /*
+ * If we're not loop timed
+ * go back to intelnal clack
+ */
+ if(! sc->t1_loop_time){
+ lmc_t1_write(sc, 0x02, 0x4b);
+ }
+
+ break;
+
+ }
+ }
+
+ reg = lmc_t1_read(sc, 0x005) & lmc_t1_read(sc, 0x0d);
+
+ if(reg & 0x04){
+ printk(KERN_DEBUG "%s: Inband: Loop up\n", sc->name);
+ sc->loop_timer = 305;
+ lmc_t1_write(sc, 0x002, 0xa3); /* Enter loop timeing */
+ lmc_t1_write(sc, 0x014, 0x04); /* Loop up */
+ }
+ if(reg & 0x08){
+ printk(KERN_DEBUG "%s: Inband: Loop down\n", sc->name);
+ lmc_t1_write(sc, 0x014, 0x00);
+ /*
+ * If we're not loop timed
+ * go back to intelnal clack
+ */
+ if(! sc->t1_loop_time){
+ lmc_t1_write(sc, 0x02, 0x4b);
+ }
+ }
+
+ return 0;
+}
+
+
+static void lmc_set_protocol (lmc_softc_t * const sc, lmc_ctl_t * ctl) /*fold00*/
{
if (ctl == 0)
{
--- /dev/null
+ /*
+ * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+ * All rights reserved. www.lanmedia.com
+ *
+ * This code is written by:
+ * Andrew Stanley-Jones (asj@cban.com)
+ *
+ * With Help By:
+ * David Boggs
+ * Ron Crane
+ * Allan Cox
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License version 2, incorporated herein by reference.
+ *
+ * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards.
+ */
+
+#include <linux/version.h>
+//#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/segment.h>
+#include <asm/smp.h>
+
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "../syncppp.h"
+#include <linux/inet.h>
+#include <linux/tqueue.h>
+#include <linux/proc_fs.h>
+
+#include "lmc_ver.h"
+#include "lmc.h"
+#include "lmc_var.h"
+#include "lmc_debug.h"
+#include "lmc_ioctl.h"
+#include "lmc_proto.h"
+//#include "lmc_proto_raw.h"
+
+/*
+ * The compile-time variable SPPPSTUP causes the module to be
+ * compiled without referencing any of the sync ppp routines.
+ */
+#ifdef SPPPSTUB
+#define SYNC_PPP_init() (void)0
+#define SPPP_detach(d) (void)0
+#define SPPP_open(d) 0
+#define SPPP_reopen(d) (void)0
+#define SPPP_close(d) (void)0
+#define SPPP_attach(d) (void)0
+#define SPPP_do_ioctl(d,i,c) -EOPNOTSUPP
+#else
+#if LINUX_VERSION_CODE < 0x20211
+#define SYNC_PPP_init sync_ppp_init
+#define SPPP_attach(x) sppp_attach((struct ppp_device *)(x)->lmc_device)
+#define SPPP_detach(x) sppp_detach((x)->lmc_device)
+#define SPPP_open(x) sppp_open((x)->lmc_device)
+#define SPPP_reopen(x) sppp_reopen((x)->lmc_device)
+#define SPPP_close(x) sppp_close((x)->lmc_device)
+#define SPPP_do_ioctl(x, y, z) sppp_do_ioctl((x)->lmc_device, (y), (z))
+#else
+#define SYNC_PPP_init sync_ppp_init
+#define SPPP_attach(x) sppp_attach((x)->pd)
+#define SPPP_detach(x) sppp_detach((x)->pd->dev)
+#define SPPP_open(x) sppp_open((x)->pd->dev)
+#define SPPP_reopen(x) sppp_reopen((x)->pd->dev)
+#define SPPP_close(x) sppp_close((x)->pd->dev)
+#define SPPP_do_ioctl(x, y, z) sppp_do_ioctl((x)->pd->dev, (y), (z))
+#endif
+#endif
+
+static int lmc_first_ppp_load = 0;
+
+// init
+void lmc_proto_init(lmc_softc_t *sc) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_init in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ if(lmc_first_ppp_load == 0) {
+ lmc_first_ppp_load = 1;
+#ifndef MODULE
+ SYNC_PPP_init();
+#endif
+ }
+
+#if LINUX_VERSION_CODE >= 0x20210
+ sc->pd = kmalloc(sizeof(struct ppp_device), GFP_KERNEL);
+ sc->pd->dev = sc->lmc_device;
+#endif
+ sc->if_ptr = sc->pd;
+ break;
+ case LMC_RAW:
+ break;
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_init out");
+}
+
+// attach
+void lmc_proto_attach(lmc_softc_t *sc) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_attach in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ {
+ struct net_device *dev = sc->lmc_device;
+ SPPP_attach(sc);
+ dev->do_ioctl = lmc_ioctl;
+ }
+ break;
+ case LMC_NET:
+ {
+ struct net_device *dev = sc->lmc_device;
+ /*
+ * They set a few basics because they don't use sync_ppp
+ */
+ dev->flags |= IFF_POINTOPOINT;
+ dev->hard_header = 0;
+ dev->hard_header_len = 0;
+ dev->addr_len = 0;
+ }
+ case LMC_RAW: /* Setup the task queue, maybe we should notify someone? */
+ {
+ }
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_attach out");
+}
+
+// detach
+void lmc_proto_detach(lmc_softc_t *sc) /*FOLD00*/
+{
+ switch(sc->if_type){
+ case LMC_PPP:
+ SPPP_detach(sc);
+ break;
+ case LMC_RAW: /* Tell someone we're detaching? */
+ break;
+ default:
+ break;
+ }
+
+}
+
+// reopen
+void lmc_proto_reopen(lmc_softc_t *sc) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_reopen in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ SPPP_reopen(sc);
+ break;
+ case LMC_RAW: /* Reset the interface after being down, prerape to receive packets again */
+ break;
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_reopen out");
+}
+
+
+// ioctl
+int lmc_proto_ioctl(lmc_softc_t *sc, struct ifreq *ifr, int cmd) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_ioctl out");
+ switch(sc->if_type){
+ case LMC_PPP:
+ return SPPP_do_ioctl (sc, ifr, cmd);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_ioctl out");
+}
+
+// open
+void lmc_proto_open(lmc_softc_t *sc) /*FOLD00*/
+{
+ int ret;
+
+ lmc_trace(sc->lmc_device, "lmc_proto_open in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ ret = SPPP_open(sc);
+ if(ret < 0)
+ printk("%s: syncPPP open failed: %d\n", sc->name, ret);
+ break;
+ case LMC_RAW: /* We're about to start getting packets! */
+ break;
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_open out");
+}
+
+// close
+
+void lmc_proto_close(lmc_softc_t *sc) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_close in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ SPPP_close(sc);
+ break;
+ case LMC_RAW: /* Interface going down */
+ break;
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_close out");
+}
+
+unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_type in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ return htons(ETH_P_WAN_PPP);
+ break;
+ case LMC_NET:
+ return htons(ETH_P_802_2);
+ break;
+ case LMC_RAW: /* Packet type for skbuff kind of useless */
+ return htons(ETH_P_802_2);
+ break;
+ default:
+ printk(KERN_WARNING "%s: No protocol set for this interface, assuming 802.2 (which is wrong!!)\n", sc->name);
+ return htons(ETH_P_802_2);
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_tye out");
+
+}
+
+void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_netif in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ case LMC_NET:
+ default:
+ netif_rx(skb);
+ break;
+ case LMC_RAW:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_netif out");
+}
+
--- /dev/null
+#ifndef _LMC_PROTO_H_
+#define _LMC_PROTO_H_
+
+void lmc_proto_init(lmc_softc_t *sc);
+void lmc_proto_attach(lmc_softc_t *sc);
+void lmc_proto_detach(lmc_softc_t *sc);
+void lmc_proto_reopen(lmc_softc_t *sc);
+int lmc_proto_ioctl(lmc_softc_t *sc, struct ifreq *ifr, int cmd);
+void lmc_proto_open(lmc_softc_t *sc);
+void lmc_proto_close(lmc_softc_t *sc);
+unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb);
+void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb);
+int lmc_skb_rawpackets(char *buf, char **start, off_t offset, int len, int unused);
+
+#endif
\ No newline at end of file
#ifndef _LMC_VAR_H_
#define _LMC_VAR_H_
-/* $Id: lmc_var.h,v 1.14 2000/01/21 13:29:50 asj Exp $ */
+/* $Id: lmc_var.h,v 1.24 2000/06/16 23:37:16 asj Exp $ */
/*
* Copyright (c) 1997-2000 LAN Media Corporation (LMC)
*/
#include <linux/timer.h>
+#include <linux/version.h>
#ifndef __KERNEL__
typedef signed char s8;
typedef signed long long s64;
typedef unsigned long long u64;
+#if LINUX_VERSION_CODE >= 0x20363
+struct timer_list {
+};
+#endif
+
+typedef u32 spinlock_t;
+typedef u32 dma_addr_t;
+
#define BITS_PER_LONG 32
#endif
typedef struct lmc___media lmc_media_t;
typedef struct lmc___ctl lmc_ctl_t;
-#define lmc_csrptr_t u32
+#define lmc_csrptr_t unsigned long
#define u_int16_t u16
#define u_int8_t u8
#define tulip_uint32_t u32
#define LMC_CSR_READ(sc, csr) \
inl((sc)->lmc_csrs.csr)
#define LMC_CSR_WRITE(sc, reg, val) \
- outl(val, (sc)->lmc_csrs.reg)
+ outl((val), (sc)->lmc_csrs.reg)
-#ifdef _LINUX_DELAY_H
- #define SLOW_DOWN_IO udelay(2);
- #undef __SLOW_DOWN_IO
- #define __SLOW_DOWN_IO udelay(2);
-#endif
+//#ifdef _LINUX_DELAY_H
+// #define SLOW_DOWN_IO udelay(2);
+// #undef __SLOW_DOWN_IO
+// #define __SLOW_DOWN_IO udelay(2);
+//#endif
#define DELAY(n) SLOW_DOWN_IO
/* This macro sync's up with the mii so that reads and writes can take place */
#define LMC_MII_SYNC(sc) do {int n=32; while( n >= 0 ) { \
- LMC_CSR_WRITE((sc), csr_9, 0x20000); \
+ LMC_CSR_WRITE((sc), csr_9, 0x20000); \
lmc_delay(); \
LMC_CSR_WRITE((sc), csr_9, 0x30000); \
- lmc_delay(); \
+ lmc_delay(); \
n--; }} while(0);
struct lmc_regfile_t {
void (* set_crc_length)(lmc_softc_t * const, int);
void (* set_circuit_type)(lmc_softc_t * const, int);
void (* watchdog)(lmc_softc_t * const);
+ int (* ioctl)(lmc_softc_t * const, void *);
+ int (* got_interupt)(lmc_softc_t * const);
};
*/
struct lmc_statistics
{
- int rx_packets; /* total packets received */
- int tx_packets; /* total packets transmitted */
- int rx_bytes;
- int tx_bytes;
+ unsigned long rx_packets; /* total packets received */
+ unsigned long tx_packets; /* total packets transmitted */
+ unsigned long rx_bytes;
+ unsigned long tx_bytes;
- int rx_errors; /* bad packets received */
- int tx_errors; /* packet transmit problems */
- int rx_dropped; /* no space in linux buffers */
- int tx_dropped; /* no space available in linux */
- int multicast; /* multicast packets received */
- int collisions;
+ unsigned long rx_errors; /* bad packets received */
+ unsigned long tx_errors; /* packet transmit problems */
+ unsigned long rx_dropped; /* no space in linux buffers */
+ unsigned long tx_dropped; /* no space available in linux */
+ unsigned long multicast; /* multicast packets received */
+ unsigned long collisions;
/* detailed rx_errors: */
- int rx_length_errors;
- int rx_over_errors; /* receiver ring buff overflow */
- int rx_crc_errors; /* recved pkt with crc error */
- int rx_frame_errors; /* recv'd frame alignment error */
- int rx_fifo_errors; /* recv'r fifo overrun */
- int rx_missed_errors; /* receiver missed packet */
+ unsigned long rx_length_errors;
+ unsigned long rx_over_errors; /* receiver ring buff overflow */
+ unsigned long rx_crc_errors; /* recved pkt with crc error */
+ unsigned long rx_frame_errors; /* recv'd frame alignment error */
+ unsigned long rx_fifo_errors; /* recv'r fifo overrun */
+ unsigned long rx_missed_errors; /* receiver missed packet */
/* detailed tx_errors */
- int tx_aborted_errors;
- int tx_carrier_errors;
- int tx_fifo_errors;
- int tx_heartbeat_errors;
- int tx_window_errors;
+ unsigned long tx_aborted_errors;
+ unsigned long tx_carrier_errors;
+ unsigned long tx_fifo_errors;
+ unsigned long tx_heartbeat_errors;
+ unsigned long tx_window_errors;
/* for cslip etc */
unsigned long rx_compressed;
u_int32_t tx_MaxXmtsB4Int;
u_int32_t tx_TimeoutCnt;
u_int32_t tx_OutOfSyncPtr;
+ u_int32_t tx_tbusy0;
+ u_int32_t tx_tbusy1;
+ u_int32_t tx_tbusy_calls;
u_int32_t resetCount;
u_int32_t lmc_txfull;
u_int32_t tbusy;
* forward decl
*/
struct lmc___softc {
+ void *if_ptr; /* General purpose pointer (used by SPPP >= 2.4) */
char *name;
u8 board_idx;
struct lmc_statistics stats;
- struct device *lmc_device;
+ struct net_device *lmc_device;
int hang, rxdesc, bad_packet, some_counter;
u_int32_t txgo;
u_int32_t lmc_gpio; /* state of outputs */
struct sk_buff* lmc_txq[LMC_TXDESCS];
struct sk_buff* lmc_rxq[LMC_RXDESCS];
+ volatile
struct tulip_desc_t lmc_rxring[LMC_RXDESCS];
+ volatile
struct tulip_desc_t lmc_txring[LMC_TXDESCS];
unsigned int lmc_next_rx, lmc_next_tx;
+ volatile
unsigned int lmc_taint_tx, lmc_taint_rx;
int lmc_tx_start, lmc_txfull;
int lmc_txbusy;
int last_link_status;
int lmc_cardtype;
u_int32_t last_frameerr;
- lmc_media_t *lmc_media;
+ lmc_media_t *lmc_media;
struct timer_list timer;
lmc_ctl_t ictl;
u_int32_t TxDescriptControlInit;
- struct device *next_module; /* Link to the next module */
+ struct net_device *next_module; /* Link to the next module */
int tx_TimeoutInd; /* additional driver state */
int tx_TimeoutDisplay;
unsigned int lastlmc_taint_tx;
int lasttx_packets;
u_int32_t tx_clockState;
u_int32_t lmc_crcSize;
- LMC_XINFO lmc_xinfo;
- char lmc_yel, lmc_blue, lmc_red; /* for T1 and DS3 */
+ LMC_XINFO lmc_xinfo;
char lmc_timing; /* for HSSI and SSI */
int got_irq;
char last_led_err[4];
+ char yellow_alarm; /* Time in seconds to run yellow alarm for */
+ char red_alarm; /* Time in seconds to run red alarm for */
+ char blue_alarm; /* Time in seconds to run blue alarm for */
#if LINUX_VERSION_CODE >= 0x20200
spinlock_t lmc_lock;
#endif
+#if LINUX_VERSION_CODE >= 0x20363
+ struct pci_dev *pdev;
+ dma_addr_t sc_dma_handle;
+ struct lmc___softc *sc_dma;
+#endif
+ u_int16_t if_type; /* PPP or NET */
+ struct ppp_device *pd;
+
+ /* Failure cases */
+ u8 failed_ring;
+ u8 failed_recv_alloc;
+
+ /* T1 Specicfic Variable */
+ u16 loop_timer; /* Time out loop up requests */
+ u8 t1_amisf;
+ u32 t1_frac_mask;
+ u8 t1_loop_time;
+
+ /* Structure check */
+ u32 check;
};
#define LMC_PCI_TIME 1
*
*/
+#if LINUX_VERSION_CODE < 0x20363
+#define net_device device
+#define dev_kfree_skb_irq LMC_DEV_KFREE_SKB
+#endif
+
+#if LINUX_VERSION_CODE < 0x20363
+#define LMC_XMITTER_BUSY(x) (x)->tbusy = 1
+#define LMC_XMITTER_FREE(x) (x)->tbusy = 0
+#define LMC_XMITTER_INIT(x) (x)->tbusy = 0
+#else
+#define LMC_XMITTER_BUSY(x) netif_stop_queue(x)
+#define LMC_XMITTER_FREE(x) netif_wake_queue(x)
+#define LMC_XMITTER_INIT(x) netif_start_queue(x)
+
+#endif
+
+
#if LINUX_VERSION_CODE < 0x20100
-typedef unsigned int u_int32_t;
+//typedef unsigned int u_int32_t;
#define LMC_SETUP_20_DEV {\
int indx; \
dev->pa_addr = 0; \
dev->pa_brdaddr = 0; \
dev->pa_mask = 0xFCFFFFFF; \
- dev->pa_alen = 4; /* IP addr. sizeof(u32) */
+ dev->pa_alen = 4; /* IP addr. sizeof(u32) */
+
+#define cpu_to_le32(x) (x)
+#define le32_to_cpu(x) (x)
+#define le16_to_cpu(x) (x)
#else
#define LMC_SKB_FREE(skb, val)
#endif
-#define LMC_SPIN_FLAGS unsigned long flags;
-#if (LINUX_VERSION_CODE >= 0x20200)
+#if LINUX_VERSION_CODE >= 0x20200
+#define LMC_SPIN_FLAGS unsigned long flags;
#define LMC_SPIN_LOCK_INIT(x) spin_lock_init(&(x)->lmc_lock);
#define LMC_SPIN_UNLOCK(x) ((x)->lmc_lock = SPIN_LOCK_UNLOCKED)
#define LMC_SPIN_LOCK_IRQSAVE(x) spin_lock_irqsave (&(x)->lmc_lock, flags);
#define LMC_SPIN_UNLOCK_IRQRESTORE(x) spin_unlock_irqrestore (&(x)->lmc_lock, flags);
#else
-#define LMC_SPIN_FLAGS
-#define LMC_SPIN_LOCK_INIT(x)
-#define LMC_SPIN_UNLOCK(x)
-#define LMC_SPIN_LOCK_IRQSAVE(x)
-#define LMC_SPIN_UNLOCK_IRQRESTORE(x)
+#define LMC_SPIN_FLAGS unsigned long flags;
+#define LMC_SPIN_LOCK_INIT(x)
+#define LMC_SPIN_UNLOCK(x)
+#define LMC_SPIN_LOCK_IRQSAVE(x) save_flags(flags); cli();
+#define LMC_SPIN_UNLOCK_IRQRESTORE(x) restore_flags(flags);
#endif
#endif
+
+#if LINUX_VERSION_CODE >= 0x20200
+#else
+#define mdelay(x) { int j; for(j = 0; j < x; j++){ udelay(1000); } }
+
+#endif
+
+/*
+ * See DMA-mapping.txt for info
+ */
+
+#if LINUX_VERSION_CODE < 0x20363
+#else
+#define LMC_PCI_ALLOC_CONSISTENT(x, y, z) pci_alloc_consistent(x, y, z)
+#endif
+
/* done changing address */
out_8(&mb->iac, 0);
+#ifndef CONFIG_MACE_AAUI_PORT
out_8(&mb->plscc, PORTSEL_GPSI + ENPLSIO);
+#else
+ out_8(&mb->plscc, PORTSEL_AUI + ENPLSIO);
+#endif /* CONFIG_MACE_AAUI_PORT */
}
static void __mace_set_address(struct device *dev, void *addr)
Copyright 1992 - 2000 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Wed Feb 2 22:04:05 2000 by makisara@kai.makisara.local
+ Last modified: Sat Jun 17 17:29:35 2000 by makisara@kai.makisara.local
Some small formal changes - aeb, 950809
*/
scsi_tape_flush(struct file * filp)
{
int result = 0, result2;
- static unsigned char cmd[10];
+ unsigned char cmd[10];
Scsi_Cmnd * SCpnt;
Scsi_Tape * STp;
ST_mode * STm;
ssize_t i, do_count, blks, retval, transfer;
int write_threshold;
int doing_write = 0;
- static unsigned char cmd[10];
+ unsigned char cmd[10];
const char *b_point;
Scsi_Cmnd * SCpnt = NULL;
Scsi_Tape * STp;
read_tape(struct inode *inode, long count, Scsi_Cmnd **aSCpnt)
{
int transfer, blks, bytes;
- static unsigned char cmd[10];
+ unsigned char cmd[10];
Scsi_Cmnd *SCpnt;
Scsi_Tape *STp;
ST_mode * STm;
return 0;
case SNDCTL_DSP_GETOSPACE:
- if (!(s->ctrl & CTRL_DAC2_EN) && (val = prog_dmabuf_dac1(s)) != 0)
+ if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
return 0;
case SNDCTL_DSP_GETOSPACE:
- if (!(s->ctrl & CTRL_DAC2_EN) && (val = prog_dmabuf_dac1(s)) != 0)
+ if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
u16 rel; /* reliability */
u32 time;
}__attribute__ ((packed)) cisco_packet;
+#define CISCO_PACKET_LEN 18
+#define CISCO_BIG_PACKET_LEN 20
* Interrupt Source Registers
*/
-#define OPENPIC_SENSE_POLARITY 0x00800000 /* Undoc'd */
+#define OPENPIC_POLARITY_POSITIVE 0x00800000
+#define OPENPIC_POLARITY_NEGATIVE 0x00000000
+#define OPENPIC_POLARITY_MASK 0x00800000
#define OPENPIC_SENSE_LEVEL 0x00400000
+#define OPENPIC_SENSE_EDGE 0x00000000
+#define OPENPIC_SENSE_MASK 0x00400000
/*
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
int swappable:1;
- int trashing_mem:1;
/* process credentials */
uid_t uid,euid,suid,fsuid;
gid_t gid,egid,sgid,fsgid;
/* utime */ {0,0,0,0},0, \
/* per CPU times */ {0, }, {0, }, \
/* flt */ 0,0,0,0,0,0, \
-/* swp */ 0,0, \
+/* swp */ 0, \
/* process credentials */ \
/* uid etc */ 0,0,0,0,0,0,0,0, \
/* suppl grps*/ 0, {0,}, \
unsigned long OfoPruned;
unsigned long OutOfWindowIcmps;
unsigned long LockDroppedIcmps;
+ unsigned long SockMallocOOM;
};
#endif
extern struct sk_buff *sock_wmalloc(struct sock *sk,
unsigned long size, int force,
int priority);
+
+extern struct sk_buff *sock_wmalloc_err(struct sock *sk,
+ unsigned long size, int force,
+ int priority, int *err);
extern struct sk_buff *sock_rmalloc(struct sock *sk,
unsigned long size, int force,
int priority);
static int do_try_to_free_pages(unsigned int gfp_mask)
{
int priority;
+ int ret = 0;
+ int swapcount;
int count = SWAP_CLUSTER_MAX;
lock_kernel();
priority = 6;
do {
while (shrink_mmap(priority, gfp_mask)) {
+ ret = 1;
if (!--count)
goto done;
}
/* Try to get rid of some shared memory pages.. */
if (gfp_mask & __GFP_IO) {
while (shm_swap(priority, gfp_mask)) {
+ ret = 1;
if (!--count)
goto done;
}
}
/* Then, try to page stuff out.. */
+ swapcount = count;
while (swap_out(priority, gfp_mask)) {
- if (!--count)
- goto done;
+ ret = 1;
+ if (!--swapcount)
+ break;
}
shrink_dcache_memory(priority, gfp_mask);
printk("VM: do_try_to_free_pages failed for %s...\n",
current->comm);
/* Return success if we freed a page. */
- return priority >= 0;
+ return ret;
}
/*
skb->sk = sk;
return skb;
}
+ net_statistics.SockMallocOOM++;
+ }
+ return NULL;
+}
+
+/*
+ * Allocate memory from the sockets send buffer, telling caller about real OOM.
+ * err is only set for oom, not for socket buffer overflow.
+ */
+struct sk_buff *sock_wmalloc_err(struct sock *sk, unsigned long size, int force, int priority, int *err)
+{
+ *err = 0;
+ /* Note: overcommitment possible */
+ if (force || atomic_read(&sk->wmem_alloc) < sk->sndbuf) {
+ struct sk_buff * skb;
+ *err = -ENOMEM;
+ skb = alloc_skb(size, priority);
+ if (skb) {
+ *err = 0;
+ atomic_add(skb->truesize, &sk->wmem_alloc);
+ skb->destructor = sock_wfree;
+ skb->sk = sk;
+ return skb;
+ }
+ net_statistics.SockMallocOOM++;
}
return NULL;
}
skb->sk = sk;
return skb;
}
+ net_statistics.SockMallocOOM++;
}
return NULL;
}
if (mem)
return mem;
atomic_sub(size, &sk->omem_alloc);
+ net_statistics.SockMallocOOM++;
}
return NULL;
}
len = sprintf(buffer,
"TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
" EmbryonicRsts PruneCalled RcvPruned OfoPruned"
- " OutOfWindowIcmps LockDroppedIcmps\n"
- "TcpExt: %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
+ " OutOfWindowIcmps LockDroppedIcmps SockMallocOOM\n"
+ "TcpExt: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
net_statistics.SyncookiesSent,
net_statistics.SyncookiesRecv,
net_statistics.SyncookiesFailed,
net_statistics.RcvPruned,
net_statistics.OfoPruned,
net_statistics.OutOfWindowIcmps,
- net_statistics.LockDroppedIcmps);
+ net_statistics.LockDroppedIcmps,
+ net_statistics.SockMallocOOM);
if (offset >= len)
{
}
/*
- * Wait for more memory for a socket
- *
- * If we got here an allocation has failed on us. We cannot
- * spin here or we may block the very code freeing memory
- * for us.
+ * Wait for more memory for a socket.
+ * Special case is err == -ENOMEM, in this case just sleep a bit waiting
+ * for the system to free up some memory.
*/
-static void wait_for_tcp_memory(struct sock * sk)
+static void wait_for_tcp_memory(struct sock * sk, int err)
{
release_sock(sk);
if (!tcp_memory_free(sk)) {
struct wait_queue wait = { current, NULL };
+
sk->socket->flags &= ~SO_NOSPACE;
add_wait_queue(sk->sleep, &wait);
for (;;) {
if (signal_pending(current))
break;
current->state = TASK_INTERRUPTIBLE;
- if (tcp_memory_free(sk))
+ if (tcp_memory_free(sk) && !err)
break;
if (sk->shutdown & SEND_SHUTDOWN)
break;
if (sk->err)
break;
- schedule();
+ if (!err)
+ schedule();
+ else {
+ schedule_timeout(1);
+ break;
+ }
}
current->state = TASK_RUNNING;
remove_wait_queue(sk->sleep, &wait);
}
- else
- {
- /* Yield time to the memory freeing paths */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
- }
lock_sock(sk);
}
tmp += copy;
queue_it = 0;
}
- skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL);
+ skb = sock_wmalloc_err(sk, tmp, 0, GFP_KERNEL, &err);
/* If we didn't get any memory, we need to sleep. */
if (skb == NULL) {
err = -ERESTARTSYS;
goto do_interrupted;
}
- tcp_push_pending_frames(sk, tp);
- wait_for_tcp_memory(sk);
+ /* In OOM that would fail anyways so do not bother. */
+ if (!err)
+ tcp_push_pending_frames(sk, tp);
+ wait_for_tcp_memory(sk, err);
/* If SACK's were formed or PMTU events happened,
* we must find out about it.
echo "# Using defaults found in" $DEFAULTS
echo "#"
. $DEFAULTS
- sed -e 's/# \(.*\) is not.*/\1=n/' < $DEFAULTS > .config-is-not.$$
+ sed -e 's/# \(CONFIG_[^ ]*\) is not.*/\1=n/' <$DEFAULTS >.config-is-not.$$
. .config-is-not.$$
rm .config-is-not.$$
else