linux/drivers/thunderbolt/icm.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Internal Thunderbolt Connection Manager. This is a firmware running on
 * the Thunderbolt host controller performing most of the low-level
 * handling.
 *
 * Copyright (C) 2017, Intel Corporation
 * Authors: Michael Jamet <[email protected]>
 *          Mika Westerberg <[email protected]>
 */

#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/platform_data/x86/apple.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/workqueue.h>

#include "ctl.h"
#include "nhi_regs.h"
#include "tb.h"

#define PCIE2CIO_CMD
#define PCIE2CIO_CMD_TIMEOUT
#define PCIE2CIO_CMD_START
#define PCIE2CIO_CMD_WRITE
#define PCIE2CIO_CMD_CS_MASK
#define PCIE2CIO_CMD_CS_SHIFT
#define PCIE2CIO_CMD_PORT_MASK
#define PCIE2CIO_CMD_PORT_SHIFT

#define PCIE2CIO_WRDATA
#define PCIE2CIO_RDDATA

#define PHY_PORT_CS1
#define PHY_PORT_CS1_LINK_DISABLE
#define PHY_PORT_CS1_LINK_STATE_MASK
#define PHY_PORT_CS1_LINK_STATE_SHIFT

#define ICM_TIMEOUT
#define ICM_RETRIES
#define ICM_APPROVE_TIMEOUT
#define ICM_MAX_LINK

static bool start_icm;
module_param(start_icm, bool, 0444);
MODULE_PARM_DESC();

/**
 * struct usb4_switch_nvm_auth - Holds USB4 NVM_AUTH status
 * @reply: Reply from ICM firmware is placed here
 * @request: Request that is sent to ICM firmware
 * @icm: Pointer to ICM private data
 */
struct usb4_switch_nvm_auth {};

/**
 * struct icm - Internal connection manager private data
 * @request_lock: Makes sure only one message is send to ICM at time
 * @rescan_work: Work used to rescan the surviving switches after resume
 * @upstream_port: Pointer to the PCIe upstream port this host
 *		   controller is connected. This is only set for systems
 *		   where ICM needs to be started manually
 * @vnd_cap: Vendor defined capability where PCIe2CIO mailbox resides
 *	     (only set when @upstream_port is not %NULL)
 * @safe_mode: ICM is in safe mode
 * @max_boot_acl: Maximum number of preboot ACL entries (%0 if not supported)
 * @rpm: Does the controller support runtime PM (RTD3)
 * @can_upgrade_nvm: Can the NVM firmware be upgrade on this controller
 * @proto_version: Firmware protocol version
 * @last_nvm_auth: Last USB4 router NVM_AUTH result (or %NULL if not set)
 * @veto: Is RTD3 veto in effect
 * @is_supported: Checks if we can support ICM on this controller
 * @cio_reset: Trigger CIO reset
 * @get_mode: Read and return the ICM firmware mode (optional)
 * @get_route: Find a route string for given switch
 * @save_devices: Ask ICM to save devices to ACL when suspending (optional)
 * @driver_ready: Send driver ready message to ICM
 * @set_uuid: Set UUID for the root switch (optional)
 * @device_connected: Handle device connected ICM message
 * @device_disconnected: Handle device disconnected ICM message
 * @xdomain_connected: Handle XDomain connected ICM message
 * @xdomain_disconnected: Handle XDomain disconnected ICM message
 * @rtd3_veto: Handle RTD3 veto notification ICM message
 */
struct icm {};

struct icm_notification {};

struct ep_name_entry {};

#define EP_NAME_INTEL_VSS

/* Intel Vendor specific structure */
struct intel_vss {};

#define INTEL_VSS_FLAGS_RTD3

static const struct intel_vss *parse_intel_vss(const void *ep_name, size_t size)
{}

static bool intel_vss_is_rtd3(const void *ep_name, size_t size)
{}

static inline struct tb *icm_to_tb(struct icm *icm)
{}

static inline u8 phy_port_from_route(u64 route, u8 depth)
{}

static inline u8 dual_link_from_link(u8 link)
{}

static inline u64 get_route(u32 route_hi, u32 route_lo)
{}

static inline u64 get_parent_route(u64 route)
{}

static int pci2cio_wait_completion(struct icm *icm, unsigned long timeout_msec)
{}

