firehose: Improve startup time significantly

The firehose_read() at the start of firehose_run() serves the purpose of
waiting for the programmer to show up and to consume any <log/> messages
spat out, so that we're ready to invoke the <configure/>.

On MSM8916 there are no <log/> entries, so this is a 5 second loop
hitting -ETIMEDOUTs in firehose_read(). On other tested targets, it does
drain the <log/> entries and then hits -ETIMEDOUTs for the remainder of
5 seconds.

On the newer targets, we could perhaps determine when the programmer is
up by looking for <log/> entries, but this doesn't help the MSM8916
model and it doesn't fit with the current implementation.

If we instead tweak the timeouts and error handling of
firehose_configure(), we can speculatively attempt to configure the
programmer until success.

This meets both the observed models, and shows savings between 4 and 4.5
seconds in startup time across the tested devices.

Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
This commit is contained in:
Bjorn Andersson
2025-09-16 20:04:50 -05:00
committed by Bjorn Andersson
parent 5449037f1c
commit 841a0a8e7f
3 changed files with 53 additions and 21 deletions

View File

@@ -305,7 +305,6 @@ static int firehose_send_configure(struct qdl_device *qdl, size_t payload_size,
xmlNode *root;
xmlNode *node;
xmlDoc *doc;
int ret;
doc = xmlNewDoc((xmlChar *)"1.0");
root = xmlNewNode(NULL, (xmlChar *)"data");
@@ -318,16 +317,14 @@ static int firehose_send_configure(struct qdl_device *qdl, size_t payload_size,
xml_setpropf(node, "ZLPAwareHost", "%d", 1);
xml_setpropf(node, "SkipStorageInit", "%d", skip_storage_init);
ret = firehose_write(qdl, doc);
firehose_write(qdl, doc);
xmlFreeDoc(doc);
if (ret < 0)
return ret;
return firehose_read(qdl, 5000, firehose_configure_response_parser, max_payload_size);
return firehose_read(qdl, 100, firehose_configure_response_parser, max_payload_size);
}
static int firehose_configure(struct qdl_device *qdl, bool skip_storage_init,
const char *storage)
static int firehose_try_configure(struct qdl_device *qdl, bool skip_storage_init,
const char *storage)
{
size_t max_sector_size;
size_t sector_sizes[] = { 512, 4096 };
@@ -339,10 +336,8 @@ static int firehose_configure(struct qdl_device *qdl, bool skip_storage_init,
ret = firehose_send_configure(qdl, qdl->max_payload_size, skip_storage_init,
storage, &size);
if (ret < 0) {
ux_err("configure request failed\n");
return -1;
}
if (ret < 0)
return ret;
/*
* In simulateion mode "remote" target can't propose different size, so
@@ -932,13 +927,42 @@ static int firehose_reset(struct qdl_device *qdl)
return ret == FIREHOSE_ACK ? 0 : -1;
}
static int firehose_detect_and_configure(struct qdl_device *qdl,
bool skip_storage_init,
const char *storage,
unsigned int timeout_s)
{
struct timeval timeout = { .tv_sec = timeout_s };
struct timeval now;
int ret;
gettimeofday(&now, NULL);
timeradd(&now, &timeout, &timeout);
for (;;) {
ret = firehose_try_configure(qdl, false, storage);
if (ret == FIREHOSE_ACK) {
break;
} else if (ret != -ETIMEDOUT) {
ux_err("configure request failed\n");
return -1;
}
gettimeofday(&now, NULL);
if (timercmp(&now, &timeout, >)) {
ux_err("failed to detect firehose programmer\n");
return -1;
}
}
return 0;
}
int firehose_provision(struct qdl_device *qdl)
{
int ret;
firehose_read(qdl, 5000, firehose_generic_parser, NULL);
ret = firehose_configure(qdl, true, "ufs");
ret = firehose_detect_and_configure(qdl, true, "ufs", 5);
if (ret)
return ret;
@@ -964,9 +988,7 @@ int firehose_run(struct qdl_device *qdl, const char *storage)
ux_info("waiting for programmer...\n");
firehose_read(qdl, 5000, firehose_generic_parser, NULL);
ret = firehose_configure(qdl, false, storage);
ret = firehose_detect_and_configure(qdl, true, storage, 5);
if (ret)
return ret;

9
io.c
View File

@@ -53,6 +53,15 @@ int qdl_read(struct qdl_device *qdl, void *buf, size_t len, unsigned int timeout
return qdl->read(qdl, buf, len, timeout);
}
/**
* qdl_write() - Write a message from the device
* @qdl: device handle
* @buf: buffer with data to be written
* @len: length of data to be written
*
* Returns: number of bytes read
* negative errno on failure (notably -ETIMEDOUT)
*/
int qdl_write(struct qdl_device *qdl, const void *buf, size_t len)
{
return qdl->write(qdl, buf, len);

9
usb.c
View File

@@ -262,11 +262,12 @@ static int usb_write(struct qdl_device *qdl, const void *buf, size_t len)
ret = libusb_bulk_transfer(qdl_usb->usb_handle, qdl_usb->out_ep, data,
xfer, &actual, 1000);
if ((ret != 0 && ret != LIBUSB_ERROR_TIMEOUT) ||
(ret == LIBUSB_ERROR_TIMEOUT && actual == 0)) {
if (ret != 0 && ret != LIBUSB_ERROR_TIMEOUT) {
warnx("bulk write failed: %s", libusb_strerror(ret));
return -1;
return -EIO;
}
if (ret == LIBUSB_ERROR_TIMEOUT && actual == 0)
return -ETIMEDOUT;
count += actual;
len -= actual;
@@ -277,7 +278,7 @@ static int usb_write(struct qdl_device *qdl, const void *buf, size_t len)
ret = libusb_bulk_transfer(qdl_usb->usb_handle, qdl_usb->out_ep, NULL,
0, &actual, 1000);
if (ret < 0)
return -1;
return -EIO;
}
return count;