#define DMA_PORT_TIMEOUT 5000 /* ms */ #define DMA_PORT_RETRIES 3
/** * 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 { struct tb_switch *sw;
u8 port;
u32 base;
u8 *buf;
};
/* * When the switch is in safe mode it supports very little functionality * so we don't validate that much here.
*/ staticbool dma_port_match(conststruct tb_cfg_request *req, conststruct ctl_pkg *pkg)
{
u64 route = tb_cfg_get_route(pkg->buffer) & ~BIT_ULL(63);
if (pkg->frame.eof == TB_CFG_PKG_ERROR) returntrue; if (pkg->frame.eof != req->response_type) returnfalse; if (route != tb_cfg_get_route(req->request)) returnfalse; if (pkg->frame.size != req->response_size) returnfalse;
/* * The DMA (NHI) port is either 3, 5 or 7 depending on the * controller. Try all of them.
*/ for (i = 0; i < ARRAY_SIZE(ports); i++) {
u32 type; int ret;
ret = dma_port_read(sw->tb->ctl, &type, tb_route(sw), ports[i],
2, 1, DMA_PORT_TIMEOUT); if (!ret && (type & 0xffffff) == TB_TYPE_NHI) return ports[i];
}
return -ENODEV;
}
/** * 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)
{ struct tb_dma_port *dma; int port;
port = dma_find_port(sw); if (port < 0) return NULL;
dma = kzalloc(sizeof(*dma), GFP_KERNEL); if (!dma) return NULL;
/* Write the block to MAIL_DATA registers */
ret = dma_port_write(sw->tb->ctl, buf, tb_route(sw), dma->port,
dma->base + MAIL_DATA, dwords, DMA_PORT_TIMEOUT); if (ret) return ret;
in = MAIL_IN_CMD_FLASH_WRITE << MAIL_IN_CMD_SHIFT;
/* CSS header write is always done to the same magic address */ if (dwaddress >= DMA_PORT_CSS_ADDRESS)
in |= MAIL_IN_CSS;
in |= ((dwords - 1) << MAIL_IN_DWORDS_SHIFT) & MAIL_IN_DWORDS_MASK;
in |= (dwaddress << MAIL_IN_ADDRESS_SHIFT) & MAIL_IN_ADDRESS_MASK;
in |= MAIL_IN_OP_REQUEST;
return dma_port_request(dma, in, DMA_PORT_TIMEOUT);
}
/** * 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, unsignedint address, void *buf, size_t size)
{ return tb_nvm_read_data(address, buf, size, DMA_PORT_RETRIES,
dma_port_flash_read_block, dma);
}
/** * 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, unsignedint address, constvoid *buf, size_t size)
{ if (address >= DMA_PORT_CSS_ADDRESS && size > DMA_PORT_CSS_MAX_SIZE) return -E2BIG;
/** * 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)
{
u32 in;
in = MAIL_IN_CMD_FLASH_UPDATE_AUTH << MAIL_IN_CMD_SHIFT;
in |= MAIL_IN_OP_REQUEST;
return dma_port_request(dma, in, 150);
}
/** * 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)
{ struct tb_switch *sw = dma->sw;
u32 out, cmd; int ret;
ret = dma_port_read(sw->tb->ctl, &out, tb_route(sw), dma->port,
dma->base + MAIL_OUT, 1, DMA_PORT_TIMEOUT); if (ret) return ret;
/* Check if the status relates to flash update auth */
cmd = (out & MAIL_OUT_STATUS_CMD_MASK) >> MAIL_OUT_STATUS_CMD_SHIFT; if (cmd == MAIL_IN_CMD_FLASH_UPDATE_AUTH) { if (status)
*status = out & MAIL_OUT_STATUS_MASK;
/* Reset is needed in any case */ return 1;
}
return 0;
}
/** * 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)
{
u32 in;
in = MAIL_IN_CMD_POWER_CYCLE << MAIL_IN_CMD_SHIFT;
in |= MAIL_IN_OP_REQUEST;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.