cxgb4: Add functions to read memory via PCIE memory window
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>
This commit is contained in:
Родитель
3eb4afbfce
Коммит
5afc8b84eb
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче