USB: xhci: Print NEC firmware version.
The NEC xHCI host controller firmware version can be found by putting a vendor-specific command on the command ring and extracting the BCD encoded-version out of the vendor-specific event TRB. The firmware version debug line in dmesg will look like: xhci_hcd 0000:05:00.0: NEC firmware version 30.21 (NEC merged with Renesas Technologies and became Renesas Electronics on April 1, 2010. I have their OK to merge this vendor-specific code.) Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Cc: Satoshi Otani <satoshi.otani.xm@renesas.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
ed07453fd3
commit
0238634d02
@@ -78,6 +78,8 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
|
|||||||
xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure"
|
xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure"
|
||||||
" endpoint cmd after reset endpoint\n");
|
" endpoint cmd after reset endpoint\n");
|
||||||
}
|
}
|
||||||
|
if (pdev->vendor == PCI_VENDOR_ID_NEC)
|
||||||
|
xhci->quirks |= XHCI_NEC_HOST;
|
||||||
|
|
||||||
/* Make sure the HC is halted. */
|
/* Make sure the HC is halted. */
|
||||||
retval = xhci_halt(xhci);
|
retval = xhci_halt(xhci);
|
||||||
|
@@ -1071,6 +1071,15 @@ bandwidth_change:
|
|||||||
xhci_warn(xhci, "Reset device command completion "
|
xhci_warn(xhci, "Reset device command completion "
|
||||||
"for disabled slot %u\n", slot_id);
|
"for disabled slot %u\n", slot_id);
|
||||||
break;
|
break;
|
||||||
|
case TRB_TYPE(TRB_NEC_GET_FW):
|
||||||
|
if (!(xhci->quirks & XHCI_NEC_HOST)) {
|
||||||
|
xhci->error_bitmask |= 1 << 6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
xhci_dbg(xhci, "NEC firmware version %2x.%02x\n",
|
||||||
|
NEC_FW_MAJOR(event->status),
|
||||||
|
NEC_FW_MINOR(event->status));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* Skip over unknown commands on the event ring */
|
/* Skip over unknown commands on the event ring */
|
||||||
xhci->error_bitmask |= 1 << 6;
|
xhci->error_bitmask |= 1 << 6;
|
||||||
@@ -1079,6 +1088,17 @@ bandwidth_change:
|
|||||||
inc_deq(xhci, xhci->cmd_ring, false);
|
inc_deq(xhci, xhci->cmd_ring, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_vendor_event(struct xhci_hcd *xhci,
|
||||||
|
union xhci_trb *event)
|
||||||
|
{
|
||||||
|
u32 trb_type;
|
||||||
|
|
||||||
|
trb_type = TRB_FIELD_TO_TYPE(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);
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_port_status(struct xhci_hcd *xhci,
|
static void handle_port_status(struct xhci_hcd *xhci,
|
||||||
union xhci_trb *event)
|
union xhci_trb *event)
|
||||||
{
|
{
|
||||||
@@ -1659,7 +1679,10 @@ void xhci_handle_event(struct xhci_hcd *xhci)
|
|||||||
update_ptrs = 0;
|
update_ptrs = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
xhci->error_bitmask |= 1 << 3;
|
if ((event->event_cmd.flags & TRB_TYPE_BITMASK) >= TRB_TYPE(48))
|
||||||
|
handle_vendor_event(xhci, event);
|
||||||
|
else
|
||||||
|
xhci->error_bitmask |= 1 << 3;
|
||||||
}
|
}
|
||||||
/* Any of the above functions may drop and re-acquire the lock, so check
|
/* 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.
|
* to make sure a watchdog timer didn't mark the host as non-responsive.
|
||||||
@@ -2378,6 +2401,12 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
|
|||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int xhci_queue_vendor_command(struct xhci_hcd *xhci,
|
||||||
|
u32 field1, u32 field2, u32 field3, u32 field4)
|
||||||
|
{
|
||||||
|
return queue_command(xhci, field1, field2, field3, field4, false);
|
||||||
|
}
|
||||||
|
|
||||||
/* Queue a reset device command TRB */
|
/* Queue a reset device command TRB */
|
||||||
int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id)
|
int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id)
|
||||||
{
|
{
|
||||||
|
@@ -486,6 +486,9 @@ int xhci_run(struct usb_hcd *hcd)
|
|||||||
|
|
||||||
if (NUM_TEST_NOOPS > 0)
|
if (NUM_TEST_NOOPS > 0)
|
||||||
doorbell = xhci_setup_one_noop(xhci);
|
doorbell = xhci_setup_one_noop(xhci);
|
||||||
|
if (xhci->quirks & XHCI_NEC_HOST)
|
||||||
|
xhci_queue_vendor_command(xhci, 0, 0, 0,
|
||||||
|
TRB_TYPE(TRB_NEC_GET_FW));
|
||||||
|
|
||||||
if (xhci_start(xhci)) {
|
if (xhci_start(xhci)) {
|
||||||
xhci_halt(xhci);
|
xhci_halt(xhci);
|
||||||
@@ -495,6 +498,8 @@ int xhci_run(struct usb_hcd *hcd)
|
|||||||
xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp);
|
xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp);
|
||||||
if (doorbell)
|
if (doorbell)
|
||||||
(*doorbell)(xhci);
|
(*doorbell)(xhci);
|
||||||
|
if (xhci->quirks & XHCI_NEC_HOST)
|
||||||
|
xhci_ring_cmd_db(xhci);
|
||||||
|
|
||||||
xhci_dbg(xhci, "Finished xhci_run\n");
|
xhci_dbg(xhci, "Finished xhci_run\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -925,6 +925,7 @@ union xhci_trb {
|
|||||||
/* TRB bit mask */
|
/* TRB bit mask */
|
||||||
#define TRB_TYPE_BITMASK (0xfc00)
|
#define TRB_TYPE_BITMASK (0xfc00)
|
||||||
#define TRB_TYPE(p) ((p) << 10)
|
#define TRB_TYPE(p) ((p) << 10)
|
||||||
|
#define TRB_FIELD_TO_TYPE(p) (((p) & TRB_TYPE_BITMASK) >> 10)
|
||||||
/* TRB type IDs */
|
/* TRB type IDs */
|
||||||
/* bulk, interrupt, isoc scatter/gather, and control data stage */
|
/* bulk, interrupt, isoc scatter/gather, and control data stage */
|
||||||
#define TRB_NORMAL 1
|
#define TRB_NORMAL 1
|
||||||
@@ -992,6 +993,14 @@ union xhci_trb {
|
|||||||
#define TRB_MFINDEX_WRAP 39
|
#define TRB_MFINDEX_WRAP 39
|
||||||
/* TRB IDs 40-47 reserved, 48-63 is vendor-defined */
|
/* TRB IDs 40-47 reserved, 48-63 is vendor-defined */
|
||||||
|
|
||||||
|
/* Nec vendor-specific command completion event. */
|
||||||
|
#define TRB_NEC_CMD_COMP 48
|
||||||
|
/* Get NEC firmware revision. */
|
||||||
|
#define TRB_NEC_GET_FW 49
|
||||||
|
|
||||||
|
#define NEC_FW_MINOR(p) (((p) >> 0) & 0xff)
|
||||||
|
#define NEC_FW_MAJOR(p) (((p) >> 8) & 0xff)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TRBS_PER_SEGMENT must be a multiple of 4,
|
* TRBS_PER_SEGMENT must be a multiple of 4,
|
||||||
* since the command ring is 64-byte aligned.
|
* since the command ring is 64-byte aligned.
|
||||||
@@ -1172,6 +1181,7 @@ struct xhci_hcd {
|
|||||||
unsigned int quirks;
|
unsigned int quirks;
|
||||||
#define XHCI_LINK_TRB_QUIRK (1 << 0)
|
#define XHCI_LINK_TRB_QUIRK (1 << 0)
|
||||||
#define XHCI_RESET_EP_QUIRK (1 << 1)
|
#define XHCI_RESET_EP_QUIRK (1 << 1)
|
||||||
|
#define XHCI_NEC_HOST (1 << 2)
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For testing purposes */
|
/* For testing purposes */
|
||||||
@@ -1379,6 +1389,8 @@ void xhci_set_hc_event_deq(struct xhci_hcd *xhci);
|
|||||||
int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id);
|
int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id);
|
||||||
int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
|
int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
|
||||||
u32 slot_id);
|
u32 slot_id);
|
||||||
|
int xhci_queue_vendor_command(struct xhci_hcd *xhci,
|
||||||
|
u32 field1, u32 field2, u32 field3, u32 field4);
|
||||||
int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
|
int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
|
||||||
unsigned int ep_index);
|
unsigned int ep_index);
|
||||||
int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
|
int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
|
||||||
|
Reference in New Issue
Block a user