// SPDX-License-Identifier: GPL-2.0 /* * Thunderbolt DMA configuration based mailbox support * * Copyright (C) 2017, Intel Corporation * Authors: Michael Jamet <[email protected]> * Mika Westerberg <[email protected]> */ #include <linux/delay.h> #include <linux/slab.h> #include "dma_port.h" #include "tb_regs.h" #define DMA_PORT_CAP … #define MAIL_DATA … #define MAIL_DATA_DWORDS … #define MAIL_IN … #define MAIL_IN_CMD_SHIFT … #define MAIL_IN_CMD_MASK … #define MAIL_IN_CMD_FLASH_WRITE … #define MAIL_IN_CMD_FLASH_UPDATE_AUTH … #define MAIL_IN_CMD_FLASH_READ … #define MAIL_IN_CMD_POWER_CYCLE … #define MAIL_IN_DWORDS_SHIFT … #define MAIL_IN_DWORDS_MASK … #define MAIL_IN_ADDRESS_SHIFT … #define MAIL_IN_ADDRESS_MASK … #define MAIL_IN_CSS … #define MAIL_IN_OP_REQUEST … #define MAIL_OUT … #define MAIL_OUT_STATUS_RESPONSE … #define MAIL_OUT_STATUS_CMD_SHIFT … #define MAIL_OUT_STATUS_CMD_MASK … #define MAIL_OUT_STATUS_MASK … #define MAIL_OUT_STATUS_COMPLETED … #define MAIL_OUT_STATUS_ERR_AUTH … #define MAIL_OUT_STATUS_ERR_ACCESS … #define DMA_PORT_TIMEOUT … #define DMA_PORT_RETRIES … /** * struct tb_dma_port - DMA control port * @sw: Switch the DMA port belongs to * @port: Switch port number where DMA capability is found * @base: Start offset of the mailbox registers * @buf: Temporary buffer to store a single block */ struct tb_dma_port { … }; /* * When the switch is in safe mode it supports very little functionality * so we don't validate that much here. */ static bool dma_port_match(const struct tb_cfg_request *req, const struct ctl_pkg *pkg) { … } static bool dma_port_copy(struct tb_cfg_request *req, const struct ctl_pkg *pkg) { … } static int dma_port_read(struct tb_ctl *ctl, void *buffer, u64 route, u32 port, u32 offset, u32 length, int timeout_msec) { … } static int dma_port_write(struct tb_ctl *ctl, const void *buffer, u64 route, u32 port, u32 offset, u32 length, int timeout_msec) { … } static int dma_find_port(struct tb_switch *sw) { … } /** * dma_port_alloc() - Finds DMA control port from a switch pointed by route * @sw: Switch from where find the DMA port * * Function checks if the switch NHI port supports DMA configuration * based mailbox capability and if it does, allocates and initializes * DMA port structure. Returns %NULL if the capabity was not found. * * The DMA control port is functional also when the switch is in safe * mode. */ struct tb_dma_port *dma_port_alloc(struct tb_switch *sw) { … } /** * dma_port_free() - Release DMA control port structure * @dma: DMA control port */ void dma_port_free(struct tb_dma_port *dma) { … } static int dma_port_wait_for_completion(struct tb_dma_port *dma, unsigned int timeout) { … } static int status_to_errno(u32 status) { … } static int dma_port_request(struct tb_dma_port *dma, u32 in, unsigned int timeout) { … } static int dma_port_flash_read_block(void *data, unsigned int dwaddress, void *buf, size_t dwords) { … } static int dma_port_flash_write_block(void *data, unsigned int dwaddress, const void *buf, size_t dwords) { … } /** * dma_port_flash_read() - Read from active flash region * @dma: DMA control port * @address: Address relative to the start of active region * @buf: Buffer where the data is read * @size: Size of the buffer */ int dma_port_flash_read(struct tb_dma_port *dma, unsigned int address, void *buf, size_t size) { … } /** * dma_port_flash_write() - Write to non-active flash region * @dma: DMA control port * @address: Address relative to the start of non-active region * @buf: Data to write * @size: Size of the buffer * * Writes block of data to the non-active flash region of the switch. If * the address is given as %DMA_PORT_CSS_ADDRESS the block is written * using CSS command. */ int dma_port_flash_write(struct tb_dma_port *dma, unsigned int address, const void *buf, size_t size) { … } /** * dma_port_flash_update_auth() - Starts flash authenticate cycle * @dma: DMA control port * * Starts the flash update authentication cycle. If the image in the * non-active area was valid, the switch starts upgrade process where * active and non-active area get swapped in the end. Caller should call * dma_port_flash_update_auth_status() to get status of this command. * This is because if the switch in question is root switch the * thunderbolt host controller gets reset as well. */ int dma_port_flash_update_auth(struct tb_dma_port *dma) { … } /** * dma_port_flash_update_auth_status() - Reads status of update auth command * @dma: DMA control port * @status: Status code of the operation * * The function checks if there is status available from the last update * auth command. Returns %0 if there is no status and no further * action is required. If there is status, %1 is returned instead and * @status holds the failure code. * * Negative return means there was an error reading status from the * switch. */ int dma_port_flash_update_auth_status(struct tb_dma_port *dma, u32 *status) { … } /** * dma_port_power_cycle() - Power cycles the switch * @dma: DMA control port * * Triggers power cycle to the switch. */ int dma_port_power_cycle(struct tb_dma_port *dma) { … }