/* * tegra-nvlink.h: * This header contains the structures and APIs needed by Tegra NVLINK core and * endpoint drivers for interacting with each other. * * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef TEGRA_NVLINK_H #define TEGRA_NVLINK_H #include #define NVLINK_MAX_DEVICES 2 #define NVLINK_MAX_LINKS 2 #define DEFAULT_LOOP_SLEEP_US 100 #define DEFAULT_LOOP_TIMEOUT_US 1000000 #define LINK_BITRATE_150MHZ_16GBPS 15500000000ULL #define LINK_BITRATE_156MHZ_16GBPS 16145830000ULL #define LINK_BITRATE_150MHZ_20GBPS 19200000000ULL #define LINK_BITRATE_156MHZ_20GBPS 20001280000ULL struct nvlink_link; struct nvlink_device; enum nvlink_log_categories { nvlink_log_err = BIT(0), /* Error prints - these will be printed unconditionally */ nvlink_log_dbg = BIT(1), /* Debug prints */ }; #ifdef CONFIG_DEBUG_FS /* This is the root debugfs directory for the entire NVLINK driver stack */ extern struct dentry *nvlink_debugfs_root; /* This is the parent debugfs directory for NVLINK tests */ extern struct dentry *nvlink_debugfs_tests; #endif /* CONFIG_DEBUG_FS */ extern u32 nvlink_log_mask; #define NVLINK_DEFAULT_LOG_MASK nvlink_log_err #define nvlink_print(log_mask, fmt, arg...) \ do { \ if ((log_mask) & nvlink_log_mask) \ printk("%s: %s: %d: " fmt "\n", \ NVLINK_MODULE_NAME, \ __func__, \ __LINE__, \ ##arg); \ } while (0) #define nvlink_err(fmt, arg...) nvlink_print(nvlink_log_err, fmt, ##arg) #define nvlink_dbg(fmt, arg...) nvlink_print(nvlink_log_dbg, fmt, ##arg) /* Enum to represent link speed. Nvlink 2.0 can support below 2 speeds */ enum nvlink_speed { NVLINK_SPEED_16, NVLINK_SPEED_20 }; /* Enum nvlink_endpt will be used to initialize device ID in device struct */ enum nvlink_endpt { NVLINK_ENDPT_T19X, NVLINK_ENDPT_GV100 }; /* * Link modes are SW defined. Some modes map to HW link state, while some * falicitate transiting to a power state or off state. */ enum link_mode { NVLINK_LINK_OFF, NVLINK_LINK_HS, NVLINK_LINK_SAFE, NVLINK_LINK_FAULT, NVLINK_LINK_RCVY_AC, NVLINK_LINK_RCVY_SW, NVLINK_LINK_RCVY_RX, NVLINK_LINK_DETECT, NVLINK_LINK_RESET, NVLINK_LINK_ENABLE_PM, NVLINK_LINK_DISABLE_PM, NVLINK_LINK_DISABLE_ERR_DETECT, NVLINK_LINK_LANE_DISABLE, NVLINK_LINK_LANE_SHUTDOWN }; /* * TX_mode and RX_mode contains SW defined sublink modes. Some modes map to HW * sublink states while some are intermediate states needed for link training * and other sequences. */ enum tx_mode { NVLINK_TX_HS, NVLINK_TX_ENABLE_PM, NVLINK_TX_DISABLE_PM, NVLINK_TX_SINGLE_LANE, NVLINK_TX_SAFE, NVLINK_TX_OFF, NVLINK_TX_COMMON, NVLINK_TX_COMMON_DISABLE, NVLINK_TX_DATA_READY, NVLINK_TX_PRBS_EN, }; enum rx_mode { NVLINK_RX_HS, NVLINK_RX_ENABLE_PM, NVLINK_RX_DISABLE_PM, NVLINK_RX_SINGLE_LANE, NVLINK_RX_SAFE, NVLINK_RX_OFF, NVLINK_RX_RXCAL, }; /* * During nvlink device initialization, we use enum init_state to keep track of * what state we have reached. Based on the init state and the link mode, only * necessary steps will be executed. This allows us to call enumerate function * multiple times. * * NVLINK_DEV_OFF : The device is off and no part of nvlink controller hardware * is out of reset and clocked. * * NVLINK_DEV_EARLY_INIT_DONE: The clocks are up, all resets deasserted, the * minion has booted and device level interrupts are initialized. * * NVLINK_LINK_EARLY_INIT_DONE: The link level initialization is done like - * initialization of PHY, link interrupts and TLC buffers. * * NVLINK_DEV_INTERFACE_INIT_DONE: The memory interface is initialized. * * NVLINK_REG_INIT_DONE: The prod settings are incorporated. At this point * the link is ready to transition to safe mode and eventually to * High-Speed mode. */ enum init_state { NVLINK_DEV_OFF, NVLINK_DEV_EARLY_INIT_DONE, NVLINK_LINK_EARLY_INIT_DONE, NVLINK_DEV_INTERFACE_INIT_DONE, NVLINK_DEV_REG_INIT_DONE, NVLINK_INIT_STATE_INVALID }; /* * These callbacks should be registered with core-driver during link * registration. These link_ops allow core-driver to enquire/set link and * sublink modes. Some help during link initializatiion. * * TODO: Pass struct nvlink_link as argument to below link_ops instead of using * struct nvlink_device. All the link level readl/writel functions need to * use link struct instead of device struct for above change. */ struct link_operations { u32 (*get_link_mode)(struct nvlink_device *ndev); int (*set_link_mode)(struct nvlink_device *ndev, u32 mode); u32 (*get_sublink_mode)(struct nvlink_device *ndev, bool is_rx_sublink); int (*set_sublink_mode)(struct nvlink_device *ndev, bool is_rx_sublink, u32 mode); u32 (*get_link_state)(struct nvlink_device *ndev); void (*get_tx_sublink_state)(struct nvlink_device *ndev, u32 *tx_sublink_state); void (*get_rx_sublink_state)(struct nvlink_device *ndev, u32 *rx_sublink_state); int (*link_early_init)(struct nvlink_device *ndev); }; /* These dev_ops expose interface between the core driver and endpoint device */ struct device_operations { int (*dev_early_init)(struct nvlink_device *ndev); int (*dev_interface_init)(struct nvlink_device *ndev); int (*dev_reg_init)(struct nvlink_device *ndev); int (*dev_interface_disable)(struct nvlink_device *ndev); int (*dev_shutdown)(struct nvlink_device *ndev); }; struct nvlink_device_pci_info { u16 domain; u16 bus; u16 device; u16 function; u32 pci_device_id; }; /* * The core-driver maintains the topology information. We use remote_device_info * so that the endpoint driver can pass the topology information to the core * driver. */ struct remote_device_info { /* Device id of remote device connected */ enum nvlink_endpt device_id; /* Link id of the remote link connected */ u32 link_id; /* Information about device's PCI connection */ struct nvlink_device_pci_info pci_info; }; /* Structure representing the MINION ucode header */ struct minion_hdr { u32 os_code_offset; u32 os_code_size; u32 os_data_offset; u32 os_data_size; u32 num_apps; u32 *app_code_offsets; u32 *app_code_sizes; u32 *app_data_offsets; u32 *app_data_sizes; u32 ovl_offset; u32 ovl_size; u32 ucode_data_size; }; /* * nvlink_link struct stores all link specific data which is relevant * to core-driver. */ struct nvlink_link { /* * The link id is unique across the entire nvlink system. Same link_id * should not be used in different device structs. This is a HACK we * need while we hardcode the topology in device tree. * TODO: Add an enum for link_id like we have for device_id. */ u32 link_id; /* ID of the device that this link belongs to */ enum nvlink_endpt device_id; /* link mode TODO: Add locks to protect the link_mode changes */ enum link_mode mode; /* * is the link connected to an endpt. Useful for devices with multiple * links. Currenly unused on Tegra. * TODO: Set this before registering the link */ bool is_connected; /* Is single-lane mode supported for this link ? */ bool is_sl_supported; /* Pointer to device info of connected end point */ struct remote_device_info remote_dev_info; /* * Pointer to struct containing callback functions to do link specific * operation from core driver */ struct link_operations link_ops; /* Pointer to parent struct nvlink_device */ struct nvlink_device *ndev; /* Pointer to implementations specific private data */ void *priv; }; /* nvlink_device struct stores all device specific data. */ struct nvlink_device { /* device_id */ enum nvlink_endpt device_id; /* Information about device's PCI connection */ struct nvlink_device_pci_info pci_info; /* init state */ enum init_state init_state; /* Mutex to protect init_state access */ struct mutex init_state_mutex; /* * Only the master device can initiate enumeration and data transfer * on nvlink. bool to check this device is master. */ bool is_master; /* NVlink Speed */ enum nvlink_speed speed; /* The bitrate at which the link is operating */ u64 link_bitrate; /* MINION FW - contains both the ucode header and image */ const struct firmware *minion_fw; /* MINION ucode header */ struct minion_hdr minion_hdr; /* MINION ucode image */ const u8 *minion_img; /*nvlink link data. We assume there is single link per device*/ struct nvlink_link link; /* Pointer to struct containing callback functions to do device specific * operation from core driver */ struct device_operations dev_ops; /* pointer to private data of this device */ void *priv; }; /* APIs used by endpoint drivers for interfacing with the core driver */ void nvlink_print_topology(void); void __nvlink_dma_flush_area(const void *ptr, size_t size); int nvlink_register_device(struct nvlink_device* device); int nvlink_register_link(struct nvlink_link* link); int nvlink_unregister_device(struct nvlink_device* device); int nvlink_unregister_link(struct nvlink_link* link); int nvlink_get_init_state(struct nvlink_device *ndev, enum init_state *state); int nvlink_set_init_state(struct nvlink_device *ndev, enum init_state state); int nvlink_enumerate(struct nvlink_device *ndev); int nvlink_transition_intranode_conn_off_to_safe(struct nvlink_device *ndev); int nvlink_train_intranode_conn_safe_to_hs(struct nvlink_device *ndev); int nvlink_initialize_endpoint(struct nvlink_device *ndev); int nvlink_transition_intranode_conn_hs_to_safe(struct nvlink_device *ndev); int nvlink_shutdown(struct nvlink_device *ndev); #endif /* TEGRA_NVLINK_H */