linux/drivers/thunderbolt/usb4_port.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * USB4 port device
   4 *
   5 * Copyright (C) 2021, Intel Corporation
   6 * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
   7 */
   8
   9#include <linux/pm_runtime.h>
  10
  11#include "tb.h"
  12
  13static ssize_t link_show(struct device *dev, struct device_attribute *attr,
  14                         char *buf)
  15{
  16        struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
  17        struct tb_port *port = usb4->port;
  18        struct tb *tb = port->sw->tb;
  19        const char *link;
  20
  21        if (mutex_lock_interruptible(&tb->lock))
  22                return -ERESTARTSYS;
  23
  24        if (tb_is_upstream_port(port))
  25                link = port->sw->link_usb4 ? "usb4" : "tbt";
  26        else if (tb_port_has_remote(port))
  27                link = port->remote->sw->link_usb4 ? "usb4" : "tbt";
  28        else
  29                link = "none";
  30
  31        mutex_unlock(&tb->lock);
  32
  33        return sysfs_emit(buf, "%s\n", link);
  34}
  35static DEVICE_ATTR_RO(link);
  36
  37static struct attribute *common_attrs[] = {
  38        &dev_attr_link.attr,
  39        NULL
  40};
  41
  42static const struct attribute_group common_group = {
  43        .attrs = common_attrs,
  44};
  45
  46static int usb4_port_offline(struct usb4_port *usb4)
  47{
  48        struct tb_port *port = usb4->port;
  49        int ret;
  50
  51        ret = tb_acpi_power_on_retimers(port);
  52        if (ret)
  53                return ret;
  54
  55        ret = usb4_port_router_offline(port);
  56        if (ret) {
  57                tb_acpi_power_off_retimers(port);
  58                return ret;
  59        }
  60
  61        ret = tb_retimer_scan(port, false);
  62        if (ret) {
  63                usb4_port_router_online(port);
  64                tb_acpi_power_off_retimers(port);
  65        }
  66
  67        return ret;
  68}
  69
  70static void usb4_port_online(struct usb4_port *usb4)
  71{
  72        struct tb_port *port = usb4->port;
  73
  74        usb4_port_router_online(port);
  75        tb_acpi_power_off_retimers(port);
  76}
  77
  78static ssize_t offline_show(struct device *dev,
  79        struct device_attribute *attr, char *buf)
  80{
  81        struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
  82
  83        return sysfs_emit(buf, "%d\n", usb4->offline);
  84}
  85
  86static ssize_t offline_store(struct device *dev,
  87        struct device_attribute *attr, const char *buf, size_t count)
  88{
  89        struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
  90        struct tb_port *port = usb4->port;
  91        struct tb *tb = port->sw->tb;
  92        bool val;
  93        int ret;
  94
  95        ret = kstrtobool(buf, &val);
  96        if (ret)
  97                return ret;
  98
  99        pm_runtime_get_sync(&usb4->dev);
 100
 101        if (mutex_lock_interruptible(&tb->lock)) {
 102                ret = -ERESTARTSYS;
 103                goto out_rpm;
 104        }
 105
 106        if (val == usb4->offline)
 107                goto out_unlock;
 108
 109        /* Offline mode works only for ports that are not connected */
 110        if (tb_port_has_remote(port)) {
 111                ret = -EBUSY;
 112                goto out_unlock;
 113        }
 114
 115        if (val) {
 116                ret = usb4_port_offline(usb4);
 117                if (ret)
 118                        goto out_unlock;
 119        } else {
 120                usb4_port_online(usb4);
 121                tb_retimer_remove_all(port);
 122        }
 123
 124        usb4->offline = val;
 125        tb_port_dbg(port, "%s offline mode\n", val ? "enter" : "exit");
 126
 127out_unlock:
 128        mutex_unlock(&tb->lock);
 129out_rpm:
 130        pm_runtime_mark_last_busy(&usb4->dev);
 131        pm_runtime_put_autosuspend(&usb4->dev);
 132
 133        return ret ? ret : count;
 134}
 135static DEVICE_ATTR_RW(offline);
 136
 137static ssize_t rescan_store(struct device *dev,
 138        struct device_attribute *attr, const char *buf, size_t count)
 139{
 140        struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
 141        struct tb_port *port = usb4->port;
 142        struct tb *tb = port->sw->tb;
 143        bool val;
 144        int ret;
 145
 146        ret = kstrtobool(buf, &val);
 147        if (ret)
 148                return ret;
 149
 150        if (!val)
 151                return count;
 152
 153        pm_runtime_get_sync(&usb4->dev);
 154
 155        if (mutex_lock_interruptible(&tb->lock)) {
 156                ret = -ERESTARTSYS;
 157                goto out_rpm;
 158        }
 159
 160        /* Must be in offline mode already */
 161        if (!usb4->offline) {
 162                ret = -EINVAL;
 163                goto out_unlock;
 164        }
 165
 166        tb_retimer_remove_all(port);
 167        ret = tb_retimer_scan(port, true);
 168
 169out_unlock:
 170        mutex_unlock(&tb->lock);
 171out_rpm:
 172        pm_runtime_mark_last_busy(&usb4->dev);
 173        pm_runtime_put_autosuspend(&usb4->dev);
 174
 175        return ret ? ret : count;
 176}
 177static DEVICE_ATTR_WO(rescan);
 178
 179static struct attribute *service_attrs[] = {
 180        &dev_attr_offline.attr,
 181        &dev_attr_rescan.attr,
 182        NULL
 183};
 184
 185static umode_t service_attr_is_visible(struct kobject *kobj,
 186                                       struct attribute *attr, int n)
 187{
 188        struct device *dev = kobj_to_dev(kobj);
 189        struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
 190
 191        /*
 192         * Always need some platform help to cycle the modes so that
 193         * retimers can be accessed through the sideband.
 194         */
 195        return usb4->can_offline ? attr->mode : 0;
 196}
 197
 198static const struct attribute_group service_group = {
 199        .attrs = service_attrs,
 200        .is_visible = service_attr_is_visible,
 201};
 202
 203static const struct attribute_group *usb4_port_device_groups[] = {
 204        &common_group,
 205        &service_group,
 206        NULL
 207};
 208
 209static void usb4_port_device_release(struct device *dev)
 210{
 211        struct usb4_port *usb4 = container_of(dev, struct usb4_port, dev);
 212
 213        kfree(usb4);
 214}
 215
 216struct device_type usb4_port_device_type = {
 217        .name = "usb4_port",
 218        .groups = usb4_port_device_groups,
 219        .release = usb4_port_device_release,
 220};
 221
 222/**
 223 * usb4_port_device_add() - Add USB4 port device
 224 * @port: Lane 0 adapter port to add the USB4 port
 225 *
 226 * Creates and registers a USB4 port device for @port. Returns the new
 227 * USB4 port device pointer or ERR_PTR() in case of error.
 228 */
 229struct usb4_port *usb4_port_device_add(struct tb_port *port)
 230{
 231        struct usb4_port *usb4;
 232        int ret;
 233
 234        usb4 = kzalloc(sizeof(*usb4), GFP_KERNEL);
 235        if (!usb4)
 236                return ERR_PTR(-ENOMEM);
 237
 238        usb4->port = port;
 239        usb4->dev.type = &usb4_port_device_type;
 240        usb4->dev.parent = &port->sw->dev;
 241        dev_set_name(&usb4->dev, "usb4_port%d", port->port);
 242
 243        ret = device_register(&usb4->dev);
 244        if (ret) {
 245                put_device(&usb4->dev);
 246                return ERR_PTR(ret);
 247        }
 248
 249        pm_runtime_no_callbacks(&usb4->dev);
 250        pm_runtime_set_active(&usb4->dev);
 251        pm_runtime_enable(&usb4->dev);
 252        pm_runtime_set_autosuspend_delay(&usb4->dev, TB_AUTOSUSPEND_DELAY);
 253        pm_runtime_mark_last_busy(&usb4->dev);
 254        pm_runtime_use_autosuspend(&usb4->dev);
 255
 256        return usb4;
 257}
 258
 259/**
 260 * usb4_port_device_remove() - Removes USB4 port device
 261 * @usb4: USB4 port device
 262 *
 263 * Unregisters the USB4 port device from the system. The device will be
 264 * released when the last reference is dropped.
 265 */
 266void usb4_port_device_remove(struct usb4_port *usb4)
 267{
 268        device_unregister(&usb4->dev);
 269}
 270
 271/**
 272 * usb4_port_device_resume() - Resumes USB4 port device
 273 * @usb4: USB4 port device
 274 *
 275 * Used to resume USB4 port device after sleep state.
 276 */
 277int usb4_port_device_resume(struct usb4_port *usb4)
 278{
 279        return usb4->offline ? usb4_port_offline(usb4) : 0;
 280}
 281