Enable dynamic debug (dyndbg) of Admin Command Interface (ACI) for e610 adapter. Utilizes the standard dynamic debug interface. For example to enable dyndbg at driver load: insmod ixgbe.ko dyndbg='+p' ACI debug output for e610 adapter is immediately printed into a kernel log (dmesg). Example output: ixgbe 0000:01:00.0 eth0: CQ CMD: opcode 0x0701, flags 0x3003, datalen 0x0060, retval 0x0000 ixgbe 0000:01:00.0 eth0: cookie (h,l) 0x00000000 0x00000000 ixgbe 0000:01:00.0 eth0: param (0,1) 0x8194E044 0x00600000 ixgbe 0000:01:00.0 eth0: addr (h,l) 0x00000000 0x00000000 ixgbe 0000:01:00.0 eth0: Buffer: ixgbe 0000:01:00.0 eth0: 00000000: 01 00 17 00 00 00 00 00 00 00 00 00 00 00 00 00 ixgbe 0000:01:00.0 eth0: 00000010: 1d 00 00 00 0b d5 1e 15 5e 4b 90 63 aa 0b 21 31 ixgbe 0000:01:00.0 eth0: 00000020: 69 eb cd ab dc f8 8a fd f4 53 e2 dc 54 e0 81 fa ixgbe 0000:01:00.0 eth0: 00000030: 12 dc 41 82 01 00 00 00 24 20 08 26 53 08 00 00 ixgbe 0000:01:00.0 eth0: 00000040: 08 00 14 00 00 00 00 00 00 00 00 00 00 00 00 00 ixgbe 0000:01:00.0 eth0: 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ixgbe 0000:01:00.0 eth0: CQ CMD: opcode 0x0009, flags 0x2003, datalen 0x0000, retval 0x0000 ixgbe 0000:01:00.0 eth0: cookie (h,l) 0x00000000 0x00000000 ixgbe 0000:01:00.0 eth0: param (0,1) 0x00000001 0x00000000 ixgbe 0000:01:00.0 eth0: addr (h,l) 0x00000000 0x00000000 Co-developed-by: Stefan Wegrzyn Signed-off-by: Stefan Wegrzyn Reviewed-by: Aleksandr Loktionov Signed-off-by: Piotr Kwapulinski --- v1 -> v2 Commit message updated v2 -> v3 Remove unnecessary commit: e610: Convert ACI descriptor buffer to little endian --- drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 112 ++++++++++++++++-- 1 file changed, 105 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c index c2f8189..ad58e11 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c @@ -9,6 +9,78 @@ #include "ixgbe_mbx.h" #include "ixgbe_phy.h" +#define IXGBE_ACI_DEBUG_ROW_SIZE 16 +#define IXGBE_ACI_DEBUG_GROUP_SIZE 1 +#define IXGBE_NETDEV_PREFIX_BUF_SIZE 64 + +/** + * ixgbe_hex_debug_dump - dump a blob of data in "hex ASCII" format + * @hw: hardware structure address + * @buf: data blob to dump + * @buf_size: number of bytes in the @buf + * + * Dump a blob of data into a kernel log. The blob is printed in lines + * consisting of 16 or 32 bytes decorated with PCI device string. Each byte is + * printed in a "hex ASCII" format. + * Example output: + * ixgbe 0000:01:00.1 eth14: 00000000: 01 00 17 00 00 00 00 00 00 00 00 00 00 00 00 00 + * ixgbe 0000:01:00.1 eth14: 00000010: 1d 00 00 00 0b d5 1e 15 5e 4b 90 63 aa 0b 21 31 + * ixgbe 0000:01:00.1 eth14: 00000020: 69 eb cd ab dc f8 8a fd f4 53 e2 dc 54 e0 81 fa + */ +static void ixgbe_hex_debug_dump(struct ixgbe_hw *hw, void *buf, + size_t buf_size) +{ + char netdev_info[IXGBE_NETDEV_PREFIX_BUF_SIZE]; + struct ixgbe_adapter *adapter = hw->back; + struct pci_dev *pdev = adapter->pdev; + + snprintf(netdev_info, IXGBE_NETDEV_PREFIX_BUF_SIZE, + "%s %s %s: ", ixgbe_driver_name, pci_name(pdev), + netdev_name(adapter->netdev)); + print_hex_dump_debug(netdev_info, DUMP_PREFIX_OFFSET, + IXGBE_ACI_DEBUG_ROW_SIZE, + IXGBE_ACI_DEBUG_GROUP_SIZE, + buf, buf_size, false); +} + +/** + * ixgbe_aci_debug - dump the ACI content + * @hw: pointer to the hardware structure + * @desc: pointer to control queue descriptor + * @buf: pointer to command buffer + * @buf_len: max length of buf + * + * Dump individual ACI commands and its descriptor details. + */ +static void ixgbe_aci_debug(struct ixgbe_hw *hw, void *desc, void *buf, + u16 buf_len) +{ + struct libie_aq_desc *aq_desc = desc; + u16 datalen, flags; + + datalen = le16_to_cpu(aq_desc->datalen); + flags = le16_to_cpu(aq_desc->flags); + + hw_dbg(hw, "CQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n", + le16_to_cpu(aq_desc->opcode), flags, datalen, + le16_to_cpu(aq_desc->retval)); + hw_dbg(hw, "\tcookie (h,l) 0x%08X 0x%08X\n", + le32_to_cpu(aq_desc->cookie_high), + le32_to_cpu(aq_desc->cookie_low)); + hw_dbg(hw, "\tparam (0,1) 0x%08X 0x%08X\n", + le32_to_cpu(aq_desc->params.generic.param0), + le32_to_cpu(aq_desc->params.generic.param1)); + hw_dbg(hw, "\taddr (h,l) 0x%08X 0x%08X\n", + le32_to_cpu(aq_desc->params.generic.addr_high), + le32_to_cpu(aq_desc->params.generic.addr_low)); + + if (buf && datalen && (flags & (LIBIE_AQ_FLAG_DD | LIBIE_AQ_FLAG_CMP | + LIBIE_AQ_FLAG_RD))) { + hw_dbg(hw, "Buffer:\n"); + ixgbe_hex_debug_dump(hw, buf, min(buf_len, datalen)); + } +} + /** * ixgbe_should_retry_aci_send_cmd_execute - decide if ACI command should * be resent @@ -69,26 +141,33 @@ static int ixgbe_aci_send_cmd_execute(struct ixgbe_hw *hw, /* It's necessary to check if mechanism is enabled */ hicr = IXGBE_READ_REG(hw, IXGBE_PF_HICR); - if (!(hicr & IXGBE_PF_HICR_EN)) + if (!(hicr & IXGBE_PF_HICR_EN)) { + hw_dbg(hw, "CSR mechanism is not enabled\n"); return -EIO; + } if (hicr & IXGBE_PF_HICR_C) { hw->aci.last_status = LIBIE_AQ_RC_EBUSY; + hw_dbg(hw, "CSR mechanism is busy\n"); return -EBUSY; } opcode = le16_to_cpu(desc->opcode); - if (buf_size > IXGBE_ACI_MAX_BUFFER_SIZE) + if (buf_size > IXGBE_ACI_MAX_BUFFER_SIZE) { + hw_dbg(hw, "buf_size is too big\n"); return -EINVAL; + } if (buf) desc->flags |= cpu_to_le16(LIBIE_AQ_FLAG_BUF); if (desc->flags & cpu_to_le16(LIBIE_AQ_FLAG_BUF)) { if ((buf && !buf_size) || - (!buf && buf_size)) + (!buf && buf_size)) { + hw_dbg(hw, "error: invalid argument buf or buf_size\n"); return -EINVAL; + } if (buf && buf_size) valid_buf = true; } @@ -106,8 +185,12 @@ static int ixgbe_aci_send_cmd_execute(struct ixgbe_hw *hw, if (desc->flags & cpu_to_le16(LIBIE_AQ_FLAG_RD)) { for (i = 0; i < buf_size / 4; i++) IXGBE_WRITE_REG(hw, IXGBE_PF_HIBA(i), ((u32 *)buf)[i]); - if (buf_tail_size) + ixgbe_aci_debug(hw, desc, buf, buf_size); + if (buf_tail_size) { IXGBE_WRITE_REG(hw, IXGBE_PF_HIBA(i), buf_tail); + ixgbe_aci_debug(hw, desc, &buf_tail, + buf_tail_size); + } } } @@ -147,6 +230,7 @@ static int ixgbe_aci_send_cmd_execute(struct ixgbe_hw *hw, raw_desc[i] = IXGBE_READ_REG(hw, IXGBE_PF_HIDA(i)); raw_desc[i] = raw_desc[i]; } + ixgbe_aci_debug(hw, raw_desc, NULL, 0); } /* Read async Admin Command response */ @@ -155,14 +239,21 @@ static int ixgbe_aci_send_cmd_execute(struct ixgbe_hw *hw, raw_desc[i] = IXGBE_READ_REG(hw, IXGBE_PF_HIDA_2(i)); raw_desc[i] = raw_desc[i]; } + ixgbe_aci_debug(hw, raw_desc, NULL, 0); } /* Handle timeout and invalid state of HICR register */ - if (hicr & IXGBE_PF_HICR_C) + if (hicr & IXGBE_PF_HICR_C) { + hw_dbg(hw, "error: Admin Command 0x%X command timeout\n", + le16_to_cpu(desc->opcode)); return -ETIME; + } - if (!(hicr & IXGBE_PF_HICR_SV) && !(hicr & IXGBE_PF_HICR_EV)) + if (!(hicr & IXGBE_PF_HICR_SV) && !(hicr & IXGBE_PF_HICR_EV)) { + hw_dbg(hw, "error: Admin Command 0x%X invalid state of HICR register\n", + le16_to_cpu(desc->opcode)); return -EIO; + } /* For every command other than 0x0014 treat opcode mismatch * as an error. Response to 0x0014 command read from HIDA_2 @@ -170,12 +261,16 @@ static int ixgbe_aci_send_cmd_execute(struct ixgbe_hw *hw, * different opcode than the command. */ if (desc->opcode != cpu_to_le16(opcode) && - opcode != ixgbe_aci_opc_get_fw_event) + opcode != ixgbe_aci_opc_get_fw_event) { + hw_dbg(hw, "error: Admin Command failed, bad opcode returned\n"); return -EIO; + } if (desc->retval) { hw->aci.last_status = (enum libie_aq_err) le16_to_cpu(desc->retval); + hw_dbg(hw, "error: Admin Command failed with error %x\n", + le16_to_cpu(desc->retval)); return -EIO; } @@ -183,10 +278,13 @@ static int ixgbe_aci_send_cmd_execute(struct ixgbe_hw *hw, if (valid_buf) { for (i = 0; i < buf_size / 4; i++) ((u32 *)buf)[i] = IXGBE_READ_REG(hw, IXGBE_PF_HIBA(i)); + ixgbe_aci_debug(hw, raw_desc, buf, buf_size); if (buf_tail_size) { buf_tail = IXGBE_READ_REG(hw, IXGBE_PF_HIBA(i)); memcpy(buf + buf_size - buf_tail_size, &buf_tail, buf_tail_size); + ixgbe_aci_debug(hw, raw_desc, &buf_tail, + buf_tail_size); } } -- 2.47.1