Commit 6ac48313 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: ctc driver changes

From: Peter Tiedemann <ptiedem@de.ibm.com>

ctc driver changes:
 - Make use of the debug feature to ease debugging.
 - ctctty: use dev_alloc_name to allocate a network device name.
 - ctctty: avoid deadlock of ctc_tty_close vs ctc_tty_flush_buffer.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 17f0cb1f
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# S/390 network devices # S/390 network devices
# #
ctc-objs := ctcmain.o ctctty.o ctc-objs := ctcmain.o ctctty.o ctcdbug.o
obj-$(CONFIG_IUCV) += iucv.o obj-$(CONFIG_IUCV) += iucv.o
obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
......
/*
*
* linux/drivers/s390/net/ctcdbug.c ($Revision: 1.1 $)
*
* Linux on zSeries OSA Express and HiperSockets support
*
* Copyright 2000,2003 IBM Corporation
*
* Author(s): Original Code written by
* Peter Tiedemann (ptiedem@de.ibm.com)
*
* $Revision: 1.1 $ $Date: 2004/07/02 16:31:22 $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "ctcdbug.h"
/**
* Debug Facility Stuff
*/
debug_info_t *dbf_setup = NULL;
debug_info_t *dbf_data = NULL;
debug_info_t *dbf_trace = NULL;
DEFINE_PER_CPU(char[256], dbf_txt_buf);
void
unregister_dbf_views(void)
{
if (dbf_setup)
debug_unregister(dbf_setup);
if (dbf_data)
debug_unregister(dbf_data);
if (dbf_trace)
debug_unregister(dbf_trace);
}
int
register_dbf_views(void)
{
dbf_setup = debug_register(CTC_DBF_SETUP_NAME,
CTC_DBF_SETUP_INDEX,
CTC_DBF_SETUP_NR_AREAS,
CTC_DBF_SETUP_LEN);
dbf_data = debug_register(CTC_DBF_DATA_NAME,
CTC_DBF_DATA_INDEX,
CTC_DBF_DATA_NR_AREAS,
CTC_DBF_DATA_LEN);
dbf_trace = debug_register(CTC_DBF_TRACE_NAME,
CTC_DBF_TRACE_INDEX,
CTC_DBF_TRACE_NR_AREAS,
CTC_DBF_TRACE_LEN);
if ((dbf_setup == NULL) || (dbf_data == NULL) ||
(dbf_trace == NULL)) {
unregister_dbf_views();
return -ENOMEM;
}
debug_register_view(dbf_setup, &debug_hex_ascii_view);
debug_set_level(dbf_setup, CTC_DBF_SETUP_LEVEL);
debug_register_view(dbf_data, &debug_hex_ascii_view);
debug_set_level(dbf_data, CTC_DBF_DATA_LEVEL);
debug_register_view(dbf_trace, &debug_hex_ascii_view);
debug_set_level(dbf_trace, CTC_DBF_TRACE_LEVEL);
return 0;
}
/*
*
* linux/drivers/s390/net/ctcdbug.h ($Revision: 1.1 $)
*
* Linux on zSeries OSA Express and HiperSockets support
*
* Copyright 2000,2003 IBM Corporation
*
* Author(s): Original Code written by
* Peter Tiedemann (ptiedem@de.ibm.com)
*
* $Revision: 1.1 $ $Date: 2004/07/02 16:31:22 $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <asm/debug.h>
/**
* Debug Facility stuff
*/
#define CTC_DBF_SETUP_NAME "ctc_setup"
#define CTC_DBF_SETUP_LEN 16
#define CTC_DBF_SETUP_INDEX 3
#define CTC_DBF_SETUP_NR_AREAS 1
#define CTC_DBF_SETUP_LEVEL 3
#define CTC_DBF_DATA_NAME "ctc_data"
#define CTC_DBF_DATA_LEN 128
#define CTC_DBF_DATA_INDEX 3
#define CTC_DBF_DATA_NR_AREAS 1
#define CTC_DBF_DATA_LEVEL 2
#define CTC_DBF_TRACE_NAME "ctc_trace"
#define CTC_DBF_TRACE_LEN 16
#define CTC_DBF_TRACE_INDEX 2
#define CTC_DBF_TRACE_NR_AREAS 2
#define CTC_DBF_TRACE_LEVEL 3
#define DBF_TEXT(name,level,text) \
do { \
debug_text_event(dbf_##name,level,text); \
} while (0)
#define DBF_HEX(name,level,addr,len) \
do { \
debug_event(dbf_##name,level,(void*)(addr),len); \
} while (0)
extern DEFINE_PER_CPU(char[256], dbf_txt_buf);
extern debug_info_t *dbf_setup;
extern debug_info_t *dbf_data;
extern debug_info_t *dbf_trace;
#define DBF_TEXT_(name,level,text...) \
do { \
char* dbf_txt_buf = get_cpu_var(dbf_txt_buf); \
sprintf(dbf_txt_buf, text); \
debug_text_event(dbf_##name,level,dbf_txt_buf); \
put_cpu_var(dbf_txt_buf); \
} while (0)
#define DBF_SPRINTF(name,level,text...) \
do { \
debug_sprintf_event(dbf_trace, level, ##text ); \
debug_sprintf_event(dbf_trace, level, text ); \
} while (0)
int register_dbf_views(void);
void unregister_dbf_views(void);
/**
* some more debug stuff
*/
#define HEXDUMP16(importance,header,ptr) \
PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
"%02x %02x %02x %02x %02x %02x %02x %02x\n", \
*(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
*(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
*(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
*(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
*(((char*)ptr)+12),*(((char*)ptr)+13), \
*(((char*)ptr)+14),*(((char*)ptr)+15)); \
PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
"%02x %02x %02x %02x %02x %02x %02x %02x\n", \
*(((char*)ptr)+16),*(((char*)ptr)+17), \
*(((char*)ptr)+18),*(((char*)ptr)+19), \
*(((char*)ptr)+20),*(((char*)ptr)+21), \
*(((char*)ptr)+22),*(((char*)ptr)+23), \
*(((char*)ptr)+24),*(((char*)ptr)+25), \
*(((char*)ptr)+26),*(((char*)ptr)+27), \
*(((char*)ptr)+28),*(((char*)ptr)+29), \
*(((char*)ptr)+30),*(((char*)ptr)+31));
static inline void
hex_dump(unsigned char *buf, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
if (i && !(i % 16))
printk("\n");
printk("%02x ", *(buf + i));
}
printk("\n");
}
This diff is collapsed.
/* /*
* $Id: ctctty.c,v 1.17 2004/03/31 17:06:34 ptiedem Exp $ * $Id: ctctty.c,v 1.21 2004/07/02 16:31:22 ptiedem Exp $
* *
* CTC / ESCON network driver, tty interface. * CTC / ESCON network driver, tty interface.
* *
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h>
#include "ctctty.h" #include "ctctty.h"
#include "ctcdbug.h"
#define CTC_TTY_MAJOR 43 #define CTC_TTY_MAJOR 43
#define CTC_TTY_MAX_DEVICES 64 #define CTC_TTY_MAX_DEVICES 64
...@@ -103,6 +104,7 @@ ctc_tty_try_read(ctc_tty_info * info, struct sk_buff *skb) ...@@ -103,6 +104,7 @@ ctc_tty_try_read(ctc_tty_info * info, struct sk_buff *skb)
int len; int len;
struct tty_struct *tty; struct tty_struct *tty;
DBF_TEXT(trace, 2, __FUNCTION__);
if ((tty = info->tty)) { if ((tty = info->tty)) {
if (info->mcr & UART_MCR_RTS) { if (info->mcr & UART_MCR_RTS) {
c = TTY_FLIPBUF_SIZE - tty->flip.count; c = TTY_FLIPBUF_SIZE - tty->flip.count;
...@@ -132,6 +134,7 @@ ctc_tty_readmodem(ctc_tty_info *info) ...@@ -132,6 +134,7 @@ ctc_tty_readmodem(ctc_tty_info *info)
int ret = 1; int ret = 1;
struct tty_struct *tty; struct tty_struct *tty;
DBF_TEXT(trace, 2, __FUNCTION__);
if ((tty = info->tty)) { if ((tty = info->tty)) {
if (info->mcr & UART_MCR_RTS) { if (info->mcr & UART_MCR_RTS) {
int c = TTY_FLIPBUF_SIZE - tty->flip.count; int c = TTY_FLIPBUF_SIZE - tty->flip.count;
...@@ -165,6 +168,7 @@ ctc_tty_setcarrier(struct net_device *netdev, int on) ...@@ -165,6 +168,7 @@ ctc_tty_setcarrier(struct net_device *netdev, int on)
{ {
int i; int i;
DBF_TEXT(trace, 2, __FUNCTION__);
if ((!driver) || ctc_tty_shuttingdown) if ((!driver) || ctc_tty_shuttingdown)
return; return;
for (i = 0; i < CTC_TTY_MAX_DEVICES; i++) for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
...@@ -185,6 +189,7 @@ ctc_tty_netif_rx(struct sk_buff *skb) ...@@ -185,6 +189,7 @@ ctc_tty_netif_rx(struct sk_buff *skb)
int i; int i;
ctc_tty_info *info = NULL; ctc_tty_info *info = NULL;
DBF_TEXT(trace, 2, __FUNCTION__);
if (!skb) if (!skb)
return; return;
if ((!skb->dev) || (!driver) || ctc_tty_shuttingdown) { if ((!skb->dev) || (!driver) || ctc_tty_shuttingdown) {
...@@ -249,6 +254,7 @@ ctc_tty_tint(ctc_tty_info * info) ...@@ -249,6 +254,7 @@ ctc_tty_tint(ctc_tty_info * info)
int wake = 1; int wake = 1;
int rc; int rc;
DBF_TEXT(trace, 2, __FUNCTION__);
if (!info->netdev) { if (!info->netdev) {
if (skb) if (skb)
kfree_skb(skb); kfree_skb(skb);
...@@ -341,6 +347,7 @@ ctc_tty_inject(ctc_tty_info *info, char c) ...@@ -341,6 +347,7 @@ ctc_tty_inject(ctc_tty_info *info, char c)
int skb_res; int skb_res;
struct sk_buff *skb; struct sk_buff *skb;
DBF_TEXT(trace, 2, __FUNCTION__);
if (ctc_tty_shuttingdown) if (ctc_tty_shuttingdown)
return; return;
skb_res = info->netdev->hard_header_len + sizeof(info->mcr) + skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
...@@ -361,6 +368,7 @@ ctc_tty_inject(ctc_tty_info *info, char c) ...@@ -361,6 +368,7 @@ ctc_tty_inject(ctc_tty_info *info, char c)
static void static void
ctc_tty_transmit_status(ctc_tty_info *info) ctc_tty_transmit_status(ctc_tty_info *info)
{ {
DBF_TEXT(trace, 2, __FUNCTION__);
if (ctc_tty_shuttingdown) if (ctc_tty_shuttingdown)
return; return;
info->flags |= CTC_ASYNC_TX_LINESTAT; info->flags |= CTC_ASYNC_TX_LINESTAT;
...@@ -374,6 +382,7 @@ ctc_tty_change_speed(ctc_tty_info * info) ...@@ -374,6 +382,7 @@ ctc_tty_change_speed(ctc_tty_info * info)
unsigned int quot; unsigned int quot;
int i; int i;
DBF_TEXT(trace, 2, __FUNCTION__);
if (!info->tty || !info->tty->termios) if (!info->tty || !info->tty->termios)
return; return;
cflag = info->tty->termios->c_cflag; cflag = info->tty->termios->c_cflag;
...@@ -412,6 +421,7 @@ ctc_tty_change_speed(ctc_tty_info * info) ...@@ -412,6 +421,7 @@ ctc_tty_change_speed(ctc_tty_info * info)
static int static int
ctc_tty_startup(ctc_tty_info * info) ctc_tty_startup(ctc_tty_info * info)
{ {
DBF_TEXT(trace, 2, __FUNCTION__);
if (info->flags & CTC_ASYNC_INITIALIZED) if (info->flags & CTC_ASYNC_INITIALIZED)
return 0; return 0;
#ifdef CTC_DEBUG_MODEM_OPEN #ifdef CTC_DEBUG_MODEM_OPEN
...@@ -454,6 +464,7 @@ ctc_tty_stopdev(unsigned long data) ...@@ -454,6 +464,7 @@ ctc_tty_stopdev(unsigned long data)
static void static void
ctc_tty_shutdown(ctc_tty_info * info) ctc_tty_shutdown(ctc_tty_info * info)
{ {
DBF_TEXT(trace, 2, __FUNCTION__);
if (!(info->flags & CTC_ASYNC_INITIALIZED)) if (!(info->flags & CTC_ASYNC_INITIALIZED))
return; return;
#ifdef CTC_DEBUG_MODEM_OPEN #ifdef CTC_DEBUG_MODEM_OPEN
...@@ -486,14 +497,17 @@ ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int cou ...@@ -486,14 +497,17 @@ ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int cou
int total = 0; int total = 0;
ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
DBF_TEXT(trace, 2, __FUNCTION__);
if (ctc_tty_shuttingdown) if (ctc_tty_shuttingdown)
return 0; goto ex;
if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_write")) if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_write"))
return 0; goto ex;
if (!tty) if (!tty)
return 0; goto ex;
if (!info->netdev) if (!info->netdev) {
return -ENODEV; total = -ENODEV;
goto ex;
}
if (from_user) if (from_user)
down(&info->write_sem); down(&info->write_sem);
while (1) { while (1) {
...@@ -530,6 +544,8 @@ ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int cou ...@@ -530,6 +544,8 @@ ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int cou
} }
if (from_user) if (from_user)
up(&info->write_sem); up(&info->write_sem);
ex:
DBF_TEXT(trace, 6, __FUNCTION__);
return total; return total;
} }
...@@ -559,13 +575,14 @@ ctc_tty_flush_buffer(struct tty_struct *tty) ...@@ -559,13 +575,14 @@ ctc_tty_flush_buffer(struct tty_struct *tty)
ctc_tty_info *info; ctc_tty_info *info;
unsigned long flags; unsigned long flags;
DBF_TEXT(trace, 2, __FUNCTION__);
if (!tty) if (!tty)
return; goto ex;
spin_lock_irqsave(&ctc_tty_lock, flags); spin_lock_irqsave(&ctc_tty_lock, flags);
info = (ctc_tty_info *) tty->driver_data; info = (ctc_tty_info *) tty->driver_data;
if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_flush_buffer")) { if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_flush_buffer")) {
spin_unlock_irqrestore(&ctc_tty_lock, flags); spin_unlock_irqrestore(&ctc_tty_lock, flags);
return; goto ex;
} }
skb_queue_purge(&info->tx_queue); skb_queue_purge(&info->tx_queue);
info->lsr |= UART_LSR_TEMT; info->lsr |= UART_LSR_TEMT;
...@@ -574,6 +591,9 @@ ctc_tty_flush_buffer(struct tty_struct *tty) ...@@ -574,6 +591,9 @@ ctc_tty_flush_buffer(struct tty_struct *tty)
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup) tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup) (tty); (tty->ldisc.write_wakeup) (tty);
ex:
DBF_TEXT_(trace, 2, "ex: %s ", __FUNCTION__);
return;
} }
static void static void
...@@ -783,7 +803,6 @@ ctc_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) ...@@ -783,7 +803,6 @@ ctc_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
{ {
ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
unsigned int cflag = tty->termios->c_cflag; unsigned int cflag = tty->termios->c_cflag;
ctc_tty_change_speed(info); ctc_tty_change_speed(info);
/* Handle transition to B0 */ /* Handle transition to B0 */
...@@ -1032,8 +1051,10 @@ ctc_tty_close(struct tty_struct *tty, struct file *filp) ...@@ -1032,8 +1051,10 @@ ctc_tty_close(struct tty_struct *tty, struct file *filp)
} }
} }
ctc_tty_shutdown(info); ctc_tty_shutdown(info);
if (tty->driver->flush_buffer) if (tty->driver->flush_buffer) {
tty->driver->flush_buffer(tty); skb_queue_purge(&info->tx_queue);
info->lsr |= UART_LSR_TEMT;
}
if (tty->ldisc.flush_buffer) if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty); tty->ldisc.flush_buffer(tty);
info->tty = 0; info->tty = 0;
...@@ -1059,7 +1080,6 @@ ctc_tty_hangup(struct tty_struct *tty) ...@@ -1059,7 +1080,6 @@ ctc_tty_hangup(struct tty_struct *tty)
{ {
ctc_tty_info *info = (ctc_tty_info *)tty->driver_data; ctc_tty_info *info = (ctc_tty_info *)tty->driver_data;
unsigned long saveflags; unsigned long saveflags;
if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_hangup")) if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_hangup"))
return; return;
ctc_tty_shutdown(info); ctc_tty_shutdown(info);
...@@ -1185,6 +1205,21 @@ ctc_tty_register_netdev(struct net_device *dev) { ...@@ -1185,6 +1205,21 @@ ctc_tty_register_netdev(struct net_device *dev) {
"with NULL dev or NULL dev-name\n"); "with NULL dev or NULL dev-name\n");
return -1; return -1;
} }
/*
* If the name is a format string the caller wants us to
* do a name allocation : format string must end with %d
*/
if (strchr(dev->name, '%'))
{
int err = dev_alloc_name(dev, dev->name); // dev->name is changed by this
if (err < 0) {
printk(KERN_DEBUG "dev_alloc returned error %d\n", err);
return err;
}
}
for (p = dev->name; p && ((*p < '0') || (*p > '9')); p++); for (p = dev->name; p && ((*p < '0') || (*p > '9')); p++);
ttynum = simple_strtoul(p, &err, 0); ttynum = simple_strtoul(p, &err, 0);
if ((ttynum < 0) || (ttynum >= CTC_TTY_MAX_DEVICES) || if ((ttynum < 0) || (ttynum >= CTC_TTY_MAX_DEVICES) ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment