diff -urN -X kernel-patches/dontdiff linux-2.4.18-rc1/arch/i386/kernel/setup.c linux-2.4.18-rc1-elan/arch/i386/kernel/setup.c --- linux-2.4.18-rc1/arch/i386/kernel/setup.c Wed Feb 13 22:51:14 2002 +++ linux-2.4.18-rc1-elan/arch/i386/kernel/setup.c Wed Feb 13 22:57:58 2002 @@ -319,6 +319,7 @@ static char command_line[COMMAND_LINE_SIZE]; char saved_command_line[COMMAND_LINE_SIZE]; +/* ioport resources for standard PCs */ struct resource standard_io_resources[] = { { "dma1", 0x00, 0x1f, IORESOURCE_BUSY }, { "pic1", 0x20, 0x3f, IORESOURCE_BUSY }, @@ -329,9 +330,33 @@ { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY }, { "fpu", 0xf0, 0xff, IORESOURCE_BUSY } }; - #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource)) +/* ioport resources for AMD Elan SC400, SC410 */ +struct resource elan4x0_io_resources[] = { + { "dma1", 0x00, 0x0f, IORESOURCE_BUSY }, + { "pic1", 0x20, 0x21, IORESOURCE_BUSY }, + { "csc", 0x22, 0x23, IORESOURCE_BUSY }, + { "timer", 0x40, 0x43, IORESOURCE_BUSY }, + { "keyboard", 0x60, 0x64, IORESOURCE_BUSY }, + { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY }, + { "pic2", 0xa0, 0xa1, IORESOURCE_BUSY }, + { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY }, +}; +#define ELAN4X0_IO_RESOURCES (sizeof(elan4x0_io_resources)/sizeof(struct resource)) + +/* ioport resources for AMD Elan SC520 */ +struct resource elan520_io_resources[] = { + { "dma1", 0x00, 0x0f, IORESOURCE_BUSY }, + { "pic1", 0x20, 0x21, IORESOURCE_BUSY }, + { "timer", 0x40, 0x43, IORESOURCE_BUSY }, + { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY }, + { "pic2", 0xa0, 0xa1, IORESOURCE_BUSY }, + { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY }, + { "fpu", 0xf0, 0xff, IORESOURCE_BUSY } +}; +#define ELAN520_IO_RESOURCES (sizeof(elan520_io_resources)/sizeof(struct resource)) + static struct resource code_resource = { "Kernel code", 0x100000, 0 }; static struct resource data_resource = { "Kernel data", 0, 0 }; static struct resource vram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_BUSY }; @@ -1026,9 +1051,22 @@ } request_resource(&iomem_resource, &vram_resource); - /* request I/O space for devices used on all i[345]86 PCs */ - for (i = 0; i < STANDARD_IO_RESOURCES; i++) - request_resource(&ioport_resource, standard_io_resources+i); + /* + * request I/O space for devices used on all i[345]86 PCs + * test for AMD Elan CPUs (which have reduced ressources): if we + * have one of these processors allocate resources later in init_amd() + * (x86=4,x86_model=10: AMD SC410; x86=4,x86_model=9: AMD SC520) + */ + + if (!( (strcmp(boot_cpu_data.x86_vendor_id,"AuthenticAMD")==0) && + boot_cpu_data.x86 == 4 && + ((boot_cpu_data.x86_model==10) || (boot_cpu_data.x86_model==9)) + ) + ) + { + for (i = 0; i < STANDARD_IO_RESOURCES; i++) + request_resource(&ioport_resource, standard_io_resources+i); + } /* Tell the PCI layer not to allocate too close to the RAM area.. */ low_mem_size = ((max_low_pfn << PAGE_SHIFT) + 0xfffff) & ~0xfffff; @@ -1172,6 +1210,7 @@ u32 l, h; int mbytes = max_mapnr >> (20-PAGE_SHIFT); int r; + int i; /* * FIXME: We should handle the K5 here. Set up the write @@ -1187,6 +1226,24 @@ switch(c->x86) { + case 4: + if ( c->x86_model == 9 ) /* Elan SC520 FIXME: empirical value! */ + { + /* request resources */ + for (i = 0; i < ELAN520_IO_RESOURCES; i++) + request_resource(&ioport_resource, elan520_io_resources+i); + break; + } + + if ( c->x86_model == 10 ) /* Elan SC410 FIXME: empirical value! */ + { + /* request resources */ + for (i = 0; i < ELAN4X0_IO_RESOURCES; i++) + request_resource(&ioport_resource, elan4x0_io_resources+i); + break; + } + break; + case 5: if( c->x86_model < 6 ) { diff -urN -X kernel-patches/dontdiff linux-2.4.18-rc1/drivers/char/serial.c linux-2.4.18-rc1-elan/drivers/char/serial.c --- linux-2.4.18-rc1/drivers/char/serial.c Wed Feb 13 22:51:21 2002 +++ linux-2.4.18-rc1-elan/drivers/char/serial.c Wed Feb 13 22:57:58 2002 @@ -57,6 +57,11 @@ * 10/00: add in optional software flow control for serial console. * Kanoj Sarcar (Modified by Theodore Ts'o) * + * 02/02: Fix for AMD Elan bug in transmit irq routine, by + * Christer Weinigel , + * Robert Schwebel , + * Juergen Beisert , + * Theodore Ts'o */ static char *serial_version = "5.05c"; @@ -801,7 +806,7 @@ */ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) { - int status; + int status, iir; struct async_struct * info; int pass_counter = 0; struct async_struct *end_mark = 0; @@ -826,7 +831,7 @@ do { if (!info->tty || - (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) { + ((iir=serial_in(info, UART_IIR)) & UART_IIR_NO_INT)) { if (!end_mark) end_mark = info; goto next; @@ -845,7 +850,9 @@ if (status & UART_LSR_DR) receive_chars(info, &status, regs); check_modem_status(info); - if (status & UART_LSR_THRE) + if ((status & UART_LSR_THRE) || + /* for buggy ELAN processors */ + ((iir & UART_IIR_ID) == UART_IIR_THRI)) transmit_chars(info, 0); next: @@ -879,7 +886,7 @@ */ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) { - int status; + int status, iir; int pass_counter = 0; struct async_struct * info; #ifdef CONFIG_SERIAL_MULTIPORT @@ -901,6 +908,7 @@ first_multi = inb(multi->port_monitor); #endif + iir = serial_in(info, UART_IIR); do { status = serial_inp(info, UART_LSR); #ifdef SERIAL_DEBUG_INTR @@ -909,18 +917,21 @@ if (status & UART_LSR_DR) receive_chars(info, &status, regs); check_modem_status(info); - if (status & UART_LSR_THRE) + if ((status & UART_LSR_THRE) || + /* For buggy ELAN processors */ + ((iir & UART_IIR_ID) == UART_IIR_THRI)) transmit_chars(info, 0); if (pass_counter++ > RS_ISR_PASS_LIMIT) { -#if 0 +#if SERIAL_DEBUG_INTR printk("rs_single loop break.\n"); #endif break; } + iir = serial_in(info, UART_IIR); #ifdef SERIAL_DEBUG_INTR - printk("IIR = %x...", serial_in(info, UART_IIR)); + printk("IIR = %x...", iir); #endif - } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT)); + } while ((iir & UART_IIR_NO_INT) == 0); info->last_active = jiffies; #ifdef CONFIG_SERIAL_MULTIPORT if (multi->port_monitor)