// SPDX-License-Identifier: GPL-2.0
/*
* Thunderbolt driver - bus logic (NHI independent)
*
* Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
* Copyright (C) 2019, Intel Corporation
*/
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include "tb.h"
#include "tb_regs.h"
#include "tunnel.h"
/**
* struct tb_cm - Simple Thunderbolt connection manager
* @tunnel_list: List of active tunnels
* @dp_resources: List of available DP resources for DP tunneling
* @hotplug_active: tb_handle_hotplug will stop progressing plug
* events and exit if this is not set (it needs to
* acquire the lock one more time). Used to drain wq
* after cfg has been paused.
*/
struct tb_cm {
struct list_head tunnel_list;
struct list_head dp_resources;
bool hotplug_active;
};
struct tb_hotplug_event {
struct work_struct work;
struct tb *tb;
u64 route;
u8 port;
bool unplug;
};
static void tb_handle_hotplug(struct work_struct *work);
static void tb_queue_hotplug(struct tb *tb, u64 route, u8 port, bool unplug)
{
struct tb_hotplug_event *ev;
ev = kmalloc(sizeof(*ev), GFP_KERNEL);
if (!ev)
return;
ev->tb = tb;
ev->route = route;
ev->port = port;
ev->unplug = unplug;
INIT_WORK(&ev->work, tb_handle_hotplug);
queue_work(tb->wq, &ev->work);
}
/* enumeration & hot plug handling */
static void tb_add_dp_resources(struct tb_switch *sw)
{
struct tb_cm *tcm = tb_priv(sw->tb);
struct tb_port *port;
tb_switch_for_each_port(sw, port) {
if (!tb_port_is_dpin(port))
continue;
if (!tb_switch_query_dp_resource(sw, port))
continue;
list_add_tail(&port->list, &tcm->dp_resources);
tb_port_dbg(port, "DP IN resource available\n");
}
}
static void tb_remove_dp_resources(struct tb_switch *sw)
{
struct tb_cm *tcm