19a44c1ccSLoic Poulain // SPDX-License-Identifier: GPL-2.0-only 29a44c1ccSLoic Poulain /* Copyright (c) 2021, Linaro Ltd <loic.poulain@linaro.org> */ 39a44c1ccSLoic Poulain 49a44c1ccSLoic Poulain #include <linux/err.h> 59a44c1ccSLoic Poulain #include <linux/errno.h> 69a44c1ccSLoic Poulain #include <linux/fs.h> 79a44c1ccSLoic Poulain #include <linux/init.h> 89a44c1ccSLoic Poulain #include <linux/idr.h> 99a44c1ccSLoic Poulain #include <linux/kernel.h> 109a44c1ccSLoic Poulain #include <linux/module.h> 119a44c1ccSLoic Poulain #include <linux/poll.h> 129a44c1ccSLoic Poulain #include <linux/skbuff.h> 139a44c1ccSLoic Poulain #include <linux/slab.h> 149a44c1ccSLoic Poulain #include <linux/types.h> 15e263c5b2SSergey Ryazanov #include <linux/termios.h> 169a44c1ccSLoic Poulain #include <linux/wwan.h> 1788b71053SJohannes Berg #include <net/rtnetlink.h> 1888b71053SJohannes Berg #include <uapi/linux/wwan.h> 199a44c1ccSLoic Poulain 2072eedfc4SSergey Ryazanov /* Maximum number of minors in use */ 2172eedfc4SSergey Ryazanov #define WWAN_MAX_MINORS (1 << MINORBITS) 229a44c1ccSLoic Poulain 239a44c1ccSLoic Poulain static DEFINE_MUTEX(wwan_register_lock); /* WWAN device create|remove lock */ 249a44c1ccSLoic Poulain static DEFINE_IDA(minors); /* minors for WWAN port chardevs */ 259a44c1ccSLoic Poulain static DEFINE_IDA(wwan_dev_ids); /* for unique WWAN device IDs */ 269a44c1ccSLoic Poulain static struct class *wwan_class; 279a44c1ccSLoic Poulain static int wwan_major; 289a44c1ccSLoic Poulain 299a44c1ccSLoic Poulain #define to_wwan_dev(d) container_of(d, struct wwan_device, dev) 309a44c1ccSLoic Poulain #define to_wwan_port(d) container_of(d, struct wwan_port, dev) 319a44c1ccSLoic Poulain 329a44c1ccSLoic Poulain /* WWAN port flags */ 33b8c55ce2SLoic Poulain #define WWAN_PORT_TX_OFF 0 349a44c1ccSLoic Poulain 359a44c1ccSLoic Poulain /** 369a44c1ccSLoic Poulain * struct wwan_device - The structure that defines a WWAN device 379a44c1ccSLoic Poulain * 389a44c1ccSLoic Poulain * @id: WWAN device unique ID. 399a44c1ccSLoic Poulain * @dev: Underlying device. 4088b71053SJohannes Berg * @port_id: Current available port ID to pick. 4188b71053SJohannes Berg * @ops: wwan device ops 4288b71053SJohannes Berg * @ops_ctxt: context to pass to ops 439a44c1ccSLoic Poulain */ 449a44c1ccSLoic Poulain struct wwan_device { 459a44c1ccSLoic Poulain unsigned int id; 469a44c1ccSLoic Poulain struct device dev; 4788b71053SJohannes Berg atomic_t port_id; 4888b71053SJohannes Berg const struct wwan_ops *ops; 4988b71053SJohannes Berg void *ops_ctxt; 509a44c1ccSLoic Poulain }; 519a44c1ccSLoic Poulain 529a44c1ccSLoic Poulain /** 539a44c1ccSLoic Poulain * struct wwan_port - The structure that defines a WWAN port 549a44c1ccSLoic Poulain * @type: Port type 559a44c1ccSLoic Poulain * @start_count: Port start counter 569a44c1ccSLoic Poulain * @flags: Store port state and capabilities 579a44c1ccSLoic Poulain * @ops: Pointer to WWAN port operations 589a44c1ccSLoic Poulain * @ops_lock: Protect port ops 599a44c1ccSLoic Poulain * @dev: Underlying device 609a44c1ccSLoic Poulain * @rxq: Buffer inbound queue 619a44c1ccSLoic Poulain * @waitqueue: The waitqueue for port fops (read/write/poll) 62c230035cSSergey Ryazanov * @data_lock: Port specific data access serialization 63c230035cSSergey Ryazanov * @at_data: AT port specific data 649a44c1ccSLoic Poulain */ 659a44c1ccSLoic Poulain struct wwan_port { 669a44c1ccSLoic Poulain enum wwan_port_type type; 679a44c1ccSLoic Poulain unsigned int start_count; 689a44c1ccSLoic Poulain unsigned long flags; 699a44c1ccSLoic Poulain const struct wwan_port_ops *ops; 709a44c1ccSLoic Poulain struct mutex ops_lock; /* Serialize ops + protect against removal */ 719a44c1ccSLoic Poulain struct device dev; 729a44c1ccSLoic Poulain struct sk_buff_head rxq; 739a44c1ccSLoic Poulain wait_queue_head_t waitqueue; 74c230035cSSergey Ryazanov struct mutex data_lock; /* Port specific data access serialization */ 75c230035cSSergey Ryazanov union { 76c230035cSSergey Ryazanov struct { 77c230035cSSergey Ryazanov struct ktermios termios; 78c230035cSSergey Ryazanov int mdmbits; 79c230035cSSergey Ryazanov } at_data; 80c230035cSSergey Ryazanov }; 819a44c1ccSLoic Poulain }; 829a44c1ccSLoic Poulain 83e4e92ee7SLoic Poulain static ssize_t index_show(struct device *dev, struct device_attribute *attr, char *buf) 84e4e92ee7SLoic Poulain { 85e4e92ee7SLoic Poulain struct wwan_device *wwan = to_wwan_dev(dev); 86e4e92ee7SLoic Poulain 87e4e92ee7SLoic Poulain return sprintf(buf, "%d\n", wwan->id); 88e4e92ee7SLoic Poulain } 89e4e92ee7SLoic Poulain static DEVICE_ATTR_RO(index); 90e4e92ee7SLoic Poulain 91e4e92ee7SLoic Poulain static struct attribute *wwan_dev_attrs[] = { 92e4e92ee7SLoic Poulain &dev_attr_index.attr, 93e4e92ee7SLoic Poulain NULL, 94e4e92ee7SLoic Poulain }; 95e4e92ee7SLoic Poulain ATTRIBUTE_GROUPS(wwan_dev); 96e4e92ee7SLoic Poulain 979a44c1ccSLoic Poulain static void wwan_dev_destroy(struct device *dev) 989a44c1ccSLoic Poulain { 999a44c1ccSLoic Poulain struct wwan_device *wwandev = to_wwan_dev(dev); 1009a44c1ccSLoic Poulain 1019a44c1ccSLoic Poulain ida_free(&wwan_dev_ids, wwandev->id); 1029a44c1ccSLoic Poulain kfree(wwandev); 1039a44c1ccSLoic Poulain } 1049a44c1ccSLoic Poulain 1059a44c1ccSLoic Poulain static const struct device_type wwan_dev_type = { 1069a44c1ccSLoic Poulain .name = "wwan_dev", 1079a44c1ccSLoic Poulain .release = wwan_dev_destroy, 108e4e92ee7SLoic Poulain .groups = wwan_dev_groups, 1099a44c1ccSLoic Poulain }; 1109a44c1ccSLoic Poulain 1119a44c1ccSLoic Poulain static int wwan_dev_parent_match(struct device *dev, const void *parent) 1129a44c1ccSLoic Poulain { 11388b71053SJohannes Berg return (dev->type == &wwan_dev_type && 11488b71053SJohannes Berg (dev->parent == parent || dev == parent)); 1159a44c1ccSLoic Poulain } 1169a44c1ccSLoic Poulain 1179a44c1ccSLoic Poulain static struct wwan_device *wwan_dev_get_by_parent(struct device *parent) 1189a44c1ccSLoic Poulain { 1199a44c1ccSLoic Poulain struct device *dev; 1209a44c1ccSLoic Poulain 1219a44c1ccSLoic Poulain dev = class_find_device(wwan_class, NULL, parent, wwan_dev_parent_match); 1229a44c1ccSLoic Poulain if (!dev) 1239a44c1ccSLoic Poulain return ERR_PTR(-ENODEV); 1249a44c1ccSLoic Poulain 1259a44c1ccSLoic Poulain return to_wwan_dev(dev); 1269a44c1ccSLoic Poulain } 1279a44c1ccSLoic Poulain 12888b71053SJohannes Berg static int wwan_dev_name_match(struct device *dev, const void *name) 12988b71053SJohannes Berg { 13088b71053SJohannes Berg return dev->type == &wwan_dev_type && 13188b71053SJohannes Berg strcmp(dev_name(dev), name) == 0; 13288b71053SJohannes Berg } 13388b71053SJohannes Berg 13488b71053SJohannes Berg static struct wwan_device *wwan_dev_get_by_name(const char *name) 13588b71053SJohannes Berg { 13688b71053SJohannes Berg struct device *dev; 13788b71053SJohannes Berg 13888b71053SJohannes Berg dev = class_find_device(wwan_class, NULL, name, wwan_dev_name_match); 13988b71053SJohannes Berg if (!dev) 14088b71053SJohannes Berg return ERR_PTR(-ENODEV); 14188b71053SJohannes Berg 14288b71053SJohannes Berg return to_wwan_dev(dev); 14388b71053SJohannes Berg } 14488b71053SJohannes Berg 1459a44c1ccSLoic Poulain /* This function allocates and registers a new WWAN device OR if a WWAN device 1469a44c1ccSLoic Poulain * already exist for the given parent, it gets a reference and return it. 1479a44c1ccSLoic Poulain * This function is not exported (for now), it is called indirectly via 1489a44c1ccSLoic Poulain * wwan_create_port(). 1499a44c1ccSLoic Poulain */ 1509a44c1ccSLoic Poulain static struct wwan_device *wwan_create_dev(struct device *parent) 1519a44c1ccSLoic Poulain { 1529a44c1ccSLoic Poulain struct wwan_device *wwandev; 1539a44c1ccSLoic Poulain int err, id; 1549a44c1ccSLoic Poulain 1559a44c1ccSLoic Poulain /* The 'find-alloc-register' operation must be protected against 1569a44c1ccSLoic Poulain * concurrent execution, a WWAN device is possibly shared between 1579a44c1ccSLoic Poulain * multiple callers or concurrently unregistered from wwan_remove_dev(). 1589a44c1ccSLoic Poulain */ 1599a44c1ccSLoic Poulain mutex_lock(&wwan_register_lock); 1609a44c1ccSLoic Poulain 1619a44c1ccSLoic Poulain /* If wwandev already exists, return it */ 1629a44c1ccSLoic Poulain wwandev = wwan_dev_get_by_parent(parent); 1639a44c1ccSLoic Poulain if (!IS_ERR(wwandev)) 1649a44c1ccSLoic Poulain goto done_unlock; 1659a44c1ccSLoic Poulain 1669a44c1ccSLoic Poulain id = ida_alloc(&wwan_dev_ids, GFP_KERNEL); 1679a44c1ccSLoic Poulain if (id < 0) 1689a44c1ccSLoic Poulain goto done_unlock; 1699a44c1ccSLoic Poulain 1709a44c1ccSLoic Poulain wwandev = kzalloc(sizeof(*wwandev), GFP_KERNEL); 1719a44c1ccSLoic Poulain if (!wwandev) { 1729a44c1ccSLoic Poulain ida_free(&wwan_dev_ids, id); 1739a44c1ccSLoic Poulain goto done_unlock; 1749a44c1ccSLoic Poulain } 1759a44c1ccSLoic Poulain 1769a44c1ccSLoic Poulain wwandev->dev.parent = parent; 1779a44c1ccSLoic Poulain wwandev->dev.class = wwan_class; 1789a44c1ccSLoic Poulain wwandev->dev.type = &wwan_dev_type; 1799a44c1ccSLoic Poulain wwandev->id = id; 1809a44c1ccSLoic Poulain dev_set_name(&wwandev->dev, "wwan%d", wwandev->id); 1819a44c1ccSLoic Poulain 1829a44c1ccSLoic Poulain err = device_register(&wwandev->dev); 1839a44c1ccSLoic Poulain if (err) { 1849a44c1ccSLoic Poulain put_device(&wwandev->dev); 1859a44c1ccSLoic Poulain wwandev = NULL; 1869a44c1ccSLoic Poulain } 1879a44c1ccSLoic Poulain 1889a44c1ccSLoic Poulain done_unlock: 1899a44c1ccSLoic Poulain mutex_unlock(&wwan_register_lock); 1909a44c1ccSLoic Poulain 1919a44c1ccSLoic Poulain return wwandev; 1929a44c1ccSLoic Poulain } 1939a44c1ccSLoic Poulain 1949a44c1ccSLoic Poulain static int is_wwan_child(struct device *dev, void *data) 1959a44c1ccSLoic Poulain { 1969a44c1ccSLoic Poulain return dev->class == wwan_class; 1979a44c1ccSLoic Poulain } 1989a44c1ccSLoic Poulain 1999a44c1ccSLoic Poulain static void wwan_remove_dev(struct wwan_device *wwandev) 2009a44c1ccSLoic Poulain { 2019a44c1ccSLoic Poulain int ret; 2029a44c1ccSLoic Poulain 2039a44c1ccSLoic Poulain /* Prevent concurrent picking from wwan_create_dev */ 2049a44c1ccSLoic Poulain mutex_lock(&wwan_register_lock); 2059a44c1ccSLoic Poulain 2069a44c1ccSLoic Poulain /* WWAN device is created and registered (get+add) along with its first 2079a44c1ccSLoic Poulain * child port, and subsequent port registrations only grab a reference 2089a44c1ccSLoic Poulain * (get). The WWAN device must then be unregistered (del+put) along with 20988b71053SJohannes Berg * its last port, and reference simply dropped (put) otherwise. In the 21088b71053SJohannes Berg * same fashion, we must not unregister it when the ops are still there. 2119a44c1ccSLoic Poulain */ 21288b71053SJohannes Berg if (wwandev->ops) 21388b71053SJohannes Berg ret = 1; 21488b71053SJohannes Berg else 2159a44c1ccSLoic Poulain ret = device_for_each_child(&wwandev->dev, NULL, is_wwan_child); 21688b71053SJohannes Berg 2179a44c1ccSLoic Poulain if (!ret) 2189a44c1ccSLoic Poulain device_unregister(&wwandev->dev); 2199a44c1ccSLoic Poulain else 2209a44c1ccSLoic Poulain put_device(&wwandev->dev); 2219a44c1ccSLoic Poulain 2229a44c1ccSLoic Poulain mutex_unlock(&wwan_register_lock); 2239a44c1ccSLoic Poulain } 2249a44c1ccSLoic Poulain 2259a44c1ccSLoic Poulain /* ------- WWAN port management ------- */ 2269a44c1ccSLoic Poulain 227392c26f7SSergey Ryazanov static const struct { 228392c26f7SSergey Ryazanov const char * const name; /* Port type name */ 229392c26f7SSergey Ryazanov const char * const devsuf; /* Port devce name suffix */ 230392c26f7SSergey Ryazanov } wwan_port_types[WWAN_PORT_MAX + 1] = { 231392c26f7SSergey Ryazanov [WWAN_PORT_AT] = { 232392c26f7SSergey Ryazanov .name = "AT", 233392c26f7SSergey Ryazanov .devsuf = "at", 234392c26f7SSergey Ryazanov }, 235392c26f7SSergey Ryazanov [WWAN_PORT_MBIM] = { 236392c26f7SSergey Ryazanov .name = "MBIM", 237392c26f7SSergey Ryazanov .devsuf = "mbim", 238392c26f7SSergey Ryazanov }, 239392c26f7SSergey Ryazanov [WWAN_PORT_QMI] = { 240392c26f7SSergey Ryazanov .name = "QMI", 241392c26f7SSergey Ryazanov .devsuf = "qmi", 242392c26f7SSergey Ryazanov }, 243392c26f7SSergey Ryazanov [WWAN_PORT_QCDM] = { 244392c26f7SSergey Ryazanov .name = "QCDM", 245392c26f7SSergey Ryazanov .devsuf = "qcdm", 246392c26f7SSergey Ryazanov }, 247392c26f7SSergey Ryazanov [WWAN_PORT_FIREHOSE] = { 248392c26f7SSergey Ryazanov .name = "FIREHOSE", 249392c26f7SSergey Ryazanov .devsuf = "firehose", 250392c26f7SSergey Ryazanov }, 251b3e22e10SLoic Poulain }; 252b3e22e10SLoic Poulain 253b3e22e10SLoic Poulain static ssize_t type_show(struct device *dev, struct device_attribute *attr, 254b3e22e10SLoic Poulain char *buf) 255b3e22e10SLoic Poulain { 256b3e22e10SLoic Poulain struct wwan_port *port = to_wwan_port(dev); 257b3e22e10SLoic Poulain 258392c26f7SSergey Ryazanov return sprintf(buf, "%s\n", wwan_port_types[port->type].name); 259b3e22e10SLoic Poulain } 260b3e22e10SLoic Poulain static DEVICE_ATTR_RO(type); 261b3e22e10SLoic Poulain 262b3e22e10SLoic Poulain static struct attribute *wwan_port_attrs[] = { 263b3e22e10SLoic Poulain &dev_attr_type.attr, 264b3e22e10SLoic Poulain NULL, 265b3e22e10SLoic Poulain }; 266b3e22e10SLoic Poulain ATTRIBUTE_GROUPS(wwan_port); 267b3e22e10SLoic Poulain 2689a44c1ccSLoic Poulain static void wwan_port_destroy(struct device *dev) 2699a44c1ccSLoic Poulain { 2709a44c1ccSLoic Poulain struct wwan_port *port = to_wwan_port(dev); 2719a44c1ccSLoic Poulain 2729a44c1ccSLoic Poulain ida_free(&minors, MINOR(port->dev.devt)); 273c230035cSSergey Ryazanov mutex_destroy(&port->data_lock); 2749a44c1ccSLoic Poulain mutex_destroy(&port->ops_lock); 2759a44c1ccSLoic Poulain kfree(port); 2769a44c1ccSLoic Poulain } 2779a44c1ccSLoic Poulain 2789a44c1ccSLoic Poulain static const struct device_type wwan_port_dev_type = { 2799a44c1ccSLoic Poulain .name = "wwan_port", 2809a44c1ccSLoic Poulain .release = wwan_port_destroy, 281b3e22e10SLoic Poulain .groups = wwan_port_groups, 2829a44c1ccSLoic Poulain }; 2839a44c1ccSLoic Poulain 2849a44c1ccSLoic Poulain static int wwan_port_minor_match(struct device *dev, const void *minor) 2859a44c1ccSLoic Poulain { 2869a44c1ccSLoic Poulain return (dev->type == &wwan_port_dev_type && 2879a44c1ccSLoic Poulain MINOR(dev->devt) == *(unsigned int *)minor); 2889a44c1ccSLoic Poulain } 2899a44c1ccSLoic Poulain 2909a44c1ccSLoic Poulain static struct wwan_port *wwan_port_get_by_minor(unsigned int minor) 2919a44c1ccSLoic Poulain { 2929a44c1ccSLoic Poulain struct device *dev; 2939a44c1ccSLoic Poulain 2949a44c1ccSLoic Poulain dev = class_find_device(wwan_class, NULL, &minor, wwan_port_minor_match); 2959a44c1ccSLoic Poulain if (!dev) 2969a44c1ccSLoic Poulain return ERR_PTR(-ENODEV); 2979a44c1ccSLoic Poulain 2989a44c1ccSLoic Poulain return to_wwan_port(dev); 2999a44c1ccSLoic Poulain } 3009a44c1ccSLoic Poulain 301f458709fSSergey Ryazanov /* Allocate and set unique name based on passed format 302f458709fSSergey Ryazanov * 303f458709fSSergey Ryazanov * Name allocation approach is highly inspired by the __dev_alloc_name() 304f458709fSSergey Ryazanov * function. 305f458709fSSergey Ryazanov * 306f458709fSSergey Ryazanov * To avoid names collision, the caller must prevent the new port device 307f458709fSSergey Ryazanov * registration as well as concurrent invocation of this function. 308f458709fSSergey Ryazanov */ 309f458709fSSergey Ryazanov static int __wwan_port_dev_assign_name(struct wwan_port *port, const char *fmt) 310f458709fSSergey Ryazanov { 311f458709fSSergey Ryazanov struct wwan_device *wwandev = to_wwan_dev(port->dev.parent); 312f458709fSSergey Ryazanov const unsigned int max_ports = PAGE_SIZE * 8; 313f458709fSSergey Ryazanov struct class_dev_iter iter; 314f458709fSSergey Ryazanov unsigned long *idmap; 315f458709fSSergey Ryazanov struct device *dev; 316f458709fSSergey Ryazanov char buf[0x20]; 317f458709fSSergey Ryazanov int id; 318f458709fSSergey Ryazanov 319f458709fSSergey Ryazanov idmap = (unsigned long *)get_zeroed_page(GFP_KERNEL); 320f458709fSSergey Ryazanov if (!idmap) 321f458709fSSergey Ryazanov return -ENOMEM; 322f458709fSSergey Ryazanov 323f458709fSSergey Ryazanov /* Collect ids of same name format ports */ 324f458709fSSergey Ryazanov class_dev_iter_init(&iter, wwan_class, NULL, &wwan_port_dev_type); 325f458709fSSergey Ryazanov while ((dev = class_dev_iter_next(&iter))) { 326f458709fSSergey Ryazanov if (dev->parent != &wwandev->dev) 327f458709fSSergey Ryazanov continue; 328f458709fSSergey Ryazanov if (sscanf(dev_name(dev), fmt, &id) != 1) 329f458709fSSergey Ryazanov continue; 330f458709fSSergey Ryazanov if (id < 0 || id >= max_ports) 331f458709fSSergey Ryazanov continue; 332f458709fSSergey Ryazanov set_bit(id, idmap); 333f458709fSSergey Ryazanov } 334f458709fSSergey Ryazanov class_dev_iter_exit(&iter); 335f458709fSSergey Ryazanov 336f458709fSSergey Ryazanov /* Allocate unique id */ 337f458709fSSergey Ryazanov id = find_first_zero_bit(idmap, max_ports); 338f458709fSSergey Ryazanov free_page((unsigned long)idmap); 339f458709fSSergey Ryazanov 340f458709fSSergey Ryazanov snprintf(buf, sizeof(buf), fmt, id); /* Name generation */ 341f458709fSSergey Ryazanov 342f458709fSSergey Ryazanov dev = device_find_child_by_name(&wwandev->dev, buf); 343f458709fSSergey Ryazanov if (dev) { 344f458709fSSergey Ryazanov put_device(dev); 345f458709fSSergey Ryazanov return -ENFILE; 346f458709fSSergey Ryazanov } 347f458709fSSergey Ryazanov 348f458709fSSergey Ryazanov return dev_set_name(&port->dev, buf); 349f458709fSSergey Ryazanov } 350f458709fSSergey Ryazanov 3519a44c1ccSLoic Poulain struct wwan_port *wwan_create_port(struct device *parent, 3529a44c1ccSLoic Poulain enum wwan_port_type type, 3539a44c1ccSLoic Poulain const struct wwan_port_ops *ops, 3549a44c1ccSLoic Poulain void *drvdata) 3559a44c1ccSLoic Poulain { 3569a44c1ccSLoic Poulain struct wwan_device *wwandev; 3579a44c1ccSLoic Poulain struct wwan_port *port; 3589a44c1ccSLoic Poulain int minor, err = -ENOMEM; 359f458709fSSergey Ryazanov char namefmt[0x20]; 3609a44c1ccSLoic Poulain 361b64d76b7SSergey Ryazanov if (type > WWAN_PORT_MAX || !ops) 3629a44c1ccSLoic Poulain return ERR_PTR(-EINVAL); 3639a44c1ccSLoic Poulain 3649a44c1ccSLoic Poulain /* A port is always a child of a WWAN device, retrieve (allocate or 3659a44c1ccSLoic Poulain * pick) the WWAN device based on the provided parent device. 3669a44c1ccSLoic Poulain */ 3679a44c1ccSLoic Poulain wwandev = wwan_create_dev(parent); 3689a44c1ccSLoic Poulain if (IS_ERR(wwandev)) 3699a44c1ccSLoic Poulain return ERR_CAST(wwandev); 3709a44c1ccSLoic Poulain 3719a44c1ccSLoic Poulain /* A port is exposed as character device, get a minor */ 3729a44c1ccSLoic Poulain minor = ida_alloc_range(&minors, 0, WWAN_MAX_MINORS - 1, GFP_KERNEL); 3739a44c1ccSLoic Poulain if (minor < 0) 3749a44c1ccSLoic Poulain goto error_wwandev_remove; 3759a44c1ccSLoic Poulain 3769a44c1ccSLoic Poulain port = kzalloc(sizeof(*port), GFP_KERNEL); 3779a44c1ccSLoic Poulain if (!port) { 3789a44c1ccSLoic Poulain ida_free(&minors, minor); 3799a44c1ccSLoic Poulain goto error_wwandev_remove; 3809a44c1ccSLoic Poulain } 3819a44c1ccSLoic Poulain 3829a44c1ccSLoic Poulain port->type = type; 3839a44c1ccSLoic Poulain port->ops = ops; 3849a44c1ccSLoic Poulain mutex_init(&port->ops_lock); 3859a44c1ccSLoic Poulain skb_queue_head_init(&port->rxq); 3869a44c1ccSLoic Poulain init_waitqueue_head(&port->waitqueue); 387c230035cSSergey Ryazanov mutex_init(&port->data_lock); 3889a44c1ccSLoic Poulain 3899a44c1ccSLoic Poulain port->dev.parent = &wwandev->dev; 3909a44c1ccSLoic Poulain port->dev.class = wwan_class; 3919a44c1ccSLoic Poulain port->dev.type = &wwan_port_dev_type; 3929a44c1ccSLoic Poulain port->dev.devt = MKDEV(wwan_major, minor); 3939a44c1ccSLoic Poulain dev_set_drvdata(&port->dev, drvdata); 3949a44c1ccSLoic Poulain 395f458709fSSergey Ryazanov /* allocate unique name based on wwan device id, port type and number */ 396f458709fSSergey Ryazanov snprintf(namefmt, sizeof(namefmt), "wwan%u%s%%d", wwandev->id, 397392c26f7SSergey Ryazanov wwan_port_types[port->type].devsuf); 3989a44c1ccSLoic Poulain 399f458709fSSergey Ryazanov /* Serialize ports registration */ 400f458709fSSergey Ryazanov mutex_lock(&wwan_register_lock); 401f458709fSSergey Ryazanov 402f458709fSSergey Ryazanov __wwan_port_dev_assign_name(port, namefmt); 4039a44c1ccSLoic Poulain err = device_register(&port->dev); 404f458709fSSergey Ryazanov 405f458709fSSergey Ryazanov mutex_unlock(&wwan_register_lock); 406f458709fSSergey Ryazanov 4079a44c1ccSLoic Poulain if (err) 4089a44c1ccSLoic Poulain goto error_put_device; 4099a44c1ccSLoic Poulain 4109a44c1ccSLoic Poulain return port; 4119a44c1ccSLoic Poulain 4129a44c1ccSLoic Poulain error_put_device: 4139a44c1ccSLoic Poulain put_device(&port->dev); 4149a44c1ccSLoic Poulain error_wwandev_remove: 4159a44c1ccSLoic Poulain wwan_remove_dev(wwandev); 4169a44c1ccSLoic Poulain 4179a44c1ccSLoic Poulain return ERR_PTR(err); 4189a44c1ccSLoic Poulain } 4199a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_create_port); 4209a44c1ccSLoic Poulain 4219a44c1ccSLoic Poulain void wwan_remove_port(struct wwan_port *port) 4229a44c1ccSLoic Poulain { 4239a44c1ccSLoic Poulain struct wwan_device *wwandev = to_wwan_dev(port->dev.parent); 4249a44c1ccSLoic Poulain 4259a44c1ccSLoic Poulain mutex_lock(&port->ops_lock); 4269a44c1ccSLoic Poulain if (port->start_count) 4279a44c1ccSLoic Poulain port->ops->stop(port); 4289a44c1ccSLoic Poulain port->ops = NULL; /* Prevent any new port operations (e.g. from fops) */ 4299a44c1ccSLoic Poulain mutex_unlock(&port->ops_lock); 4309a44c1ccSLoic Poulain 4319a44c1ccSLoic Poulain wake_up_interruptible(&port->waitqueue); 4329a44c1ccSLoic Poulain 4339a44c1ccSLoic Poulain skb_queue_purge(&port->rxq); 4349a44c1ccSLoic Poulain dev_set_drvdata(&port->dev, NULL); 4359a44c1ccSLoic Poulain device_unregister(&port->dev); 4369a44c1ccSLoic Poulain 4379a44c1ccSLoic Poulain /* Release related wwan device */ 4389a44c1ccSLoic Poulain wwan_remove_dev(wwandev); 4399a44c1ccSLoic Poulain } 4409a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_remove_port); 4419a44c1ccSLoic Poulain 4429a44c1ccSLoic Poulain void wwan_port_rx(struct wwan_port *port, struct sk_buff *skb) 4439a44c1ccSLoic Poulain { 4449a44c1ccSLoic Poulain skb_queue_tail(&port->rxq, skb); 4459a44c1ccSLoic Poulain wake_up_interruptible(&port->waitqueue); 4469a44c1ccSLoic Poulain } 4479a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_port_rx); 4489a44c1ccSLoic Poulain 4499a44c1ccSLoic Poulain void wwan_port_txon(struct wwan_port *port) 4509a44c1ccSLoic Poulain { 4519a44c1ccSLoic Poulain clear_bit(WWAN_PORT_TX_OFF, &port->flags); 4529a44c1ccSLoic Poulain wake_up_interruptible(&port->waitqueue); 4539a44c1ccSLoic Poulain } 4549a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_port_txon); 4559a44c1ccSLoic Poulain 4569a44c1ccSLoic Poulain void wwan_port_txoff(struct wwan_port *port) 4579a44c1ccSLoic Poulain { 4589a44c1ccSLoic Poulain set_bit(WWAN_PORT_TX_OFF, &port->flags); 4599a44c1ccSLoic Poulain } 4609a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_port_txoff); 4619a44c1ccSLoic Poulain 4629a44c1ccSLoic Poulain void *wwan_port_get_drvdata(struct wwan_port *port) 4639a44c1ccSLoic Poulain { 4649a44c1ccSLoic Poulain return dev_get_drvdata(&port->dev); 4659a44c1ccSLoic Poulain } 4669a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_port_get_drvdata); 4679a44c1ccSLoic Poulain 4689a44c1ccSLoic Poulain static int wwan_port_op_start(struct wwan_port *port) 4699a44c1ccSLoic Poulain { 4709a44c1ccSLoic Poulain int ret = 0; 4719a44c1ccSLoic Poulain 4729a44c1ccSLoic Poulain mutex_lock(&port->ops_lock); 4739a44c1ccSLoic Poulain if (!port->ops) { /* Port got unplugged */ 4749a44c1ccSLoic Poulain ret = -ENODEV; 4759a44c1ccSLoic Poulain goto out_unlock; 4769a44c1ccSLoic Poulain } 4779a44c1ccSLoic Poulain 4789a44c1ccSLoic Poulain /* If port is already started, don't start again */ 4799a44c1ccSLoic Poulain if (!port->start_count) 4809a44c1ccSLoic Poulain ret = port->ops->start(port); 4819a44c1ccSLoic Poulain 4829a44c1ccSLoic Poulain if (!ret) 4839a44c1ccSLoic Poulain port->start_count++; 4849a44c1ccSLoic Poulain 4859a44c1ccSLoic Poulain out_unlock: 4869a44c1ccSLoic Poulain mutex_unlock(&port->ops_lock); 4879a44c1ccSLoic Poulain 4889a44c1ccSLoic Poulain return ret; 4899a44c1ccSLoic Poulain } 4909a44c1ccSLoic Poulain 4919a44c1ccSLoic Poulain static void wwan_port_op_stop(struct wwan_port *port) 4929a44c1ccSLoic Poulain { 4939a44c1ccSLoic Poulain mutex_lock(&port->ops_lock); 4949a44c1ccSLoic Poulain port->start_count--; 49550467203SSergey Ryazanov if (!port->start_count) { 49650467203SSergey Ryazanov if (port->ops) 4979a44c1ccSLoic Poulain port->ops->stop(port); 49850467203SSergey Ryazanov skb_queue_purge(&port->rxq); 49950467203SSergey Ryazanov } 5009a44c1ccSLoic Poulain mutex_unlock(&port->ops_lock); 5019a44c1ccSLoic Poulain } 5029a44c1ccSLoic Poulain 50331c143f7SStephan Gerhold static int wwan_port_op_tx(struct wwan_port *port, struct sk_buff *skb, 50431c143f7SStephan Gerhold bool nonblock) 5059a44c1ccSLoic Poulain { 5069a44c1ccSLoic Poulain int ret; 5079a44c1ccSLoic Poulain 5089a44c1ccSLoic Poulain mutex_lock(&port->ops_lock); 5099a44c1ccSLoic Poulain if (!port->ops) { /* Port got unplugged */ 5109a44c1ccSLoic Poulain ret = -ENODEV; 5119a44c1ccSLoic Poulain goto out_unlock; 5129a44c1ccSLoic Poulain } 5139a44c1ccSLoic Poulain 51431c143f7SStephan Gerhold if (nonblock || !port->ops->tx_blocking) 5159a44c1ccSLoic Poulain ret = port->ops->tx(port, skb); 51631c143f7SStephan Gerhold else 51731c143f7SStephan Gerhold ret = port->ops->tx_blocking(port, skb); 5189a44c1ccSLoic Poulain 5199a44c1ccSLoic Poulain out_unlock: 5209a44c1ccSLoic Poulain mutex_unlock(&port->ops_lock); 5219a44c1ccSLoic Poulain 5229a44c1ccSLoic Poulain return ret; 5239a44c1ccSLoic Poulain } 5249a44c1ccSLoic Poulain 5259a44c1ccSLoic Poulain static bool is_read_blocked(struct wwan_port *port) 5269a44c1ccSLoic Poulain { 5279a44c1ccSLoic Poulain return skb_queue_empty(&port->rxq) && port->ops; 5289a44c1ccSLoic Poulain } 5299a44c1ccSLoic Poulain 5309a44c1ccSLoic Poulain static bool is_write_blocked(struct wwan_port *port) 5319a44c1ccSLoic Poulain { 5329a44c1ccSLoic Poulain return test_bit(WWAN_PORT_TX_OFF, &port->flags) && port->ops; 5339a44c1ccSLoic Poulain } 5349a44c1ccSLoic Poulain 5359a44c1ccSLoic Poulain static int wwan_wait_rx(struct wwan_port *port, bool nonblock) 5369a44c1ccSLoic Poulain { 5379a44c1ccSLoic Poulain if (!is_read_blocked(port)) 5389a44c1ccSLoic Poulain return 0; 5399a44c1ccSLoic Poulain 5409a44c1ccSLoic Poulain if (nonblock) 5419a44c1ccSLoic Poulain return -EAGAIN; 5429a44c1ccSLoic Poulain 5439a44c1ccSLoic Poulain if (wait_event_interruptible(port->waitqueue, !is_read_blocked(port))) 5449a44c1ccSLoic Poulain return -ERESTARTSYS; 5459a44c1ccSLoic Poulain 5469a44c1ccSLoic Poulain return 0; 5479a44c1ccSLoic Poulain } 5489a44c1ccSLoic Poulain 5499a44c1ccSLoic Poulain static int wwan_wait_tx(struct wwan_port *port, bool nonblock) 5509a44c1ccSLoic Poulain { 5519a44c1ccSLoic Poulain if (!is_write_blocked(port)) 5529a44c1ccSLoic Poulain return 0; 5539a44c1ccSLoic Poulain 5549a44c1ccSLoic Poulain if (nonblock) 5559a44c1ccSLoic Poulain return -EAGAIN; 5569a44c1ccSLoic Poulain 5579a44c1ccSLoic Poulain if (wait_event_interruptible(port->waitqueue, !is_write_blocked(port))) 5589a44c1ccSLoic Poulain return -ERESTARTSYS; 5599a44c1ccSLoic Poulain 5609a44c1ccSLoic Poulain return 0; 5619a44c1ccSLoic Poulain } 5629a44c1ccSLoic Poulain 5639a44c1ccSLoic Poulain static int wwan_port_fops_open(struct inode *inode, struct file *file) 5649a44c1ccSLoic Poulain { 5659a44c1ccSLoic Poulain struct wwan_port *port; 5669a44c1ccSLoic Poulain int err = 0; 5679a44c1ccSLoic Poulain 5689a44c1ccSLoic Poulain port = wwan_port_get_by_minor(iminor(inode)); 5699a44c1ccSLoic Poulain if (IS_ERR(port)) 5709a44c1ccSLoic Poulain return PTR_ERR(port); 5719a44c1ccSLoic Poulain 5729a44c1ccSLoic Poulain file->private_data = port; 5739a44c1ccSLoic Poulain stream_open(inode, file); 5749a44c1ccSLoic Poulain 5759a44c1ccSLoic Poulain err = wwan_port_op_start(port); 5769a44c1ccSLoic Poulain if (err) 5779a44c1ccSLoic Poulain put_device(&port->dev); 5789a44c1ccSLoic Poulain 5799a44c1ccSLoic Poulain return err; 5809a44c1ccSLoic Poulain } 5819a44c1ccSLoic Poulain 5829a44c1ccSLoic Poulain static int wwan_port_fops_release(struct inode *inode, struct file *filp) 5839a44c1ccSLoic Poulain { 5849a44c1ccSLoic Poulain struct wwan_port *port = filp->private_data; 5859a44c1ccSLoic Poulain 5869a44c1ccSLoic Poulain wwan_port_op_stop(port); 5879a44c1ccSLoic Poulain put_device(&port->dev); 5889a44c1ccSLoic Poulain 5899a44c1ccSLoic Poulain return 0; 5909a44c1ccSLoic Poulain } 5919a44c1ccSLoic Poulain 5929a44c1ccSLoic Poulain static ssize_t wwan_port_fops_read(struct file *filp, char __user *buf, 5939a44c1ccSLoic Poulain size_t count, loff_t *ppos) 5949a44c1ccSLoic Poulain { 5959a44c1ccSLoic Poulain struct wwan_port *port = filp->private_data; 5969a44c1ccSLoic Poulain struct sk_buff *skb; 5979a44c1ccSLoic Poulain size_t copied; 5989a44c1ccSLoic Poulain int ret; 5999a44c1ccSLoic Poulain 6009a44c1ccSLoic Poulain ret = wwan_wait_rx(port, !!(filp->f_flags & O_NONBLOCK)); 6019a44c1ccSLoic Poulain if (ret) 6029a44c1ccSLoic Poulain return ret; 6039a44c1ccSLoic Poulain 6049a44c1ccSLoic Poulain skb = skb_dequeue(&port->rxq); 6059a44c1ccSLoic Poulain if (!skb) 6069a44c1ccSLoic Poulain return -EIO; 6079a44c1ccSLoic Poulain 6089a44c1ccSLoic Poulain copied = min_t(size_t, count, skb->len); 6099a44c1ccSLoic Poulain if (copy_to_user(buf, skb->data, copied)) { 6109a44c1ccSLoic Poulain kfree_skb(skb); 6119a44c1ccSLoic Poulain return -EFAULT; 6129a44c1ccSLoic Poulain } 6139a44c1ccSLoic Poulain skb_pull(skb, copied); 6149a44c1ccSLoic Poulain 6159a44c1ccSLoic Poulain /* skb is not fully consumed, keep it in the queue */ 6169a44c1ccSLoic Poulain if (skb->len) 6179a44c1ccSLoic Poulain skb_queue_head(&port->rxq, skb); 6189a44c1ccSLoic Poulain else 6199a44c1ccSLoic Poulain consume_skb(skb); 6209a44c1ccSLoic Poulain 6219a44c1ccSLoic Poulain return copied; 6229a44c1ccSLoic Poulain } 6239a44c1ccSLoic Poulain 6249a44c1ccSLoic Poulain static ssize_t wwan_port_fops_write(struct file *filp, const char __user *buf, 6259a44c1ccSLoic Poulain size_t count, loff_t *offp) 6269a44c1ccSLoic Poulain { 6279a44c1ccSLoic Poulain struct wwan_port *port = filp->private_data; 6289a44c1ccSLoic Poulain struct sk_buff *skb; 6299a44c1ccSLoic Poulain int ret; 6309a44c1ccSLoic Poulain 6319a44c1ccSLoic Poulain ret = wwan_wait_tx(port, !!(filp->f_flags & O_NONBLOCK)); 6329a44c1ccSLoic Poulain if (ret) 6339a44c1ccSLoic Poulain return ret; 6349a44c1ccSLoic Poulain 6359a44c1ccSLoic Poulain skb = alloc_skb(count, GFP_KERNEL); 6369a44c1ccSLoic Poulain if (!skb) 6379a44c1ccSLoic Poulain return -ENOMEM; 6389a44c1ccSLoic Poulain 6399a44c1ccSLoic Poulain if (copy_from_user(skb_put(skb, count), buf, count)) { 6409a44c1ccSLoic Poulain kfree_skb(skb); 6419a44c1ccSLoic Poulain return -EFAULT; 6429a44c1ccSLoic Poulain } 6439a44c1ccSLoic Poulain 64431c143f7SStephan Gerhold ret = wwan_port_op_tx(port, skb, !!(filp->f_flags & O_NONBLOCK)); 6459a44c1ccSLoic Poulain if (ret) { 6469a44c1ccSLoic Poulain kfree_skb(skb); 6479a44c1ccSLoic Poulain return ret; 6489a44c1ccSLoic Poulain } 6499a44c1ccSLoic Poulain 6509a44c1ccSLoic Poulain return count; 6519a44c1ccSLoic Poulain } 6529a44c1ccSLoic Poulain 6539a44c1ccSLoic Poulain static __poll_t wwan_port_fops_poll(struct file *filp, poll_table *wait) 6549a44c1ccSLoic Poulain { 6559a44c1ccSLoic Poulain struct wwan_port *port = filp->private_data; 6569a44c1ccSLoic Poulain __poll_t mask = 0; 6579a44c1ccSLoic Poulain 6589a44c1ccSLoic Poulain poll_wait(filp, &port->waitqueue, wait); 6599a44c1ccSLoic Poulain 66031c143f7SStephan Gerhold mutex_lock(&port->ops_lock); 66131c143f7SStephan Gerhold if (port->ops && port->ops->tx_poll) 66231c143f7SStephan Gerhold mask |= port->ops->tx_poll(port, filp, wait); 66331c143f7SStephan Gerhold else if (!is_write_blocked(port)) 6649a44c1ccSLoic Poulain mask |= EPOLLOUT | EPOLLWRNORM; 6659a44c1ccSLoic Poulain if (!is_read_blocked(port)) 6669a44c1ccSLoic Poulain mask |= EPOLLIN | EPOLLRDNORM; 66757e22247SLoic Poulain if (!port->ops) 66857e22247SLoic Poulain mask |= EPOLLHUP | EPOLLERR; 66931c143f7SStephan Gerhold mutex_unlock(&port->ops_lock); 6709a44c1ccSLoic Poulain 6719a44c1ccSLoic Poulain return mask; 6729a44c1ccSLoic Poulain } 6739a44c1ccSLoic Poulain 674c230035cSSergey Ryazanov /* Implements minimalistic stub terminal IOCTLs support */ 675c230035cSSergey Ryazanov static long wwan_port_fops_at_ioctl(struct wwan_port *port, unsigned int cmd, 676c230035cSSergey Ryazanov unsigned long arg) 677c230035cSSergey Ryazanov { 678c230035cSSergey Ryazanov int ret = 0; 679c230035cSSergey Ryazanov 680c230035cSSergey Ryazanov mutex_lock(&port->data_lock); 681c230035cSSergey Ryazanov 682c230035cSSergey Ryazanov switch (cmd) { 683c230035cSSergey Ryazanov case TCFLSH: 684c230035cSSergey Ryazanov break; 685c230035cSSergey Ryazanov 686c230035cSSergey Ryazanov case TCGETS: 687c230035cSSergey Ryazanov if (copy_to_user((void __user *)arg, &port->at_data.termios, 688c230035cSSergey Ryazanov sizeof(struct termios))) 689c230035cSSergey Ryazanov ret = -EFAULT; 690c230035cSSergey Ryazanov break; 691c230035cSSergey Ryazanov 692c230035cSSergey Ryazanov case TCSETS: 693c230035cSSergey Ryazanov case TCSETSW: 694c230035cSSergey Ryazanov case TCSETSF: 695c230035cSSergey Ryazanov if (copy_from_user(&port->at_data.termios, (void __user *)arg, 696c230035cSSergey Ryazanov sizeof(struct termios))) 697c230035cSSergey Ryazanov ret = -EFAULT; 698c230035cSSergey Ryazanov break; 699c230035cSSergey Ryazanov 700c230035cSSergey Ryazanov #ifdef TCGETS2 701c230035cSSergey Ryazanov case TCGETS2: 702c230035cSSergey Ryazanov if (copy_to_user((void __user *)arg, &port->at_data.termios, 703c230035cSSergey Ryazanov sizeof(struct termios2))) 704c230035cSSergey Ryazanov ret = -EFAULT; 705c230035cSSergey Ryazanov break; 706c230035cSSergey Ryazanov 707c230035cSSergey Ryazanov case TCSETS2: 708c230035cSSergey Ryazanov case TCSETSW2: 709c230035cSSergey Ryazanov case TCSETSF2: 710c230035cSSergey Ryazanov if (copy_from_user(&port->at_data.termios, (void __user *)arg, 711c230035cSSergey Ryazanov sizeof(struct termios2))) 712c230035cSSergey Ryazanov ret = -EFAULT; 713c230035cSSergey Ryazanov break; 714c230035cSSergey Ryazanov #endif 715c230035cSSergey Ryazanov 716c230035cSSergey Ryazanov case TIOCMGET: 717c230035cSSergey Ryazanov ret = put_user(port->at_data.mdmbits, (int __user *)arg); 718c230035cSSergey Ryazanov break; 719c230035cSSergey Ryazanov 720c230035cSSergey Ryazanov case TIOCMSET: 721c230035cSSergey Ryazanov case TIOCMBIC: 722c230035cSSergey Ryazanov case TIOCMBIS: { 723c230035cSSergey Ryazanov int mdmbits; 724c230035cSSergey Ryazanov 725c230035cSSergey Ryazanov if (copy_from_user(&mdmbits, (int __user *)arg, sizeof(int))) { 726c230035cSSergey Ryazanov ret = -EFAULT; 727c230035cSSergey Ryazanov break; 728c230035cSSergey Ryazanov } 729c230035cSSergey Ryazanov if (cmd == TIOCMBIC) 730c230035cSSergey Ryazanov port->at_data.mdmbits &= ~mdmbits; 731c230035cSSergey Ryazanov else if (cmd == TIOCMBIS) 732c230035cSSergey Ryazanov port->at_data.mdmbits |= mdmbits; 733c230035cSSergey Ryazanov else 734c230035cSSergey Ryazanov port->at_data.mdmbits = mdmbits; 735c230035cSSergey Ryazanov break; 736c230035cSSergey Ryazanov } 737c230035cSSergey Ryazanov 738c230035cSSergey Ryazanov default: 739c230035cSSergey Ryazanov ret = -ENOIOCTLCMD; 740c230035cSSergey Ryazanov } 741c230035cSSergey Ryazanov 742c230035cSSergey Ryazanov mutex_unlock(&port->data_lock); 743c230035cSSergey Ryazanov 744c230035cSSergey Ryazanov return ret; 745c230035cSSergey Ryazanov } 746c230035cSSergey Ryazanov 747e263c5b2SSergey Ryazanov static long wwan_port_fops_ioctl(struct file *filp, unsigned int cmd, 748e263c5b2SSergey Ryazanov unsigned long arg) 749e263c5b2SSergey Ryazanov { 750e263c5b2SSergey Ryazanov struct wwan_port *port = filp->private_data; 751c230035cSSergey Ryazanov int res; 752c230035cSSergey Ryazanov 753c230035cSSergey Ryazanov if (port->type == WWAN_PORT_AT) { /* AT port specific IOCTLs */ 754c230035cSSergey Ryazanov res = wwan_port_fops_at_ioctl(port, cmd, arg); 755c230035cSSergey Ryazanov if (res != -ENOIOCTLCMD) 756c230035cSSergey Ryazanov return res; 757c230035cSSergey Ryazanov } 758e263c5b2SSergey Ryazanov 759e263c5b2SSergey Ryazanov switch (cmd) { 760e263c5b2SSergey Ryazanov case TIOCINQ: { /* aka SIOCINQ aka FIONREAD */ 761e263c5b2SSergey Ryazanov unsigned long flags; 762e263c5b2SSergey Ryazanov struct sk_buff *skb; 763e263c5b2SSergey Ryazanov int amount = 0; 764e263c5b2SSergey Ryazanov 765e263c5b2SSergey Ryazanov spin_lock_irqsave(&port->rxq.lock, flags); 766e263c5b2SSergey Ryazanov skb_queue_walk(&port->rxq, skb) 767e263c5b2SSergey Ryazanov amount += skb->len; 768e263c5b2SSergey Ryazanov spin_unlock_irqrestore(&port->rxq.lock, flags); 769e263c5b2SSergey Ryazanov 770e263c5b2SSergey Ryazanov return put_user(amount, (int __user *)arg); 771e263c5b2SSergey Ryazanov } 772e263c5b2SSergey Ryazanov 773e263c5b2SSergey Ryazanov default: 774e263c5b2SSergey Ryazanov return -ENOIOCTLCMD; 775e263c5b2SSergey Ryazanov } 776e263c5b2SSergey Ryazanov } 777e263c5b2SSergey Ryazanov 7789a44c1ccSLoic Poulain static const struct file_operations wwan_port_fops = { 7799a44c1ccSLoic Poulain .owner = THIS_MODULE, 7809a44c1ccSLoic Poulain .open = wwan_port_fops_open, 7819a44c1ccSLoic Poulain .release = wwan_port_fops_release, 7829a44c1ccSLoic Poulain .read = wwan_port_fops_read, 7839a44c1ccSLoic Poulain .write = wwan_port_fops_write, 7849a44c1ccSLoic Poulain .poll = wwan_port_fops_poll, 785e263c5b2SSergey Ryazanov .unlocked_ioctl = wwan_port_fops_ioctl, 786e263c5b2SSergey Ryazanov #ifdef CONFIG_COMPAT 787e263c5b2SSergey Ryazanov .compat_ioctl = compat_ptr_ioctl, 788e263c5b2SSergey Ryazanov #endif 7899a44c1ccSLoic Poulain .llseek = noop_llseek, 7909a44c1ccSLoic Poulain }; 7919a44c1ccSLoic Poulain 79288b71053SJohannes Berg static int wwan_rtnl_validate(struct nlattr *tb[], struct nlattr *data[], 79388b71053SJohannes Berg struct netlink_ext_ack *extack) 79488b71053SJohannes Berg { 79588b71053SJohannes Berg if (!data) 79688b71053SJohannes Berg return -EINVAL; 79788b71053SJohannes Berg 79888b71053SJohannes Berg if (!tb[IFLA_PARENT_DEV_NAME]) 79988b71053SJohannes Berg return -EINVAL; 80088b71053SJohannes Berg 80188b71053SJohannes Berg if (!data[IFLA_WWAN_LINK_ID]) 80288b71053SJohannes Berg return -EINVAL; 80388b71053SJohannes Berg 80488b71053SJohannes Berg return 0; 80588b71053SJohannes Berg } 80688b71053SJohannes Berg 80788b71053SJohannes Berg static struct device_type wwan_type = { .name = "wwan" }; 80888b71053SJohannes Berg 80988b71053SJohannes Berg static struct net_device *wwan_rtnl_alloc(struct nlattr *tb[], 81088b71053SJohannes Berg const char *ifname, 81188b71053SJohannes Berg unsigned char name_assign_type, 81288b71053SJohannes Berg unsigned int num_tx_queues, 81388b71053SJohannes Berg unsigned int num_rx_queues) 81488b71053SJohannes Berg { 81588b71053SJohannes Berg const char *devname = nla_data(tb[IFLA_PARENT_DEV_NAME]); 81688b71053SJohannes Berg struct wwan_device *wwandev = wwan_dev_get_by_name(devname); 81788b71053SJohannes Berg struct net_device *dev; 81888b71053SJohannes Berg 81988b71053SJohannes Berg if (IS_ERR(wwandev)) 82088b71053SJohannes Berg return ERR_CAST(wwandev); 82188b71053SJohannes Berg 82288b71053SJohannes Berg /* only supported if ops were registered (not just ports) */ 82388b71053SJohannes Berg if (!wwandev->ops) { 82488b71053SJohannes Berg dev = ERR_PTR(-EOPNOTSUPP); 82588b71053SJohannes Berg goto out; 82688b71053SJohannes Berg } 82788b71053SJohannes Berg 82888b71053SJohannes Berg dev = alloc_netdev_mqs(wwandev->ops->priv_size, ifname, name_assign_type, 82988b71053SJohannes Berg wwandev->ops->setup, num_tx_queues, num_rx_queues); 83088b71053SJohannes Berg 83188b71053SJohannes Berg if (dev) { 83288b71053SJohannes Berg SET_NETDEV_DEV(dev, &wwandev->dev); 83388b71053SJohannes Berg SET_NETDEV_DEVTYPE(dev, &wwan_type); 83488b71053SJohannes Berg } 83588b71053SJohannes Berg 83688b71053SJohannes Berg out: 83788b71053SJohannes Berg /* release the reference */ 83888b71053SJohannes Berg put_device(&wwandev->dev); 83988b71053SJohannes Berg return dev; 84088b71053SJohannes Berg } 84188b71053SJohannes Berg 84288b71053SJohannes Berg static int wwan_rtnl_newlink(struct net *src_net, struct net_device *dev, 84388b71053SJohannes Berg struct nlattr *tb[], struct nlattr *data[], 84488b71053SJohannes Berg struct netlink_ext_ack *extack) 84588b71053SJohannes Berg { 84688b71053SJohannes Berg struct wwan_device *wwandev = wwan_dev_get_by_parent(dev->dev.parent); 84788b71053SJohannes Berg u32 link_id = nla_get_u32(data[IFLA_WWAN_LINK_ID]); 84888b71053SJohannes Berg int ret; 84988b71053SJohannes Berg 85088b71053SJohannes Berg if (IS_ERR(wwandev)) 85188b71053SJohannes Berg return PTR_ERR(wwandev); 85288b71053SJohannes Berg 85388b71053SJohannes Berg /* shouldn't have a netdev (left) with us as parent so WARN */ 85488b71053SJohannes Berg if (WARN_ON(!wwandev->ops)) { 85588b71053SJohannes Berg ret = -EOPNOTSUPP; 85688b71053SJohannes Berg goto out; 85788b71053SJohannes Berg } 85888b71053SJohannes Berg 85988b71053SJohannes Berg if (wwandev->ops->newlink) 86088b71053SJohannes Berg ret = wwandev->ops->newlink(wwandev->ops_ctxt, dev, 86188b71053SJohannes Berg link_id, extack); 86288b71053SJohannes Berg else 86388b71053SJohannes Berg ret = register_netdevice(dev); 86488b71053SJohannes Berg 86588b71053SJohannes Berg out: 86688b71053SJohannes Berg /* release the reference */ 86788b71053SJohannes Berg put_device(&wwandev->dev); 86888b71053SJohannes Berg return ret; 86988b71053SJohannes Berg } 87088b71053SJohannes Berg 87188b71053SJohannes Berg static void wwan_rtnl_dellink(struct net_device *dev, struct list_head *head) 87288b71053SJohannes Berg { 87388b71053SJohannes Berg struct wwan_device *wwandev = wwan_dev_get_by_parent(dev->dev.parent); 87488b71053SJohannes Berg 87588b71053SJohannes Berg if (IS_ERR(wwandev)) 87688b71053SJohannes Berg return; 87788b71053SJohannes Berg 87888b71053SJohannes Berg /* shouldn't have a netdev (left) with us as parent so WARN */ 87988b71053SJohannes Berg if (WARN_ON(!wwandev->ops)) 88088b71053SJohannes Berg goto out; 88188b71053SJohannes Berg 88288b71053SJohannes Berg if (wwandev->ops->dellink) 88388b71053SJohannes Berg wwandev->ops->dellink(wwandev->ops_ctxt, dev, head); 88488b71053SJohannes Berg else 885f492fccfSSergey Ryazanov unregister_netdevice_queue(dev, head); 88688b71053SJohannes Berg 88788b71053SJohannes Berg out: 88888b71053SJohannes Berg /* release the reference */ 88988b71053SJohannes Berg put_device(&wwandev->dev); 89088b71053SJohannes Berg } 89188b71053SJohannes Berg 89288b71053SJohannes Berg static const struct nla_policy wwan_rtnl_policy[IFLA_WWAN_MAX + 1] = { 89388b71053SJohannes Berg [IFLA_WWAN_LINK_ID] = { .type = NLA_U32 }, 89488b71053SJohannes Berg }; 89588b71053SJohannes Berg 89688b71053SJohannes Berg static struct rtnl_link_ops wwan_rtnl_link_ops __read_mostly = { 89788b71053SJohannes Berg .kind = "wwan", 89888b71053SJohannes Berg .maxtype = __IFLA_WWAN_MAX, 89988b71053SJohannes Berg .alloc = wwan_rtnl_alloc, 90088b71053SJohannes Berg .validate = wwan_rtnl_validate, 90188b71053SJohannes Berg .newlink = wwan_rtnl_newlink, 90288b71053SJohannes Berg .dellink = wwan_rtnl_dellink, 90388b71053SJohannes Berg .policy = wwan_rtnl_policy, 90488b71053SJohannes Berg }; 90588b71053SJohannes Berg 906*ca374290SSergey Ryazanov static void wwan_create_default_link(struct wwan_device *wwandev, 907*ca374290SSergey Ryazanov u32 def_link_id) 908*ca374290SSergey Ryazanov { 909*ca374290SSergey Ryazanov struct nlattr *tb[IFLA_MAX + 1], *linkinfo[IFLA_INFO_MAX + 1]; 910*ca374290SSergey Ryazanov struct nlattr *data[IFLA_WWAN_MAX + 1]; 911*ca374290SSergey Ryazanov struct net_device *dev; 912*ca374290SSergey Ryazanov struct nlmsghdr *nlh; 913*ca374290SSergey Ryazanov struct sk_buff *msg; 914*ca374290SSergey Ryazanov 915*ca374290SSergey Ryazanov /* Forge attributes required to create a WWAN netdev. We first 916*ca374290SSergey Ryazanov * build a netlink message and then parse it. This looks 917*ca374290SSergey Ryazanov * odd, but such approach is less error prone. 918*ca374290SSergey Ryazanov */ 919*ca374290SSergey Ryazanov msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 920*ca374290SSergey Ryazanov if (WARN_ON(!msg)) 921*ca374290SSergey Ryazanov return; 922*ca374290SSergey Ryazanov nlh = nlmsg_put(msg, 0, 0, RTM_NEWLINK, 0, 0); 923*ca374290SSergey Ryazanov if (WARN_ON(!nlh)) 924*ca374290SSergey Ryazanov goto free_attrs; 925*ca374290SSergey Ryazanov 926*ca374290SSergey Ryazanov if (nla_put_string(msg, IFLA_PARENT_DEV_NAME, dev_name(&wwandev->dev))) 927*ca374290SSergey Ryazanov goto free_attrs; 928*ca374290SSergey Ryazanov tb[IFLA_LINKINFO] = nla_nest_start(msg, IFLA_LINKINFO); 929*ca374290SSergey Ryazanov if (!tb[IFLA_LINKINFO]) 930*ca374290SSergey Ryazanov goto free_attrs; 931*ca374290SSergey Ryazanov linkinfo[IFLA_INFO_DATA] = nla_nest_start(msg, IFLA_INFO_DATA); 932*ca374290SSergey Ryazanov if (!linkinfo[IFLA_INFO_DATA]) 933*ca374290SSergey Ryazanov goto free_attrs; 934*ca374290SSergey Ryazanov if (nla_put_u32(msg, IFLA_WWAN_LINK_ID, def_link_id)) 935*ca374290SSergey Ryazanov goto free_attrs; 936*ca374290SSergey Ryazanov nla_nest_end(msg, linkinfo[IFLA_INFO_DATA]); 937*ca374290SSergey Ryazanov nla_nest_end(msg, tb[IFLA_LINKINFO]); 938*ca374290SSergey Ryazanov 939*ca374290SSergey Ryazanov nlmsg_end(msg, nlh); 940*ca374290SSergey Ryazanov 941*ca374290SSergey Ryazanov /* The next three parsing calls can not fail */ 942*ca374290SSergey Ryazanov nlmsg_parse_deprecated(nlh, 0, tb, IFLA_MAX, NULL, NULL); 943*ca374290SSergey Ryazanov nla_parse_nested_deprecated(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO], 944*ca374290SSergey Ryazanov NULL, NULL); 945*ca374290SSergey Ryazanov nla_parse_nested_deprecated(data, IFLA_WWAN_MAX, 946*ca374290SSergey Ryazanov linkinfo[IFLA_INFO_DATA], NULL, NULL); 947*ca374290SSergey Ryazanov 948*ca374290SSergey Ryazanov rtnl_lock(); 949*ca374290SSergey Ryazanov 950*ca374290SSergey Ryazanov dev = rtnl_create_link(&init_net, "wwan%d", NET_NAME_ENUM, 951*ca374290SSergey Ryazanov &wwan_rtnl_link_ops, tb, NULL); 952*ca374290SSergey Ryazanov if (WARN_ON(IS_ERR(dev))) 953*ca374290SSergey Ryazanov goto unlock; 954*ca374290SSergey Ryazanov 955*ca374290SSergey Ryazanov if (WARN_ON(wwan_rtnl_newlink(&init_net, dev, tb, data, NULL))) { 956*ca374290SSergey Ryazanov free_netdev(dev); 957*ca374290SSergey Ryazanov goto unlock; 958*ca374290SSergey Ryazanov } 959*ca374290SSergey Ryazanov 960*ca374290SSergey Ryazanov unlock: 961*ca374290SSergey Ryazanov rtnl_unlock(); 962*ca374290SSergey Ryazanov 963*ca374290SSergey Ryazanov free_attrs: 964*ca374290SSergey Ryazanov nlmsg_free(msg); 965*ca374290SSergey Ryazanov } 966*ca374290SSergey Ryazanov 967355a4e7eSSergey Ryazanov /** 968355a4e7eSSergey Ryazanov * wwan_register_ops - register WWAN device ops 969355a4e7eSSergey Ryazanov * @parent: Device to use as parent and shared by all WWAN ports and 970355a4e7eSSergey Ryazanov * created netdevs 971355a4e7eSSergey Ryazanov * @ops: operations to register 972355a4e7eSSergey Ryazanov * @ctxt: context to pass to operations 973*ca374290SSergey Ryazanov * @def_link_id: id of the default link that will be automatically created by 974*ca374290SSergey Ryazanov * the WWAN core for the WWAN device. The default link will not be created 975*ca374290SSergey Ryazanov * if the passed value is WWAN_NO_DEFAULT_LINK. 976355a4e7eSSergey Ryazanov * 977355a4e7eSSergey Ryazanov * Returns: 0 on success, a negative error code on failure 978355a4e7eSSergey Ryazanov */ 979355a4e7eSSergey Ryazanov int wwan_register_ops(struct device *parent, const struct wwan_ops *ops, 980*ca374290SSergey Ryazanov void *ctxt, u32 def_link_id) 981355a4e7eSSergey Ryazanov { 982355a4e7eSSergey Ryazanov struct wwan_device *wwandev; 983355a4e7eSSergey Ryazanov 98458c3b421SSergey Ryazanov if (WARN_ON(!parent || !ops || !ops->setup)) 985355a4e7eSSergey Ryazanov return -EINVAL; 986355a4e7eSSergey Ryazanov 987355a4e7eSSergey Ryazanov wwandev = wwan_create_dev(parent); 988355a4e7eSSergey Ryazanov if (!wwandev) 989355a4e7eSSergey Ryazanov return -ENOMEM; 990355a4e7eSSergey Ryazanov 991355a4e7eSSergey Ryazanov if (WARN_ON(wwandev->ops)) { 992355a4e7eSSergey Ryazanov wwan_remove_dev(wwandev); 993355a4e7eSSergey Ryazanov return -EBUSY; 994355a4e7eSSergey Ryazanov } 995355a4e7eSSergey Ryazanov 996355a4e7eSSergey Ryazanov wwandev->ops = ops; 997355a4e7eSSergey Ryazanov wwandev->ops_ctxt = ctxt; 998355a4e7eSSergey Ryazanov 999*ca374290SSergey Ryazanov /* NB: we do not abort ops registration in case of default link 1000*ca374290SSergey Ryazanov * creation failure. Link ops is the management interface, while the 1001*ca374290SSergey Ryazanov * default link creation is a service option. And we should not prevent 1002*ca374290SSergey Ryazanov * a user from manually creating a link latter if service option failed 1003*ca374290SSergey Ryazanov * now. 1004*ca374290SSergey Ryazanov */ 1005*ca374290SSergey Ryazanov if (def_link_id != WWAN_NO_DEFAULT_LINK) 1006*ca374290SSergey Ryazanov wwan_create_default_link(wwandev, def_link_id); 1007*ca374290SSergey Ryazanov 1008355a4e7eSSergey Ryazanov return 0; 1009355a4e7eSSergey Ryazanov } 1010355a4e7eSSergey Ryazanov EXPORT_SYMBOL_GPL(wwan_register_ops); 1011355a4e7eSSergey Ryazanov 10122f752380SSergey Ryazanov /* Enqueue child netdev deletion */ 10132f752380SSergey Ryazanov static int wwan_child_dellink(struct device *dev, void *data) 10142f752380SSergey Ryazanov { 10152f752380SSergey Ryazanov struct list_head *kill_list = data; 10162f752380SSergey Ryazanov 10172f752380SSergey Ryazanov if (dev->type == &wwan_type) 10182f752380SSergey Ryazanov wwan_rtnl_dellink(to_net_dev(dev), kill_list); 10192f752380SSergey Ryazanov 10202f752380SSergey Ryazanov return 0; 10212f752380SSergey Ryazanov } 10222f752380SSergey Ryazanov 1023355a4e7eSSergey Ryazanov /** 1024355a4e7eSSergey Ryazanov * wwan_unregister_ops - remove WWAN device ops 1025355a4e7eSSergey Ryazanov * @parent: Device to use as parent and shared by all WWAN ports and 1026355a4e7eSSergey Ryazanov * created netdevs 1027355a4e7eSSergey Ryazanov */ 1028355a4e7eSSergey Ryazanov void wwan_unregister_ops(struct device *parent) 1029355a4e7eSSergey Ryazanov { 1030355a4e7eSSergey Ryazanov struct wwan_device *wwandev = wwan_dev_get_by_parent(parent); 10312f752380SSergey Ryazanov LIST_HEAD(kill_list); 1032355a4e7eSSergey Ryazanov 1033355a4e7eSSergey Ryazanov if (WARN_ON(IS_ERR(wwandev))) 1034355a4e7eSSergey Ryazanov return; 10352f752380SSergey Ryazanov if (WARN_ON(!wwandev->ops)) { 10362f752380SSergey Ryazanov put_device(&wwandev->dev); 10372f752380SSergey Ryazanov return; 10382f752380SSergey Ryazanov } 1039355a4e7eSSergey Ryazanov 1040355a4e7eSSergey Ryazanov /* put the reference obtained by wwan_dev_get_by_parent(), 1041355a4e7eSSergey Ryazanov * we should still have one (that the owner is giving back 10422f752380SSergey Ryazanov * now) due to the ops being assigned. 1043355a4e7eSSergey Ryazanov */ 1044355a4e7eSSergey Ryazanov put_device(&wwandev->dev); 1045355a4e7eSSergey Ryazanov 10462f752380SSergey Ryazanov rtnl_lock(); /* Prevent concurent netdev(s) creation/destroying */ 1047355a4e7eSSergey Ryazanov 10482f752380SSergey Ryazanov /* Remove all child netdev(s), using batch removing */ 10492f752380SSergey Ryazanov device_for_each_child(&wwandev->dev, &kill_list, 10502f752380SSergey Ryazanov wwan_child_dellink); 10512f752380SSergey Ryazanov unregister_netdevice_many(&kill_list); 10522f752380SSergey Ryazanov 10532f752380SSergey Ryazanov wwandev->ops = NULL; /* Finally remove ops */ 10542f752380SSergey Ryazanov 10552f752380SSergey Ryazanov rtnl_unlock(); 10562f752380SSergey Ryazanov 1057355a4e7eSSergey Ryazanov wwandev->ops_ctxt = NULL; 1058355a4e7eSSergey Ryazanov wwan_remove_dev(wwandev); 1059355a4e7eSSergey Ryazanov } 1060355a4e7eSSergey Ryazanov EXPORT_SYMBOL_GPL(wwan_unregister_ops); 1061355a4e7eSSergey Ryazanov 10629a44c1ccSLoic Poulain static int __init wwan_init(void) 10639a44c1ccSLoic Poulain { 106488b71053SJohannes Berg int err; 106588b71053SJohannes Berg 106688b71053SJohannes Berg err = rtnl_link_register(&wwan_rtnl_link_ops); 106788b71053SJohannes Berg if (err) 106888b71053SJohannes Berg return err; 106988b71053SJohannes Berg 10709a44c1ccSLoic Poulain wwan_class = class_create(THIS_MODULE, "wwan"); 107188b71053SJohannes Berg if (IS_ERR(wwan_class)) { 107288b71053SJohannes Berg err = PTR_ERR(wwan_class); 107388b71053SJohannes Berg goto unregister; 107488b71053SJohannes Berg } 10759a44c1ccSLoic Poulain 10769a44c1ccSLoic Poulain /* chrdev used for wwan ports */ 107772eedfc4SSergey Ryazanov wwan_major = __register_chrdev(0, 0, WWAN_MAX_MINORS, "wwan_port", 107872eedfc4SSergey Ryazanov &wwan_port_fops); 10799a44c1ccSLoic Poulain if (wwan_major < 0) { 108088b71053SJohannes Berg err = wwan_major; 108188b71053SJohannes Berg goto destroy; 10829a44c1ccSLoic Poulain } 10839a44c1ccSLoic Poulain 10849a44c1ccSLoic Poulain return 0; 108588b71053SJohannes Berg 108688b71053SJohannes Berg destroy: 108788b71053SJohannes Berg class_destroy(wwan_class); 108888b71053SJohannes Berg unregister: 108988b71053SJohannes Berg rtnl_link_unregister(&wwan_rtnl_link_ops); 109088b71053SJohannes Berg return err; 10919a44c1ccSLoic Poulain } 10929a44c1ccSLoic Poulain 10939a44c1ccSLoic Poulain static void __exit wwan_exit(void) 10949a44c1ccSLoic Poulain { 109572eedfc4SSergey Ryazanov __unregister_chrdev(wwan_major, 0, WWAN_MAX_MINORS, "wwan_port"); 109688b71053SJohannes Berg rtnl_link_unregister(&wwan_rtnl_link_ops); 10979a44c1ccSLoic Poulain class_destroy(wwan_class); 10989a44c1ccSLoic Poulain } 10999a44c1ccSLoic Poulain 11009a44c1ccSLoic Poulain module_init(wwan_init); 11019a44c1ccSLoic Poulain module_exit(wwan_exit); 11029a44c1ccSLoic Poulain 11039a44c1ccSLoic Poulain MODULE_AUTHOR("Loic Poulain <loic.poulain@linaro.org>"); 11049a44c1ccSLoic Poulain MODULE_DESCRIPTION("WWAN core"); 11059a44c1ccSLoic Poulain MODULE_LICENSE("GPL v2"); 1106