X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fsynclink.c;h=ede688a4e141ad71834fb90930d83b7466751caa;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=fee2aca3f6a5c7eb77c8c07135489644e5ec8ab2;hpb=f7ed79d23a47594e7834d66a8f14449796d4f3e6;p=linux-2.6.git diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index fee2aca3f..ede688a4e 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -941,6 +941,17 @@ static void* mgsl_get_text_ptr(void) return mgsl_get_text_ptr; } +/* + * tmp_buf is used as a temporary buffer by mgsl_write. We need to + * lock it in case the COPY_FROM_USER blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ioports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *tmp_buf; + static inline int mgsl_paranoia_check(struct mgsl_struct *info, char *name, const char *routine) { @@ -2139,7 +2150,7 @@ static int mgsl_write(struct tty_struct * tty, if (mgsl_paranoia_check(info, tty->name, "mgsl_write")) goto cleanup; - if (!tty || !info->xmit_buf) + if (!tty || !info->xmit_buf || !tmp_buf) goto cleanup; if ( info->params.mode == MGSL_MODE_HDLC || @@ -3427,6 +3438,7 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp) { struct mgsl_struct *info; int retval, line; + unsigned long page; unsigned long flags; /* verify range of specified line number */ @@ -3460,6 +3472,18 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp) goto cleanup; } + if (!tmp_buf) { + page = get_zeroed_page(GFP_KERNEL); + if (!page) { + retval = -ENOMEM; + goto cleanup; + } + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; spin_lock_irqsave(&info->netlock, flags); @@ -4478,6 +4502,11 @@ static void synclink_cleanup(void) kfree(tmp); } + if (tmp_buf) { + free_page((unsigned long) tmp_buf); + tmp_buf = NULL; + } + if (pci_registered) pci_unregister_driver(&synclink_pci_driver); } @@ -5996,7 +6025,7 @@ static void usc_set_async_mode( struct mgsl_struct *info ) * <15..8> ? RxFIFO IRQ Request Level * * Note: For async mode the receive FIFO level must be set - * to 0 to avoid the situation where the FIFO contains fewer bytes + * to 0 to aviod the situation where the FIFO contains fewer bytes * than the trigger level and no more data is expected. * * <7> 0 Exited Hunt IA (Interrupt Arm) @@ -7741,7 +7770,7 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, } info->params.encoding = new_encoding; - info->params.crc_type = new_crctype; + info->params.crc_type = new_crctype;; /* if network interface up, reprogram hardware */ if (info->netcount)