linux/net/caif/caif_dev.c
<<
>>
Prefs
   1/*
   2 * CAIF Interface registration.
   3 * Copyright (C) ST-Ericsson AB 2010
   4 * Author:      Sjur Brendeland/sjur.brandeland@stericsson.com
   5 * License terms: GNU General Public License (GPL) version 2
   6 *
   7 * Borrowed heavily from file: pn_dev.c. Thanks to
   8 *  Remi Denis-Courmont <remi.denis-courmont@nokia.com>
   9 *  and Sakari Ailus <sakari.ailus@nokia.com>
  10 */
  11
  12#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
  13
  14#include <linux/kernel.h>
  15#include <linux/if_arp.h>
  16#include <linux/net.h>
  17#include <linux/netdevice.h>
  18#include <linux/mutex.h>
  19#include <net/netns/generic.h>
  20#include <net/net_namespace.h>
  21#include <net/pkt_sched.h>
  22#include <net/caif/caif_device.h>
  23#include <net/caif/caif_layer.h>
  24#include <net/caif/cfpkt.h>
  25#include <net/caif/cfcnfg.h>
  26
  27MODULE_LICENSE("GPL");
  28
  29/* Used for local tracking of the CAIF net devices */
  30struct caif_device_entry {
  31        struct cflayer layer;
  32        struct list_head list;
  33        struct net_device *netdev;
  34        int __percpu *pcpu_refcnt;
  35};
  36
  37struct caif_device_entry_list {
  38        struct list_head list;
  39        /* Protects simulanous deletes in list */
  40        struct mutex lock;
  41};
  42
  43struct caif_net {
  44        struct cfcnfg *cfg;
  45        struct caif_device_entry_list caifdevs;
  46};
  47
  48static int caif_net_id;
  49
  50struct cfcnfg *get_cfcnfg(struct net *net)
  51{
  52        struct caif_net *caifn;
  53        BUG_ON(!net);
  54        caifn = net_generic(net, caif_net_id);
  55        BUG_ON(!caifn);
  56        return caifn->cfg;
  57}
  58EXPORT_SYMBOL(get_cfcnfg);
  59
  60static struct caif_device_entry_list *caif_device_list(struct net *net)
  61{
  62        struct caif_net *caifn;
  63        BUG_ON(!net);
  64        caifn = net_generic(net, caif_net_id);
  65        BUG_ON(!caifn);
  66        return &caifn->caifdevs;
  67}
  68
  69static void caifd_put(struct caif_device_entry *e)
  70{
  71        irqsafe_cpu_dec(*e->pcpu_refcnt);
  72}
  73
  74static void caifd_hold(struct caif_device_entry *e)
  75{
  76        irqsafe_cpu_inc(*e->pcpu_refcnt);
  77}
  78
  79static int caifd_refcnt_read(struct caif_device_entry *e)
  80{
  81        int i, refcnt = 0;
  82        for_each_possible_cpu(i)
  83                refcnt += *per_cpu_ptr(e->pcpu_refcnt, i);
  84        return refcnt;
  85}
  86
  87/* Allocate new CAIF device. */
  88static struct caif_device_entry *caif_device_alloc(struct net_device *dev)
  89{
  90        struct caif_device_entry_list *caifdevs;
  91        struct caif_device_entry *caifd;
  92
  93        caifdevs = caif_device_list(dev_net(dev));
  94        BUG_ON(!caifdevs);
  95
  96        caifd = kzalloc(sizeof(*caifd), GFP_KERNEL);
  97        if (!caifd)
  98                return NULL;
  99        caifd->pcpu_refcnt = alloc_percpu(int);
 100        if (!caifd->pcpu_refcnt) {
 101                kfree(caifd);
 102                return NULL;
 103        }
 104        caifd->netdev = dev;
 105        dev_hold(dev);
 106        return caifd;
 107}
 108
 109static struct caif_device_entry *caif_get(struct net_device *dev)
 110{
 111        struct caif_device_entry_list *caifdevs =
 112            caif_device_list(dev_net(dev));
 113        struct caif_device_entry *caifd;
 114        BUG_ON(!caifdevs);
 115        list_for_each_entry_rcu(caifd, &caifdevs->list, list) {
 116                if (caifd->netdev == dev)
 117                        return caifd;
 118        }
 119        return NULL;
 120}
 121
 122static int transmit(struct cflayer *layer, struct cfpkt *pkt)
 123{
 124        int err;
 125        struct caif_device_entry *caifd =
 126            container_of(layer, struct caif_device_entry, layer);
 127        struct sk_buff *skb;
 128
 129        skb = cfpkt_tonative(pkt);
 130        skb->dev = caifd->netdev;
 131
 132        err = dev_queue_xmit(skb);
 133        if (err > 0)
 134                err = -EIO;
 135
 136        return err;
 137}
 138
 139/*
 140 * Stuff received packets into the CAIF stack.
 141 * On error, returns non-zero and releases the skb.
 142 */
 143static int receive(struct sk_buff *skb, struct net_device *dev,
 144                   struct packet_type *pkttype, struct net_device *orig_dev)
 145{
 146        struct cfpkt *pkt;
 147        struct caif_device_entry *caifd;
 148        int err;
 149
 150        pkt = cfpkt_fromnative(CAIF_DIR_IN, skb);
 151
 152        rcu_read_lock();
 153        caifd = caif_get(dev);
 154
 155        if (!caifd || !caifd->layer.up || !caifd->layer.up->receive ||
 156                        !netif_oper_up(caifd->netdev)) {
 157                rcu_read_unlock();
 158                kfree_skb(skb);
 159                return NET_RX_DROP;
 160        }
 161
 162        /* Hold reference to netdevice while using CAIF stack */
 163        caifd_hold(caifd);
 164        rcu_read_unlock();
 165
 166        err = caifd->layer.up->receive(caifd->layer.up, pkt);
 167
 168        /* For -EILSEQ the packet is not freed so so it now */
 169        if (err == -EILSEQ)
 170                cfpkt_destroy(pkt);
 171
 172        /* Release reference to stack upwards */
 173        caifd_put(caifd);
 174        return 0;
 175}
 176
 177static struct packet_type caif_packet_type __read_mostly = {
 178        .type = cpu_to_be16(ETH_P_CAIF),
 179        .func = receive,
 180};
 181
 182static void dev_flowctrl(struct net_device *dev, int on)
 183{
 184        struct caif_device_entry *caifd;
 185
 186        rcu_read_lock();
 187
 188        caifd = caif_get(dev);
 189        if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) {
 190                rcu_read_unlock();
 191                return;
 192        }
 193
 194        caifd_hold(caifd);
 195        rcu_read_unlock();
 196
 197        caifd->layer.up->ctrlcmd(caifd->layer.up,
 198                                 on ?
 199                                 _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND :
 200                                 _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND,
 201                                 caifd->layer.id);
 202        caifd_put(caifd);
 203}
 204
 205/* notify Caif of device events */
 206static int caif_device_notify(struct notifier_block *me, unsigned long what,
 207                              void *arg)
 208{
 209        struct net_device *dev = arg;
 210        struct caif_device_entry *caifd = NULL;
 211        struct caif_dev_common *caifdev;
 212        enum cfcnfg_phy_preference pref;
 213        enum cfcnfg_phy_type phy_type;
 214        struct cfcnfg *cfg;
 215        struct caif_device_entry_list *caifdevs =
 216            caif_device_list(dev_net(dev));
 217
 218        if (dev->type != ARPHRD_CAIF)
 219                return 0;
 220
 221        cfg = get_cfcnfg(dev_net(dev));
 222        if (cfg == NULL)
 223                return 0;
 224
 225        switch (what) {
 226        case NETDEV_REGISTER:
 227                caifd = caif_device_alloc(dev);
 228                if (!caifd)
 229                        return 0;
 230
 231                caifdev = netdev_priv(dev);
 232                caifdev->flowctrl = dev_flowctrl;
 233
 234                caifd->layer.transmit = transmit;
 235
 236                if (caifdev->use_frag)
 237                        phy_type = CFPHYTYPE_FRAG;
 238                else
 239                        phy_type = CFPHYTYPE_CAIF;
 240
 241                switch (caifdev->link_select) {
 242                case CAIF_LINK_HIGH_BANDW:
 243                        pref = CFPHYPREF_HIGH_BW;
 244                        break;
 245                case CAIF_LINK_LOW_LATENCY:
 246                        pref = CFPHYPREF_LOW_LAT;
 247                        break;
 248                default:
 249                        pref = CFPHYPREF_HIGH_BW;
 250                        break;
 251                }
 252                strncpy(caifd->layer.name, dev->name,
 253                        sizeof(caifd->layer.name) - 1);
 254                caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0;
 255
 256                mutex_lock(&caifdevs->lock);
 257                list_add_rcu(&caifd->list, &caifdevs->list);
 258
 259                cfcnfg_add_phy_layer(cfg,
 260                                     phy_type,
 261                                     dev,
 262                                     &caifd->layer,
 263                                     pref,
 264                                     caifdev->use_fcs,
 265                                     caifdev->use_stx);
 266                mutex_unlock(&caifdevs->lock);
 267                break;
 268
 269        case NETDEV_UP:
 270                rcu_read_lock();
 271
 272                caifd = caif_get(dev);
 273                if (caifd == NULL) {
 274                        rcu_read_unlock();
 275                        break;
 276                }
 277
 278                cfcnfg_set_phy_state(cfg, &caifd->layer, true);
 279                rcu_read_unlock();
 280
 281                break;
 282
 283        case NETDEV_DOWN:
 284                rcu_read_lock();
 285
 286                caifd = caif_get(dev);
 287                if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) {
 288                        rcu_read_unlock();
 289                        return -EINVAL;
 290                }
 291
 292                cfcnfg_set_phy_state(cfg, &caifd->layer, false);
 293                caifd_hold(caifd);
 294                rcu_read_unlock();
 295
 296                caifd->layer.up->ctrlcmd(caifd->layer.up,
 297                                         _CAIF_CTRLCMD_PHYIF_DOWN_IND,
 298                                         caifd->layer.id);
 299                caifd_put(caifd);
 300                break;
 301
 302        case NETDEV_UNREGISTER:
 303                mutex_lock(&caifdevs->lock);
 304
 305                caifd = caif_get(dev);
 306                if (caifd == NULL) {
 307                        mutex_unlock(&caifdevs->lock);
 308                        break;
 309                }
 310                list_del_rcu(&caifd->list);
 311
 312                /*
 313                 * NETDEV_UNREGISTER is called repeatedly until all reference
 314                 * counts for the net-device are released. If references to
 315                 * caifd is taken, simply ignore NETDEV_UNREGISTER and wait for
 316                 * the next call to NETDEV_UNREGISTER.
 317                 *
 318                 * If any packets are in flight down the CAIF Stack,
 319                 * cfcnfg_del_phy_layer will return nonzero.
 320                 * If no packets are in flight, the CAIF Stack associated
 321                 * with the net-device un-registering is freed.
 322                 */
 323
 324                if (caifd_refcnt_read(caifd) != 0 ||
 325                        cfcnfg_del_phy_layer(cfg, &caifd->layer) != 0) {
 326
 327                        pr_info("Wait for device inuse\n");
 328                        /* Enrole device if CAIF Stack is still in use */
 329                        list_add_rcu(&caifd->list, &caifdevs->list);
 330                        mutex_unlock(&caifdevs->lock);
 331                        break;
 332                }
 333
 334                synchronize_rcu();
 335                dev_put(caifd->netdev);
 336                free_percpu(caifd->pcpu_refcnt);
 337                kfree(caifd);
 338
 339                mutex_unlock(&caifdevs->lock);
 340                break;
 341        }
 342        return 0;
 343}
 344
 345static struct notifier_block caif_device_notifier = {
 346        .notifier_call = caif_device_notify,
 347        .priority = 0,
 348};
 349
 350/* Per-namespace Caif devices handling */
 351static int caif_init_net(struct net *net)
 352{
 353        struct caif_net *caifn = net_generic(net, caif_net_id);
 354        BUG_ON(!caifn);
 355        INIT_LIST_HEAD(&caifn->caifdevs.list);
 356        mutex_init(&caifn->caifdevs.lock);
 357
 358        caifn->cfg = cfcnfg_create();
 359        if (!caifn->cfg) {
 360                pr_warn("can't create cfcnfg\n");
 361                return -ENOMEM;
 362        }
 363
 364        return 0;
 365}
 366
 367static void caif_exit_net(struct net *net)
 368{
 369        struct caif_device_entry *caifd, *tmp;
 370        struct caif_device_entry_list *caifdevs =
 371            caif_device_list(net);
 372        struct cfcnfg *cfg;
 373
 374        rtnl_lock();
 375        mutex_lock(&caifdevs->lock);
 376
 377        cfg = get_cfcnfg(net);
 378        if (cfg == NULL) {
 379                mutex_unlock(&caifdevs->lock);
 380                return;
 381        }
 382
 383        list_for_each_entry_safe(caifd, tmp, &caifdevs->list, list) {
 384                int i = 0;
 385                list_del_rcu(&caifd->list);
 386                cfcnfg_set_phy_state(cfg, &caifd->layer, false);
 387
 388                while (i < 10 &&
 389                        (caifd_refcnt_read(caifd) != 0 ||
 390                        cfcnfg_del_phy_layer(cfg, &caifd->layer) != 0)) {
 391
 392                        pr_info("Wait for device inuse\n");
 393                        msleep(250);
 394                        i++;
 395                }
 396                synchronize_rcu();
 397                dev_put(caifd->netdev);
 398                free_percpu(caifd->pcpu_refcnt);
 399                kfree(caifd);
 400        }
 401        cfcnfg_remove(cfg);
 402
 403        mutex_unlock(&caifdevs->lock);
 404        rtnl_unlock();
 405}
 406
 407static struct pernet_operations caif_net_ops = {
 408        .init = caif_init_net,
 409        .exit = caif_exit_net,
 410        .id   = &caif_net_id,
 411        .size = sizeof(struct caif_net),
 412};
 413
 414/* Initialize Caif devices list */
 415static int __init caif_device_init(void)
 416{
 417        int result;
 418
 419        result = register_pernet_device(&caif_net_ops);
 420
 421        if (result)
 422                return result;
 423
 424        register_netdevice_notifier(&caif_device_notifier);
 425        dev_add_pack(&caif_packet_type);
 426
 427        return result;
 428}
 429
 430static void __exit caif_device_exit(void)
 431{
 432        unregister_pernet_device(&caif_net_ops);
 433        unregister_netdevice_notifier(&caif_device_notifier);
 434        dev_remove_pack(&caif_packet_type);
 435}
 436
 437module_init(caif_device_init);
 438module_exit(caif_device_exit);
 439