cxgb4: Add functions to read memory via PCIE memory window
authorVipul Pandya <vipul@chelsio.com>
Wed, 26 Sep 2012 02:39:37 +0000 (02:39 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 27 Sep 2012 21:55:50 +0000 (17:55 -0400)
This patch implements two new functions t4_mem_win_read and t4_memory_read.
These new functions can be used to read memory via the PCIE memory window.
Please note, for proper execution of these functions PCIE_MEM_ACCESS_BASE_WIN
registers must be setup correctly like how setup_memwin in the cxgb4 driver
does it.

Signed-off-by: Jay Hernandez <jay@chelsio.com>
Signed-off-by: Vipul Pandya <vipul@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.h

index f3fe23669f8af5f54686d89a7ef6f25f1bf70fde..7de740a8b76469c056609b617d72a1b232e89034 100644 (file)
@@ -664,6 +664,8 @@ int t4_wait_dev_ready(struct adapter *adap);
 int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
                  struct link_config *lc);
 int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port);
+int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len,
+                   __be32 *buf);
 int t4_seeprom_wp(struct adapter *adapter, bool enable);
 int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size);
 int t4_check_fw_version(struct adapter *adapter);
index 8e988d699d05788b66d7adf5e1c795e1fee0428b..259d0dcb00892a422c7efca0de3ded6d4fb3e96b 100644 (file)
@@ -330,6 +330,143 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
        return 0;
 }
 
+/*
+ *     t4_mem_win_rw - read/write memory through PCIE memory window
+ *     @adap: the adapter
+ *     @addr: address of first byte requested
+ *     @data: MEMWIN0_APERTURE bytes of data containing the requested address
+ *     @dir: direction of transfer 1 => read, 0 => write
+ *
+ *     Read/write MEMWIN0_APERTURE bytes of data from MC starting at a
+ *     MEMWIN0_APERTURE-byte-aligned address that covers the requested
+ *     address @addr.
+ */
+static int t4_mem_win_rw(struct adapter *adap, u32 addr, __be32 *data, int dir)
+{
+       int i;
+
+       /*
+        * Setup offset into PCIE memory window.  Address must be a
+        * MEMWIN0_APERTURE-byte-aligned address.  (Read back MA register to
+        * ensure that changes propagate before we attempt to use the new
+        * values.)
+        */
+       t4_write_reg(adap, PCIE_MEM_ACCESS_OFFSET,
+                    addr & ~(MEMWIN0_APERTURE - 1));
+       t4_read_reg(adap, PCIE_MEM_ACCESS_OFFSET);
+
+       /* Collecting data 4 bytes at a time upto MEMWIN0_APERTURE */
+       for (i = 0; i < MEMWIN0_APERTURE; i = i+0x4) {
+               if (dir)
+                       *data++ = t4_read_reg(adap, (MEMWIN0_BASE + i));
+               else
+                       t4_write_reg(adap, (MEMWIN0_BASE + i), *data++);
+       }
+
+       return 0;
+}
+
+/**
+ *     t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window
+ *     @adap: the adapter
+ *     @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC
+ *     @addr: address within indicated memory type
+ *     @len: amount of memory to transfer
+ *     @buf: host memory buffer
+ *     @dir: direction of transfer 1 => read, 0 => write
+ *
+ *     Reads/writes an [almost] arbitrary memory region in the firmware: the
+ *     firmware memory address, length and host buffer must be aligned on
+ *     32-bit boudaries.  The memory is transferred as a raw byte sequence
+ *     from/to the firmware's memory.  If this memory contains data
+ *     structures which contain multi-byte integers, it's the callers
+ *     responsibility to perform appropriate byte order conversions.
+ */
+static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len,
+                       __be32 *buf, int dir)
+{
+       u32 pos, start, end, offset, memoffset;
+       int ret;
+
+       /*
+        * Argument sanity checks ...
+        */
+       if ((addr & 0x3) || (len & 0x3))
+               return -EINVAL;
+
+       /*
+        * Offset into the region of memory which is being accessed
+        * MEM_EDC0 = 0
+        * MEM_EDC1 = 1
+        * MEM_MC   = 2
+        */
+       memoffset = (mtype * (5 * 1024 * 1024));
+
+       /* Determine the PCIE_MEM_ACCESS_OFFSET */
+       addr = addr + memoffset;
+
+       /*
+        * The underlaying EDC/MC read routines read MEMWIN0_APERTURE bytes
+        * at a time so we need to round down the start and round up the end.
+        * We'll start copying out of the first line at (addr - start) a word
+        * at a time.
+        */
+       start = addr & ~(MEMWIN0_APERTURE-1);
+       end = (addr + len + MEMWIN0_APERTURE-1) & ~(MEMWIN0_APERTURE-1);
+       offset = (addr - start)/sizeof(__be32);
+
+       for (pos = start; pos < end; pos += MEMWIN0_APERTURE, offset = 0) {
+               __be32 data[MEMWIN0_APERTURE/sizeof(__be32)];
+
+               /*
+                * If we're writing, copy the data from the caller's memory
+                * buffer
+                */
+               if (!dir) {
+                       /*
+                        * If we're doing a partial write, then we need to do
+                        * a read-modify-write ...
+                        */
+                       if (offset || len < MEMWIN0_APERTURE) {
+                               ret = t4_mem_win_rw(adap, pos, data, 1);
+                               if (ret)
+                                       return ret;
+                       }
+                       while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) &&
+                              len > 0) {
+                               data[offset++] = *buf++;
+                               len -= sizeof(__be32);
+                       }
+               }
+
+               /*
+                * Transfer a block of memory and bail if there's an error.
+                */
+               ret = t4_mem_win_rw(adap, pos, data, dir);
+               if (ret)
+                       return ret;
+
+               /*
+                * If we're reading, copy the data into the caller's memory
+                * buffer.
+                */
+               if (dir)
+                       while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) &&
+                              len > 0) {
+                               *buf++ = data[offset++];
+                               len -= sizeof(__be32);
+                       }
+       }
+
+       return 0;
+}
+
+int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len,
+                   __be32 *buf)
+{
+       return t4_memory_rw(adap, mtype, addr, len, buf, 0);
+}
+
 #define EEPROM_STAT_ADDR   0x7bfc
 #define VPD_BASE           0
 #define VPD_LEN            512
