diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-05 06:47:02 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-05 06:47:02 +0000 |
commit | 99a7e12f34b3661a0d1354eef83a0eef4df5e34c (patch) | |
tree | 3560aca9ca86792f9ab7bd87861ea143a1b3c7a3 /drivers/sbus/char/zs.c | |
parent | e73a04659c0b8cdee4dd40e58630e2cf63afb316 (diff) |
Merge with Linux 2.3.38.
Diffstat (limited to 'drivers/sbus/char/zs.c')
-rw-r--r-- | drivers/sbus/char/zs.c | 407 |
1 files changed, 274 insertions, 133 deletions
diff --git a/drivers/sbus/char/zs.c b/drivers/sbus/char/zs.c index 8ed6e2737..d0ec266c0 100644 --- a/drivers/sbus/char/zs.c +++ b/drivers/sbus/char/zs.c @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.45 1999/09/01 08:09:35 davem Exp $ +/* $Id: zs.c,v 1.52 1999/12/15 14:29:20 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -23,6 +23,7 @@ #include <linux/console.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/bootmem.h> #include <linux/sysrq.h> #include <asm/io.h> @@ -32,6 +33,8 @@ #include <asm/uaccess.h> #include <asm/bitops.h> #include <asm/kdebug.h> +#include <asm/page.h> +#include <asm/pgtable.h> #include <asm/sbus.h> #ifdef __sparc_v9__ @@ -65,8 +68,8 @@ static int num_serial = 2; /* sun4/sun4c/sun4m - Two chips on board. */ #else #define ZSDELAY() #define ZSDELAY_LONG() -#define ZS_WSYNC(channel) \ - ((void) *((volatile unsigned char *)(&((channel)->control)))) +#define ZS_WSYNC(__channel) \ + sbus_readb(&((__channel)->control)) #endif struct sun_zslayout **zs_chips; @@ -164,6 +167,47 @@ static struct termios **serial_termios_locked; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif +#undef ZS_LOG +#ifdef ZS_LOG +struct zs_logent { + u8 reg, val; + u8 write, __pad; +#define REGIRQ 0xff +#define REGDATA 0xfe +#define REGCTRL 0xfd +}; +struct zs_logent zslog[32]; +int zs_curlog = 0; +#define ZSLOG(__reg, __val, __write) \ +do{ int index = zs_curlog; \ + zslog[index].reg = (__reg); \ + zslog[index].val = (__val); \ + zslog[index].write = (__write); \ + zs_curlog = (index + 1) & (32 - 1); \ +}while(0) +int zs_dumplog(char *buffer) +{ + int len = 0; + int i; + + for (i = 0; i < 32; i++) { + u8 reg, val, write; + + reg = zslog[i].reg; + val = zslog[i].val; + write = zslog[i].write; + len += sprintf(buffer + len, + "ZSLOG[%2d]: reg %2x val %2x %s\n", + i, reg, val, write ? "write" : "read"); + } + len += sprintf(buffer + len, "ZS current log index %d\n", + zs_curlog); + return len; +} +#else +#define ZSLOG(x,y,z) do { } while (0) +#endif + /* * tmp_buf is used as a temporary buffer by serial_write. We need to * lock it in case the memcpy_fromfs blocks while swapping in a page, @@ -197,15 +241,13 @@ static inline int serial_paranoia_check(struct sun_serial *info, return 0; } -/* - * This is used to figure out the divisor speeds and the timeouts - */ +/* This is used to figure out the divisor speeds and the timeouts. */ static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 76800, 0 }; + 9600, 19200, 38400, 76800, 0 +}; -/* - * Reading and writing Zilog8530 registers. The delays are to make this +/* Reading and writing Zilog8530 registers. The delays are to make this * driver work on the Sun4 which needs a settling delay after each chip * register access, other machines handle this in hardware via auxiliary * flip-flops which implement the settle time we do in software. @@ -215,26 +257,28 @@ static inline unsigned char read_zsreg(struct sun_zschannel *channel, { unsigned char retval; - channel->control = reg; + sbus_writeb(reg, &channel->control); ZSDELAY(); - retval = channel->control; + retval = sbus_readb(&channel->control); ZSDELAY(); + ZSLOG(reg, retval, 0); return retval; } static inline void write_zsreg(struct sun_zschannel *channel, unsigned char reg, unsigned char value) { - channel->control = reg; + ZSLOG(reg, value, 1); + sbus_writeb(reg, &channel->control); ZSDELAY(); - channel->control = value; + sbus_writeb(value, &channel->control); ZSDELAY(); } static inline void load_zsregs(struct sun_serial *info, unsigned char *regs) { - unsigned long flags; struct sun_zschannel *channel = info->zs_channel; + unsigned long flags; unsigned char stat; int i; @@ -287,12 +331,18 @@ static inline void zs_put_char(struct sun_zschannel *channel, char ch) * a timed polling loop and on sparc64 ZSDELAY * is a nop. -DaveM */ - while((channel->control & Tx_BUF_EMP) == 0 && --loops) + do { + u8 val = sbus_readb(&channel->control); + ZSLOG(REGCTRL, val, 0); + if (val & Tx_BUF_EMP) + break; udelay(5); + } while (--loops); - channel->data = ch; + sbus_writeb(ch, &channel->data); ZSDELAY(); ZS_WSYNC(channel); + ZSLOG(REGDATA, ch, 1); } /* Sets or clears DTR/RTS on the requested line */ @@ -339,7 +389,7 @@ static inline void kgdb_chaninit(struct sun_serial *ss, int intson, int bps) */ static void zs_stop(struct tty_struct *tty) { - struct sun_serial *info = (struct sun_serial *)tty->driver_data; + struct sun_serial *info = (struct sun_serial *) tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->device, "zs_stop")) @@ -355,7 +405,7 @@ static void zs_stop(struct tty_struct *tty) static void zs_start(struct tty_struct *tty) { - struct sun_serial *info = (struct sun_serial *)tty->driver_data; + struct sun_serial *info = (struct sun_serial *) tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->device, "zs_start")) @@ -374,6 +424,8 @@ static void zs_start(struct tty_struct *tty) */ void batten_down_hatches(void) { + if (!stop_a_enabled) + return; /* If we are doing kadb, we call the debugger * else we just drop into the boot monitor. * Note that we must flush the user windows @@ -424,7 +476,7 @@ void batten_down_hatches(void) * processing in the software interrupt portion of the driver. */ static _INLINE_ void zs_sched_event(struct sun_serial *info, - int event) + int event) { info->event |= 1 << event; queue_task(&info->tqueue, &tq_serial); @@ -439,9 +491,12 @@ static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs { struct tty_struct *tty = info->tty; unsigned char ch, stat; + int do_queue_task = 1; do { - ch = (info->zs_channel->data) & info->parity_mask; + ch = sbus_readb(&info->zs_channel->data); + ZSLOG(REGDATA, ch, 0); + ch &= info->parity_mask; ZSDELAY(); /* If this is the console keyboard, we need to handle @@ -466,14 +521,16 @@ static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs return; } sunkbd_inchar(ch, regs); - return; + do_queue_task = 0; + goto next_char; } if(info->cons_mouse) { - sun_mouse_inbyte(ch); - return; + sun_mouse_inbyte(ch, 0); + do_queue_task = 0; + goto next_char; } if(info->is_cons) { - if(ch==0) { + if(ch == 0) { /* whee, break received */ batten_down_hatches(); /* Continue execution... */ @@ -502,9 +559,11 @@ static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs *tty->flip.flag_buf_ptr++ = 0; *tty->flip.char_buf_ptr++ = ch; + next_char: /* Check if we have another character... */ - stat = info->zs_channel->control; + stat = sbus_readb(&info->zs_channel->control); ZSDELAY(); + ZSLOG(REGCTRL, stat, 0); if (!(stat & Rx_CH_AV)) break; @@ -512,7 +571,8 @@ static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs stat = read_zsreg(info->zs_channel, R1); } while (!(stat & (PAR_ERR | Rx_OVR | CRC_ERR))); - queue_task(&tty->flip.tqueue, &tq_timer); + if (do_queue_task != 0) + queue_task(&tty->flip.tqueue, &tq_timer); } static _INLINE_ void transmit_chars(struct sun_serial *info) @@ -528,9 +588,10 @@ static _INLINE_ void transmit_chars(struct sun_serial *info) if((info->xmit_cnt <= 0) || (tty != 0 && tty->stopped)) { /* That's peculiar... */ - info->zs_channel->control = RES_Tx_P; + sbus_writeb(RES_Tx_P, &info->zs_channel->control); ZSDELAY(); ZS_WSYNC(info->zs_channel); + ZSLOG(REGCTRL, RES_Tx_P, 1); return; } @@ -543,9 +604,10 @@ static _INLINE_ void transmit_chars(struct sun_serial *info) zs_sched_event(info, RS_EVENT_WRITE_WAKEUP); if(info->xmit_cnt <= 0) { - info->zs_channel->control = RES_Tx_P; + sbus_writeb(RES_Tx_P, &info->zs_channel->control); ZSDELAY(); ZS_WSYNC(info->zs_channel); + ZSLOG(REGCTRL, RES_Tx_P, 1); } } @@ -554,13 +616,14 @@ static _INLINE_ void status_handle(struct sun_serial *info) unsigned char status; /* Get status from Read Register 0 */ - status = info->zs_channel->control; + status = sbus_readb(&info->zs_channel->control); ZSDELAY(); + ZSLOG(REGCTRL, status, 0); /* Clear status condition... */ - info->zs_channel->control = RES_EXT_INT; + sbus_writeb(RES_EXT_INT, &info->zs_channel->control); ZSDELAY(); ZS_WSYNC(info->zs_channel); - + ZSLOG(REGCTRL, RES_EXT_INT, 1); #if 0 if(status & DCD) { if((info->tty->termios->c_cflag & CRTSCTS) && @@ -579,8 +642,12 @@ static _INLINE_ void status_handle(struct sun_serial *info) * 'break asserted' status change interrupt, call * the boot prom. */ - if((status & BRK_ABRT) && info->break_abort) - batten_down_hatches(); + if(status & BRK_ABRT) { + if (info->break_abort) + batten_down_hatches(); + if (info->cons_mouse) + sun_mouse_inbyte(0, 1); + } /* XXX Whee, put in a buffer somewhere, the status information * XXX whee whee whee... Where does the information go... @@ -595,8 +662,9 @@ static _INLINE_ void special_receive(struct sun_serial *info) stat = read_zsreg(info->zs_channel, R1); if (stat & (PAR_ERR | Rx_OVR | CRC_ERR)) { - ch = info->zs_channel->data; + ch = sbus_readb(&info->zs_channel->data); ZSDELAY(); + ZSLOG(REGDATA, ch, 0); } if (!tty) @@ -616,9 +684,10 @@ static _INLINE_ void special_receive(struct sun_serial *info) done: queue_task(&tty->flip.tqueue, &tq_timer); clear: - info->zs_channel->control = ERR_RES; + sbus_writeb(ERR_RES, &info->zs_channel->control); ZSDELAY(); ZS_WSYNC(info->zs_channel); + ZSLOG(REGCTRL, ERR_RES, 1); } @@ -632,6 +701,7 @@ void zs_interrupt(int irq, void *dev_id, struct pt_regs * regs) int i; info = (struct sun_serial *)dev_id; + ZSLOG(REGIRQ, 0, 0); for (i = 0; i < NUM_SERIAL; i++) { zs_intreg = read_zsreg(info->zs_next->zs_channel, 2); zs_intreg &= STATUS_MASK; @@ -797,13 +867,15 @@ static int startup(struct sun_serial * info) /* * Clear the interrupt registers. */ - info->zs_channel->control = ERR_RES; + sbus_writeb(ERR_RES, &info->zs_channel->control); ZSDELAY(); ZS_WSYNC(info->zs_channel); + ZSLOG(REGCTRL, ERR_RES, 1); - info->zs_channel->control = RES_H_IUS; + sbus_writeb(RES_H_IUS, &info->zs_channel->control); ZSDELAY(); ZS_WSYNC(info->zs_channel); + ZSLOG(REGCTRL, RES_H_IUS, 1); /* * Now, initialize the Zilog @@ -826,13 +898,15 @@ static int startup(struct sun_serial * info) /* * And clear the interrupt registers again for luck. */ - info->zs_channel->control = ERR_RES; + sbus_writeb(ERR_RES, &info->zs_channel->control); ZSDELAY(); ZS_WSYNC(info->zs_channel); + ZSLOG(REGCTRL, ERR_RES, 1); - info->zs_channel->control = RES_H_IUS; + sbus_writeb(RES_H_IUS, &info->zs_channel->control); ZSDELAY(); ZS_WSYNC(info->zs_channel); + ZSLOG(REGCTRL, RES_H_IUS, 1); if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); @@ -1035,24 +1109,32 @@ void putDebugChar(char kgdb_char) { struct sun_zschannel *chan = zs_kgdbchan; - while((chan->control & Tx_BUF_EMP)==0) + while((sbus_readb(&chan->control) & Tx_BUF_EMP)==0) udelay(5); - chan->data = kgdb_char; + sbus_writeb(kgdb_char, &chan->data); ZS_WSYNC(chan); + ZSLOG(REGDATA, kgdb_char, 1); } char getDebugChar(void) { struct sun_zschannel *chan = zs_kgdbchan; + u8 val; - while((chan->control & Rx_CH_AV)==0) + do { + val = sbus_readb(&chan->control); + ZSLOG(REGCTRL, val, 0); udelay(5); - return chan->data; + } while ((val & Rx_CH_AV) == 0); + + val = sbus_readb(&chan->data); + ZSLOG(REGDATA, val, 0); + return val; } static void zs_flush_chars(struct tty_struct *tty) { - struct sun_serial *info = (struct sun_serial *)tty->driver_data; + struct sun_serial *info = (struct sun_serial *) tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->device, "zs_flush_chars")) @@ -1087,9 +1169,9 @@ out: static int zs_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { - int c, total = 0; - struct sun_serial *info = (struct sun_serial *)tty->driver_data; + struct sun_serial *info = (struct sun_serial *) tty->driver_data; unsigned long flags; + int c, total = 0; if (serial_paranoia_check(info, tty->device, "zs_write")) return 0; @@ -1143,8 +1225,8 @@ static int zs_write(struct tty_struct * tty, int from_user, static int zs_write_room(struct tty_struct *tty) { - struct sun_serial *info = (struct sun_serial *)tty->driver_data; - int ret; + struct sun_serial *info = (struct sun_serial *) tty->driver_data; + int ret; if (serial_paranoia_check(info, tty->device, "zs_write_room")) return 0; @@ -1156,7 +1238,7 @@ static int zs_write_room(struct tty_struct *tty) static int zs_chars_in_buffer(struct tty_struct *tty) { - struct sun_serial *info = (struct sun_serial *)tty->driver_data; + struct sun_serial *info = (struct sun_serial *) tty->driver_data; if (serial_paranoia_check(info, tty->device, "zs_chars_in_buffer")) return 0; @@ -1165,7 +1247,7 @@ static int zs_chars_in_buffer(struct tty_struct *tty) static void zs_flush_buffer(struct tty_struct *tty) { - struct sun_serial *info = (struct sun_serial *)tty->driver_data; + struct sun_serial *info = (struct sun_serial *) tty->driver_data; if (serial_paranoia_check(info, tty->device, "zs_flush_buffer")) return; @@ -1188,7 +1270,7 @@ static void zs_flush_buffer(struct tty_struct *tty) */ static void zs_throttle(struct tty_struct * tty) { - struct sun_serial *info = (struct sun_serial *)tty->driver_data; + struct sun_serial *info = (struct sun_serial *) tty->driver_data; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; @@ -1211,7 +1293,7 @@ static void zs_throttle(struct tty_struct * tty) static void zs_unthrottle(struct tty_struct * tty) { - struct sun_serial *info = (struct sun_serial *)tty->driver_data; + struct sun_serial *info = (struct sun_serial *) tty->driver_data; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; @@ -1268,7 +1350,7 @@ static int set_serial_info(struct sun_serial * info, { struct serial_struct new_serial; struct sun_serial old_info; - int retval = 0; + int retval = 0; if (!new_info || copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; @@ -1326,10 +1408,11 @@ static int get_lsr_info(struct sun_serial * info, unsigned int *value) unsigned char status; cli(); - status = info->zs_channel->control; + status = sbus_readb(&info->zs_channel->control); ZSDELAY(); + ZSLOG(REGCTRL, status, 0); sti(); - put_user_ret(status,value, -EFAULT); + put_user_ret(status, value, -EFAULT); return 0; } @@ -1339,8 +1422,9 @@ static int get_modem_info(struct sun_serial * info, unsigned int *value) unsigned int result; cli(); - status = info->zs_channel->control; + status = sbus_readb(&info->zs_channel->control); ZSDELAY(); + ZSLOG(REGCTRL, status, 0); sti(); result = ((info->curregs[5] & RTS) ? TIOCM_RTS : 0) | ((info->curregs[5] & DTR) ? TIOCM_DTR : 0) @@ -1402,7 +1486,7 @@ static void send_break( struct sun_serial * info, int duration) static int zs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - struct sun_serial * info = (struct sun_serial *)tty->driver_data; + struct sun_serial * info = (struct sun_serial *) tty->driver_data; int retval; if (serial_paranoia_check(info, tty->device, "zs_ioctl")) @@ -1469,7 +1553,7 @@ static int zs_ioctl(struct tty_struct *tty, struct file * file, static void zs_set_termios(struct tty_struct *tty, struct termios *old_termios) { - struct sun_serial *info = (struct sun_serial *)tty->driver_data; + struct sun_serial *info = (struct sun_serial *) tty->driver_data; if (tty->termios->c_cflag == old_termios->c_cflag) return; @@ -1495,7 +1579,7 @@ static void zs_set_termios(struct tty_struct *tty, struct termios *old_termios) */ static void zs_close(struct tty_struct *tty, struct file * filp) { - struct sun_serial * info = (struct sun_serial *)tty->driver_data; + struct sun_serial * info = (struct sun_serial *) tty->driver_data; unsigned long flags; if (!info || serial_paranoia_check(info, tty->device, "zs_close")) @@ -1598,7 +1682,7 @@ static void zs_close(struct tty_struct *tty, struct file * filp) */ void zs_hangup(struct tty_struct *tty) { - struct sun_serial * info = (struct sun_serial *)tty->driver_data; + struct sun_serial * info = (struct sun_serial *) tty->driver_data; if (serial_paranoia_check(info, tty->device, "zs_hangup")) return; @@ -1629,9 +1713,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, struct sun_serial *info) { DECLARE_WAITQUEUE(wait, current); - int retval; - int do_clocal = 0; - unsigned char r0; + int retval, do_clocal = 0; + unsigned char r0; /* * If the device is in the middle of being closed, then block @@ -1769,10 +1852,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, */ int zs_open(struct tty_struct *tty, struct file * filp) { - struct sun_serial *info; - int retval, line; + struct sun_serial *info; + int retval, line; line = MINOR(tty->device) - tty->driver.minor_start; + /* The zilog lines for the mouse/keyboard must be * opened using their respective drivers. */ @@ -1844,7 +1928,7 @@ int zs_open(struct tty_struct *tty, struct file * filp) static void show_serial_version(void) { - char *revision = "$Revision: 1.45 $"; + char *revision = "$Revision: 1.52 $"; char *version, *p; version = strchr(revision, ' '); @@ -1869,16 +1953,19 @@ static struct sun_zslayout * __init get_zs(int chip) int busnode, seen, zsnode, sun4u_ino; static int irq = 0; - if(chip < 0 || chip >= NUM_SERIAL) - panic("get_zs bogon zs chip number"); + if(chip < 0 || chip >= NUM_SERIAL) { + prom_printf("get_zs bogon zs chip number"); + prom_halt(); + } if(central_bus) busnode = central_bus->child->prom_node; else busnode = prom_searchsiblings(prom_getchild(prom_root_node), "sbus"); - if(busnode == 0 || busnode == -1) - panic("get_zs: no zs bus to search"); - + if(busnode == 0 || busnode == -1) { + prom_printf("get_zs: no zs bus to search"); + prom_halt(); + } zsnode = prom_getchild(busnode); seen = 0; while(zsnode) { @@ -1891,8 +1978,8 @@ static struct sun_zslayout * __init get_zs(int chip) (void *) vaddr, sizeof(vaddr)); if(len == -1 || central_bus != NULL) { - struct linux_sbus *sbus = NULL; - struct linux_sbus_device *sdev = NULL; + struct sbus_bus *sbus = NULL; + struct sbus_dev *sdev = NULL; /* "address" property is not guarenteed, * everything in I/O is implicitly mapped @@ -1911,11 +1998,9 @@ static struct sun_zslayout * __init get_zs(int chip) if (sdev == NULL && central_bus == NULL) prom_halt(); if (central_bus == NULL) { - prom_apply_sbus_ranges(sbus, sdev->reg_addrs, 1, sdev); - mapped_addr = (unsigned long) - sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, - PAGE_SIZE, "Zilog Registers", - sdev->reg_addrs[0].which_io, 0x0); + mapped_addr = + sbus_ioremap(&sdev->resource[0], 0, + PAGE_SIZE, "Zilog Registers"); } else { struct linux_prom_registers zsregs[1]; int err; @@ -1927,11 +2012,11 @@ static struct sun_zslayout * __init get_zs(int chip) prom_printf("ZS: Cannot map Zilog regs.\n"); prom_halt(); } - prom_apply_fhc_ranges(central_bus->child, &zsregs[0], 1); - prom_apply_central_ranges(central_bus, &zsregs[0], 1); - mapped_addr = (unsigned long) - __va((((unsigned long)zsregs[0].which_io)<<32) | - (((unsigned long)zsregs[0].phys_addr))); + apply_fhc_ranges(central_bus->child, &zsregs[0], 1); + apply_central_ranges(central_bus, &zsregs[0], 1); + mapped_addr = + ((((u64)zsregs[0].which_io)<<32UL)| + ((u64)zsregs[0].phys_addr)); } } else if(len % sizeof(unsigned int)) { prom_printf("WHOOPS: proplen for %s " @@ -1946,13 +2031,14 @@ static struct sun_zslayout * __init get_zs(int chip) (sizeof(sun4u_ino))); if(!irq) { if (central_bus) { - irq = zilog_irq = - build_irq(12, 0, - ¢ral_bus->child->fhc_regs.uregs->fhc_uart_iclr, - ¢ral_bus->child->fhc_regs.uregs->fhc_uart_imap); + unsigned long iclr, imap; + + iclr = central_bus->child->fhc_regs.uregs + FHC_UREGS_ICLR; + imap = central_bus->child->fhc_regs.uregs + FHC_UREGS_IMAP; + irq = zilog_irq = build_irq(12, 0, iclr, imap); } else { irq = zilog_irq = - sbus_build_irq(SBus_chain, sun4u_ino); + sbus_build_irq(sbus_root, sun4u_ino); } } break; @@ -1964,10 +2050,20 @@ static struct sun_zslayout * __init get_zs(int chip) panic("get_zs: whee chip not found"); if(!vaddr[0] && !mapped_addr) panic("get_zs: whee no serial chip mappable"); - if (mapped_addr != 0) + if (mapped_addr != 0) { return (struct sun_zslayout *) mapped_addr; - else - return (struct sun_zslayout *) (unsigned long) vaddr[0]; + } else { + pgd_t *pgd = pgd_offset_k((unsigned long)vaddr[0]); + pmd_t *pmd = pmd_offset(pgd, (unsigned long)vaddr[0]); + pte_t *pte = pte_offset(pmd, (unsigned long)vaddr[0]); + unsigned long base = pte_val(*pte) & _PAGE_PADDR; + + /* Translate PROM's mapping we captured at boot + * time into physical address. + */ + base += ((unsigned long)vaddr[0] & ~PAGE_MASK); + return (struct sun_zslayout *) base; + } } #else /* !(__sparc_v9__) */ static struct sun_zslayout * __init get_zs(int chip) @@ -1990,6 +2086,8 @@ static struct sun_zslayout * __init get_zs(int chip) panic("get_zs bogon zs chip number"); if(sparc_cpu_model == sun4) { + struct resource dummy_resource; + /* Grrr, these have to be hardcoded aieee */ switch(chip) { case 0: @@ -2003,9 +2101,11 @@ static struct sun_zslayout * __init get_zs(int chip) zs_nodes[chip] = 0; if(!irq) zilog_irq = irq = 12; - vaddr[0] = (unsigned long) - sparc_alloc_io(paddr, 0, 8, - "Zilog Serial", iospace, 0); + dummy_resource.start = paddr; + dummy_resource.end = paddr + 8 - 1; + dummy_resource.flags = IORESOURCE_IO; + vaddr[0] = sbus_ioremap(&dummy_resource, 0, + 8, "Zilog Serial"); } else { /* Can use the prom for other machine types */ zsnode = prom_getchild(prom_root_node); @@ -2056,15 +2156,18 @@ static struct sun_zslayout * __init get_zs(int chip) } else { /* On sun4d don't have address property :( */ struct linux_prom_registers zsreg[4]; + struct resource res; if (prom_getproperty(zsnode, "reg", (char *)zsreg, sizeof(zsreg)) == -1) { prom_printf ("Cannot map zs regs\n"); prom_halt(); } prom_apply_generic_ranges(bbnode, cpunode, zsreg, 1); - vaddr[0] = (unsigned long) - sparc_alloc_io(zsreg[0].phys_addr, 0, 8, - "Zilog Serial", zsreg[0].which_io, 0); + res.start = zsreg[0].phys_addr; + res.end = res.start + 8 - 1; + res.flags = zsreg[0].which_io | IORESOURCE_IO; + vaddr[0] = sbus_ioremap(&res, 0, + 8, "Zilog Serial"); } zs_nodes[chip] = zsnode; len = prom_getproperty(zsnode, "intr", @@ -2074,9 +2177,9 @@ static struct sun_zslayout * __init get_zs(int chip) prom_printf( "WHOOPS: proplen for %s " "was %d, need multiple of " - "%d\n", "address", len, + "%d\n", "intr", len, sizeof(struct linux_prom_irqs)); - panic("zilog: address property"); + panic("zilog: intr property"); } if(!irq) { irq = zilog_irq = tmp_irq[0].pri; @@ -2110,11 +2213,62 @@ void zs_change_mouse_baud(int newbaud) write_zsreg(zs_soft[channel].zs_channel, R13, ((brg >> 8) & 0xff)); } -int __init zs_probe (unsigned long *memory_start) +void __init zs_init_alloc_failure(const char *table_name) +{ + prom_printf("zs_probe: Cannot alloc %s.\n", table_name); + prom_halt(); +} + +void * __init zs_alloc_bootmem(unsigned long size) +{ + void *ret; + + ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL); + if (ret != NULL) + memset(ret, 0, size); + + return ret; +} + +void __init zs_alloc_tables(void) +{ + zs_chips = (struct sun_zslayout **) + zs_alloc_bootmem(NUM_SERIAL * sizeof(struct sun_zslayout *)); + if (zs_chips == NULL) + zs_init_alloc_failure("zs_chips"); + zs_channels = (struct sun_zschannel **) + zs_alloc_bootmem(NUM_CHANNELS * sizeof(struct sun_zschannel *)); + if (zs_channels == NULL) + zs_init_alloc_failure("zs_channels"); + zs_nodes = (int *) + zs_alloc_bootmem(NUM_SERIAL * sizeof(int)); + if (zs_nodes == NULL) + zs_init_alloc_failure("zs_nodes"); + zs_soft = (struct sun_serial *) + zs_alloc_bootmem(NUM_CHANNELS * sizeof(struct sun_serial)); + if (zs_soft == NULL) + zs_init_alloc_failure("zs_soft"); + zs_ttys = (struct tty_struct *) + zs_alloc_bootmem(NUM_CHANNELS * sizeof(struct tty_struct)); + if (zs_ttys == NULL) + zs_init_alloc_failure("zs_ttys"); + serial_table = (struct tty_struct **) + zs_alloc_bootmem(NUM_CHANNELS * sizeof(struct tty_struct *)); + if (serial_table == NULL) + zs_init_alloc_failure("serial_table"); + serial_termios = (struct termios **) + zs_alloc_bootmem(NUM_CHANNELS * sizeof(struct termios *)); + if (serial_termios == NULL) + zs_init_alloc_failure("serial_termios"); + serial_termios_locked = (struct termios **) + zs_alloc_bootmem(NUM_CHANNELS * sizeof(struct termios *)); + if (serial_termios_locked == NULL) + zs_init_alloc_failure("serial_termios_locked"); +} + +int __init zs_probe(void) { - char *p; int node; - int i; if(sparc_cpu_model == sun4) goto no_probe; @@ -2166,42 +2320,24 @@ int __init zs_probe (unsigned long *memory_start) NUM_SERIAL = 2; no_probe: - p = (char *)((*memory_start + 7) & ~7); - zs_chips = (struct sun_zslayout **)(p); - i = NUM_SERIAL * sizeof (struct sun_zslayout *); - zs_channels = (struct sun_zschannel **)(p + i); - i += NUM_CHANNELS * sizeof (struct sun_zschannel *); - zs_nodes = (int *)(p + i); - i += NUM_SERIAL * sizeof (int); - zs_soft = (struct sun_serial *)(p + i); - i += NUM_CHANNELS * sizeof (struct sun_serial); - zs_ttys = (struct tty_struct *)(p + i); - i += NUM_CHANNELS * sizeof (struct tty_struct); - serial_table = (struct tty_struct **)(p + i); - i += NUM_CHANNELS * sizeof (struct tty_struct *); - serial_termios = (struct termios **)(p + i); - i += NUM_CHANNELS * sizeof (struct termios *); - serial_termios_locked = (struct termios **)(p + i); - i += NUM_CHANNELS * sizeof (struct termios *); - memset (p, 0, i); - *memory_start = (((unsigned long)p) + i + 7) & ~7; + zs_alloc_tables(); /* Fill in rs_ops struct... */ #ifdef CONFIG_SERIAL_CONSOLE - sunserial_setinitfunc(memory_start, zs_console_init); + sunserial_setinitfunc(zs_console_init); #endif - sunserial_setinitfunc(memory_start, zs_init); + sunserial_setinitfunc(zs_init); rs_ops.rs_kgdb_hook = zs_kgdb_hook; rs_ops.rs_change_mouse_baud = zs_change_mouse_baud; - sunkbd_setinitfunc(memory_start, sun_kbd_init); + sunkbd_setinitfunc(sun_kbd_init); kbd_ops.compute_shiftstate = sun_compute_shiftstate; kbd_ops.setledstate = sun_setledstate; kbd_ops.getledstate = sun_getledstate; kbd_ops.setkeycode = sun_setkeycode; kbd_ops.getkeycode = sun_getkeycode; #if defined(__sparc_v9__) && defined(CONFIG_PCI) - sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count, + sunkbd_install_keymaps(sun_key_maps, sun_keymap_count, sun_func_buf, sun_func_table, sun_funcbufsize, sun_funcbufleft, sun_accent_table, sun_accent_table_size); @@ -2214,7 +2350,8 @@ static inline void zs_prepare(void) int channel, chip; unsigned long flags; - if (!NUM_SERIAL) return; + if (!NUM_SERIAL) + return; save_and_cli(flags); @@ -2346,12 +2483,13 @@ int __init zs_init(void) */ if (request_irq(zilog_irq, zs_interrupt, (SA_INTERRUPT | SA_STATIC_ALLOC), - "Zilog8530", zs_chain)) - panic("Unable to attach zs intr\n"); + "Zilog8530", zs_chain)) { + prom_printf("Unable to attach zs intr\n"); + prom_halt(); + } /* Initialize Hardware */ for(channel = 0; channel < NUM_CHANNELS; channel++) { - /* Hardware reset each chip */ if (!(channel & 1)) { write_zsreg(zs_soft[channel].zs_channel, R9, FHWRES); @@ -2580,12 +2718,14 @@ zs_console_putchar(struct sun_serial *info, char ch) */ static void zs_fair_output(struct sun_serial *info) { - int left; /* Output no more than that */ unsigned long flags; + int left; /* Output no more than that */ char c; - if (info == 0) return; - if (info->xmit_buf == 0) return; + if (info == NULL) + return; + if (info->xmit_buf == NULL) + return; save_flags(flags); cli(); left = info->xmit_cnt; @@ -2602,8 +2742,9 @@ static void zs_fair_output(struct sun_serial *info) } /* Last character is being transmitted now (hopefully). */ - info->zs_channel->control = RES_Tx_P; + sbus_writeb(RES_Tx_P, &info->zs_channel->control); ZSDELAY(); + ZSLOG(REGCTRL, RES_Tx_P, 1); restore_flags(flags); return; |