cxgb4: skip TX and RX payload regions in memory dumps
authorRahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Fri, 8 Dec 2017 04:18:39 +0000 (09:48 +0530)
committerDavid S. Miller <davem@davemloft.net>
Fri, 8 Dec 2017 19:31:50 +0000 (14:31 -0500)
Use meminfo to identify TX and RX payload regions and skip them in
collection of EDC, MC, and HMA.

Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c

index 880b1cb5b463a6c6f4c3f3307212170222c953e8..1e1719526e763fdda21f2584b0d29c77171cb725 100644 (file)
@@ -95,6 +95,13 @@ static const char * const cudbg_region[] = {
        "On-chip queues:"
 };
 
+/* Memory region info relative to current memory (i.e. wrt 0). */
+struct cudbg_region_info {
+       bool exist; /* Does region exists in current memory? */
+       u32 start;  /* Start wrt 0 */
+       u32 end;    /* End wrt 0 */
+};
+
 struct cudbg_mem_desc {
        u32 base;
        u32 limit;
index 4e87218d44762c550d47cbd078892c0ef182a726..2e3cf36347a295a83674609243836f1c0e3f3fa4 100644 (file)
@@ -730,6 +730,116 @@ static int cudbg_meminfo_get_mem_index(struct adapter *padap,
        return CUDBG_STATUS_ENTITY_NOT_FOUND;
 }
 
+/* Fetch the @region_name's start and end from @meminfo. */
+static int cudbg_get_mem_region(struct adapter *padap,
+                               struct cudbg_meminfo *meminfo,
+                               u8 mem_type, const char *region_name,
+                               struct cudbg_mem_desc *mem_desc)
+{
+       u8 mc, found = 0;
+       u32 i, idx = 0;
+       int rc;
+
+       rc = cudbg_meminfo_get_mem_index(padap, meminfo, mem_type, &mc);
+       if (rc)
+               return rc;
+
+       for (i = 0; i < ARRAY_SIZE(cudbg_region); i++) {
+               if (!strcmp(cudbg_region[i], region_name)) {
+                       found = 1;
+                       idx = i;
+                       break;
+               }
+       }
+       if (!found)
+               return -EINVAL;
+
+       found = 0;
+       for (i = 0; i < meminfo->mem_c; i++) {
+               if (meminfo->mem[i].idx >= ARRAY_SIZE(cudbg_region))
+                       continue; /* Skip holes */
+
+               if (!(meminfo->mem[i].limit))
+                       meminfo->mem[i].limit =
+                               i < meminfo->mem_c - 1 ?
+                               meminfo->mem[i + 1].base - 1 : ~0;
+
+               if (meminfo->mem[i].idx == idx) {
+                       /* Check if the region exists in @mem_type memory */
+                       if (meminfo->mem[i].base < meminfo->avail[mc].base &&
+                           meminfo->mem[i].limit < meminfo->avail[mc].base)
+                               return -EINVAL;
+
+                       if (meminfo->mem[i].base > meminfo->avail[mc].limit)
+                               return -EINVAL;
+
+                       memcpy(mem_desc, &meminfo->mem[i],
+                              sizeof(struct cudbg_mem_desc));
+                       found = 1;
+                       break;
+               }
+       }
+       if (!found)
+               return -EINVAL;
+
+       return 0;
+}
+
+/* Fetch and update the start and end of the requested memory region w.r.t 0
+ * in the corresponding EDC/MC/HMA.
+ */
+static int cudbg_get_mem_relative(struct adapter *padap,
+                                 struct cudbg_meminfo *meminfo,
+                                 u8 mem_type, u32 *out_base, u32 *out_end)
+{
+       u8 mc_idx;
+       int rc;
+
+       rc = cudbg_meminfo_get_mem_index(padap, meminfo, mem_type, &mc_idx);
+       if (rc)
+               return rc;
+
+       if (*out_base < meminfo->avail[mc_idx].base)
+               *out_base = 0;
+       else
+               *out_base -= meminfo->avail[mc_idx].base;
+
+       if (*out_end > meminfo->avail[mc_idx].limit)
+               *out_end = meminfo->avail[mc_idx].limit;
+       else
+               *out_end -= meminfo->avail[mc_idx].base;
+
+       return 0;
+}
+
+/* Get TX and RX Payload region */
+static int cudbg_get_payload_range(struct adapter *padap, u8 mem_type,
+                                  const char *region_name,
+                                  struct cudbg_region_info *payload)
+{
+       struct cudbg_mem_desc mem_desc = { 0 };
+       struct cudbg_meminfo meminfo;
+       int rc;
+
+       rc = cudbg_fill_meminfo(padap, &meminfo);
+       if (rc)
+               return rc;
+
+       rc = cudbg_get_mem_region(padap, &meminfo, mem_type, region_name,
+                                 &mem_desc);
+       if (rc) {
+               payload->exist = false;
+               return 0;
+       }
+
+       payload->exist = true;
+       payload->start = mem_desc.base;
+       payload->end = mem_desc.limit;
+
+       return cudbg_get_mem_relative(padap, &meminfo, mem_type,
+                                     &payload->start, &payload->end);
+}
+
 #define CUDBG_YIELD_ITERATION 256
 
 static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
@@ -737,11 +847,32 @@ static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
                             unsigned long tot_len,
                             struct cudbg_error *cudbg_err)
 {
+       static const char * const region_name[] = { "Tx payload:",
+                                                   "Rx payload:" };
        unsigned long bytes, bytes_left, bytes_read = 0;
        struct adapter *padap = pdbg_init->adap;
        struct cudbg_buffer temp_buff = { 0 };
+       struct cudbg_region_info payload[2];
        u32 yield_count = 0;
        int rc = 0;
+       u8 i;
+
+       /* Get TX/RX Payload region range if they exist */
+       memset(payload, 0, sizeof(payload));
+       for (i = 0; i < ARRAY_SIZE(region_name); i++) {
+               rc = cudbg_get_payload_range(padap, mem_type, region_name[i],
+                                            &payload[i]);
+               if (rc)
+                       return rc;
+
+               if (payload[i].exist) {
+                       /* Align start and end to avoid wrap around */
+                       payload[i].start = roundup(payload[i].start,
+                                                  CUDBG_CHUNK_SIZE);
+                       payload[i].end = rounddown(payload[i].end,
+                                                  CUDBG_CHUNK_SIZE);
+               }
+       }
 
        bytes_left = tot_len;
        while (bytes_left > 0) {
@@ -759,6 +890,14 @@ static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
                rc = cudbg_get_buff(dbg_buff, bytes, &temp_buff);
                if (rc)
                        return rc;
+
+               for (i = 0; i < ARRAY_SIZE(payload); i++)
+                       if (payload[i].exist &&
+                           bytes_read >= payload[i].start &&
+                           bytes_read + bytes <= payload[i].end)
+                               /* TX and RX Payload regions can't overlap */
+                               goto skip_read;
+
                spin_lock(&padap->win0_lock);
                rc = t4_memory_rw(padap, MEMWIN_NIC, mem_type,
                                  bytes_read, bytes,
@@ -770,6 +909,8 @@ static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
                        cudbg_put_buff(&temp_buff, dbg_buff);
                        return rc;
                }
+
+skip_read:
                bytes_left -= bytes;
                bytes_read += bytes;
                cudbg_write_and_release_buff(&temp_buff, dbg_buff);