xhci: avoid DMA double fetch when reading event trb type.

Instead of re-reading, masking and endianness correcting the same trb
several times to get the trb type from an event, just do it once and
store it in a local variable.

Also pass the trb_type directly to the vendor specific event handler,
avoiding one more similar read.

In addition to the security benefit this also cleans up the code
and helps readability.

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20210129130044.206855-13-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Mathias Nyman 2021-01-29 15:00:29 +02:00 committed by Greg Kroah-Hartman
parent 55f6153d8c
commit 0353810a04
2 changed files with 13 additions and 16 deletions

View File

@ -1564,11 +1564,8 @@ event_handled:
}
static void handle_vendor_event(struct xhci_hcd *xhci,
union xhci_trb *event)
union xhci_trb *event, u32 trb_type)
{
u32 trb_type;
trb_type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->generic.field[3]));
xhci_dbg(xhci, "Vendor specific event TRB type = %u\n", trb_type);
if (trb_type == TRB_NEC_CMD_COMP && (xhci->quirks & XHCI_NEC_HOST))
handle_cmd_completion(xhci, &event->event_cmd);
@ -2733,6 +2730,7 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
{
union xhci_trb *event;
int update_ptrs = 1;
u32 trb_type;
int ret;
/* Event ring hasn't been allocated yet. */
@ -2754,31 +2752,30 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
* speculative reads of the event's flags/data below.
*/
rmb();
trb_type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->event_cmd.flags));
/* FIXME: Handle more event types. */
switch (le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) {
case TRB_TYPE(TRB_COMPLETION):
switch (trb_type) {
case TRB_COMPLETION:
handle_cmd_completion(xhci, &event->event_cmd);
break;
case TRB_TYPE(TRB_PORT_STATUS):
case TRB_PORT_STATUS:
handle_port_status(xhci, event);
update_ptrs = 0;
break;
case TRB_TYPE(TRB_TRANSFER):
case TRB_TRANSFER:
ret = handle_tx_event(xhci, &event->trans_event);
if (ret >= 0)
update_ptrs = 0;
break;
case TRB_TYPE(TRB_DEV_NOTE):
case TRB_DEV_NOTE:
handle_device_notification(xhci, event);
break;
default:
if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >=
TRB_TYPE(48))
handle_vendor_event(xhci, event);
if (trb_type >= TRB_VENDOR_DEFINED_LOW)
handle_vendor_event(xhci, event, trb_type);
else
xhci_warn(xhci, "ERROR unknown event type %d\n",
TRB_FIELD_TO_TYPE(
le32_to_cpu(event->event_cmd.flags)));
xhci_warn(xhci, "ERROR unknown event type %d\n", trb_type);
}
/* Any of the above functions may drop and re-acquire the lock, so check
* to make sure a watchdog timer didn't mark the host as non-responsive.

View File

@ -1419,7 +1419,7 @@ union xhci_trb {
/* MFINDEX Wrap Event - microframe counter wrapped */
#define TRB_MFINDEX_WRAP 39
/* TRB IDs 40-47 reserved, 48-63 is vendor-defined */
#define TRB_VENDOR_DEFINED_LOW 48
/* Nec vendor-specific command completion event. */
#define TRB_NEC_CMD_COMP 48
/* Get NEC firmware revision. */