index c26b455f37de54c1075a93e6d100282ef8c6e134..f534ed7e10e9db34b55a5be07f717d93e860a7df 100644 (file)
@@ -58,6 +58,7 @@ enum {
 
 enum {
        SF_PAGE_SIZE = 256,           /* serial flash page size */
+       SF_SEC_SIZE = 64 * 1024,      /* serial flash sector size */
 };
 
 enum { RSP_TYPE_FLBUF, RSP_TYPE_CPL, RSP_TYPE_INTR }; /* response entry types */
@@ -137,4 +138,83 @@ struct rsp_ctrl {
 #define QINTR_CNT_EN       0x1
 #define QINTR_TIMER_IDX(x) ((x) << 1)
 #define QINTR_TIMER_IDX_GET(x) (((x) >> 1) & 0x7)
+
+/*
+ * Flash layout.
+ */
+#define FLASH_START(start)     ((start) * SF_SEC_SIZE)
+#define FLASH_MAX_SIZE(nsecs)  ((nsecs) * SF_SEC_SIZE)
+
+enum {
+       /*
+        * Various Expansion-ROM boot images, etc.
+        */
+       FLASH_EXP_ROM_START_SEC = 0,
+       FLASH_EXP_ROM_NSECS = 6,
+       FLASH_EXP_ROM_START = FLASH_START(FLASH_EXP_ROM_START_SEC),
+       FLASH_EXP_ROM_MAX_SIZE = FLASH_MAX_SIZE(FLASH_EXP_ROM_NSECS),
+
+       /*
+        * iSCSI Boot Firmware Table (iBFT) and other driver-related
+        * parameters ...
+        */
+       FLASH_IBFT_START_SEC = 6,
+       FLASH_IBFT_NSECS = 1,
+       FLASH_IBFT_START = FLASH_START(FLASH_IBFT_START_SEC),
+       FLASH_IBFT_MAX_SIZE = FLASH_MAX_SIZE(FLASH_IBFT_NSECS),
+
+       /*
+        * Boot configuration data.
+        */
+       FLASH_BOOTCFG_START_SEC = 7,
+       FLASH_BOOTCFG_NSECS = 1,
+       FLASH_BOOTCFG_START = FLASH_START(FLASH_BOOTCFG_START_SEC),
+       FLASH_BOOTCFG_MAX_SIZE = FLASH_MAX_SIZE(FLASH_BOOTCFG_NSECS),
+
+       /*
+        * Location of firmware image in FLASH.
+        */
+       FLASH_FW_START_SEC = 8,
+       FLASH_FW_NSECS = 8,
+       FLASH_FW_START = FLASH_START(FLASH_FW_START_SEC),
+       FLASH_FW_MAX_SIZE = FLASH_MAX_SIZE(FLASH_FW_NSECS),
+
+       /*
+        * iSCSI persistent/crash information.
+        */
+       FLASH_ISCSI_CRASH_START_SEC = 29,
+       FLASH_ISCSI_CRASH_NSECS = 1,
+       FLASH_ISCSI_CRASH_START = FLASH_START(FLASH_ISCSI_CRASH_START_SEC),
+       FLASH_ISCSI_CRASH_MAX_SIZE = FLASH_MAX_SIZE(FLASH_ISCSI_CRASH_NSECS),
+
+       /*
+        * FCoE persistent/crash information.
+        */
+       FLASH_FCOE_CRASH_START_SEC = 30,
+       FLASH_FCOE_CRASH_NSECS = 1,
+       FLASH_FCOE_CRASH_START = FLASH_START(FLASH_FCOE_CRASH_START_SEC),
+       FLASH_FCOE_CRASH_MAX_SIZE = FLASH_MAX_SIZE(FLASH_FCOE_CRASH_NSECS),
+
+       /*
+        * Location of Firmware Configuration File in FLASH.  Since the FPGA
+        * "FLASH" is smaller we need to store the Configuration File in a
+        * different location -- which will overlap the end of the firmware
+        * image if firmware ever gets that large ...
+        */
+       FLASH_CFG_START_SEC = 31,
+       FLASH_CFG_NSECS = 1,
+       FLASH_CFG_START = FLASH_START(FLASH_CFG_START_SEC),
+       FLASH_CFG_MAX_SIZE = FLASH_MAX_SIZE(FLASH_CFG_NSECS),
+
+       FLASH_FPGA_CFG_START_SEC = 15,
+       FLASH_FPGA_CFG_START = FLASH_START(FLASH_FPGA_CFG_START_SEC),
+
+       /*
+        * Sectors 32-63 are reserved for FLASH failover.
+        */
+};
+
+#undef FLASH_START
+#undef FLASH_MAX_SIZE
+
 #endif /* __T4_HW_H */