You can subscribe to this list here.
2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(11) |
Jun
(66) |
Jul
(16) |
Aug
(2) |
Sep
(7) |
Oct
(17) |
Nov
(1) |
Dec
(220) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
(154) |
Feb
(167) |
Mar
(159) |
Apr
(172) |
May
(35) |
Jun
(58) |
Jul
(97) |
Aug
(285) |
Sep
(139) |
Oct
(252) |
Nov
(8) |
Dec
(3) |
2004 |
Jan
(13) |
Feb
(159) |
Mar
(136) |
Apr
(33) |
May
(50) |
Jun
(42) |
Jul
(140) |
Aug
(42) |
Sep
(199) |
Oct
(31) |
Nov
(55) |
Dec
|
2005 |
Jan
|
Feb
(12) |
Mar
(214) |
Apr
(119) |
May
(21) |
Jun
(2) |
Jul
(127) |
Aug
(10) |
Sep
(3) |
Oct
(24) |
Nov
(1) |
Dec
|
2006 |
Jan
|
Feb
|
Mar
|
Apr
(45) |
May
(13) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(5) |
Nov
(26) |
Dec
|
2007 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(35) |
Sep
(1) |
Oct
|
Nov
|
Dec
|
From: Kenn H. <ke...@us...> - 2002-09-29 19:38:03
|
Update of /cvsroot/linux-vax/kernel-2.5 In directory usw-pr-cvs1:/tmp/cvs-serv31198 Modified Files: README.cvs-tags Log Message: Mostly-complete driver for DELQA ethernet card. First-cut driver for Q-bus adapter in KA650 CPU. Partially working serial driver for any console port driven by RXCS, RXDB, TXCS and TXDB internal processor registers. Boots to user mode on a KA42 with NFS root and no SCSI (NCR5380 driver is broken). Index: README.cvs-tags =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/README.cvs-tags,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- README.cvs-tags 27 May 2002 19:56:04 -0000 1.1 +++ README.cvs-tags 29 Sep 2002 19:37:59 -0000 1.2 @@ -25,6 +25,13 @@ fine using NFS root on my VS4000/60. (Nothing else is guaranteed). + kh-20020929 Mostly-complete driver for DELQA ethernet card. + First-cut driver for Q-bus adapter in KA650 CPU. + Partially working serial driver for any console + port driven by RXCS, RXDB, TXCS and TXDB internal + processor registers. Boots to user mode on a KA42 + with NFS root and no SCSI (NCR5380 driver is broken). + Branch: linux-2_5 Vendor branch for official Linus kernels This branch is a "vendor" branch in CVS terminology. We use it to hold |
From: Kenn H. <ke...@us...> - 2002-09-29 19:36:56
|
Update of /cvsroot/linux-vax/kernel-2.5/include/asm-vax In directory usw-pr-cvs1:/tmp/cvs-serv30876 Modified Files: types.h Log Message: Added dma64_addr_t type (some 2.5.x SCSI code needs it, even though it has no meaning on VAX). Index: types.h =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/include/asm-vax/types.h,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- types.h 18 Jul 2002 23:45:21 -0000 1.4 +++ types.h 29 Sep 2002 19:36:51 -0000 1.5 @@ -43,9 +43,12 @@ #define BITS_PER_LONG 32 -/* DMA addresses come in generic and 64-bit flavours. */ +/* DMA addresses come in generic and 64-bit flavours (although I can't + see 64-bit DMA having any meaning on VAX - KPH). */ typedef u32 dma_addr_t; + +typedef u64 dma64_addr_t; #endif /* __KERNEL__ */ |
From: Kenn H. <ke...@us...> - 2002-09-29 19:33:20
|
Update of /cvsroot/linux-vax/kernel-2.5/drivers/vax/char In directory usw-pr-cvs1:/tmp/cvs-serv29366/drivers/vax/char Modified Files: Makefile Added Files: iprcons.c Log Message: Partially-working driver for console serial ports driven by RXCS, RXDB, TXCS and TXDB internal processor registers. printk() works, but it doesn't yet work for regalar userland I/O. Enabled by CONFIG_SERIAL_IPR config option. Only supported for KA650 right now. --- NEW FILE --- /* $Id: iprcons.c,v 1.1 2002/09/29 19:33:16 kenn Exp $ Copyright (c) 2002, Kenn Humborg Serial driver for VAX console ports that are accessed through internal processor registers (IPRs). "Real" VAX CPUs use 4 internal registers to drive the console serial port (this info is from the VAX Architecture Reference Manual): RXCS Console Receive Control and Status Register Bit 7 RDY (ready, read-only) Cleared by processor initialization and by reading RXDB. When RDY is clear, RXDB is unpredictable. When RDY is set, RXDB contains valid data to be read. Bit 6 IE (interrupt enable, read/write) Cleared by processor initialization and by being written zero. If IE is set by software while RXDB RDY is already set, or if RDY is set by the console while IE is already set, then an interrupt is requested at IPL 14 (hex). That is, an interrupt is requested when the function (IE and RDY) changes from 0 to 1. RXDB Console Receive Data Buffer Register Bit 15 ERROR (read-only) An error occurred while receiving data, such as data overrun or loss of carrier. Cleared by processor initialization and by reading from RXDB. Bits 11:8 ID (read-only) If zero, then data is from the console terminal. If nonzero, then the rest of the register is implementation dependent. Cleared by processor initialization and by reading from RXDB. Bits 7:0 DATA (read-only) Data from the console terminal (if ID is zero). Unpredictable unless RXCS RDY is set. TXCS Console Transmit Control and Status Register Bit 7 RDY (read-only) Set by processor initialization. RDY is clear when the console terminal is busy writing a character written to TXDB. RDY is set when the console terminal is ready to receive another character. Bit 6 IE (interrupt enable, read/write) Cleared by processor initialization and by being written clear. If IE is set by software while RXDB RDY is already set, or if RDY is set by the console while IE is already set, then an interrupt is requested at IPL 14 (hex). That is, an interrupt is requested when the function (IE and RDY) changes from 0 to 1. TXDB Console Transmit Data Buffer Register Bits 11:8 ID (read/write) If ID is written zero when TXDB is written, the data goes to the console terminal. If ID is written with 0F (hex), the data is a message to be sent to the console. If ID is neither zero nor 0F (hex), the meaning is implementation-dependent. Bits 7:0 DATA (read/write) If ID is zero, the data is a character sent to the console terminal to type. If ID is 0F (hex), the data is a message to be sent to the console, with the following meaning: 1. Software done -- A program started by a console indirect command file is signalling successful completion. When the processor halts, the consolel should resume processing the indirect command file. 2. Boot processor -- The console should initiate a system bootstrap. 3. Clear "restart in progress" flag -- A system restart has been successfully completed. If a system restart would occur automatically, the attempt should be allowed. 4. Clear "bootstrap in progress" flag -- A system bootstrap has successfully completed. If a system bootstrap would occur automatically, the attempt should be allowed. However, the implementation of these registers varies a little bit between CPUs. For example, the KA650/655 uses the ID fields a bit differently. To handle this, this driver will evetually become a "template" driver (like drivers/scsi/NCR5380.c) which will be #include-d in individual drivers for each CPU's console port. It will provide all the generic functionality, and provide callouts for any implementation-specific functionality. TODO: o Write iprcons_set_termios(). I don't think we need to do anything here, since there is nothing configurable on these ports. o ioctl() o Write transmit code path: iprcons_write(), iprcons_put_char(), iprcons_flush_chars() and iprcons_write_root(), iprcons_start() and iprcons_stop(), iprcons_wait_until_sent(), iprcons_send_xchar(). o Write TX ISR. o Write receive code path - RX ISR o Write iprcons_close(). Release interrupts and uninit. o Write iprcons_break_ctl(). o SMP/pre-emptive issues o system console support */ #include <linux/version.h> #include <linux/module.h> #include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/major.h> #include <linux/delay.h> #include <linux/param.h> #include <linux/tqueue.h> #include <linux/interrupt.h> #include <linux/serial.h> #include <linux/serialP.h> #include <linux/generic_serial.h> /* for definition of struct console */ #if defined(CONFIG_SERIAL_CONSOLE) #include <linux/console.h> #include <asm/mv.h> /* for mtpr_putchar */ #endif /* if defined(CONFIG_SERIAL_CONSOLE) */ #include <linux/tty.h> #include <linux/tty_flip.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/mtpr.h> #define IPRCONS_XMIT_SIZE 4096 /* buffer size */ #define WAKEUP_CHARS IPRCONS_XMIT_SIZE/4 #define IPRCONS_EVENT_WRITE_WAKEUP 0 #define IPRCONS_CLOSING_WAIT_INF 0 #define IPRCONS_CLOSING_WAIT_NONE 65535 struct iprcons_serial { struct gs_port gs; /* must be first in structure */ int type; unsigned short x_char; /* pending xon/xoff character */ struct async_icount icount; /* keep track of things ... */ struct tq_struct tqueue; /* Queue for BH */ unsigned long event; /* mask used in BH */ unsigned char is_console; /* flag indicating a serial console */ }; static struct iprcons_serial console_state; static struct tty_driver iprcons_serial_driver, iprcons_callout_driver; static struct tty_struct *iprcons_table[1]; static struct termios *iprcons_termios[1]; static struct termios *iprcons_termios_locked[1]; static int iprcons_refcount; /* Register definitions */ #define PR_RXCS_RDY 0x0080 #define PR_RXCS_IE 0x0040 #define PR_RXDB_ERROR 0x8000 #define PR_RXDB_ID 0x0f00 #define PR_RXDB_DATA 0x00ff #define PR_TXCS_RDY 0x0080 #define PR_TXCS_IE 0x0040 #define PR_TXDB_ID 0x0f00 #define PR_TXDB_DATA 0x00ff /* These vectors are defined by the VAX Architecture Reference Manual */ #define IPRCONS_RX_VECTOR 0x3e #define IPRCONS_TX_VECTOR 0x3f static void iprcons_enable_rx_interrupts(void *ptr) { __mtpr(PR_RXCS_IE, PR_RXCS); } static void iprcons_disable_rx_interrupts(void *ptr) { __mtpr(0, PR_RXCS); } static void iprcons_enable_tx_interrupts(void *ptr) { __mtpr(PR_TXCS_IE, PR_TXCS); } static void iprcons_disable_tx_interrupts(void *ptr) { __mtpr(0, PR_TXCS); } static int iprcons_get_CD(void *ptr) { /* Our hardware doesn't have a CD line, so pretend that CD is always asserted */ return 1; } /* * ------------------------------------------------------------ * iprcons_sched_event () * * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver. * ------------------------------------------------------------ */ static inline void iprcons_sched_event (struct iprcons_serial *port, int event) { port->event |= 1 << event; queue_task(&port->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); } /* * ------------------------------------------------------------ * receive_char () * * This routine deals with input from the port * ------------------------------------------------------------ */ static inline void iprcons_rx_char(struct iprcons_serial *port, unsigned int rxcs, unsigned int rxdb) { struct tty_struct *tty = port->gs.tty; unsigned char ch = rxdb & PR_RXDB_DATA; if (tty->flip.count >= TTY_FLIPBUF_SIZE) { /* No space for this character */ return; } *tty->flip.char_buf_ptr = ch; *tty->flip.flag_buf_ptr = TTY_NORMAL; port->icount.rx++; /* FIXME: provide a hook here for individual CPUs to interpret their error bits and update the stats and the flag_buf flags. */ tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; tty->flip.count++; tty_flip_buffer_push(tty); } static inline void iprcons_outchar(unsigned char c) { __mtpr(c, PR_TXDB); } static inline void iprcons_tx_ready(struct iprcons_serial *port) { if (port->x_char) { /* XON/XOFF chars */ iprcons_outchar(port->x_char); port->icount.tx++; port->x_char = 0; return; } /* if nothing to do or stopped */ if (port->gs.xmit_cnt <= 0) { port->gs.flags &= ~GS_TX_INTEN; iprcons_disable_tx_interrupts(port); printk("TX interrupt: nothing to transmit\n"); return; } /* If there is anything waiting, send it now */ // iprcons_outchar(port->gs.xmit_buf[port->gs.xmit_tail]); mtpr_putchar(port->gs.xmit_buf[port->gs.xmit_tail]); // printk("TX interrupt: would transmit %02x - %c\n", // port->gs.xmit_buf[port->gs.xmit_tail], // port->gs.xmit_buf[port->gs.xmit_tail]); port->gs.xmit_tail = (port->gs.xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); port->gs.xmit_cnt--; port->icount.tx++; if (port->gs.xmit_cnt <= port->gs.wakeup_chars) { iprcons_sched_event(port, IPRCONS_EVENT_WRITE_WAKEUP); } if (port->gs.xmit_cnt <= 0) { port->gs.flags &= ~GS_TX_INTEN; iprcons_disable_tx_interrupts(port); } } static void iprcons_rx_interrupt (int irq, void *dev, struct pt_regs *regs) { unsigned int rxcs = __mfpr(PR_RXCS); unsigned int rxdb = __mfpr(PR_RXDB); struct iprcons_serial *port = dev; // printk("iprcons_rx_interrupt: RXCS=%04x RXDB=%04x\n", rxcs, rxdb); if (port->gs.flags & GS_ACTIVE) { if (rxcs & PR_RXCS_RDY) { iprcons_rx_char(port, rxcs, rxdb); } } else { iprcons_disable_rx_interrupts(port); } } static void iprcons_tx_interrupt (int irq, void *dev, struct pt_regs *regs) { unsigned int txcs = __mfpr(PR_TXCS); struct iprcons_serial *port = dev; // printk("iprcons_tx_interrupt: TXCS=%04x\n", txcs); if (port->gs.flags & GS_ACTIVE) { if (txcs & PR_TXCS_RDY) { iprcons_tx_ready(port); } } else { iprcons_disable_tx_interrupts(port); } } static void do_softint(void *ptr) { struct iprcons_serial *port = ptr; struct tty_struct *tty; tty = port->gs.tty; if (!tty) return; if (test_and_clear_bit(IPRCONS_EVENT_WRITE_WAKEUP, &port->event)) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); } } /* * ------------------------------------------------------------------- * iprcons_chars_in_buffer () * * compute the amount of characters in the _hardware's_ output buffer * ------------------------------------------------------------------- */ static int iprcons_chars_in_buffer (void *ptr) { if (__mfpr(PR_TXCS) & PR_TXCS_RDY) { /* output buffer must be empty */ return 0; } else { /* Output buffer must contain 1 character */ return 1; } } /* * ------------------------------------------------------------ * iprcons_throttle () and iprcons_unthrottle () * * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled (or not). * ------------------------------------------------------------ */ static void iprcons_throttle (struct tty_struct *tty) { struct iprcons_serial *port = tty->driver_data; if (I_IXOFF(tty)) { port->x_char = STOP_CHAR(tty); } } static void iprcons_unthrottle (struct tty_struct *tty) { struct iprcons_serial *port = tty->driver_data; if (I_IXOFF(tty)) { if (port->x_char) { port->x_char = 0; } else { port->x_char = START_CHAR(tty); } } } static void iprcons_send_xchar (struct tty_struct *tty, char ch) { struct iprcons_serial *port = tty->driver_data; port->x_char = ch; if (ch) { gs_start(port->gs.tty); } } /* * ------------------------------------------------------------ * iprcons_ioctl () and friends * ------------------------------------------------------------ */ static int iprcons_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { struct iprcons_serial *port = tty->driver_data; int retval; retval = 0; switch (cmd) { case TIOCGSOFTCAR: retval = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg); break; case TIOCSSOFTCAR: retval = get_user (arg, (unsigned long *)arg); if (retval == 0) { tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0); } break; case TIOCGSERIAL: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct)); if (retval == 0) { gs_getserial(&port->gs, (struct serial_struct *) arg); } break; case TIOCSSERIAL: retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct serial_struct)); if (retval == 0) { retval = gs_setserial(&port->gs, (struct serial_struct *) arg); } break; default: return -ENOIOCTLCMD; } return 0; } /* * ------------------------------------------------------------------- * iprcons_request_irqs() * * This routine is called during the first open() on the port to * hook interrupts. * ------------------------------------------------------------------- */ static int iprcons_request_irqs(struct iprcons_serial *port) { unsigned int retval; unsigned long flags; save_and_cli(flags); retval = request_irq(IPRCONS_TX_VECTOR, iprcons_tx_interrupt, 0, "iprcons-tx", port); if (retval) { printk("iprcons: unable to acquire TX interrupt vector\n"); } else { retval = request_irq(IPRCONS_RX_VECTOR, iprcons_rx_interrupt, 0, "iprcons-rx", port); if (retval) { free_irq(IPRCONS_TX_VECTOR, port); printk("iprcons: unable to acquire RX interrupt vector\n"); } } restore_flags (flags); return retval; } static void iprcons_free_irqs(struct iprcons_serial *port) { free_irq(IPRCONS_TX_VECTOR, port); free_irq(IPRCONS_RX_VECTOR, port); } static void iprcons_shutdown_port(void *ptr) { struct iprcons_serial *port = ptr; port->gs.flags &= ~GS_ACTIVE; iprcons_free_irqs(port); } static int iprcons_set_real_termios(void *ptr) { return 0; } static void iprcons_hungup(void *ptr) { MOD_DEC_USE_COUNT; } static void iprcons_close(void *ptr) { MOD_DEC_USE_COUNT; //printk("iprcons_close: count = %d\n", ((struct iprcons_serial *)ptr)->gs.count); } static struct real_driver iprcons_real_driver = { iprcons_disable_tx_interrupts, iprcons_enable_tx_interrupts, iprcons_disable_rx_interrupts, iprcons_enable_rx_interrupts, iprcons_get_CD, iprcons_shutdown_port, iprcons_set_real_termios, iprcons_chars_in_buffer, iprcons_close, iprcons_hungup, NULL }; /* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port. It also performs the * serial-specific initialization for the tty structure. */ static int iprcons_open (struct tty_struct *tty, struct file *filp) { struct iprcons_serial *port; int retval; port = &console_state; tty->driver_data = port; port->gs.tty = tty; port->gs.count++; port->event = 0; port->tqueue.routine = do_softint; port->tqueue.data = port; //printk("iprcons_open: entered: count = %d\n", port->gs.count); retval = gs_init_port(&port->gs); if (retval) { goto failed_1; } port->gs.flags |= GS_ACTIVE; if (port->gs.count == 1) { MOD_INC_USE_COUNT; retval = iprcons_request_irqs(port); if (retval) { goto failed_2; } } retval = gs_block_til_ready(port, filp); if (retval) { goto failed_3; } if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) { *tty->termios = port->gs.normal_termios; } else { *tty->termios = port->gs.callout_termios; } } iprcons_enable_rx_interrupts(port); port->gs.session = current->session; port->gs.pgrp = current->pgrp; return 0; failed_3: iprcons_free_irqs(port); failed_2: MOD_DEC_USE_COUNT; failed_1: port->gs.count--; return retval; } int __init iprcons_init(void) { /* Should really check for CPUs with IPR-based consoles here */ int error; struct iprcons_serial *port; memset(&iprcons_serial_driver, 0, sizeof(iprcons_serial_driver)); iprcons_serial_driver.magic = TTY_DRIVER_MAGIC; iprcons_serial_driver.name = "ttyS"; iprcons_serial_driver.major = TTY_MAJOR; iprcons_serial_driver.minor_start = 64; iprcons_serial_driver.num = 1; iprcons_serial_driver.type = TTY_DRIVER_TYPE_SERIAL; iprcons_serial_driver.subtype = SERIAL_TYPE_NORMAL; iprcons_serial_driver.init_termios = tty_std_termios; iprcons_serial_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; iprcons_serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; iprcons_serial_driver.refcount = &iprcons_refcount; iprcons_serial_driver.table = iprcons_table; iprcons_serial_driver.termios = iprcons_termios; iprcons_serial_driver.termios_locked = iprcons_termios_locked; iprcons_serial_driver.open = iprcons_open; iprcons_serial_driver.close = gs_close; iprcons_serial_driver.write = gs_write; iprcons_serial_driver.put_char = gs_put_char; iprcons_serial_driver.flush_chars = gs_flush_chars; iprcons_serial_driver.write_room = gs_write_room; iprcons_serial_driver.chars_in_buffer = gs_chars_in_buffer; iprcons_serial_driver.flush_buffer = gs_flush_buffer; iprcons_serial_driver.ioctl = iprcons_ioctl; iprcons_serial_driver.throttle = iprcons_throttle; iprcons_serial_driver.unthrottle = iprcons_unthrottle; iprcons_serial_driver.send_xchar = iprcons_send_xchar; iprcons_serial_driver.stop = gs_stop; iprcons_serial_driver.start = gs_start; iprcons_serial_driver.hangup = gs_hangup; /* * The callout device is just like normal device except for major * number and the subtype code. */ iprcons_callout_driver = iprcons_serial_driver; iprcons_callout_driver.name = "cua"; iprcons_callout_driver.major = TTYAUX_MAJOR; iprcons_callout_driver.subtype = SERIAL_TYPE_CALLOUT; error = tty_register_driver (&iprcons_serial_driver); if (error) { printk("iprcons: Couldn't register serial driver: error = %d\n", error); return 1; } error = tty_register_driver (&iprcons_callout_driver); if (error) { tty_unregister_driver(&iprcons_serial_driver); printk("iprcons: Couldn't register callout driver: error = %d\n", error); return 1; } port = &console_state; memset(port, 0, sizeof(*port)); port->gs.magic = SERIAL_MAGIC; port->gs.callout_termios = iprcons_callout_driver.init_termios; port->gs.normal_termios = iprcons_serial_driver.init_termios; port->gs.close_delay = HZ/2; port->gs.closing_wait = 30 * HZ; init_waitqueue_head(&port->gs.open_wait); init_waitqueue_head(&port->gs.close_wait); port->gs.rd = &iprcons_real_driver; printk("ttyS0: Internal processor register console\n"); return 0; } __initcall(iprcons_init); /* End of regular serial port support - the rest of this file is related to serial console (printk) support */ #ifdef CONFIG_SERIAL_CONSOLE static void iprcons_console_print(struct console *cons, const char *str, unsigned int count) { unsigned int old_ie; old_ie = __mfpr(PR_TXCS) & PR_TXCS_IE; /* Ensure TX interrupts are disabled */ __mtpr(0, PR_TXCS); while (count--) { if (*str == '\n') { mtpr_putchar('\r'); } mtpr_putchar(*str++); } /* Enable TX interrupts again if necessary */ __mtpr(old_ie, PR_TXCS); } static kdev_t iprcons_console_device(struct console *cons) { return mk_kdev(TTY_MAJOR, 64); } static struct console iprcons_sercons = { name: "ttyS", write: iprcons_console_print, device: iprcons_console_device, flags: CON_CONSDEV | CON_PRINTBUFFER, index: 0, }; void __init iprcons_serial_console_init(void) { register_console(&iprcons_sercons); } #endif /* ifdef CONFIG_SERIAL_CONSOLE */ Index: Makefile =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/drivers/vax/char/Makefile,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- Makefile 18 Jul 2002 23:39:33 -0000 1.1 +++ Makefile 29 Sep 2002 19:33:16 -0000 1.2 @@ -1,5 +1,5 @@ # -# Makefile for the Linux/VAX network device drivers. +# Makefile for the Linux/VAX character device drivers. # O_TARGET := vaxchar.o @@ -8,7 +8,7 @@ obj-m := obj-n := -# obj-$(CONFIG_SERIAL_KA650) += ka650_console.o +obj-$(CONFIG_SERIAL_IPR) += iprcons.o include $(TOPDIR)/Rules.make |
From: Kenn H. <ke...@us...> - 2002-09-29 19:33:20
|
Update of /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel In directory usw-pr-cvs1:/tmp/cvs-serv29366/arch/vax/kernel Modified Files: cpu_ka650.c Log Message: Partially-working driver for console serial ports driven by RXCS, RXDB, TXCS and TXDB internal processor registers. printk() works, but it doesn't yet work for regalar userland I/O. Enabled by CONFIG_SERIAL_IPR config option. Only supported for KA650 right now. Index: cpu_ka650.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/cpu_ka650.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- cpu_ka650.c 20 May 2002 01:09:49 -0000 1.5 +++ cpu_ka650.c 29 Sep 2002 19:33:16 -0000 1.6 @@ -54,6 +54,8 @@ unsigned int *ka650_cacr = (unsigned int *)0x20084000; +extern void iprcons_serial_console_init(void); + void ka650_pre_vm_init(void) { mv_ka650.sidex = *(unsigned int *)CVAX_SIDEX_ADDR; @@ -95,7 +97,9 @@ /* Writing to PR_CADR on the CVAX chip implicitly clears the level 1 cache */ __mtpr(KA650_CADR_S2E|KA650_CADR_S1E|KA650_CADR_ISE|KA650_CADR_DSE, PR_CADR); - register_console(&vax_console); +#if defined(CONFIG_SERIAL_IPR) && defined(CONFIG_SERIAL_CONSOLE) + iprcons_serial_console_init(); +#endif printk("KA650 sidex = %08x\n", mv_ka650.sidex); } |
From: Kenn H. <ke...@us...> - 2002-09-29 19:33:19
|
Update of /cvsroot/linux-vax/kernel-2.5/drivers/char In directory usw-pr-cvs1:/tmp/cvs-serv29366/drivers/char Modified Files: Makefile Log Message: Partially-working driver for console serial ports driven by RXCS, RXDB, TXCS and TXDB internal processor registers. printk() works, but it doesn't yet work for regalar userland I/O. Enabled by CONFIG_SERIAL_IPR config option. Only supported for KA650 right now. Index: Makefile =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/drivers/char/Makefile,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- Makefile 24 Apr 2002 08:46:44 -0000 1.1.1.1 +++ Makefile 29 Sep 2002 19:33:16 -0000 1.2 @@ -164,6 +164,7 @@ obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o +obj-$(CONFIG_SERIAL_IPR) += generic_serial.o subdir-$(CONFIG_RIO) += rio subdir-$(CONFIG_INPUT) += joystick |
From: Kenn H. <ke...@us...> - 2002-09-29 19:33:19
|
Update of /cvsroot/linux-vax/kernel-2.5/arch/vax In directory usw-pr-cvs1:/tmp/cvs-serv29366/arch/vax Modified Files: config.in ka650.config Log Message: Partially-working driver for console serial ports driven by RXCS, RXDB, TXCS and TXDB internal processor registers. printk() works, but it doesn't yet work for regalar userland I/O. Enabled by CONFIG_SERIAL_IPR config option. Only supported for KA650 right now. Index: config.in =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/config.in,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- config.in 18 Jul 2002 23:56:36 -0000 1.7 +++ config.in 29 Sep 2002 19:33:15 -0000 1.8 @@ -158,11 +158,10 @@ if [ "$CONFIG_VT" = "y" ]; then bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE fi -tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL +tristate 'Serial port support' CONFIG_SERIAL if [ "$CONFIG_SERIAL" = "y" ]; then bool 'DZ11 Serial Support' CONFIG_DZ - bool 'CPU register-based Serial Console Support' CONFIG_SERIAL_MTPR - bool 'KA640/650/655 Serial Console Support' CONFIG_SERIAL_KA650 + bool 'CPU register-based Serial Console Support' CONFIG_SERIAL_IPR bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE fi bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS Index: ka650.config =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/ka650.config,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- ka650.config 18 Jul 2002 23:56:36 -0000 1.3 +++ ka650.config 29 Sep 2002 19:33:15 -0000 1.4 @@ -273,8 +273,7 @@ # CONFIG_VT is not set CONFIG_SERIAL=y # CONFIG_DZ is not set -CONFIG_SERIAL_MTPR=y -CONFIG_SERIAL_KA650=y +CONFIG_SERIAL_IPR=y CONFIG_SERIAL_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 |
From: Kenn H. <ke...@us...> - 2002-09-29 19:29:56
|
Update of /cvsroot/linux-vax/kernel-2.5 In directory usw-pr-cvs1:/tmp/cvs-serv28936 Modified Files: Makefile Log Message: vaxchar.o from drivers/vax/char needs to be linked into kernel Index: Makefile =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/Makefile,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- Makefile 10 Aug 2002 18:04:55 -0000 1.6 +++ Makefile 29 Sep 2002 19:29:49 -0000 1.7 @@ -190,6 +190,7 @@ DRIVERS-$(CONFIG_VSBUS) += drivers/vsbus/vsbus.a DRIVERS-$(CONFIG_VAX) += drivers/vax/bus/vaxbus.o +DRIVERS-$(CONFIG_VAX) += drivers/vax/char/vaxchar.o DRIVERS-$(CONFIG_VAX) += drivers/vax/net/vaxnet.o DRIVERS := $(DRIVERS-y) |
From: Kenn H. <ke...@us...> - 2002-08-10 18:20:04
|
Update of /cvsroot/linux-vax/kernel-2.5/drivers/vax/net In directory usw-pr-cvs1:/tmp/cvs-serv21005 Modified Files: delqa.c Log Message: Add spin lock (should now be safe for SMP/pre-emtive kernel). Split DELQA reset out from delqa_open into a separate function. Index: delqa.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/drivers/vax/net/delqa.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- delqa.c 18 Jul 2002 23:39:33 -0000 1.1 +++ delqa.c 10 Aug 2002 18:20:01 -0000 1.2 @@ -14,8 +14,14 @@ TODO: Allow multiple DELQAs at different base addresses. - TODO: SMP awareness (is this just a spinlock in delqa_private?) + TODO: Reset BELQA on q-bus memory access error (is this the right + thing to do?). + TODO: Implement delqa_tx_timeout(). + + TODO: Handle multicast addresses and PROMISC flag in format_setup_frame(). + + TODO: Implement delqa_close(). */ @@ -57,8 +63,6 @@ struct delqa_bufdesc txdesc[TXDESCS+1]; }; -/* FIXME: add a spinlock to this structure */ - struct delqa_private { unsigned char *base; unsigned int qbus_vector; @@ -74,6 +78,7 @@ unsigned int next_tx_pending; /* Only written by init and interrupt code */ unsigned int next_rx; unsigned int last_tdr; /* Last Time Domain Reflectometer value on TX */ + spinlock_t lock; }; #define LOWORD(x) ((int)(x) & 0xffff) @@ -409,6 +414,8 @@ unsigned int csr; unsigned int newcsr; + spin_lock(&priv->lock); + csr = read_reg(priv, DELQA_CSR); #if DELQA_DEBUG_CSR @@ -445,10 +452,11 @@ this point. */ write_reg(priv, DELQA_CSR, newcsr); - #if DELQA_DEBUG_CSR dump_csr("delqa_interrupt exit", dev); #endif + + spin_unlock(&priv->lock); } static int delqa_start_xmit(struct sk_buff *skb, struct net_device *dev) @@ -459,6 +467,7 @@ unsigned int i; unsigned int busaddr; unsigned int csr; + unsigned int flags; if (skb->len < ETH_ZLEN) { struct sk_buff *new_skb; @@ -480,12 +489,16 @@ skb = new_skb; } + spin_lock_irqsave(&priv->lock, flags); + i = priv->next_tx_free; priv->next_tx_free++; if (priv->next_tx_free == TXDESCS) { priv->next_tx_free = 0; } + spin_unlock_irqrestore(&priv->lock, flags); + desc = priv->descs->txdesc + i; /* FIXME: These mapping registers MUST be allocated at init time @@ -528,6 +541,8 @@ dump_descs(dev); #endif + spin_lock_irqsave(&priv->lock, flags); + csr = read_reg(priv, DELQA_CSR); if (csr & DELQA_CSR_XL_INVALID) { @@ -546,6 +561,8 @@ netif_stop_queue(dev); } + spin_unlock_irqrestore(&priv->lock, flags); + return 0; } @@ -607,6 +624,8 @@ /* Point the first available TX descriptor at the setup frame and enable the transmitter */ + spin_lock(&priv->lock); + i = priv->next_tx_free; priv->next_tx_free++; @@ -614,6 +633,8 @@ priv->next_tx_free = 0; } + spin_unlock(&priv->lock); + desc = priv->descs->txdesc + i; priv->tx_map[i] = qbus_alloc_mapregs(priv->setup_frame, priv->setup_frame_len); @@ -635,6 +656,8 @@ dump_descs(dev); #endif + spin_lock(&priv->lock); + csr = read_reg(priv, DELQA_CSR); if (csr & DELQA_CSR_XL_INVALID) { @@ -646,23 +669,15 @@ write_reg(priv, DELQA_XMTH, HIWORD(busaddr)); } + spin_unlock(&priv->lock); } -static int delqa_open(struct net_device *dev) +static void delqa_reset(struct net_device *dev) { struct delqa_private *priv = (struct delqa_private *)dev->priv; - struct delqa_bufdesc *desc; unsigned int csr; - int i; - unsigned int busaddr; - - if (qbus_request_irq(priv->qbus_vector, delqa_interrupt, 0, "delqa", dev)) { - printk("delqa_open: cannot get qbus irq %d\n", priv->qbus_vector); - return -EAGAIN; - } - /* Reset the hardware */ - printk("Resetting DELQA... "); + printk("%s: resetting DELQA... ", dev->name); write_reg(priv, DELQA_CSR, DELQA_CSR_RESET); udelay(1000); @@ -672,6 +687,25 @@ write_reg(priv, DELQA_VECTOR, priv->qbus_vector); printk("done\n"); +} + +static int delqa_open(struct net_device *dev) +{ + struct delqa_private *priv = (struct delqa_private *)dev->priv; + struct delqa_bufdesc *desc; + int i; + unsigned int busaddr; + + /* Reset the hardware before hooking the interrupt vector + to guarantee that we won't get any interrupts until we + enable them. */ + + delqa_reset(dev); + + if (qbus_request_irq(priv->qbus_vector, delqa_interrupt, 0, "delqa", dev)) { + printk("delqa_open: cannot get qbus irq %d\n", priv->qbus_vector); + return -EAGAIN; + } /* Mark the transmit descriptors as not yet owned by the DELQA (and also not VALID). */ @@ -836,6 +870,8 @@ memset(dev->priv, 0, sizeof(struct delqa_private)); priv = (struct delqa_private *) dev->priv; + + spin_lock_init(&priv->lock); priv->base = ioremap(DELQA_BASE, 16); if (priv->base == NULL) { |
From: Kenn H. <ke...@us...> - 2002-08-10 18:05:03
|
Update of /cvsroot/linux-vax/kernel-2.5 In directory usw-pr-cvs1:/tmp/cvs-serv17808 Modified Files: Makefile Log Message: Include drivers/vax/bus and drivers/vax/net in the link. Also disable parallel make to give easier-to-read compile output Index: Makefile =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/Makefile,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- Makefile 6 Jun 2002 00:12:24 -0000 1.5 +++ Makefile 10 Aug 2002 18:04:55 -0000 1.6 @@ -41,7 +41,7 @@ MODFLAGS = -DMODULE CFLAGS_KERNEL = PERL = perl -MAKE = make -j3 +MAKE = make #-j3 export VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \ CONFIG_SHELL TOPDIR HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \ @@ -188,6 +188,9 @@ DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o DRIVERS-$(CONFIG_VSBUS) += drivers/vsbus/vsbus.a + +DRIVERS-$(CONFIG_VAX) += drivers/vax/bus/vaxbus.o +DRIVERS-$(CONFIG_VAX) += drivers/vax/net/vaxnet.o DRIVERS := $(DRIVERS-y) |
From: Kenn H. <ke...@us...> - 2002-07-18 23:56:46
|
Update of /cvsroot/linux-vax/kernel-2.5/arch/vax In directory usw-pr-cvs1:/tmp/cvs-serv4405 Modified Files: config.in ka650.config Log Message: Add DELQA and some KA650-related config options. Sample config for KA650 updated. Index: config.in =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/config.in,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- config.in 5 Jun 2002 21:55:03 -0000 1.6 +++ config.in 18 Jul 2002 23:56:36 -0000 1.7 @@ -73,13 +73,12 @@ endmenu -# Bus support options are not implemented yet, but they'll go here in -# the config. +# Q-bus and the "vsbus" are the only busses with any support currently mainmenu_option next_comment comment 'Bus support' bool 'Support for Q-bus' CONFIG_QBUS -bool 'Support for Unibus' CONFIG_UNIBUS -bool 'Support for VAXBI' CONFIG_VAXBI +#bool 'Support for Unibus' CONFIG_UNIBUS +#bool 'Support for VAXBI' CONFIG_VAXBI bool 'Support for Vax Station BUS (??)' CONFIG_VSBUS if [ "$CONFIG_VSBUS" != "n" ]; then bool 'Hardcode 4000/60 (temporary for now - DA)' CONFIG_VAX_4000HC @@ -142,6 +141,7 @@ fi bool 'LANCE ethernet controller support' CONFIG_VAX_LANCE bool 'SGEC ethernet controller support (EXPERIMENTAL)' CONFIG_SGEC + bool 'DELQA/DEQNA Q-bus ethernet controller support' CONFIG_DELQA fi endmenu @@ -162,6 +162,7 @@ if [ "$CONFIG_SERIAL" = "y" ]; then bool 'DZ11 Serial Support' CONFIG_DZ bool 'CPU register-based Serial Console Support' CONFIG_SERIAL_MTPR + bool 'KA640/650/655 Serial Console Support' CONFIG_SERIAL_KA650 bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE fi bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS Index: ka650.config =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/ka650.config,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- ka650.config 6 Jun 2002 00:12:24 -0000 1.2 +++ ka650.config 18 Jul 2002 23:56:36 -0000 1.3 @@ -45,8 +45,6 @@ # Bus support # CONFIG_QBUS=y -CONFIG_UNIBUS=y -CONFIG_VAXBI=y # CONFIG_VSBUS is not set # @@ -125,7 +123,13 @@ # # Network device support # -# CONFIG_NETDEVICES is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_SLIP is not set +# CONFIG_PPP is not set +# CONFIG_VAX_LANCE is not set +# CONFIG_SGEC is not set +CONFIG_DELQA=y # # File systems @@ -270,6 +274,7 @@ CONFIG_SERIAL=y # CONFIG_DZ is not set CONFIG_SERIAL_MTPR=y +CONFIG_SERIAL_KA650=y CONFIG_SERIAL_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 |
From: Kenn H. <ke...@us...> - 2002-07-18 23:53:47
|
Update of /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel In directory usw-pr-cvs1:/tmp/cvs-serv3819 Modified Files: vax_dev_init.c Log Message: init functions need to return an int Index: vax_dev_init.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/vax_dev_init.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- vax_dev_init.c 6 Jun 2002 00:12:24 -0000 1.4 +++ vax_dev_init.c 18 Jul 2002 23:53:44 -0000 1.5 @@ -14,13 +14,12 @@ #include <asm/mv.h> #include <asm/vaxcpu.h> - -static void __init vax_dev_init(void) +static int __init vax_dev_init(void) { if (mv->init_devices) { mv->init_devices(); } - return; + return 1; } subsys_initcall(vax_dev_init); |
From: Kenn H. <ke...@us...> - 2002-07-18 23:50:43
|
Update of /cvsroot/linux-vax/kernel-2.5/include/asm-vax/mm In directory usw-pr-cvs1:/tmp/cvs-serv2723 Modified Files: virtmap.h Log Message: I/O bus addresses have no simple relationship with virtual addresses. Index: virtmap.h =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/include/asm-vax/mm/virtmap.h,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- virtmap.h 31 May 2002 01:58:39 -0000 1.4 +++ virtmap.h 18 Jul 2002 23:50:40 -0000 1.5 @@ -37,11 +37,6 @@ extern void iounmap(void *addr); -/* - * IO bus memory addresses are also 1:1 with the physical address - */ -#define virt_to_bus virt_to_phys -#define bus_to_virt phys_to_virt /* Needed for BIO layer. Convert a struct page * to a physical address */ #define page_to_phys(page) (((page) - mem_map) << PAGE_SHIFT) |
From: Kenn H. <ke...@us...> - 2002-07-18 23:50:12
|
Update of /cvsroot/linux-vax/kernel-2.5/include/asm-vax/bus In directory usw-pr-cvs1:/tmp/cvs-serv2609 Added Files: qbus.h Log Message: Public interface to KA650 Q-bus driver. This is going to change greatly... --- NEW FILE --- #include <asm/dma.h> /* Soon these functions will be moved to a bus_ops structure */ void qbus_dumpmap(void); struct vax_dmamap *qbus_alloc_mapregs(void *start, unsigned int len); void qbus_unmap(struct vax_dmamap *mapping); int qbus_vector_to_irq(unsigned int vector); int qbus_request_irq(unsigned int qbus_vector, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id); |
From: Kenn H. <ke...@us...> - 2002-07-18 23:48:44
|
Update of /cvsroot/linux-vax/kernel-2.5/include/asm-vax In directory usw-pr-cvs1:/tmp/cvs-serv2191 Modified Files: dma.h Log Message: Add vax_dmamap structure - used to track mapping register allocations in bas adapter drivers. Also remove PC-related stuff that doesn't apply to VAX. Index: dma.h =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/include/asm-vax/dma.h,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- dma.h 20 May 2002 00:33:39 -0000 1.3 +++ dma.h 18 Jul 2002 23:48:41 -0000 1.4 @@ -1,13 +1,23 @@ #ifndef _VAX_DMA_H #define _VAX_DMA_H 1 + +/* This structure is used to keep track of bug map register + allocations. You get one from a bus driver's alloc_mapreg + function and release it by calling the bus driver's unmap + function. */ + +struct vax_dmamap { + unsigned int reg; + unsigned int pagelets; + void *virtaddr; + unsigned int busaddr; +}; + + /* Some peripherals are limited by their PC/ISA designs/heritage. */ /* max dma address is 16mb used in mm/init.c*/ #define MAX_DMA_ADDRESS (PAGE_OFFSET+0x1000000) -#define MAX_DMA_CHANNELS 8 - -extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ -extern void free_dma(unsigned int dmanr); /* release it again */ #endif /* _VAX_DMA_H */ |
From: Kenn H. <ke...@us...> - 2002-07-18 23:45:24
|
Update of /cvsroot/linux-vax/kernel-2.5/include/asm-vax In directory usw-pr-cvs1:/tmp/cvs-serv1395 Modified Files: types.h Log Message: We don't have 64-bit DMA addresses Index: types.h =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/include/asm-vax/types.h,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- types.h 20 May 2002 00:33:39 -0000 1.3 +++ types.h 18 Jul 2002 23:45:21 -0000 1.4 @@ -46,7 +46,6 @@ /* DMA addresses come in generic and 64-bit flavours. */ typedef u32 dma_addr_t; -typedef u64 dma64_addr_t; #endif /* __KERNEL__ */ |
From: Kenn H. <ke...@us...> - 2002-07-18 23:39:36
|
Update of /cvsroot/linux-vax/kernel-2.5/drivers/vax/net In directory usw-pr-cvs1:/tmp/cvs-serv31692/vax/net Added Files: .cvsignore Makefile delqa-regs.h delqa.c Log Message: Mostly-complete DELQA driver. First cut at driver for the Q-bus adapter in the KA650 CPU. --- NEW FILE --- *.a.flags *.o.flags .depend *.lst --- NEW FILE --- # # Makefile for the Linux/VAX network device drivers. # O_TARGET := vaxnet.o obj-y := obj-m := obj-n := obj-$(CONFIG_DELQA) += delqa.o include $(TOPDIR)/Rules.make --- NEW FILE --- /* Register offsets */ #define DELQA_ADDR1 0 #define DELQA_ADDR2 2 #define DELQA_RCLL 4 /* loword of first RX descriptor addr */ #define DELQA_RCLH 6 /* hiword of first RX descriptor addr */ #define DELQA_XMTL 8 /* loword of first TX descriptor addr */ #define DELQA_XMTH 10 /* hiword of first TX descriptor addr */ #define DELQA_VECTOR 12 /* Q-bus interrupt vector */ #define DELQA_CSR 14 /* control & status */ /* Bits in CSR */ #define DELQA_CSR_RCV_ENABLE 0x0001 /* Receiver enable */ #define DELQA_CSR_RESET 0x0002 /* Software reset */ #define DELQA_CSR_NEX_MEM_INT 0x0004 /* Non-existent memory interrupt */ #define DELQA_CSR_LOAD_ROM 0x0008 /* Load boot/diag from rom */ #define DELQA_CSR_XL_INVALID 0x0010 /* Transmit list invalid */ #define DELQA_CSR_RL_INVALID 0x0020 /* Receive list invalid */ #define DELQA_CSR_INT_ENABLE 0x0040 /* Interrupt enable */ #define DELQA_CSR_XMIT_INT 0x0080 /* Transmit interrupt */ #define DELQA_CSR_ILOOP 0x0100 /* Internal loopback */ #define DELQA_CSR_ELOOP 0x0200 /* External loopback */ #define DELQA_CSR_STIM_ENABLE 0x0400 /* Sanity timer enable */ #define DELQA_CSR_POWERUP 0x1000 /* Transceiver power on */ #define DELQA_CSR_CARRIER 0x2000 /* Carrier detect */ #define DELQA_CSR_RCV_INT 0x8000 /* Receiver interrupt */ /* Bits in ADDR_HI field in descriptors */ #define DELQA_ADDRHI_VALID 0x8000 /* ADDRHI/LO are valid */ #define DELQA_ADDRHI_CHAIN 0x4000 /* ADDRHI/LO points to next descriptor */ #define DELQA_ADDRHI_EOMSG 0x2000 /* Buffer contains last byte of frame */ #define DELQA_ADDRHI_SETUP 0x1000 /* Buffer contains a setup frame */ #define DELQA_ADDRHI_ODDEND 0x0080 /* last byte not on word boundary */ #define DELQA_ADDRHI_ODDBEGIN 0x0040 /* first byte not on word boundary */ /* Bits in buffer descriptor field STATUS1 for transmit */ #define DELQA_TXSTS1_LASTNOT 0x8000 #define DELQA_TXSTS1_ERRORUSED 0x4000 #define DELQA_TXSTS1_LOSS 0x1000 #define DELQA_TXSTS1_NOCARRIER 0x0800 #define DELQA_TXSTS1_STE16 0x0400 #define DELQA_TXSTS1_ABORT 0x0200 #define DELQA_TXSTS1_FAIL 0x0100 #define DELQA_TXSTS1_COUNT_MASK 0x00f0 #define DELQA_TXSTS1_COUNT_SHIFT 4 /* Special value that signifies that descriptor is not yet used by DELQA. The descriptor FLAG and STATUS1 fields both get initialized to this value. */ #define DELQA_NOTYET 0x8000 /* Bits in buffer descriptor field STATUS1 for transmit */ #define DELQA_TXSTS2_TDR_MASK 0x3fff #define DELQA_TXSTS2_TDR_SHIFT 0 /* Bits in buffer descriptor field STATUS1 for receive */ #define DELQA_RXSTS1_LASTNOT 0x8000 #define DELQA_RXSTS1_ERRORUSED 0x4000 #define DELQA_RXSTS1_ESETUP 0x2000 #define DELQA_RXSTS1_DISCARD 0x1000 #define DELQA_RXSTS1_RUNT 0x0800 #define DELQA_RXSTS1_LEN_HI_MASK 0x0700 #define DELQA_RXSTS1_LEN_HI_SHIFT 8 #define DELQA_RXSTS1_FRAME 0x0004 #define DELQA_RXSTS1_CRCERR 0x0002 #define DELQA_RXSTS1_OVF 0x0001 /* Bits in buffer descriptor field STATUS2 for receive */ #define DELQA_RXSTS2_LEN_LO1_MASK 0x00ff #define DELQA_RXSTS2_LEN_LO1_SHIFT 0 #define DELQA_RXSTS2_LEN_LO2_MASK 0xff00 #define DELQA_RXSTS2_LEN_LO2_SHIFT 8 --- NEW FILE --- /* $Id: delqa.c,v 1.1 2002/07/18 23:39:33 kenn Exp $ Quick-and-dirty driver for DELQA/DESQA (Q-bus ethernet adapters) (C) 2002, Kenn Humborg TODO: Pre-allocate the Q-bus mapping registers for TX at init time and re-use them, rather than allocating them for each packet. This would remove the only failure possibility from delqa_start_xmit(). TODO: Don't hard-code the interrupt vector. Add an API to the Q-bus driver to allocate a vector instead. TODO: Allow multiple DELQAs at different base addresses. TODO: SMP awareness (is this just a spinlock in delqa_private?) */ #include <linux/init.h> #include <linux/netdevice.h> #include <linux/delay.h> #include <linux/etherdevice.h> #include <asm/system.h> #include <asm/bus/qbus.h> #include "delqa-regs.h" #define DELQA_DEBUG_REGWR 0 #define DELQA_DEBUG_CSR 0 #define DELQA_DEBUG_DESC 0 #define DELQA_DEBUG_PKT 0 #define DELQA_BASE 0x20001920 #define DELQA_QBUS_VECTOR 4 /* FIXME: Are these numbers OK? These are what NetBSD uses. */ #define RXDESCS 30 #define TXDESCS 60 #define RXBUFSIZE 2048 struct delqa_bufdesc { unsigned short flag; unsigned short addr_hi; unsigned short addr_lo; signed short buflen; unsigned short status1; unsigned short status2; }; struct delqa_descs { struct delqa_bufdesc rxdesc[RXDESCS+1]; struct delqa_bufdesc txdesc[TXDESCS+1]; }; /* FIXME: add a spinlock to this structure */ struct delqa_private { unsigned char *base; unsigned int qbus_vector; struct net_device_stats stats; struct delqa_descs *descs; struct vax_dmamap *desc_map; /* DMA mapping for delqa_descs structure */ struct vax_dmamap *rx_map[RXDESCS]; /* DMA mappings for each RX buffer */ struct vax_dmamap *tx_map[TXDESCS]; /* DMA mappings for each TX buffer */ struct sk_buff *tx_skb[TXDESCS]; /* We TX direct from the SKB */ unsigned char setup_frame[128]; unsigned char setup_frame_len; unsigned int next_tx_free; /* Only written by mainline code */ unsigned int next_tx_pending; /* Only written by init and interrupt code */ unsigned int next_rx; unsigned int last_tdr; /* Last Time Domain Reflectometer value on TX */ }; #define LOWORD(x) ((int)(x) & 0xffff) #define HIWORD(x) (((int)(x)>>16) & 0xffff) static unsigned short int read_reg(struct delqa_private *priv, unsigned int offset) { volatile unsigned short int *p; p = (volatile unsigned short *)(priv->base + offset); return *p; } static void write_reg(struct delqa_private *priv, unsigned int offset, unsigned short int value) { volatile unsigned short int *p; #if DELQA_DEBUG_REGWR char *reg[8] = { "ADDR1", "ADDR2", "RCCL", "RCLH", "XMTL", "XMTH", "VECTOR", "CSR"}; printk("delqa write_reg: offset %02d(%s) value %04x\n", offset, reg[offset/2], value); #endif p = (volatile unsigned short *)(priv->base + offset); *p = value; } static void dump_csr(char *msg, struct net_device *dev) { struct delqa_private *priv = (struct delqa_private *)dev->priv; unsigned short csr = read_reg(priv, DELQA_CSR); printk("%s: %s: CSR %04x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", dev->name, msg == NULL ? "" : msg, csr, (csr & DELQA_CSR_RCV_INT) ? " RI" : "", (csr & DELQA_CSR_CARRIER) ? " CA" : "", (csr & DELQA_CSR_POWERUP) ? " OK" : "", (csr & DELQA_CSR_STIM_ENABLE) ? " SE" : "", (csr & DELQA_CSR_ELOOP) ? " EL" : "", (csr & DELQA_CSR_ILOOP) ? "" : " IL", /* active low */ (csr & DELQA_CSR_XMIT_INT) ? " XI" : "", (csr & DELQA_CSR_INT_ENABLE) ? " IE" : "", (csr & DELQA_CSR_RL_INVALID) ? " RL" : "", (csr & DELQA_CSR_XL_INVALID) ? " XL" : "", (csr & DELQA_CSR_LOAD_ROM) ? " BD" : "", (csr & DELQA_CSR_NEX_MEM_INT) ? " NI" : "", (csr & DELQA_CSR_RESET) ? " SR" : "", (csr & DELQA_CSR_RCV_ENABLE) ? " RE" : ""); } /* . -> Invalid + -> Valid, not yet used by DELQA * -> Valid, owned by DELQA (in progress) - -> Valid, processed by DELQA - no errors x -> Valid, processed by DELQA - with errors c -> Valid, chain descriptor */ static void dump_descs(struct net_device *dev) { unsigned int i; struct delqa_private *priv = (struct delqa_private *)dev->priv; struct delqa_bufdesc *desc; printk("%s: TX free=%02d pending=%02d ", dev->name, priv->next_tx_free, priv->next_tx_pending); for (i=0; i<TXDESCS+1; i++) { desc = priv->descs->txdesc + i; if (desc->addr_hi & DELQA_ADDRHI_CHAIN) { printk("c"); } else if (desc->addr_hi & DELQA_ADDRHI_VALID) { /* VALID bit set */ switch (desc->status1 & (DELQA_TXSTS1_LASTNOT|DELQA_TXSTS1_ERRORUSED)) { case 0: printk("-"); break; case DELQA_TXSTS1_ERRORUSED: printk("x"); break; case DELQA_TXSTS1_LASTNOT: if (desc->flag & 0x4000) { printk("*"); } else { printk("+"); } break; case DELQA_TXSTS1_LASTNOT|DELQA_TXSTS1_ERRORUSED: /* Don't expect this, since we never break packets across buffers */ printk("?"); break; } } else { printk("."); } } printk("\n"); printk("%s: RX next=%02d ", dev->name, priv->next_rx); for (i=0; i<RXDESCS+1; i++) { desc = priv->descs->rxdesc + i; if (desc->addr_hi & DELQA_ADDRHI_CHAIN) { printk("c"); } else if (desc->addr_hi & DELQA_ADDRHI_VALID) { /* VALID bit set */ switch (desc->status1 & (DELQA_RXSTS1_LASTNOT|DELQA_RXSTS1_ERRORUSED)) { case 0: printk("-"); break; case DELQA_RXSTS1_ERRORUSED: printk("x"); break; case DELQA_RXSTS1_LASTNOT: if (desc->flag & 0x4000) { printk("*"); } else { printk("+"); } break; case DELQA_RXSTS1_LASTNOT|DELQA_RXSTS1_ERRORUSED: /* Don't expect this, since we never break packets across buffers */ printk("?"); break; } } else { printk("."); } } printk("\n"); } static void delqa_tx_interrupt(struct net_device *dev, struct delqa_private *priv) { struct delqa_bufdesc *desc; int desc_freed = 0; unsigned int tdr; unsigned int collisions; /* Get first descriptor waiting to be "taken back" from the DELQA */ desc = priv->descs->txdesc + priv->next_tx_pending; while (desc->status1 != DELQA_NOTYET) { #if DELQA_DEBUG_PKT printk("TX desc %d, status1=%04x, status2=%04x\n", priv->next_tx_pending, desc->status1, desc->status2); #endif tdr = (desc->status2 & DELQA_TXSTS2_TDR_MASK) >> DELQA_TXSTS2_TDR_SHIFT; collisions = (desc->status1 & DELQA_TXSTS1_COUNT_MASK) >> DELQA_TXSTS1_COUNT_SHIFT; if (desc->status1 & DELQA_TXSTS1_ERRORUSED) { priv->stats.tx_errors++; if (desc->status1 & DELQA_TXSTS1_LOSS) { printk("%s: carrier lost on transmit - " "ethernet cable problem?", dev->name); } if (desc->status1 & DELQA_TXSTS1_NOCARRIER) { printk("%s: no carrier on transmit - " "transceiver or transceiver cable problem?", dev->name); } if (desc->status1 & DELQA_TXSTS1_ABORT) { if (tdr == priv->last_tdr) { printk("%s: excessive collisions on transmit", dev->name); } else { printk("%s: excessive collisions on transmit - " "cable fault at TDR=%d\n", dev->name, tdr); } if (collisions == 0) { /* Collision counter overflowed */ priv->stats.collisions += 16; } } } else { if (desc->addr_hi & DELQA_ADDRHI_SETUP) { /* Don't count setup frames in stats */ } else { /* Packet got onto the wire */ priv->stats.tx_packets++; priv->stats.tx_bytes += desc->buflen * 2; } } priv->stats.collisions += collisions; priv->last_tdr = tdr; if (desc->addr_hi & DELQA_ADDRHI_SETUP) { /* Setup frame - no associated skb */ } else { dev_kfree_skb_irq(priv->tx_skb[priv->next_tx_pending]); } /* clear VALID bit */ desc->addr_hi = 0; /* reclaim descriptor */ desc->flag = DELQA_NOTYET; desc->status1 = DELQA_NOTYET; desc->status2 = 0; /* Free the mapping registers */ qbus_unmap(priv->tx_map[priv->next_tx_pending]); /* At least one descriptor freed up */ desc_freed = 1; priv->next_tx_pending++; if (priv->next_tx_pending == TXDESCS) { priv->next_tx_pending = 0; } desc = priv->descs->txdesc + priv->next_tx_pending; } if (netif_queue_stopped(dev) && desc_freed) { netif_wake_queue(dev); } } static void delqa_rx_interrupt(struct net_device *dev, struct delqa_private *priv) { struct delqa_bufdesc *desc; unsigned int len; struct sk_buff *skb; unsigned int busaddr; /* Get first descriptor waiting to be "taken back" from the DELQA */ desc = priv->descs->rxdesc + priv->next_rx; while (desc->status1 != DELQA_NOTYET) { #if DELQA_DEBUG_PKT printk("RX desc %d, status1=%04x, status2=%04x, len=%d\n", priv->next_rx, desc->status1, desc->status2, len); #endif if (desc->status1 & DELQA_RXSTS1_ESETUP) { /* This is the loopback of a setup frame - ignore */ } if (desc->status1 & DELQA_RXSTS1_ERRORUSED) { /* Error while receiving */ priv->stats.rx_errors++; } else { /* Good frame received */ unsigned int len_hi; unsigned int len_lo1; unsigned int len_lo2; len_hi = (desc->status1 & DELQA_RXSTS1_LEN_HI_MASK) >> DELQA_RXSTS1_LEN_HI_SHIFT; len_lo1 = (desc->status2 & DELQA_RXSTS2_LEN_LO1_MASK) >> DELQA_RXSTS2_LEN_LO1_SHIFT; len_lo2 = (desc->status2 & DELQA_RXSTS2_LEN_LO2_MASK) >> DELQA_RXSTS2_LEN_LO2_SHIFT; if (len_lo1 != len_lo2) { printk("%s: DELQA status2 bytes don't match\n", dev->name); } len = (len_hi << 8) + len_lo1 + 60; skb = dev_alloc_skb(len + 2); if (skb == NULL) { printk("%s: cannot allocate skb, dropping packet\n", dev->name); priv->stats.rx_dropped++; } else { priv->stats.rx_packets++; priv->stats.rx_bytes += len; skb->dev = dev; skb_reserve(skb, 2); skb_put(skb, len); memcpy(skb->data, priv->rx_map[priv->next_rx]->virtaddr, len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); } } /* reclaim descriptor */ desc->flag = DELQA_NOTYET; desc->status1 = DELQA_NOTYET; desc->status2 = 1; /* High and low bytes must be different */ priv->next_rx++; if (priv->next_rx == RXDESCS) { priv->next_rx = 0; } desc = priv->descs->rxdesc + priv->next_rx; } /* DEQNA manual errata sheet states that we must check for an invalid receive list before leaving the ISR and reset the buffer list if it is invalid */ if (read_reg(priv, DELQA_CSR) & DELQA_CSR_RL_INVALID) { printk("%s: receive list invalid - resetting\n", dev->name); /* The descriptor pointed to by next_rx must be the first available descriptor. This is because: o The DELQA doesn't touch the receive list when RL_INVALID is set. o The while() loop above stops when next_rx points to a 'NOTYET' descriptor. */ busaddr = priv->desc_map->busaddr + offsetof(struct delqa_descs, rxdesc[priv->next_rx]); write_reg(priv, DELQA_RCLL, LOWORD(busaddr)); write_reg(priv, DELQA_RCLH, HIWORD(busaddr)); } } static void delqa_interrupt(const int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; struct delqa_private *priv = (struct delqa_private *)dev->priv; unsigned int csr; unsigned int newcsr; csr = read_reg(priv, DELQA_CSR); #if DELQA_DEBUG_CSR dump_csr("delqa_interrupt entry", dev); #endif #if DELQA_DEBUG_DESC dump_descs(dev); #endif newcsr = DELQA_CSR_ILOOP | DELQA_CSR_RCV_ENABLE | DELQA_CSR_INT_ENABLE; if (csr & DELQA_CSR_XMIT_INT) { /* Either memory read error or tx interrupt */ if (csr & DELQA_CSR_NEX_MEM_INT) { dump_csr("Q-bus memory error", dev); dump_descs(dev); qbus_dumpmap(); /* FIXME: what should we do here? */ panic("DELQA bus memory access error"); } else { newcsr |= DELQA_CSR_XMIT_INT; delqa_tx_interrupt(dev, priv); } } if (csr & DELQA_CSR_RCV_INT) { newcsr |= DELQA_CSR_RCV_INT; delqa_rx_interrupt(dev, priv); } /* Clear RX and TX interrupt bits to allow further interrupts. We also enable the receiver and turn off the internal loopback at this point. */ write_reg(priv, DELQA_CSR, newcsr); #if DELQA_DEBUG_CSR dump_csr("delqa_interrupt exit", dev); #endif } static int delqa_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct delqa_private *priv = (struct delqa_private *)dev->priv; struct delqa_bufdesc *desc; unsigned int len; unsigned int i; unsigned int busaddr; unsigned int csr; if (skb->len < ETH_ZLEN) { struct sk_buff *new_skb; new_skb = skb_copy_expand(skb, 0, ETH_ZLEN - skb->len, GFP_ATOMIC); if (new_skb == NULL) { return -ENOMEM; } memset(skb_put(new_skb, ETH_ZLEN - skb->len), 0, ETH_ZLEN - skb->len); dev_kfree_skb(skb); /* We must not return a failure after this point, since that would result in the caller trying to free the skb that we've just freed. */ skb = new_skb; } i = priv->next_tx_free; priv->next_tx_free++; if (priv->next_tx_free == TXDESCS) { priv->next_tx_free = 0; } desc = priv->descs->txdesc + i; /* FIXME: These mapping registers MUST be allocated at init time to prevent any possibility of failure here - see above comment */ priv->tx_map[i] = qbus_alloc_mapregs(skb->data, skb->len); if (priv->tx_map[i] == NULL) { /* FIXME: What should I do here? */ panic("delqa_start_xmit: no map reg"); } priv->tx_skb[i] = skb; busaddr = priv->tx_map[i]->busaddr; desc->addr_lo = LOWORD(busaddr); desc->addr_hi = HIWORD(busaddr) | DELQA_ADDRHI_EOMSG; desc->flag = DELQA_NOTYET; desc->status1 = DELQA_NOTYET; desc->status2 = 0; /* Work out the length and alignment stuff */ len = skb->len; if ((len & 1) || ((unsigned long)(skb->data) & 1)) { len += 2; } if ((unsigned long)(skb->data) & 1) { desc->addr_hi |= DELQA_ADDRHI_ODDBEGIN; } if ((unsigned long)(skb->data + len) & 1) { desc->addr_hi |= DELQA_ADDRHI_ODDEND; } desc->buflen = -(len/2); /* Set the "go" bit on this descriptor */ desc->addr_hi |= DELQA_ADDRHI_VALID; #if DELQA_DEBUG_DESC dump_descs(dev); #endif csr = read_reg(priv, DELQA_CSR); if (csr & DELQA_CSR_XL_INVALID) { /* Get Q-bus address of first TX descriptor */ busaddr = priv->desc_map->busaddr + offsetof(struct delqa_descs, txdesc[i]); write_reg(priv, DELQA_XMTL, LOWORD(busaddr)); write_reg(priv, DELQA_XMTH, HIWORD(busaddr)); } /* Check if the 'next' descriptor is actually free */ desc = priv->descs->txdesc + priv->next_tx_free; if (desc->addr_hi & DELQA_ADDRHI_VALID) { /* All descriptors in use - stop tx queue */ netif_stop_queue(dev); } return 0; } /* FIXME: implement this */ static void delqa_tx_timeout(struct net_device *dev) { printk("delqa_tx_timeout not implemented\n"); HALT; } static void store_setup_address(unsigned int index, unsigned char *addr, unsigned char *setup_frame) { unsigned int start; unsigned int i; if (index < 6) { start = index + 1; } else { start = index + 65; } for (i=0; i<6; i++) { setup_frame[start + i * 8] = addr[i]; } } static void format_setup_frame(struct net_device *dev) { struct delqa_private *priv = (struct delqa_private *)dev->priv; /* Fill in hardware, broadcast and multicast addresses here */ /* Pre-fill with all FF (has side effect of setting all addresses to the broadcast address) */ memset(priv->setup_frame, 0xff, sizeof(priv->setup_frame)); /* First address will be our unicast address */ store_setup_address(0, dev->dev_addr, priv->setup_frame); /* FIXME: Store multicast addresses here */ /* FIXME: Use MULTICAST and PROMISC flags to tweak setup_len */ priv->setup_frame_len = 128; } /* FIXME: pre-allocate mapping registers for this at init time. Then this would be a no-fail function */ static void queue_setup_frame(struct net_device *dev) { struct delqa_private *priv = (struct delqa_private *)dev->priv; struct delqa_bufdesc *desc; unsigned int busaddr; unsigned int csr; unsigned int i; /* Point the first available TX descriptor at the setup frame and enable the transmitter */ i = priv->next_tx_free; priv->next_tx_free++; if (priv->next_tx_free == TXDESCS) { priv->next_tx_free = 0; } desc = priv->descs->txdesc + i; priv->tx_map[i] = qbus_alloc_mapregs(priv->setup_frame, priv->setup_frame_len); if (priv->tx_map[i] == NULL) { panic("delqa queue_setup_frame: dma mapping failed"); } busaddr = priv->tx_map[i]->busaddr; desc->addr_lo = LOWORD(busaddr); desc->addr_hi = HIWORD(busaddr) | DELQA_ADDRHI_SETUP | DELQA_ADDRHI_EOMSG; desc->flag = DELQA_NOTYET; desc->status1 = DELQA_NOTYET; desc->status2 = 0; desc->buflen = -priv->setup_frame_len/2; /* (maybe) bytes, not words like all other uses */ desc->addr_hi |= DELQA_ADDRHI_VALID; #if DELQA_DEBUG_DESC dump_descs(dev); #endif csr = read_reg(priv, DELQA_CSR); if (csr & DELQA_CSR_XL_INVALID) { /* Get Q-bus address of first TX descriptor */ busaddr = priv->desc_map->busaddr + offsetof(struct delqa_descs, txdesc[i]); write_reg(priv, DELQA_XMTL, LOWORD(busaddr)); write_reg(priv, DELQA_XMTH, HIWORD(busaddr)); } } static int delqa_open(struct net_device *dev) { struct delqa_private *priv = (struct delqa_private *)dev->priv; struct delqa_bufdesc *desc; unsigned int csr; int i; unsigned int busaddr; if (qbus_request_irq(priv->qbus_vector, delqa_interrupt, 0, "delqa", dev)) { printk("delqa_open: cannot get qbus irq %d\n", priv->qbus_vector); return -EAGAIN; } /* Reset the hardware */ printk("Resetting DELQA... "); write_reg(priv, DELQA_CSR, DELQA_CSR_RESET); udelay(1000); csr = read_reg(priv, DELQA_CSR); write_reg(priv, DELQA_CSR, csr & ~DELQA_CSR_RESET); write_reg(priv, DELQA_VECTOR, priv->qbus_vector); printk("done\n"); /* Mark the transmit descriptors as not yet owned by the DELQA (and also not VALID). */ for (i=0; i<TXDESCS; i++) { desc = priv->descs->txdesc + i; /* Clear VALID bit */ desc->addr_hi = 0; desc->flag = DELQA_NOTYET; desc->status1 = DELQA_NOTYET; desc->status2 = 0; } /* Mark the receive descriptors as not yet owned by the DELQA. */ for (i=0; i<RXDESCS; i++) { desc = priv->descs->rxdesc + i; desc->flag = DELQA_NOTYET; desc->status1 = DELQA_NOTYET; desc->status2 = 1; } /* Tell the DELQA where the receive descriptors live (i.e. which Q-bus addresses are mapped to the descriptor addresses by the mapping registers. There is no point in setting the transmit descriptor address, since there are no valid transmit descriptors yet. When the card hits an invalid transmit descriptor, it stops the transmit logic, which can only be restarted by setting the transmit descriptor address again. */ busaddr = priv->desc_map->busaddr + offsetof(struct delqa_descs, rxdesc[0]); write_reg(priv, DELQA_RCLL, LOWORD(busaddr)); write_reg(priv, DELQA_RCLH, HIWORD(busaddr)); write_reg(priv, DELQA_CSR, DELQA_CSR_INT_ENABLE | DELQA_CSR_XMIT_INT | DELQA_CSR_RCV_INT); format_setup_frame(dev); queue_setup_frame(dev); return 0; } /* FIXME: implement delqa_close */ static int delqa_close(struct net_device *dev) { printk("delqa_close not implemented\n"); HALT; return 0; } static void delqa_set_multicast(struct net_device *dev) { format_setup_frame(dev); queue_setup_frame(dev); } static struct net_device_stats *delqa_get_stats(struct net_device *dev) { struct delqa_private *priv = (struct delqa_private *) dev->priv; return &priv->stats; } /* This function allocates the receive buffers, allocates and maps QBUS mapping registers for these buffers, initializes the receive descriptors to point to these buffers, and sets up the chain descriptors at the end of the descriptor lists */ static int init_desc_rings(struct net_device *dev) { struct delqa_private *priv = (struct delqa_private *)dev->priv; struct delqa_bufdesc *desc; unsigned int busaddr; int i; for (i=0; i<RXDESCS; i++) { unsigned char *buf; buf = kmalloc(RXBUFSIZE, GFP_KERNEL); if (buf == NULL) { printk("delqa: Cannot allocate RX buf"); goto cleanup; } priv->rx_map[i] = qbus_alloc_mapregs(buf, RXBUFSIZE); if (priv->rx_map[i] == NULL) { printk("delqa init_desc_rings: dma mapping failed"); kfree(buf); goto cleanup; } busaddr = priv->rx_map[i]->busaddr; desc = priv->descs->rxdesc + i; desc->addr_lo = LOWORD(busaddr); desc->addr_hi = HIWORD(busaddr); desc->flag = DELQA_NOTYET; desc->status1 = DELQA_NOTYET; desc->status2 = 1; desc->buflen = - (RXBUFSIZE / 2); /* words, not bytes */ desc->addr_hi |= DELQA_ADDRHI_VALID; } /* Remember that we've allocated one more descriptor than we need. This one is used to chain the end of the descriptor list back to the beginning. */ /* Last receive descriptor contains bus address of first desc */ desc = priv->descs->rxdesc + RXDESCS; busaddr = priv->desc_map->busaddr + offsetof(struct delqa_descs, rxdesc[0]); desc->addr_lo = LOWORD(busaddr); desc->addr_hi = HIWORD(busaddr) | DELQA_ADDRHI_VALID | DELQA_ADDRHI_CHAIN; desc->flag = DELQA_NOTYET; desc->status1 = DELQA_NOTYET; /* Last transmit descriptor contains bus address of first desc */ desc = priv->descs->txdesc + TXDESCS; busaddr = priv->desc_map->busaddr + offsetof(struct delqa_descs, txdesc[0]); desc->addr_lo = LOWORD(busaddr); desc->addr_hi = HIWORD(busaddr) | DELQA_ADDRHI_VALID | DELQA_ADDRHI_CHAIN; desc->flag = DELQA_NOTYET; desc->status1 = DELQA_NOTYET; priv->next_tx_free = 0; priv->next_tx_pending = 0; priv->next_rx = 0; return 0; cleanup: for (i=0; i<RXDESCS; i++) { if (priv->rx_map[i] != NULL) { kfree(priv->rx_map[i]->virtaddr); qbus_unmap(priv->rx_map[i]); priv->rx_map[i] = NULL; } } return -ENOMEM; } static int delqa_init(struct net_device *dev) { struct delqa_private *priv; int i; int status = 0; dev->priv = kmalloc(sizeof(struct delqa_private), GFP_KERNEL); if (dev->priv == NULL) { return -ENOMEM; } memset(dev->priv, 0, sizeof(struct delqa_private)); priv = (struct delqa_private *) dev->priv; priv->base = ioremap(DELQA_BASE, 16); if (priv->base == NULL) { status = -ENOMEM; goto cleanup0; } priv->descs = kmalloc(sizeof(struct delqa_descs), GFP_KERNEL); if (priv->descs == NULL) { status = -ENOMEM; goto cleanup1; } dev->mem_start = (unsigned int)priv->descs; dev->mem_end = (unsigned int)priv->descs + sizeof(*(priv->descs)); /* FIXME: get the vector from the q-bus adapter driver */ write_reg(priv, DELQA_VECTOR, DELQA_QBUS_VECTOR); priv->qbus_vector = DELQA_QBUS_VECTOR; printk("delqa qbus vector: %d (0%03o, 0x%04x)\n", priv->qbus_vector, priv->qbus_vector, priv->qbus_vector); dev->irq = qbus_vector_to_irq(priv->qbus_vector); printk("Ethernet address in ROM: "); for (i = 0; i < 6; i++) { dev->dev_addr[i] = priv->base[i*2] & 0xff; printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); } /* Here we need to setup qbus mapping registers so that the DELQA can DMA to and from our buffers */ priv->desc_map = qbus_alloc_mapregs(priv->descs, sizeof(struct delqa_descs)); if (priv->desc_map == NULL) { status = -ENOMEM; goto cleanup2; } status = init_desc_rings(dev); if (status < 0) { goto cleanup3; } dev->open = delqa_open; dev->stop = delqa_close; dev->hard_start_xmit = delqa_start_xmit; dev->tx_timeout = delqa_tx_timeout; dev->watchdog_timeo = 5*HZ; dev->get_stats = &delqa_get_stats; dev->set_multicast_list = &delqa_set_multicast; dev->dma = 0; ether_setup(dev); return status; cleanup3: qbus_unmap(priv->desc_map); cleanup2: kfree(priv->descs); cleanup1: iounmap(priv->base); cleanup0: kfree(dev->priv); dev->priv = NULL; return status; } struct net_device delqa_dev = { init: delqa_init }; int __init delqa_probe(void) { return register_netdev(&delqa_dev); } __initcall(delqa_probe); |
From: Kenn H. <ke...@us...> - 2002-07-18 23:39:36
|
Update of /cvsroot/linux-vax/kernel-2.5/drivers/vax/bus In directory usw-pr-cvs1:/tmp/cvs-serv31692/vax/bus Added Files: .cvsignore Makefile qbus.c Log Message: Mostly-complete DELQA driver. First cut at driver for the Q-bus adapter in the KA650 CPU. --- NEW FILE --- *.a.flags *.o.flags .depend *.lst --- NEW FILE --- # # Makefile for the Linux/VAX bus device drivers. # O_TARGET := vaxbus.o obj-y := obj-m := obj-n := obj-$(CONFIG_QBUS) += qbus.o include $(TOPDIR)/Rules.make --- NEW FILE --- /* Very dumb map register allocator - does linear searches for available registers. Need a better way to do this. My first thought was to use bits 30:0 in invalid map registers to contain forward and backward links to maintain a list of free registers. However, bits 30:20 are reserved (read as zero and should be written as zero), so that only leaves us with 20 bits for links. This would be OK if we allow the allocation granularity to be 8 registers. - KPH */ #include <asm/io.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/slab.h> #include <asm/bus/qbus.h> #define QBUS_DEBUG 0 #define CQBIC_MAPREGPHYS 0x20088000 #define CQBIC_NUMMAPREGS 8192 static unsigned int *cqbic_mapregbase; /* Given a (start, len), how many pagelets does this span? */ static unsigned int num_pagelets(void *start, unsigned int len) { unsigned int start_pagelet; unsigned int end_pagelet; start_pagelet = (unsigned int)start >> PAGELET_SHIFT; end_pagelet = ((unsigned int)start + len - 1) >> PAGELET_SHIFT; return end_pagelet - start_pagelet + 1; } __init static int qbus_init(void) { int i; if (cqbic_mapregbase == NULL) { cqbic_mapregbase = (unsigned int *)ioremap(CQBIC_MAPREGPHYS, CQBIC_NUMMAPREGS * sizeof(unsigned int)); #if QBUS_DEBUG printk("CQBIC map registers mapped at %p\n", cqbic_mapregbase); #endif } for (i=0; i<CQBIC_NUMMAPREGS; i++) { cqbic_mapregbase[i] = 0; } return 0; } static int find_n_free(unsigned int n) { int i; int j; i = 0; while (i < (8192 - n)) { for (j=0; j<n; j++) { if (cqbic_mapregbase[i+j]) { /* This reg in use */ break; } } if (j == n) { /* Found N contiguous free entries at offset I */ return i; } i += j+1; } return -1; } /* Allocate a bunch of map registers sufficient to map 'len' bytes at address 'start'. */ struct vax_dmamap *qbus_alloc_mapregs(void *start, unsigned int len) { struct vax_dmamap *map; map = kmalloc(sizeof(struct vax_dmamap), GFP_KERNEL); if (map != NULL) { int reg; unsigned int pagelets; pagelets = num_pagelets(start, len); reg = find_n_free(pagelets); if (reg != -1) { unsigned int pfn; unsigned int reg_value; int i; pfn = virt_to_phys(start) >> PAGELET_SHIFT; reg_value = (pfn & 0xfffff) | 0x80000000; for (i = reg; i < reg + pagelets; i++, reg_value++) { cqbic_mapregbase[i] = reg_value; } map->reg = reg; map->pagelets = pagelets; map->virtaddr = start; map->busaddr = (reg * PAGELET_SIZE) + ((unsigned int)start & ~PAGELET_MASK); #if QBUS_DEBUG printk("Using map registers 0x%04x to 0x%04x to map virt %p to %p (bus %08x)\n", reg, reg + pagelets - 1, start, (char *)start + len - 1, map->busaddr); #endif } else { kfree(map); map = NULL; } } return map; } void qbus_unmap(struct vax_dmamap *map) { #if QBUS_DEBUG printk("Zapping map registers 0x%04x to 0x%04x\n", map->reg, map->reg + map->pagelets - 1); #endif while (map->pagelets--) { cqbic_mapregbase[map->reg] = 0; map->reg++; } kfree(map); } void qbus_dumpmap(void) { int i; for (i=0; i<CQBIC_NUMMAPREGS; i++) { if (cqbic_mapregbase[i] != 0) { printk("CQBIC map reg %04x = %08x (-> %08x)\n", i, cqbic_mapregbase[i], (cqbic_mapregbase[i] & 0xfffff) << PAGELET_SHIFT); } } } int qbus_vector_to_irq(unsigned int vector) { return (vector / 4) + 128; } int qbus_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) { return request_irq(irq / 4 + 128, handler, irqflags, devname, dev_id); } __initcall(qbus_init); |
From: Kenn H. <ke...@us...> - 2002-07-18 23:39:36
|
Update of /cvsroot/linux-vax/kernel-2.5/drivers/vax In directory usw-pr-cvs1:/tmp/cvs-serv31692/vax Added Files: .cvsignore Makefile Log Message: Mostly-complete DELQA driver. First cut at driver for the Q-bus adapter in the KA650 CPU. --- NEW FILE --- *.a.flags *.o.flags .depend *.lst --- NEW FILE --- # # Makefile for the Linux/VAX kernel device drivers. # subdir-y := bus char net include $(TOPDIR)/Rules.make |
From: Kenn H. <ke...@us...> - 2002-07-18 23:39:36
|
Update of /cvsroot/linux-vax/kernel-2.5/drivers/vax/char In directory usw-pr-cvs1:/tmp/cvs-serv31692/vax/char Added Files: .cvsignore Makefile Log Message: Mostly-complete DELQA driver. First cut at driver for the Q-bus adapter in the KA650 CPU. --- NEW FILE --- *.a.flags *.o.flags .depend *.lst --- NEW FILE --- # # Makefile for the Linux/VAX network device drivers. # O_TARGET := vaxchar.o obj-y := obj-m := obj-n := # obj-$(CONFIG_SERIAL_KA650) += ka650_console.o include $(TOPDIR)/Rules.make |
From: Kenn H. <ke...@us...> - 2002-07-18 23:36:22
|
Update of /cvsroot/linux-vax/kernel-2.5/drivers In directory usw-pr-cvs1:/tmp/cvs-serv30971 Modified Files: Makefile Log Message: Add drivers/vax subdir to build - all VAX-related drivers will go in here to simplify merging with Linus later Index: Makefile =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/drivers/Makefile,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- Makefile 6 Jun 2002 00:12:24 -0000 1.3 +++ Makefile 18 Jul 2002 23:36:16 -0000 1.4 @@ -39,6 +39,7 @@ subdir-$(CONFIG_ISDN) += isdn subdir-$(CONFIG_ATM) += atm subdir-$(CONFIG_FC4) += fc4 +subdir-$(CONFIG_VAX) += vax subdir-$(CONFIG_VSBUS) += vsbus # CONFIG_HAMRADIO can be set without CONFIG_NETDEVICE being set -- ch |
From: Kenn H. <ke...@us...> - 2002-07-11 22:31:52
|
Update of /cvsroot/linux-vax/kernel-2.5/include/asm-vax/bus In directory usw-pr-cvs1:/tmp/cvs-serv14511/bus Log Message: Directory /cvsroot/linux-vax/kernel-2.5/include/asm-vax/bus added to the repository |
From: Kenn H. <ke...@us...> - 2002-07-11 22:29:34
|
Update of /cvsroot/linux-vax/kernel-2.5/drivers/vax/net In directory usw-pr-cvs1:/tmp/cvs-serv13897/net Log Message: Directory /cvsroot/linux-vax/kernel-2.5/drivers/vax/net added to the repository |
From: Kenn H. <ke...@us...> - 2002-07-11 22:29:34
|
Update of /cvsroot/linux-vax/kernel-2.5/drivers/vax/bus In directory usw-pr-cvs1:/tmp/cvs-serv13897/bus Log Message: Directory /cvsroot/linux-vax/kernel-2.5/drivers/vax/bus added to the repository |
From: Kenn H. <ke...@us...> - 2002-07-11 22:29:34
|
Update of /cvsroot/linux-vax/kernel-2.5/drivers/vax/char In directory usw-pr-cvs1:/tmp/cvs-serv13897/char Log Message: Directory /cvsroot/linux-vax/kernel-2.5/drivers/vax/char added to the repository |
From: Kenn H. <ke...@us...> - 2002-07-11 22:28:19
|
Update of /cvsroot/linux-vax/kernel-2.5/drivers/vax In directory usw-pr-cvs1:/tmp/cvs-serv13614a/vax Log Message: Directory /cvsroot/linux-vax/kernel-2.5/drivers/vax added to the repository |