Merge branch 'upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/linville...
[powerpc.git] / drivers / s390 / net / ctcmain.c
index fe986af..b20fd06 100644 (file)
@@ -6,7 +6,7 @@
  * Fixes by : Jochen Röhrig (roehrig@de.ibm.com)
  *            Arnaldo Carvalho de Melo <acme@conectiva.com.br>
              Peter Tiedemann (ptiedem@de.ibm.com)
- * Driver Model stuff by : Cornelia Huck <huckc@de.ibm.com>
+ * Driver Model stuff by : Cornelia Huck <cornelia.huck@de.ibm.com>
  *
  * Documentation used:
  *  - Principles of Operation (IBM doc#: SA22-7201-06)
@@ -45,7 +45,6 @@
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/timer.h>
-#include <linux/sched.h>
 #include <linux/bitops.h>
 
 #include <linux/signal.h>
@@ -65,7 +64,6 @@
 
 #include <asm/idals.h>
 
-#include "ctctty.h"
 #include "fsm.h"
 #include "cu3088.h"
 
@@ -370,7 +368,7 @@ ctc_dump_skb(struct sk_buff *skb, int offset)
  * @param ch The channel where this skb has been received.
  * @param pskb The received skb.
  */
-static __inline__ void
+static void
 ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
 {
        struct net_device *dev = ch->netdev;
@@ -457,7 +455,7 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
                        return;
                }
                skb_put(pskb, header->length);
-               pskb->mac.raw = pskb->data;
+               skb_reset_mac_header(pskb);
                len -= header->length;
                skb = dev_alloc_skb(pskb->len);
                if (!skb) {
@@ -474,15 +472,13 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
                        privptr->stats.rx_dropped++;
                        return;
                }
-               memcpy(skb_put(skb, pskb->len), pskb->data, pskb->len);
-               skb->mac.raw = skb->data;
+               skb_copy_from_linear_data(pskb, skb_put(skb, pskb->len),
+                                         pskb->len);
+               skb_reset_mac_header(skb);
                skb->dev = pskb->dev;
                skb->protocol = pskb->protocol;
                pskb->ip_summed = CHECKSUM_UNNECESSARY;
-               if (ch->protocol == CTC_PROTO_LINUX_TTY)
-                       ctc_tty_netif_rx(skb);
-               else
-                       netif_rx_ni(skb);
+               netif_rx_ni(skb);
                /**
                 * Successful rx; reset logflags
                 */
@@ -516,7 +512,7 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
  * @param ch          The channel, the error belongs to.
  * @param return_code The error code to inspect.
  */
-static void inline
+static void
 ccw_check_return_code(struct channel *ch, int return_code, char *msg)
 {
        DBF_TEXT(trace, 5, __FUNCTION__);
@@ -551,14 +547,13 @@ ccw_check_return_code(struct channel *ch, int return_code, char *msg)
  * @param ch    The channel, the sense code belongs to.
  * @param sense The sense code to inspect.
  */
-static void inline
+static void
 ccw_unit_check(struct channel *ch, unsigned char sense)
 {
        DBF_TEXT(trace, 5, __FUNCTION__);
        if (sense & SNS0_INTERVENTION_REQ) {
                if (sense & 0x01) {
-                       if (ch->protocol != CTC_PROTO_LINUX_TTY)
-                               ctc_pr_debug("%s: Interface disc. or Sel. reset "
+                       ctc_pr_debug("%s: Interface disc. or Sel. reset "
                                        "(remote)\n", ch->id);
                        fsm_event(ch->fsm, CH_EVENT_UC_RCRESET, ch);
                } else {
@@ -608,7 +603,7 @@ ctc_purge_skb_queue(struct sk_buff_head *q)
        }
 }
 
-static __inline__ int
+static int
 ctc_checkalloc_buffer(struct channel *ch, int warn)
 {
        DBF_TEXT(trace, 5, __FUNCTION__);
@@ -712,7 +707,8 @@ ch_action_txdone(fsm_instance * fi, int event, void *arg)
                        spin_unlock(&ch->collect_lock);
                        return;
                }
-               ch->trans_skb->tail = ch->trans_skb->data = ch->trans_skb_data;
+               ch->trans_skb->data = ch->trans_skb_data;
+               skb_reset_tail_pointer(ch->trans_skb);
                ch->trans_skb->len = 0;
                if (ch->prof.maxmulti < (ch->collect_len + 2))
                        ch->prof.maxmulti = ch->collect_len + 2;
@@ -721,8 +717,9 @@ ch_action_txdone(fsm_instance * fi, int event, void *arg)
                *((__u16 *) skb_put(ch->trans_skb, 2)) = ch->collect_len + 2;
                i = 0;
                while ((skb = skb_dequeue(&ch->collect_queue))) {
-                       memcpy(skb_put(ch->trans_skb, skb->len), skb->data,
-                              skb->len);
+                       skb_copy_from_linear_data(skb, skb_put(ch->trans_skb,
+                                                              skb->len),
+                                                 skb->len);
                        privptr->stats.tx_packets++;
                        privptr->stats.tx_bytes += skb->len - LL_HEADER_LENGTH;
                        atomic_dec(&skb->users);
@@ -837,7 +834,8 @@ ch_action_rx(fsm_instance * fi, int event, void *arg)
                ctc_unpack_skb(ch, skb);
        }
  again:
-       skb->data = skb->tail = ch->trans_skb_data;
+       skb->data = ch->trans_skb_data;
+       skb_reset_tail_pointer(skb);
        skb->len = 0;
        if (ctc_checkalloc_buffer(ch, 1))
                return;
@@ -1644,21 +1642,19 @@ add_channel(struct ccw_device *cdev, enum channel_types type)
        struct channel *ch;
 
        DBF_TEXT(trace, 2, __FUNCTION__);
-       if ((ch =
-            (struct channel *) kmalloc(sizeof (struct channel),
-                                       GFP_KERNEL)) == NULL) {
+       ch = kzalloc(sizeof(struct channel), GFP_KERNEL);
+       if (!ch) {
                ctc_pr_warn("ctc: Out of memory in add_channel\n");
                return -1;
        }
-       memset(ch, 0, sizeof (struct channel));
-       if ((ch->ccw = (struct ccw1 *) kmalloc(8*sizeof(struct ccw1),
-                                              GFP_KERNEL | GFP_DMA)) == NULL) {
+       /* assure all flags and counters are reset */
+       ch->ccw = kzalloc(8 * sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
+       if (!ch->ccw) {
                kfree(ch);
                ctc_pr_warn("ctc: Out of memory in add_channel\n");
                return -1;
        }
 
-       memset(ch->ccw, 0, 8*sizeof(struct ccw1));      // assure all flags and counters are reset
 
        /**
         * "static" ccws are used in the following way:
@@ -1698,15 +1694,14 @@ add_channel(struct ccw_device *cdev, enum channel_types type)
                return -1;
        }
        fsm_newstate(ch->fsm, CH_STATE_IDLE);
-       if ((ch->irb = (struct irb *) kmalloc(sizeof (struct irb),
-                                             GFP_KERNEL)) == NULL) {
+       ch->irb = kzalloc(sizeof(struct irb), GFP_KERNEL);
+       if (!ch->irb) {
                ctc_pr_warn("ctc: Out of memory in add_channel\n");
                kfree_fsm(ch->fsm);
                kfree(ch->ccw);
                kfree(ch);
                return -1;
        }
-       memset(ch->irb, 0, sizeof (struct irb));
        while (*c && less_than((*c)->id, ch->id))
                c = &(*c)->next;
        if (*c && (!strncmp((*c)->id, ch->id, CTC_ID_SIZE))) {
@@ -1719,6 +1714,9 @@ add_channel(struct ccw_device *cdev, enum channel_types type)
                kfree(ch);
                return 0;
        }
+
+       spin_lock_init(&ch->collect_lock);
+
        fsm_settimer(ch->fsm, &ch->timer);
        skb_queue_head_init(&ch->io_queue);
        skb_queue_head_init(&ch->collect_queue);
@@ -2034,7 +2032,6 @@ static void
 dev_action_chup(fsm_instance * fi, int event, void *arg)
 {
        struct net_device *dev = (struct net_device *) arg;
-       struct ctc_priv *privptr = dev->priv;
 
        DBF_TEXT(trace, 3, __FUNCTION__);
        switch (fsm_getstate(fi)) {
@@ -2049,8 +2046,6 @@ dev_action_chup(fsm_instance * fi, int event, void *arg)
                                fsm_newstate(fi, DEV_STATE_RUNNING);
                                ctc_pr_info("%s: connected with remote side\n",
                                            dev->name);
-                               if (privptr->protocol == CTC_PROTO_LINUX_TTY)
-                                       ctc_tty_setcarrier(dev, 1);
                                ctc_clear_busy(dev);
                        }
                        break;
@@ -2059,8 +2054,6 @@ dev_action_chup(fsm_instance * fi, int event, void *arg)
                                fsm_newstate(fi, DEV_STATE_RUNNING);
                                ctc_pr_info("%s: connected with remote side\n",
                                            dev->name);
-                               if (privptr->protocol == CTC_PROTO_LINUX_TTY)
-                                       ctc_tty_setcarrier(dev, 1);
                                ctc_clear_busy(dev);
                        }
                        break;
@@ -2086,14 +2079,10 @@ dev_action_chup(fsm_instance * fi, int event, void *arg)
 static void
 dev_action_chdown(fsm_instance * fi, int event, void *arg)
 {
-       struct net_device *dev = (struct net_device *) arg;
-       struct ctc_priv *privptr = dev->priv;
 
        DBF_TEXT(trace, 3, __FUNCTION__);
        switch (fsm_getstate(fi)) {
                case DEV_STATE_RUNNING:
-                       if (privptr->protocol == CTC_PROTO_LINUX_TTY)
-                               ctc_tty_setcarrier(dev, 0);
                        if (event == DEV_EVENT_TXDOWN)
                                fsm_newstate(fi, DEV_STATE_STARTWAIT_TX);
                        else
@@ -2238,7 +2227,8 @@ transmit_skb(struct channel *ch, struct sk_buff *skb)
                 * IDAL support in CTC is broken, so we have to
                 * care about skb's above 2G ourselves.
                 */
-               hi = ((unsigned long) skb->tail + LL_HEADER_LENGTH) >> 31;
+               hi = ((unsigned long)skb_tail_pointer(skb) +
+                     LL_HEADER_LENGTH) >> 31;
                if (hi) {
                        nskb = alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
                        if (!nskb) {
@@ -2274,11 +2264,12 @@ transmit_skb(struct channel *ch, struct sk_buff *skb)
                                return -EBUSY;
                        }
 
-                       ch->trans_skb->tail = ch->trans_skb->data;
+                       skb_reset_tail_pointer(ch->trans_skb);
                        ch->trans_skb->len = 0;
                        ch->ccw[1].count = skb->len;
-                       memcpy(skb_put(ch->trans_skb, skb->len), skb->data,
-                              skb->len);
+                       skb_copy_from_linear_data(skb, skb_put(ch->trans_skb,
+                                                              skb->len),
+                                                 skb->len);
                        atomic_dec(&skb->users);
                        dev_kfree_skb_irq(skb);
                        ccw_idx = 0;
@@ -2397,8 +2388,6 @@ ctc_tx(struct sk_buff *skb, struct net_device * dev)
         */
        if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
                fsm_event(privptr->fsm, DEV_EVENT_START, dev);
-               if (privptr->protocol == CTC_PROTO_LINUX_TTY)
-                       return -EBUSY;
                dev_kfree_skb(skb);
                privptr->stats.tx_dropped++;
                privptr->stats.tx_errors++;
@@ -2548,7 +2537,7 @@ ctc_print_statistics(struct ctc_priv *priv)
        DBF_TEXT(trace, 4, __FUNCTION__);
        if (!priv)
                return;
-       sbuf = (char *)kmalloc(2048, GFP_KERNEL);
+       sbuf = kmalloc(2048, GFP_KERNEL);
        if (sbuf == NULL)
                return;
        p = sbuf;
@@ -2608,20 +2597,13 @@ ctc_netdev_unregister(struct net_device * dev)
        if (!dev)
                return;
        privptr = (struct ctc_priv *) dev->priv;
-       if (privptr->protocol != CTC_PROTO_LINUX_TTY)
-               unregister_netdev(dev);
-       else
-               ctc_tty_unregister_netdev(dev);
+       unregister_netdev(dev);
 }
 
 static int
 ctc_netdev_register(struct net_device * dev)
 {
-       struct ctc_priv *privptr = (struct ctc_priv *) dev->priv;
-       if (privptr->protocol != CTC_PROTO_LINUX_TTY)
-               return register_netdev(dev);
-       else
-               return ctc_tty_register_netdev(dev);
+       return register_netdev(dev);
 }
 
 static void
@@ -2667,7 +2649,9 @@ ctc_proto_store(struct device *dev, struct device_attribute *attr, const char *b
        if (!priv)
                return -ENODEV;
        sscanf(buf, "%u", &value);
-       if ((value < 0) || (value > CTC_PROTO_MAX))
+       if (!((value == CTC_PROTO_S390)  ||
+             (value == CTC_PROTO_LINUX) ||
+             (value == CTC_PROTO_OS390)))
                return -EINVAL;
        priv->protocol = value;
 
@@ -2707,9 +2691,17 @@ static struct attribute_group ctc_attr_group = {
 static int
 ctc_add_attributes(struct device *dev)
 {
-       device_create_file(dev, &dev_attr_loglevel);
-       device_create_file(dev, &dev_attr_stats);
-       return 0;
+       int rc;
+
+       rc = device_create_file(dev, &dev_attr_loglevel);
+       if (rc)
+               goto out;
+       rc = device_create_file(dev, &dev_attr_stats);
+       if (!rc)
+               goto out;
+       device_remove_file(dev, &dev_attr_loglevel);
+out:
+       return rc;
 }
 
 static void
@@ -2756,14 +2748,13 @@ ctc_probe_device(struct ccwgroup_device *cgdev)
        if (!get_device(&cgdev->dev))
                return -ENODEV;
 
-       priv = kmalloc(sizeof (struct ctc_priv), GFP_KERNEL);
+       priv = kzalloc(sizeof(struct ctc_priv), GFP_KERNEL);
        if (!priv) {
                ctc_pr_err("%s: Out of memory\n", __func__);
                put_device(&cgdev->dev);
                return -ENOMEM;
        }
 
-       memset(priv, 0, sizeof (struct ctc_priv));
        rc = ctc_add_files(&cgdev->dev);
        if (rc) {
                kfree(priv);
@@ -2804,10 +2795,9 @@ ctc_init_netdevice(struct net_device * dev, int alloc_device,
        DBF_TEXT(setup, 3, __FUNCTION__);
 
        if (alloc_device) {
-               dev = kmalloc(sizeof (struct net_device), GFP_KERNEL);
+               dev = kzalloc(sizeof(struct net_device), GFP_KERNEL);
                if (!dev)
                        return NULL;
-               memset(dev, 0, sizeof (struct net_device));
        }
 
        dev->priv = privptr;
@@ -2897,10 +2887,7 @@ ctc_new_device(struct ccwgroup_device *cgdev)
                goto out;
        }
 
-       if (privptr->protocol == CTC_PROTO_LINUX_TTY)
-               strlcpy(dev->name, "ctctty%d", IFNAMSIZ);
-       else
-               strlcpy(dev->name, "ctc%d", IFNAMSIZ);
+       strlcpy(dev->name, "ctc%d", IFNAMSIZ);
 
        for (direction = READ; direction <= WRITE; direction++) {
                privptr->channel[direction] =
@@ -2925,7 +2912,12 @@ ctc_new_device(struct ccwgroup_device *cgdev)
                goto out;
        }
 
-       ctc_add_attributes(&cgdev->dev);
+       if (ctc_add_attributes(&cgdev->dev)) {
+               ctc_netdev_unregister(dev);
+               dev->priv = NULL;
+               ctc_free_netdevice(dev, 1);
+               goto out;
+       }
 
        strlcpy(privptr->fsm->name, dev->name, sizeof (privptr->fsm->name));
 
@@ -3046,7 +3038,6 @@ ctc_exit(void)
 {
        DBF_TEXT(setup, 3, __FUNCTION__);
        unregister_cu3088_discipline(&ctc_group_driver);
-       ctc_tty_cleanup();
        ctc_unregister_dbf_views();
        ctc_pr_info("CTC driver unloaded\n");
 }
@@ -3073,10 +3064,8 @@ ctc_init(void)
                ctc_pr_crit("ctc_init failed with ctc_register_dbf_views rc = %d\n", ret);
                return ret;
        }
-       ctc_tty_init();
        ret = register_cu3088_discipline(&ctc_group_driver);
        if (ret) {
-               ctc_tty_cleanup();
                ctc_unregister_dbf_views();
        }
        return ret;