static int pcie2cio_read(struct icm *icm, enum tb_cfg_space cs,
			 unsigned int port, unsigned int index, u32 *data)
{}

static int pcie2cio_write(struct icm *icm, enum tb_cfg_space cs,
			  unsigned int port, unsigned int index, u32 data)
{}

static bool icm_match(const struct tb_cfg_request *req,
		      const struct ctl_pkg *pkg)
{}

static bool icm_copy(struct tb_cfg_request *req, const struct ctl_pkg *pkg)
{}

static int icm_request(struct tb *tb, const void *request, size_t request_size,
		       void *response, size_t response_size, size_t npackets,
		       int retries, unsigned int timeout_msec)
{}

/*
 * If rescan is queued to run (we are resuming), postpone it to give the
 * firmware some more time to send device connected notifications for next
 * devices in the chain.
 */
static void icm_postpone_rescan(struct tb *tb)
{}

static void icm_veto_begin(struct tb *tb)
{}

static void icm_veto_end(struct tb *tb)
{}

static bool icm_firmware_running(const struct tb_nhi *nhi)
{}

static bool icm_fr_is_supported(struct tb *tb)
{}

static inline int icm_fr_get_switch_index(u32 port)
{}

static int icm_fr_get_route(struct tb *tb, u8 link, u8 depth, u64 *route)
{}

static void icm_fr_save_devices(struct tb *tb)
{}

static int
icm_fr_driver_ready(struct tb *tb, enum tb_security_level *security_level,
		    u8 *proto_version, size_t *nboot_acl, bool *rpm)
{}

static int icm_fr_approve_switch(struct tb *tb, struct tb_switch *sw)
{}

static int icm_fr_add_switch_key(struct tb *tb, struct tb_switch *sw)
{}

static int icm_fr_challenge_switch_key(struct tb *tb, struct tb_switch *sw,
				       const u8 *challenge, u8 *response)
{}

static int icm_fr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
					int transmit_path, int transmit_ring,
					int receive_path, int receive_ring)
{}

static int icm_fr_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
					   int transmit_path, int transmit_ring,
					   int receive_path, int receive_ring)
{}

static struct tb_switch *alloc_switch(struct tb_switch *parent_sw, u64 route,
				      const uuid_t *uuid)
{}

static int add_switch(struct tb_switch *parent_sw, struct tb_switch *sw)
{}

static void update_switch(struct tb_switch *sw, u64 route, u8 connection_id,
			  u8 connection_key, u8 link, u8 depth, bool boot)
{}

static void remove_switch(struct tb_switch *sw)
{}

static void add_xdomain(struct tb_switch *sw, u64 route,
			const uuid_t *local_uuid, const uuid_t *remote_uuid,
			u8 link, u8 depth)
{}

static void update_xdomain(struct tb_xdomain *xd, u64 route, u8 link)
{}

static void remove_xdomain(struct tb_xdomain *xd)
{}

static void
icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
{}

static void
icm_fr_device_disconnected(struct tb *tb, const struct icm_pkg_header *hdr)
{}

static void
icm_fr_xdomain_connected(struct tb *tb, const struct icm_pkg_header *hdr)
{}

static void
icm_fr_xdomain_disconnected(struct tb *tb, const struct icm_pkg_header *hdr)
{}

static int icm_tr_cio_reset(struct tb *tb)
{}

static int
icm_tr_driver_ready(struct tb *tb, enum tb_security_level *security_level,
		    u8 *proto_version, size_t *nboot_acl, bool *rpm)
{}

static int icm_tr_approve_switch(struct tb *tb, struct tb_switch *sw)
{}

static int icm_tr_add_switch_key(struct tb *tb, struct tb_switch *sw)
{}

static int icm_tr_challenge_switch_key(struct tb *tb, struct tb_switch *sw,
				       const u8 *challenge, u8 *response)
{}

static int icm_tr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
					int transmit_path, int transmit_ring,
					int receive_path, int receive_ring)
{}

static int icm_tr_xdomain_tear_down(struct tb *tb, struct tb_xdomain *xd,
				    int stage)
{}

static int icm_tr_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
					   int transmit_path, int transmit_ring,
					   int receive_path, int receive_ring)
{}

static void
__icm_tr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr,
			  bool force_rtd3)
{}

static void
icm_tr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
{}

