/** * tb_retimer_nvm_read() - Read contents of retimer NVM * @rt: Retimer device * @address: NVM address (in bytes) to start reading * @buf: Data read from NVM is stored here * @size: Number of bytes to read * * Reads retimer NVM and copies the contents to @buf. Returns %0 if the * read was successful and negative errno in case of failure.
*/ int tb_retimer_nvm_read(struct tb_retimer *rt, unsignedint address, void *buf,
size_t size)
{ return usb4_port_retimer_nvm_read(rt->port, rt->index, address, buf, size);
}
if (auth_only) {
ret = usb4_port_retimer_nvm_set_offset(rt->port, rt->index, 0); if (ret) return ret;
}
ret = usb4_port_retimer_nvm_authenticate(rt->port, rt->index); if (ret) return ret;
usleep_range(100, 150);
/* * Check the status now if we still can access the retimer. It * is expected that the below fails.
*/
ret = usb4_port_retimer_nvm_authenticate_status(rt->port, rt->index,
&status); if (!ret) {
rt->auth_status = status; return status ? -EINVAL : 0;
}
if (!mutex_trylock(&rt->tb->lock)) return restart_syscall();
if (!rt->nvm)
ret = -EAGAIN; else
ret = sysfs_emit(buf, "%#x\n", rt->auth_status);
mutex_unlock(&rt->tb->lock);
return ret;
}
staticvoid tb_retimer_nvm_authenticate_status(struct tb_port *port, u32 *status)
{ int i;
tb_port_dbg(port, "reading NVM authentication status of retimers\n");
/* * Before doing anything else, read the authentication status. * If the retimer has it set, store it for the new retimer * device instance.
*/ for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++) { if (usb4_port_retimer_nvm_authenticate_status(port, i, &status[i])) break;
}
}
staticvoid tb_retimer_set_inbound_sbtx(struct tb_port *port)
{ int i;
/* * When USB4 port is online sideband communications are * already up.
*/ if (!usb4_port_device_is_offline(port->usb4)) return;
for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++)
usb4_port_retimer_set_inbound_sbtx(port, i);
}
staticvoid tb_retimer_unset_inbound_sbtx(struct tb_port *port)
{ int i;
/* * When USB4 port is offline we need to keep the sideband * communications up to make it possible to communicate with * the connected retimers.
*/ if (usb4_port_device_is_offline(port->usb4)) return;
if (!mutex_trylock(&rt->tb->lock)) {
ret = restart_syscall(); goto exit_rpm;
}
if (!rt->nvm) {
ret = -EAGAIN; goto exit_unlock;
}
ret = kstrtoint(buf, 10, &val); if (ret) goto exit_unlock;
/* Always clear status */
rt->auth_status = 0;
if (val) { /* * When NVM authentication starts the retimer is not * accessible so calling tb_retimer_unset_inbound_sbtx() * will fail and therefore we do not call it. Exception * is when the validation fails or we only write the new * NVM image without authentication.
*/
tb_retimer_set_inbound_sbtx(rt->port); if (val == AUTHENTICATE_ONLY) {
ret = tb_retimer_nvm_authenticate(rt, true);
} else { if (!rt->nvm->flushed) { if (!rt->nvm->buf) {
ret = -EINVAL; goto exit_unlock;
}
ret = tb_retimer_nvm_validate_and_write(rt); if (ret || val == WRITE_ONLY) goto exit_unlock;
} if (val == WRITE_AND_AUTHENTICATE)
ret = tb_retimer_nvm_authenticate(rt, false);
}
}
exit_unlock: if (ret || val == WRITE_ONLY)
tb_retimer_unset_inbound_sbtx(rt->port);
mutex_unlock(&rt->tb->lock);
exit_rpm:
pm_runtime_mark_last_busy(&rt->dev);
pm_runtime_put_autosuspend(&rt->dev);
if (ret) return ret; return count;
} static DEVICE_ATTR_RW(nvm_authenticate);
/* * Only support NVM upgrade for on-board retimers. The retimers * on the other side of the connection.
*/ if (!on_board || usb4_port_retimer_nvm_sector_size(port, index) <= 0)
rt->no_nvm_upgrade = true;
dev = device_find_child(&port->usb4->dev, &lookup, retimer_match); if (dev) return tb_to_retimer(dev);
return NULL;
}
/** * tb_retimer_scan() - Scan for on-board retimers under port * @port: USB4 port to scan * @add: If true also registers found retimers * * Brings the sideband into a state where retimers can be accessed. * Then Tries to enumerate on-board retimers connected to @port. Found * retimers are registered as children of @port if @add is set. Does * not scan for cable retimers for now.
*/ int tb_retimer_scan(struct tb_port *port, bool add)
{
u32 status[TB_MAX_RETIMER_INDEX + 1] = {}; int ret, i, max, last_idx = 0;
/* * Send broadcast RT to make sure retimer indices facing this * port are set.
*/
ret = usb4_port_enumerate_retimers(port); if (ret) return ret;
/* * Immediately after sending enumerate retimers read the * authentication status of each retimer.
*/
tb_retimer_nvm_authenticate_status(port, status);
/* * Enable sideband channel for each retimer. We can do this * regardless whether there is device connected or not.
*/
tb_retimer_set_inbound_sbtx(port);
for (max = 1, i = 1; i <= TB_MAX_RETIMER_INDEX; i++) { /* * Last retimer is true only for the last on-board * retimer (the one connected directly to the Type-C * port).
*/
ret = usb4_port_retimer_is_last(port, i); if (ret > 0)
last_idx = i; elseif (ret < 0) break;
max = i;
}
ret = 0; if (!IS_ENABLED(CONFIG_USB4_DEBUGFS_MARGINING))
max = min(last_idx, max);
/* Add retimers if they do not exist already */ for (i = 1; i <= max; i++) { struct tb_retimer *rt;
/* Skip cable retimers */ if (usb4_port_retimer_is_cable(port, i)) continue;
rt = tb_port_find_retimer(port, i); if (rt) {
put_device(&rt->dev);
} elseif (add) {
ret = tb_retimer_add(port, i, status[i], i <= last_idx); if (ret && ret != -EOPNOTSUPP) break;
}
}
if (rt && rt->port == port)
tb_retimer_remove(rt); return 0;
}
/** * tb_retimer_remove_all() - Remove all retimers under port * @port: USB4 port whose retimers to remove * * This removes all previously added retimers under @port.
*/ void tb_retimer_remove_all(struct tb_port *port)
{ struct usb4_port *usb4;
usb4 = port->usb4; if (usb4)
device_for_each_child_reverse(&usb4->dev, port,
remove_retimer);
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
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.