diff options
Diffstat (limited to 'drivers/tty/n_gsm.c')
-rw-r--r-- | drivers/tty/n_gsm.c | 111 |
1 files changed, 91 insertions, 20 deletions
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 9a13e510daea..a38114b01fea 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c | |||
@@ -133,6 +133,7 @@ struct gsm_dlci { | |||
133 | #define DLCI_OPENING 1 /* Sending SABM not seen UA */ | 133 | #define DLCI_OPENING 1 /* Sending SABM not seen UA */ |
134 | #define DLCI_OPEN 2 /* SABM/UA complete */ | 134 | #define DLCI_OPEN 2 /* SABM/UA complete */ |
135 | #define DLCI_CLOSING 3 /* Sending DISC not seen UA/DM */ | 135 | #define DLCI_CLOSING 3 /* Sending DISC not seen UA/DM */ |
136 | struct kref ref; /* freed from port or mux close */ | ||
136 | struct mutex mutex; | 137 | struct mutex mutex; |
137 | 138 | ||
138 | /* Link layer */ | 139 | /* Link layer */ |
@@ -194,6 +195,7 @@ struct gsm_mux { | |||
194 | struct tty_struct *tty; /* The tty our ldisc is bound to */ | 195 | struct tty_struct *tty; /* The tty our ldisc is bound to */ |
195 | spinlock_t lock; | 196 | spinlock_t lock; |
196 | unsigned int num; | 197 | unsigned int num; |
198 | struct kref ref; | ||
197 | 199 | ||
198 | /* Events on the GSM channel */ | 200 | /* Events on the GSM channel */ |
199 | wait_queue_head_t event; | 201 | wait_queue_head_t event; |
@@ -1606,6 +1608,7 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr) | |||
1606 | if (dlci == NULL) | 1608 | if (dlci == NULL) |
1607 | return NULL; | 1609 | return NULL; |
1608 | spin_lock_init(&dlci->lock); | 1610 | spin_lock_init(&dlci->lock); |
1611 | kref_init(&dlci->ref); | ||
1609 | mutex_init(&dlci->mutex); | 1612 | mutex_init(&dlci->mutex); |
1610 | dlci->fifo = &dlci->_fifo; | 1613 | dlci->fifo = &dlci->_fifo; |
1611 | if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) { | 1614 | if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) { |
@@ -1632,26 +1635,52 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr) | |||
1632 | } | 1635 | } |
1633 | 1636 | ||
1634 | /** | 1637 | /** |
1635 | * gsm_dlci_free - release DLCI | 1638 | * gsm_dlci_free - free DLCI |
1639 | * @dlci: DLCI to free | ||
1640 | * | ||
1641 | * Free up a DLCI. | ||
1642 | * | ||
1643 | * Can sleep. | ||
1644 | */ | ||
1645 | static void gsm_dlci_free(struct kref *ref) | ||
1646 | { | ||
1647 | struct gsm_dlci *dlci = container_of(ref, struct gsm_dlci, ref); | ||
1648 | |||
1649 | del_timer_sync(&dlci->t1); | ||
1650 | dlci->gsm->dlci[dlci->addr] = NULL; | ||
1651 | kfifo_free(dlci->fifo); | ||
1652 | while ((dlci->skb = skb_dequeue(&dlci->skb_list))) | ||
1653 | kfree_skb(dlci->skb); | ||
1654 | kfree(dlci); | ||
1655 | } | ||
1656 | |||
1657 | static inline void dlci_get(struct gsm_dlci *dlci) | ||
1658 | { | ||
1659 | kref_get(&dlci->ref); | ||
1660 | } | ||
1661 | |||
1662 | static inline void dlci_put(struct gsm_dlci *dlci) | ||
1663 | { | ||
1664 | kref_put(&dlci->ref, gsm_dlci_free); | ||
1665 | } | ||
1666 | |||
1667 | /** | ||
1668 | * gsm_dlci_release - release DLCI | ||
1636 | * @dlci: DLCI to destroy | 1669 | * @dlci: DLCI to destroy |
1637 | * | 1670 | * |
1638 | * Free up a DLCI. Currently to keep the lifetime rules sane we only | 1671 | * Release a DLCI. Actual free is deferred until either |
1639 | * clean up DLCI objects when the MUX closes rather than as the port | 1672 | * mux is closed or tty is closed - whichever is last. |
1640 | * is closed down on both the tty and mux levels. | ||
1641 | * | 1673 | * |
1642 | * Can sleep. | 1674 | * Can sleep. |
1643 | */ | 1675 | */ |
1644 | static void gsm_dlci_free(struct gsm_dlci *dlci) | 1676 | static void gsm_dlci_release(struct gsm_dlci *dlci) |
1645 | { | 1677 | { |
1646 | struct tty_struct *tty = tty_port_tty_get(&dlci->port); | 1678 | struct tty_struct *tty = tty_port_tty_get(&dlci->port); |
1647 | if (tty) { | 1679 | if (tty) { |
1648 | tty_vhangup(tty); | 1680 | tty_vhangup(tty); |
1649 | tty_kref_put(tty); | 1681 | tty_kref_put(tty); |
1650 | } | 1682 | } |
1651 | del_timer_sync(&dlci->t1); | 1683 | dlci_put(dlci); |
1652 | dlci->gsm->dlci[dlci->addr] = NULL; | ||
1653 | kfifo_free(dlci->fifo); | ||
1654 | kfree(dlci); | ||
1655 | } | 1684 | } |
1656 | 1685 | ||
1657 | /* | 1686 | /* |
@@ -1989,7 +2018,7 @@ void gsm_cleanup_mux(struct gsm_mux *gsm) | |||
1989 | /* Free up any link layer users */ | 2018 | /* Free up any link layer users */ |
1990 | for (i = 0; i < NUM_DLCI; i++) | 2019 | for (i = 0; i < NUM_DLCI; i++) |
1991 | if (gsm->dlci[i]) | 2020 | if (gsm->dlci[i]) |
1992 | gsm_dlci_free(gsm->dlci[i]); | 2021 | gsm_dlci_release(gsm->dlci[i]); |
1993 | /* Now wipe the queues */ | 2022 | /* Now wipe the queues */ |
1994 | for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) { | 2023 | for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) { |
1995 | gsm->tx_head = txq->next; | 2024 | gsm->tx_head = txq->next; |
@@ -2050,8 +2079,7 @@ EXPORT_SYMBOL_GPL(gsm_activate_mux); | |||
2050 | * gsm_free_mux - free up a mux | 2079 | * gsm_free_mux - free up a mux |
2051 | * @mux: mux to free | 2080 | * @mux: mux to free |
2052 | * | 2081 | * |
2053 | * Dispose of allocated resources for a dead mux. No refcounting | 2082 | * Dispose of allocated resources for a dead mux |
2054 | * at present so the mux must be truly dead. | ||
2055 | */ | 2083 | */ |
2056 | void gsm_free_mux(struct gsm_mux *gsm) | 2084 | void gsm_free_mux(struct gsm_mux *gsm) |
2057 | { | 2085 | { |
@@ -2062,6 +2090,28 @@ void gsm_free_mux(struct gsm_mux *gsm) | |||
2062 | EXPORT_SYMBOL_GPL(gsm_free_mux); | 2090 | EXPORT_SYMBOL_GPL(gsm_free_mux); |
2063 | 2091 | ||
2064 | /** | 2092 | /** |
2093 | * gsm_free_muxr - free up a mux | ||
2094 | * @mux: mux to free | ||
2095 | * | ||
2096 | * Dispose of allocated resources for a dead mux | ||
2097 | */ | ||
2098 | static void gsm_free_muxr(struct kref *ref) | ||
2099 | { | ||
2100 | struct gsm_mux *gsm = container_of(ref, struct gsm_mux, ref); | ||
2101 | gsm_free_mux(gsm); | ||
2102 | } | ||
2103 | |||
2104 | static inline void mux_get(struct gsm_mux *gsm) | ||
2105 | { | ||
2106 | kref_get(&gsm->ref); | ||
2107 | } | ||
2108 | |||
2109 | static inline void mux_put(struct gsm_mux *gsm) | ||
2110 | { | ||
2111 | kref_put(&gsm->ref, gsm_free_muxr); | ||
2112 | } | ||
2113 | |||
2114 | /** | ||
2065 | * gsm_alloc_mux - allocate a mux | 2115 | * gsm_alloc_mux - allocate a mux |
2066 | * | 2116 | * |
2067 | * Creates a new mux ready for activation. | 2117 | * Creates a new mux ready for activation. |
@@ -2084,6 +2134,7 @@ struct gsm_mux *gsm_alloc_mux(void) | |||
2084 | return NULL; | 2134 | return NULL; |
2085 | } | 2135 | } |
2086 | spin_lock_init(&gsm->lock); | 2136 | spin_lock_init(&gsm->lock); |
2137 | kref_init(&gsm->ref); | ||
2087 | 2138 | ||
2088 | gsm->t1 = T1; | 2139 | gsm->t1 = T1; |
2089 | gsm->t2 = T2; | 2140 | gsm->t2 = T2; |
@@ -2255,7 +2306,7 @@ static void gsmld_close(struct tty_struct *tty) | |||
2255 | 2306 | ||
2256 | gsmld_flush_buffer(tty); | 2307 | gsmld_flush_buffer(tty); |
2257 | /* Do other clean up here */ | 2308 | /* Do other clean up here */ |
2258 | gsm_free_mux(gsm); | 2309 | mux_put(gsm); |
2259 | } | 2310 | } |
2260 | 2311 | ||
2261 | /** | 2312 | /** |
@@ -2554,12 +2605,22 @@ static void net_free(struct kref *ref) | |||
2554 | } | 2605 | } |
2555 | } | 2606 | } |
2556 | 2607 | ||
2608 | static inline void muxnet_get(struct gsm_mux_net *mux_net) | ||
2609 | { | ||
2610 | kref_get(&mux_net->ref); | ||
2611 | } | ||
2612 | |||
2613 | static inline void muxnet_put(struct gsm_mux_net *mux_net) | ||
2614 | { | ||
2615 | kref_put(&mux_net->ref, net_free); | ||
2616 | } | ||
2617 | |||
2557 | static int gsm_mux_net_start_xmit(struct sk_buff *skb, | 2618 | static int gsm_mux_net_start_xmit(struct sk_buff *skb, |
2558 | struct net_device *net) | 2619 | struct net_device *net) |
2559 | { | 2620 | { |
2560 | struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); | 2621 | struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); |
2561 | struct gsm_dlci *dlci = mux_net->dlci; | 2622 | struct gsm_dlci *dlci = mux_net->dlci; |
2562 | kref_get(&mux_net->ref); | 2623 | muxnet_get(mux_net); |
2563 | 2624 | ||
2564 | skb_queue_head(&dlci->skb_list, skb); | 2625 | skb_queue_head(&dlci->skb_list, skb); |
2565 | STATS(net).tx_packets++; | 2626 | STATS(net).tx_packets++; |
@@ -2567,7 +2628,7 @@ static int gsm_mux_net_start_xmit(struct sk_buff *skb, | |||
2567 | gsm_dlci_data_kick(dlci); | 2628 | gsm_dlci_data_kick(dlci); |
2568 | /* And tell the kernel when the last transmit started. */ | 2629 | /* And tell the kernel when the last transmit started. */ |
2569 | net->trans_start = jiffies; | 2630 | net->trans_start = jiffies; |
2570 | kref_put(&mux_net->ref, net_free); | 2631 | muxnet_put(mux_net); |
2571 | return NETDEV_TX_OK; | 2632 | return NETDEV_TX_OK; |
2572 | } | 2633 | } |
2573 | 2634 | ||
@@ -2587,14 +2648,14 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, | |||
2587 | struct net_device *net = dlci->net; | 2648 | struct net_device *net = dlci->net; |
2588 | struct sk_buff *skb; | 2649 | struct sk_buff *skb; |
2589 | struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); | 2650 | struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); |
2590 | kref_get(&mux_net->ref); | 2651 | muxnet_get(mux_net); |
2591 | 2652 | ||
2592 | /* Allocate an sk_buff */ | 2653 | /* Allocate an sk_buff */ |
2593 | skb = dev_alloc_skb(size + NET_IP_ALIGN); | 2654 | skb = dev_alloc_skb(size + NET_IP_ALIGN); |
2594 | if (!skb) { | 2655 | if (!skb) { |
2595 | /* We got no receive buffer. */ | 2656 | /* We got no receive buffer. */ |
2596 | STATS(net).rx_dropped++; | 2657 | STATS(net).rx_dropped++; |
2597 | kref_put(&mux_net->ref, net_free); | 2658 | muxnet_put(mux_net); |
2598 | return; | 2659 | return; |
2599 | } | 2660 | } |
2600 | skb_reserve(skb, NET_IP_ALIGN); | 2661 | skb_reserve(skb, NET_IP_ALIGN); |
@@ -2609,7 +2670,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, | |||
2609 | /* update out statistics */ | 2670 | /* update out statistics */ |
2610 | STATS(net).rx_packets++; | 2671 | STATS(net).rx_packets++; |
2611 | STATS(net).rx_bytes += size; | 2672 | STATS(net).rx_bytes += size; |
2612 | kref_put(&mux_net->ref, net_free); | 2673 | muxnet_put(mux_net); |
2613 | return; | 2674 | return; |
2614 | } | 2675 | } |
2615 | 2676 | ||
@@ -2652,7 +2713,7 @@ static void gsm_destroy_network(struct gsm_dlci *dlci) | |||
2652 | if (!dlci->net) | 2713 | if (!dlci->net) |
2653 | return; | 2714 | return; |
2654 | mux_net = (struct gsm_mux_net *)netdev_priv(dlci->net); | 2715 | mux_net = (struct gsm_mux_net *)netdev_priv(dlci->net); |
2655 | kref_put(&mux_net->ref, net_free); | 2716 | muxnet_put(mux_net); |
2656 | } | 2717 | } |
2657 | 2718 | ||
2658 | 2719 | ||
@@ -2814,6 +2875,9 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) | |||
2814 | port = &dlci->port; | 2875 | port = &dlci->port; |
2815 | port->count++; | 2876 | port->count++; |
2816 | tty->driver_data = dlci; | 2877 | tty->driver_data = dlci; |
2878 | dlci_get(dlci); | ||
2879 | dlci_get(dlci->gsm->dlci[0]); | ||
2880 | mux_get(dlci->gsm); | ||
2817 | tty_port_tty_set(port, tty); | 2881 | tty_port_tty_set(port, tty); |
2818 | 2882 | ||
2819 | dlci->modem_rx = 0; | 2883 | dlci->modem_rx = 0; |
@@ -2829,16 +2893,23 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) | |||
2829 | static void gsmtty_close(struct tty_struct *tty, struct file *filp) | 2893 | static void gsmtty_close(struct tty_struct *tty, struct file *filp) |
2830 | { | 2894 | { |
2831 | struct gsm_dlci *dlci = tty->driver_data; | 2895 | struct gsm_dlci *dlci = tty->driver_data; |
2896 | struct gsm_mux *gsm; | ||
2897 | |||
2832 | if (dlci == NULL) | 2898 | if (dlci == NULL) |
2833 | return; | 2899 | return; |
2834 | mutex_lock(&dlci->mutex); | 2900 | mutex_lock(&dlci->mutex); |
2835 | gsm_destroy_network(dlci); | 2901 | gsm_destroy_network(dlci); |
2836 | mutex_unlock(&dlci->mutex); | 2902 | mutex_unlock(&dlci->mutex); |
2903 | gsm = dlci->gsm; | ||
2837 | if (tty_port_close_start(&dlci->port, tty, filp) == 0) | 2904 | if (tty_port_close_start(&dlci->port, tty, filp) == 0) |
2838 | return; | 2905 | goto out; |
2839 | gsm_dlci_begin_close(dlci); | 2906 | gsm_dlci_begin_close(dlci); |
2840 | tty_port_close_end(&dlci->port, tty); | 2907 | tty_port_close_end(&dlci->port, tty); |
2841 | tty_port_tty_set(&dlci->port, NULL); | 2908 | tty_port_tty_set(&dlci->port, NULL); |
2909 | out: | ||
2910 | dlci_put(dlci); | ||
2911 | dlci_put(gsm->dlci[0]); | ||
2912 | mux_put(gsm); | ||
2842 | } | 2913 | } |
2843 | 2914 | ||
2844 | static void gsmtty_hangup(struct tty_struct *tty) | 2915 | static void gsmtty_hangup(struct tty_struct *tty) |