From febbbcc32ee9b19dc4b1307bdc52da8fd7b85a71 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 29 Nov 2017 13:19:50 -0800 Subject: [PATCH] firehose: Negotiate max payload size When the host propose a larger payload size than the device accepts the device will respond with a NACK, containing the maximum payload size. Similarily the ACK will contain the supported max if the host requests a lower value than the device supports. In both cases we pick the largest possible value and send a second configure message to select this payload size. Reported-by: Kirill Kapranov Signed-off-by: Bjorn Andersson --- firehose.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/firehose.c b/firehose.c index 72e771e..f5dc477 100644 --- a/firehose.c +++ b/firehose.c @@ -229,22 +229,41 @@ static int firehose_nop(int fd) static size_t max_payload_size = 1048576; +/** + * firehose_configure_response_parser() - parse a configure response + * @node: response xmlNode + * + * Return: max size supported by the remote, or negative errno on failure + */ static int firehose_configure_response_parser(xmlNode *node) { + xmlChar *payload; xmlChar *value; + size_t max_size; value = xmlGetProp(node, (xmlChar*)"value"); - if (xmlStrcmp(value, (xmlChar*)"ACK")) + payload = xmlGetProp(node, (xmlChar*)"MaxPayloadSizeToTargetInBytes"); + if (!value || !payload) return -EINVAL; - value = xmlGetProp(node, (xmlChar*)"MaxPayloadSizeToTargetInBytes"); - if (value) - max_payload_size = strtoul((char*)value, NULL, 10); + max_size = strtoul((char*)payload, NULL, 10); - return 0; + /* + * When receiving an ACK the remote may indicate that we should attempt + * a larger payload size + */ + if (!xmlStrcmp(value, (xmlChar*)"ACK")) { + payload = xmlGetProp(node, (xmlChar*)"MaxPayloadSizeToTargetInBytesSupported"); + if (!payload) + return -EINVAL; + + max_size = strtoul((char*)payload, NULL, 10); + } + + return max_size; } -static int firehose_configure(int fd) +static int firehose_send_configure(int fd, size_t payload_size) { xmlNode *root; xmlNode *node; @@ -257,7 +276,7 @@ static int firehose_configure(int fd) node = xmlNewChild(root, NULL, (xmlChar*)"configure", NULL); xml_setpropf(node, "MemoryName", "ufs"); - xml_setpropf(node, "MaxPayloadSizeToTargetInBytes", "%d", max_payload_size); + xml_setpropf(node, "MaxPayloadSizeToTargetInBytes", "%d", payload_size); xml_setpropf(node, "verbose", "%d", 0); xml_setpropf(node, "ZLPAwareHost", "%d", 0); @@ -268,6 +287,31 @@ static int firehose_configure(int fd) return firehose_read(fd, -1, firehose_configure_response_parser); } +static int firehose_configure(int fd) +{ + int ret; + + ret = firehose_send_configure(fd, max_payload_size); + if (ret < 0) + return ret; + + /* Retry if remote proposed different size */ + if (ret != max_payload_size) { + ret = firehose_send_configure(fd, ret); + if (ret < 0) + return ret; + + max_payload_size = ret; + } + + if (qdl_debug) { + fprintf(stderr, "[CONFIGURE] max payload size: %ld\n", + max_payload_size); + } + + return 0; +} + #define MIN(x, y) ((x) < (y) ? (x) : (y)) #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))