From patchwork Thu Jul 28 07:02:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dario Binacchi X-Patchwork-Id: 2275 Return-Path: X-Original-To: linux-amarula@patchwork.amarulasolutions.com Delivered-To: linux-amarula@patchwork.amarulasolutions.com Received: from mail-ej1-f72.google.com (mail-ej1-f72.google.com [209.85.218.72]) by ganimede.amarulasolutions.com (Postfix) with ESMTPS id 2F0C83F013 for ; Thu, 28 Jul 2022 09:03:09 +0200 (CEST) Received: by mail-ej1-f72.google.com with SMTP id nc23-20020a1709071c1700b0072b94109144sf327459ejc.2 for ; Thu, 28 Jul 2022 00:03:09 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1658991789; cv=pass; d=google.com; s=arc-20160816; b=jxCvMv2n7z4SBaM11xWzqQgTRP/Q+mzOVbNfExut8vY0hIUC3tiTdNDOq5rQeO4zvI 9paVlGqMwJ6ApYwQqFd+zKY1pS0+AAz6MytqfBGDPEabD/zuXOOFdeawZ0uGUR9Gs+KL 4n6WCeBHaz7a2G90G2p0WjRieqZ7sumxlMzz8hMN3wNJCBuibMvownDRujXNq1vfXuUA w/Y+GxR1klHlsEUoEOHk9yJCYRqwGJf45rTUSq9yWzkLchV0yR9RKWZnbqO7HdU0pQOD mX5GKRTaoexWqSHVofHUe3qSLww6VknZvL4sWYQjA3PTdGEr32lbnj7AIix9M/xghq3a NmqA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-archive:list-help:list-post:list-id :mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=UgZbut/qa8HdXoS+rtwo0+PB8PCkOZ7vNOusfdkdrNI=; b=mCA3LfIB6Iqrnomtlczna0pSD9ECjr9SHF/mUWjNSfQHptIrYxwgg95a2f1XVMs6Tt UVllC6TEKPb2soEFMYa6+g6GmYo9l63fwNhaNwpPW49ptbdtzTAy9V1lxmua5BnGw+YX MlAEnkNPocAydrIw/psrfVK+j1DICoYDECM3d+IWpN75bMXDnI8ENny1TyD2wbxtU8VN OEUKHeqhl/zGsxYkHQEzaXFhuAviAki6CWrantwOMRUdb0jdjrhWDx9ASzMizCOtLbd0 Noz7Jtvl5iBzj1PopP4jzE7KWyjfrNIdA4zt+HIlblyL8OT/x7JzXn6pOmpM1iatyBG0 81Jw== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@amarulasolutions.com header.s=google header.b=pFlhC11P; spf=pass (google.com: domain of dario.binacchi@amarulasolutions.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=dario.binacchi@amarulasolutions.com; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=amarulasolutions.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amarulasolutions.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:x-original-sender:x-original-authentication-results :precedence:mailing-list:list-id:list-post:list-help:list-archive :list-unsubscribe; bh=UgZbut/qa8HdXoS+rtwo0+PB8PCkOZ7vNOusfdkdrNI=; b=TptKJxpbI+eTw0uGZgoYnjnlG8ejWesAkraWegDUFUx+wuxCGXrjFKQ6zJK0uSikyk 9mRQAwbMu7ojSMaVZ9gjISWRu/j5RM9wPSxwN4Gr1wesEvJd7mx8Qn7gpASsXFyRPDy7 GLJ3INwK5BJWMEQFJ767m26ybfTOagzZxwS4Q= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :x-spam-checked-in-group:list-post:list-help:list-archive :list-unsubscribe; bh=UgZbut/qa8HdXoS+rtwo0+PB8PCkOZ7vNOusfdkdrNI=; b=Rw5z1GI0VjVePjlBMNRKOVdXKF60n2pdYH5MB+ilj1L+6lJ5fBqI/X3OFc6UOObANC kolVPSvKx93kzjAHrtTY7KmQxk1g2EkA0aBpgrxIr+xekpk9TUtxqbDFBn7LZLfLEtpx Zpifjp0Vld/02Jg1dGa4VC+mIjx9i1k+l7nLLsDF3lHaT4DbtYLcOtlpmlZ1FquZFzj3 33jZRVXL4XuyjUG2bnp57OCivJRQEOVHrCFS2Qbh1JNvIleD9PlnjjNJk3AP1plwL6c4 yJP1bJNgN+Em5vysX7XBAMGMmXDOS2IzAYwlk+7YGn70cxq5PtJaMB9oshG7dS7g+7OG vj+Q== X-Gm-Message-State: AJIora8M6Vb5p+Gucsmy1LICO5Zce4sM6CIGwLLig97TktKHBfrX6dUK T/O2Z/yOpeBvF4xaQi2BTThc1e4A X-Google-Smtp-Source: AGRyM1vR++/De521R+aj57E+ibNCxd833KjkC7bz82sh3OiXy9L64EuTZ7FXPwqnrTskz3fCENFadA== X-Received: by 2002:a17:907:2855:b0:72b:67b7:2c28 with SMTP id el21-20020a170907285500b0072b67b72c28mr20608572ejc.331.1658991788984; Thu, 28 Jul 2022 00:03:08 -0700 (PDT) X-BeenThere: linux-amarula@amarulasolutions.com Received: by 2002:a17:906:6d0e:b0:72b:41fa:b554 with SMTP id m14-20020a1709066d0e00b0072b41fab554ls413529ejr.10.-pod-prod-gmail; Thu, 28 Jul 2022 00:03:07 -0700 (PDT) X-Received: by 2002:a17:906:4785:b0:72e:dd6c:1ba1 with SMTP id cw5-20020a170906478500b0072edd6c1ba1mr20301408ejc.712.1658991787720; Thu, 28 Jul 2022 00:03:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1658991787; cv=none; d=google.com; s=arc-20160816; b=VlzQslUpQpoC3giXFvkdgwSJ9dIuDH+mfVxSLN4jkS9aK/n2EukUO+THPadhpG8u2V ODbH6tx61v/O0fcKnymXkabwBLoT0HSwXY891uIPl8+wS8KAaNLy29xzi4wf9Ao42wFc HijWEc/cxXmfRd6I2gripzwPzwhXQgkBgLaTq9y83Hyoe4lTdk3u+GJBJ+jO9Ui7UtGz 7iSmIPqiqSa/nJRpPLED+WD7YIUVgaCnwCZ3k7MY4M1olvcpKhnjnzcB3x4kuvq1H/4M UCsLEL8IwpgpijbM5QVLJzhtWYy6ztKPdWqgzCICrNPUthznniylydQwyzmSwDMXBuIf Y8ww== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=RIwpnqXVkEPVC9y6D6imEtiW45Xx5sUlsaiN9YQ/yrc=; b=jKoKAbHeXkEqMZiiW3sy92sWEaeiNygtdStuh4e0mj6qz9WOBG7e5jxIEqOZOlP2uU w35vxmgZn88ZyFHbahwjsskZM2tEcMNLRubsn5axy3+ORT8U+iinr4cxRuW7NV5smeb2 +wNhIG54kv15snHqT/7VrT0FmG6/3nvZC6WLY0Rxl9EqzdE2JTAMvs25JlV+/nMkn1GU 5YRFYEcRbspvVYT7pyVRz5CGyYRpp+YmPECUZqfQrw4Xy4IrnhlotbE80qHma8spQVi1 piwmrhG8i0vYluK5w/NyQ4W7KJcjoptJ6mrZ+O4Zq/RHBkqeHd60Cb03FoCg/sffa0Tz uDhQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@amarulasolutions.com header.s=google header.b=pFlhC11P; spf=pass (google.com: domain of dario.binacchi@amarulasolutions.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=dario.binacchi@amarulasolutions.com; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=amarulasolutions.com Received: from mail-sor-f41.google.com (mail-sor-f41.google.com. [209.85.220.41]) by mx.google.com with SMTPS id bx19-20020a170906a1d300b0072b960ca210sor58766ejb.86.2022.07.28.00.03.07 for (Google Transport Security); Thu, 28 Jul 2022 00:03:07 -0700 (PDT) Received-SPF: pass (google.com: domain of dario.binacchi@amarulasolutions.com designates 209.85.220.41 as permitted sender) client-ip=209.85.220.41; X-Received: by 2002:a17:907:8690:b0:72b:552e:67c0 with SMTP id qa16-20020a170907869000b0072b552e67c0mr20012840ejc.600.1658991787258; Thu, 28 Jul 2022 00:03:07 -0700 (PDT) Received: from dario-ThinkPad-T14s-Gen-2i.homenet.telecomitalia.it (host-79-31-31-9.retail.telecomitalia.it. [79.31.31.9]) by smtp.gmail.com with ESMTPSA id r18-20020aa7d152000000b0042de3d661d2sm154742edo.1.2022.07.28.00.03.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 Jul 2022 00:03:06 -0700 (PDT) From: Dario Binacchi To: linux-kernel@vger.kernel.org Cc: linux-can@vger.kernel.org, Marc Kleine-Budde , Jeroen Hofstee , michael@amarulasolutions.com, Amarula patchwork , Oliver Hartkopp , Dario Binacchi , Max Staudt , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Wolfgang Grandegger , netdev@vger.kernel.org Subject: [PATCH v4 3/7] can: slcan: remove legacy infrastructure Date: Thu, 28 Jul 2022 09:02:50 +0200 Message-Id: <20220728070254.267974-4-dario.binacchi@amarulasolutions.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220728070254.267974-1-dario.binacchi@amarulasolutions.com> References: <20220728070254.267974-1-dario.binacchi@amarulasolutions.com> MIME-Version: 1.0 X-Original-Sender: dario.binacchi@amarulasolutions.com X-Original-Authentication-Results: mx.google.com; dkim=pass header.i=@amarulasolutions.com header.s=google header.b=pFlhC11P; spf=pass (google.com: domain of dario.binacchi@amarulasolutions.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=dario.binacchi@amarulasolutions.com; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=amarulasolutions.com Content-Type: text/plain; charset="UTF-8" Precedence: list Mailing-list: list linux-amarula@amarulasolutions.com; contact linux-amarula+owners@amarulasolutions.com List-ID: X-Spam-Checked-In-Group: linux-amarula@amarulasolutions.com X-Google-Group-Id: 476853432473 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Taking inspiration from the drivers/net/can/can327.c driver and at the suggestion of its author Max Staudt, I removed legacy stuff like `SLCAN_MAGIC' and `slcan_devs' resulting in simplification of the code and its maintainability. The use of slcan_devs is derived from a very old kernel, since slip.c is about 30 years old, so today's kernel allows us to remove it. The .hangup() ldisc function, which only called the ldisc .close(), has been removed since the ldisc layer calls .close() in a good place anyway. The old slcanX name has been dropped in order to use the standard canX interface naming. The ioctl SIOCGIFNAME can be used to query the name of the created interface. Furthermore, there are several ways to get stable interfaces names in user space, e.g. udev or systemd-networkd. The `maxdev' module parameter has also been removed. CC: Max Staudt Signed-off-by: Dario Binacchi Reviewed-by: Max Staudt --- Changes in v4: - Add Max Staudt's `Reviewed-by' tag. Changes in v3: - Update the commit message. - Use 1 space in front of the =. Changes in v2: - Update the commit description. - Drop the old "slcan" name to use the standard canX interface naming. drivers/net/can/slcan/slcan-core.c | 318 ++++++----------------------- 1 file changed, 63 insertions(+), 255 deletions(-) diff --git a/drivers/net/can/slcan/slcan-core.c b/drivers/net/can/slcan/slcan-core.c index ca383c43167d..0d309d0636df 100644 --- a/drivers/net/can/slcan/slcan-core.c +++ b/drivers/net/can/slcan/slcan-core.c @@ -1,11 +1,14 @@ /* * slcan.c - serial line CAN interface driver (using tty line discipline) * - * This file is derived from linux/drivers/net/slip/slip.c + * This file is derived from linux/drivers/net/slip/slip.c and got + * inspiration from linux/drivers/net/can/can327.c for the rework made + * on the line discipline code. * * slip.c Authors : Laurence Culhane * Fred N. van Kempen * slcan.c Author : Oliver Hartkopp + * can327.c Author : Max Staudt * * 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 @@ -38,7 +41,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include #include @@ -48,7 +50,6 @@ #include #include #include -#include #include #include #include @@ -63,15 +64,6 @@ MODULE_DESCRIPTION("serial line CAN interface"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Oliver Hartkopp "); -#define SLCAN_MAGIC 0x53CA - -static int maxdev = 10; /* MAX number of SLCAN channels; - * This can be overridden with - * insmod slcan.ko maxdev=nnn - */ -module_param(maxdev, int, 0); -MODULE_PARM_DESC(maxdev, "Maximum number of slcan interfaces"); - /* maximum rx buffer len: extended CAN frame with timestamp */ #define SLC_MTU (sizeof("T1111222281122334455667788EA5F\r") + 1) @@ -85,7 +77,6 @@ MODULE_PARM_DESC(maxdev, "Maximum number of slcan interfaces"); SLC_STATE_BE_TXCNT_LEN) struct slcan { struct can_priv can; - int magic; /* Various fields. */ struct tty_struct *tty; /* ptr to TTY structure */ @@ -101,17 +92,14 @@ struct slcan { int xleft; /* bytes left in XMIT queue */ unsigned long flags; /* Flag values/ mode etc */ -#define SLF_INUSE 0 /* Channel in use */ -#define SLF_ERROR 1 /* Parity, etc. error */ -#define SLF_XCMD 2 /* Command transmission */ +#define SLF_ERROR 0 /* Parity, etc. error */ +#define SLF_XCMD 1 /* Command transmission */ unsigned long cmd_flags; /* Command flags */ #define CF_ERR_RST 0 /* Reset errors on open */ wait_queue_head_t xcmd_wait; /* Wait queue for commands */ /* transmission */ }; -static struct net_device **slcan_devs; - static const u32 slcan_bitrate_const[] = { 10000, 20000, 50000, 100000, 125000, 250000, 500000, 800000, 1000000 @@ -555,9 +543,8 @@ static void slcan_transmit(struct work_struct *work) spin_lock_bh(&sl->lock); /* First make sure we're connected. */ - if (!sl->tty || sl->magic != SLCAN_MAGIC || - (unlikely(!netif_running(sl->dev)) && - likely(!test_bit(SLF_XCMD, &sl->flags)))) { + if (unlikely(!netif_running(sl->dev)) && + likely(!test_bit(SLF_XCMD, &sl->flags))) { spin_unlock_bh(&sl->lock); return; } @@ -592,13 +579,9 @@ static void slcan_transmit(struct work_struct *work) */ static void slcan_write_wakeup(struct tty_struct *tty) { - struct slcan *sl; + struct slcan *sl = (struct slcan *)tty->disc_data; - rcu_read_lock(); - sl = rcu_dereference(tty->disc_data); - if (sl) - schedule_work(&sl->tx_work); - rcu_read_unlock(); + schedule_work(&sl->tx_work); } /* Send a can_frame to a TTY queue. */ @@ -669,25 +652,21 @@ static int slc_close(struct net_device *dev) struct slcan *sl = netdev_priv(dev); int err; - spin_lock_bh(&sl->lock); - if (sl->tty) { - if (sl->can.bittiming.bitrate && - sl->can.bittiming.bitrate != CAN_BITRATE_UNKNOWN) { - spin_unlock_bh(&sl->lock); - err = slcan_transmit_cmd(sl, "C\r"); - spin_lock_bh(&sl->lock); - if (err) - netdev_warn(dev, - "failed to send close command 'C\\r'\n"); - } - - /* TTY discipline is running. */ - clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); + if (sl->can.bittiming.bitrate && + sl->can.bittiming.bitrate != CAN_BITRATE_UNKNOWN) { + err = slcan_transmit_cmd(sl, "C\r"); + if (err) + netdev_warn(dev, + "failed to send close command 'C\\r'\n"); } + + /* TTY discipline is running. */ + clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); + flush_work(&sl->tx_work); + netif_stop_queue(dev); sl->rcount = 0; sl->xleft = 0; - spin_unlock_bh(&sl->lock); close_candev(dev); sl->can.state = CAN_STATE_STOPPED; if (sl->can.bittiming.bitrate == CAN_BITRATE_UNKNOWN) @@ -703,9 +682,6 @@ static int slc_open(struct net_device *dev) unsigned char cmd[SLC_MTU]; int err, s; - if (!sl->tty) - return -ENODEV; - /* The baud rate is not set with the command * `ip link set type can bitrate ' and therefore * can.bittiming.bitrate is CAN_BITRATE_UNSET (0), causing @@ -720,8 +696,6 @@ static int slc_open(struct net_device *dev) return err; } - sl->flags &= BIT(SLF_INUSE); - if (sl->can.bittiming.bitrate != CAN_BITRATE_UNKNOWN) { for (s = 0; s < ARRAY_SIZE(slcan_bitrate_const); s++) { if (sl->can.bittiming.bitrate == slcan_bitrate_const[s]) @@ -765,14 +739,6 @@ static int slc_open(struct net_device *dev) return err; } -static void slc_dealloc(struct slcan *sl) -{ - int i = sl->dev->base_addr; - - free_candev(sl->dev); - slcan_devs[i] = NULL; -} - static int slcan_change_mtu(struct net_device *dev, int new_mtu) { return -EINVAL; @@ -802,7 +768,7 @@ static void slcan_receive_buf(struct tty_struct *tty, { struct slcan *sl = (struct slcan *)tty->disc_data; - if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev)) + if (!netif_running(sl->dev)) return; /* Read the characters out of the buffer */ @@ -817,80 +783,15 @@ static void slcan_receive_buf(struct tty_struct *tty, } } -/************************************ - * slcan_open helper routines. - ************************************/ - -/* Collect hanged up channels */ -static void slc_sync(void) -{ - int i; - struct net_device *dev; - struct slcan *sl; - - for (i = 0; i < maxdev; i++) { - dev = slcan_devs[i]; - if (!dev) - break; - - sl = netdev_priv(dev); - if (sl->tty) - continue; - if (dev->flags & IFF_UP) - dev_close(dev); - } -} - -/* Find a free SLCAN channel, and link in this `tty' line. */ -static struct slcan *slc_alloc(void) -{ - int i; - struct net_device *dev = NULL; - struct slcan *sl; - - for (i = 0; i < maxdev; i++) { - dev = slcan_devs[i]; - if (!dev) - break; - } - - /* Sorry, too many, all slots in use */ - if (i >= maxdev) - return NULL; - - dev = alloc_candev(sizeof(*sl), 1); - if (!dev) - return NULL; - - snprintf(dev->name, sizeof(dev->name), KBUILD_MODNAME "%d", i); - dev->netdev_ops = &slc_netdev_ops; - dev->base_addr = i; - slcan_set_ethtool_ops(dev); - sl = netdev_priv(dev); - - /* Initialize channel control data */ - sl->magic = SLCAN_MAGIC; - sl->dev = dev; - sl->can.bitrate_const = slcan_bitrate_const; - sl->can.bitrate_const_cnt = ARRAY_SIZE(slcan_bitrate_const); - spin_lock_init(&sl->lock); - INIT_WORK(&sl->tx_work, slcan_transmit); - init_waitqueue_head(&sl->xcmd_wait); - slcan_devs[i] = dev; - - return sl; -} - /* Open the high-level part of the SLCAN channel. * This function is called by the TTY module when the - * SLCAN line discipline is called for. Because we are - * sure the tty line exists, we only have to link it to - * a free SLCAN channel... + * SLCAN line discipline is called for. * * Called in process context serialized from other ldisc calls. */ static int slcan_open(struct tty_struct *tty) { + struct net_device *dev; struct slcan *sl; int err; @@ -900,72 +801,49 @@ static int slcan_open(struct tty_struct *tty) if (!tty->ops->write) return -EOPNOTSUPP; - /* RTnetlink lock is misused here to serialize concurrent - * opens of slcan channels. There are better ways, but it is - * the simplest one. - */ - rtnl_lock(); + dev = alloc_candev(sizeof(*sl), 1); + if (!dev) + return -ENFILE; - /* Collect hanged up channels. */ - slc_sync(); + sl = netdev_priv(dev); - sl = tty->disc_data; + /* Configure TTY interface */ + tty->receive_room = 65536; /* We don't flow control */ + sl->rcount = 0; + sl->xleft = 0; + spin_lock_init(&sl->lock); + INIT_WORK(&sl->tx_work, slcan_transmit); + init_waitqueue_head(&sl->xcmd_wait); - err = -EEXIST; - /* First make sure we're not already connected. */ - if (sl && sl->magic == SLCAN_MAGIC) - goto err_exit; + /* Configure CAN metadata */ + sl->can.bitrate_const = slcan_bitrate_const; + sl->can.bitrate_const_cnt = ARRAY_SIZE(slcan_bitrate_const); - /* OK. Find a free SLCAN channel to use. */ - err = -ENFILE; - sl = slc_alloc(); - if (!sl) - goto err_exit; + /* Configure netdev interface */ + sl->dev = dev; + dev->netdev_ops = &slc_netdev_ops; + slcan_set_ethtool_ops(dev); + /* Mark ldisc channel as alive */ sl->tty = tty; tty->disc_data = sl; - if (!test_bit(SLF_INUSE, &sl->flags)) { - /* Perform the low-level SLCAN initialization. */ - sl->rcount = 0; - sl->xleft = 0; - - set_bit(SLF_INUSE, &sl->flags); - - rtnl_unlock(); - err = register_candev(sl->dev); - if (err) { - pr_err("can't register candev\n"); - goto err_free_chan; - } - } else { - rtnl_unlock(); + err = register_candev(dev); + if (err) { + free_candev(dev); + pr_err("can't register candev\n"); + return err; } - tty->receive_room = 65536; /* We don't flow control */ - + netdev_info(dev, "slcan on %s.\n", tty->name); /* TTY layer expects 0 on success */ return 0; - -err_free_chan: - rtnl_lock(); - sl->tty = NULL; - tty->disc_data = NULL; - clear_bit(SLF_INUSE, &sl->flags); - slc_dealloc(sl); - rtnl_unlock(); - return err; - -err_exit: - rtnl_unlock(); - - /* Count references from TTY module */ - return err; } /* Close down a SLCAN channel. * This means flushing out any pending queues, and then returning. This * call is serialized against other ldisc functions. + * Once this is called, no other ldisc function of ours is entered. * * We also use this method for a hangup event. */ @@ -973,28 +851,20 @@ static void slcan_close(struct tty_struct *tty) { struct slcan *sl = (struct slcan *)tty->disc_data; - /* First make sure we're connected. */ - if (!sl || sl->magic != SLCAN_MAGIC || sl->tty != tty) - return; + /* unregister_netdev() calls .ndo_stop() so we don't have to. + * Our .ndo_stop() also flushes the TTY write wakeup handler, + * so we can safely set sl->tty = NULL after this. + */ + unregister_candev(sl->dev); + /* Mark channel as dead */ spin_lock_bh(&sl->lock); - rcu_assign_pointer(tty->disc_data, NULL); + tty->disc_data = NULL; sl->tty = NULL; spin_unlock_bh(&sl->lock); - synchronize_rcu(); - flush_work(&sl->tx_work); - - slc_close(sl->dev); - unregister_candev(sl->dev); - rtnl_lock(); - slc_dealloc(sl); - rtnl_unlock(); -} - -static void slcan_hangup(struct tty_struct *tty) -{ - slcan_close(tty); + netdev_info(sl->dev, "slcan off %s.\n", tty->name); + free_candev(sl->dev); } /* Perform I/O control on an active SLCAN channel. */ @@ -1004,10 +874,6 @@ static int slcan_ioctl(struct tty_struct *tty, unsigned int cmd, struct slcan *sl = (struct slcan *)tty->disc_data; unsigned int tmp; - /* First make sure we're connected. */ - if (!sl || sl->magic != SLCAN_MAGIC) - return -EINVAL; - switch (cmd) { case SIOCGIFNAME: tmp = strlen(sl->dev->name) + 1; @@ -1029,7 +895,6 @@ static struct tty_ldisc_ops slc_ldisc = { .name = KBUILD_MODNAME, .open = slcan_open, .close = slcan_close, - .hangup = slcan_hangup, .ioctl = slcan_ioctl, .receive_buf = slcan_receive_buf, .write_wakeup = slcan_write_wakeup, @@ -1039,78 +904,21 @@ static int __init slcan_init(void) { int status; - if (maxdev < 4) - maxdev = 4; /* Sanity */ - pr_info("serial line CAN interface driver\n"); - pr_info("%d dynamic interface channels.\n", maxdev); - - slcan_devs = kcalloc(maxdev, sizeof(struct net_device *), GFP_KERNEL); - if (!slcan_devs) - return -ENOMEM; /* Fill in our line protocol discipline, and register it */ status = tty_register_ldisc(&slc_ldisc); - if (status) { + if (status) pr_err("can't register line discipline\n"); - kfree(slcan_devs); - } + return status; } static void __exit slcan_exit(void) { - int i; - struct net_device *dev; - struct slcan *sl; - unsigned long timeout = jiffies + HZ; - int busy = 0; - - if (!slcan_devs) - return; - - /* First of all: check for active disciplines and hangup them. - */ - do { - if (busy) - msleep_interruptible(100); - - busy = 0; - for (i = 0; i < maxdev; i++) { - dev = slcan_devs[i]; - if (!dev) - continue; - sl = netdev_priv(dev); - spin_lock_bh(&sl->lock); - if (sl->tty) { - busy++; - tty_hangup(sl->tty); - } - spin_unlock_bh(&sl->lock); - } - } while (busy && time_before(jiffies, timeout)); - - /* FIXME: hangup is async so we should wait when doing this second - * phase + /* This will only be called when all channels have been closed by + * userspace - tty_ldisc.c takes care of the module's refcount. */ - - for (i = 0; i < maxdev; i++) { - dev = slcan_devs[i]; - if (!dev) - continue; - - sl = netdev_priv(dev); - if (sl->tty) - netdev_err(dev, "tty discipline still running\n"); - - slc_close(dev); - unregister_candev(dev); - slc_dealloc(sl); - } - - kfree(slcan_devs); - slcan_devs = NULL; - tty_unregister_ldisc(&slc_ldisc); }