From: Paul Zimmerman <Paul.Zimmerman@xxxxxxxxxxxx> The Synopsys USB device controller requires all OUT transfer request lengths to be aligned to max packet size. The mass storage gadgets do not meet this requirement for Super Speed. The gadgets already have a function which performs this alignment for CBW packets, so use it for data packets too. The alternative would be to implement bounce buffers in the DWC3 driver, but that could have a significant impact on performance. This version is based upon a more-correct patch written by Alan Stern. Signed-off-by: Paul Zimmerman <paulz@xxxxxxxxxxxx> Signed-off-by: Felipe Balbi <balbi@xxxxxx> --- drivers/usb/gadget/f_mass_storage.c | 18 +++++++++--------- drivers/usb/gadget/file_storage.c | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 7569414..927ee88 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -958,9 +958,7 @@ static int do_write(struct fsg_common *common) * equal to the buffer size, which is divisible by * the bulk-out maxpacket size. */ - bh->outreq->length = amount; - bh->bulk_out_intended_length = amount; - bh->outreq->short_not_ok = 1; + set_bulk_out_req_length(common, bh, amount); if (!start_out_transfer(common, bh)) /* Dunno what to do if common->fsg is NULL */ return -EIO; @@ -995,6 +993,11 @@ static int do_write(struct fsg_common *common) amount = curlun->file_length - file_offset; } + /* Don't accept excess data. The spec doesn't say + * what to do in this case. We'll ignore the error. + */ + amount = min(amount, bh->bulk_out_intended_length); + /* Don't write a partial block */ amount = round_down(amount, curlun->blksize); if (amount == 0) @@ -1034,7 +1037,7 @@ static int do_write(struct fsg_common *common) empty_write: /* Did the host decide to stop early? */ - if (bh->outreq->actual != bh->outreq->length) { + if (bh->outreq->actual < bh->bulk_out_intended_length) { common->short_packet_received = 1; break; } @@ -1592,7 +1595,7 @@ static int throw_away_data(struct fsg_common *common) common->next_buffhd_to_drain = bh->next; /* A short packet or an error ends everything */ - if (bh->outreq->actual != bh->outreq->length || + if (bh->outreq->actual < bh->bulk_out_intended_length || bh->outreq->status != 0) { raise_exception(common, FSG_STATE_ABORT_BULK_OUT); @@ -1612,9 +1615,7 @@ static int throw_away_data(struct fsg_common *common) * equal to the buffer size, which is divisible by * the bulk-out maxpacket size. */ - bh->outreq->length = amount; - bh->bulk_out_intended_length = amount; - bh->outreq->short_not_ok = 1; + set_bulk_out_req_length(common, bh, amount); if (!start_out_transfer(common, bh)) /* Dunno what to do if common->fsg is NULL */ return -EIO; @@ -2289,7 +2290,6 @@ static int get_next_command(struct fsg_common *common) /* Queue a request to read a Bulk-only CBW */ set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN); - bh->outreq->short_not_ok = 1; if (!start_out_transfer(common, bh)) /* Don't know what to do if common->fsg is NULL */ return -EIO; diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 12ac30b..a230009 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1335,9 +1335,7 @@ static int do_write(struct fsg_dev *fsg) * equal to the buffer size, which is divisible by * the bulk-out maxpacket size. */ - bh->outreq->length = bh->bulk_out_intended_length = - amount; - bh->outreq->short_not_ok = 1; + set_bulk_out_req_length(fsg, bh, amount); start_transfer(fsg, fsg->bulk_out, bh->outreq, &bh->outreq_busy, &bh->state); fsg->next_buffhd_to_fill = bh->next; @@ -1370,6 +1368,11 @@ static int do_write(struct fsg_dev *fsg) amount = curlun->file_length - file_offset; } + /* Don't accept excess data. The spec doesn't say + * what to do in this case. We'll ignore the error. + */ + amount = min(amount, bh->bulk_out_intended_length); + /* Don't write a partial block */ amount = round_down(amount, curlun->blksize); if (amount == 0) @@ -1409,7 +1412,7 @@ static int do_write(struct fsg_dev *fsg) empty_write: /* Did the host decide to stop early? */ - if (bh->outreq->actual != bh->outreq->length) { + if (bh->outreq->actual < bh->bulk_out_intended_length) { fsg->short_packet_received = 1; break; } @@ -1953,7 +1956,7 @@ static int throw_away_data(struct fsg_dev *fsg) fsg->next_buffhd_to_drain = bh->next; /* A short packet or an error ends everything */ - if (bh->outreq->actual != bh->outreq->length || + if (bh->outreq->actual < bh->bulk_out_intended_length || bh->outreq->status != 0) { raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); return -EINTR; @@ -1971,9 +1974,7 @@ static int throw_away_data(struct fsg_dev *fsg) * equal to the buffer size, which is divisible by * the bulk-out maxpacket size. */ - bh->outreq->length = bh->bulk_out_intended_length = - amount; - bh->outreq->short_not_ok = 1; + set_bulk_out_req_length(fsg, bh, amount); start_transfer(fsg, fsg->bulk_out, bh->outreq, &bh->outreq_busy, &bh->state); fsg->next_buffhd_to_fill = bh->next; @@ -2652,7 +2653,6 @@ static int get_next_command(struct fsg_dev *fsg) /* Queue a request to read a Bulk-only CBW */ set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); - bh->outreq->short_not_ok = 1; start_transfer(fsg, fsg->bulk_out, bh->outreq, &bh->outreq_busy, &bh->state); -- 1.7.7 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html