static void
icm_tr_device_disconnected(struct tb *tb, const struct icm_pkg_header *hdr)
{}

static void
icm_tr_xdomain_connected(struct tb *tb, const struct icm_pkg_header *hdr)
{}

static void
icm_tr_xdomain_disconnected(struct tb *tb, const struct icm_pkg_header *hdr)
{}

static struct pci_dev *get_upstream_port(struct pci_dev *pdev)
{}

static bool icm_ar_is_supported(struct tb *tb)
{}

static int icm_ar_cio_reset(struct tb *tb)
{}

static int icm_ar_get_mode(struct tb *tb)
{}

static int
icm_ar_driver_ready(struct tb *tb, enum tb_security_level *security_level,
		    u8 *proto_version, size_t *nboot_acl, bool *rpm)
{}

static int icm_ar_get_route(struct tb *tb, u8 link, u8 depth, u64 *route)
{}

static int icm_ar_get_boot_acl(struct tb *tb, uuid_t *uuids, size_t nuuids)
{}

static int icm_ar_set_boot_acl(struct tb *tb, const uuid_t *uuids,
			       size_t nuuids)
{}

static int
icm_icl_driver_ready(struct tb *tb, enum tb_security_level *security_level,
		     u8 *proto_version, size_t *nboot_acl, bool *rpm)
{}

static void icm_icl_set_uuid(struct tb *tb)
{}

static void
icm_icl_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
{}

static void icm_icl_rtd3_veto(struct tb *tb, const struct icm_pkg_header *hdr)
{}

static bool icm_tgl_is_supported(struct tb *tb)
{}

static void icm_handle_notification(struct work_struct *work)
{}

static void icm_handle_event(struct tb *tb, enum tb_cfg_pkg_type type,
			     const void *buf, size_t size)
{}

static int
__icm_driver_ready(struct tb *tb, enum tb_security_level *security_level,
		   u8 *proto_version, size_t *nboot_acl, bool *rpm)
{}

static int icm_firmware_reset(struct tb *tb, struct tb_nhi *nhi)
{}

static int icm_firmware_start(struct tb *tb, struct tb_nhi *nhi)
{}

static int icm_reset_phy_port(struct tb *tb, int phy_port)
{}

static int icm_firmware_init(struct tb *tb)
{}

static int icm_driver_ready(struct tb *tb)
{}

static int icm_suspend(struct tb *tb)
{}

/*
 * Mark all switches (except root switch) below this one unplugged. ICM
 * firmware will send us an updated list of switches after we have send
 * it driver ready command. If a switch is not in that list it will be
 * removed when we perform rescan.
 */
static void icm_unplug_children(struct tb_switch *sw)
{}

static int complete_rpm(struct device *dev, void *data)
{}

static void remove_unplugged_switch(struct tb_switch *sw)
{}

static void icm_free_unplugged_children(struct tb_switch *sw)
{}

static void icm_rescan_work(struct work_struct *work)
{}

static void icm_complete(struct tb *tb)
{}

static int icm_runtime_suspend(struct tb *tb)
{}

static int icm_runtime_suspend_switch(struct tb_switch *sw)
{}

static int icm_runtime_resume_switch(struct tb_switch *sw)
{}

static int icm_runtime_resume(struct tb *tb)
{}

static int icm_start(struct tb *tb, bool not_used)
{}

static void icm_stop(struct tb *tb)
{}

static int icm_disconnect_pcie_paths(struct tb *tb)
{}

static void icm_usb4_switch_nvm_auth_complete(void *data)
{}

static int icm_usb4_switch_nvm_authenticate(struct tb *tb, u64 route)
{}

static int icm_usb4_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata,
			      u8 *status, const void *tx_data, size_t tx_data_len,
			      void *rx_data, size_t rx_data_len)
{}

static int icm_usb4_switch_nvm_authenticate_status(struct tb_switch *sw,
						   u32 *status)
{}

/* Falcon Ridge */
static const struct tb_cm_ops icm_fr_ops =;

/* Alpine Ridge */
static const struct tb_cm_ops icm_ar_ops =;

/* Titan Ridge */
static const struct tb_cm_ops icm_tr_ops =;

/* Ice Lake */
static const struct tb_cm_ops icm_icl_ops =;

struct tb *icm_probe(struct tb_nhi *nhi)
{}