diff options
author | Vipul Pandya <vipul@chelsio.com> | 2012-09-25 22:39:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-09-27 17:55:50 -0400 |
commit | 5afc8b84eb7b29e4646d6e8ca7e6d7196031d6f7 (patch) | |
tree | 34382fe914af703cbe1bf921c6a2ddac040f91e3 | |
parent | 3eb4afbfceb44750d9afb832e6c992adec9fc571 (diff) |
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>
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 137 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 80 |
3 files changed, 219 insertions, 0 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index f3fe23669f8a..7de740a8b764 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | |||
@@ -664,6 +664,8 @@ int t4_wait_dev_ready(struct adapter *adap); | |||
664 | int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, | 664 | int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, |
665 | struct link_config *lc); | 665 | struct link_config *lc); |
666 | int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port); | 666 | int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port); |
667 | int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len, | ||
668 | __be32 *buf); | ||
667 | int t4_seeprom_wp(struct adapter *adapter, bool enable); | 669 | int t4_seeprom_wp(struct adapter *adapter, bool enable); |
668 | int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size); | 670 | int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size); |
669 | int t4_check_fw_version(struct adapter *adapter); | 671 | int t4_check_fw_version(struct adapter *adapter); |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 8e988d699d05..259d0dcb0089 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | |||
@@ -330,6 +330,143 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc) | |||
330 | return 0; | 330 | return 0; |
331 | } | 331 | } |
332 | 332 | ||
333 | /* | ||
334 | * t4_mem_win_rw - read/write memory through PCIE memory window | ||
335 | * @adap: the adapter | ||
336 | * @addr: address of first byte requested | ||
337 | * @data: MEMWIN0_APERTURE bytes of data containing the requested address | ||
338 | * @dir: direction of transfer 1 => read, 0 => write | ||
339 | * | ||
340 | * Read/write MEMWIN0_APERTURE bytes of data from MC starting at a | ||
341 | * MEMWIN0_APERTURE-byte-aligned address that covers the requested | ||
342 | * address @addr. | ||
343 | */ | ||
344 | static int t4_mem_win_rw(struct adapter *adap, u32 addr, __be32 *data, int dir) | ||
345 | { | ||
346 | int i; | ||
347 | |||
348 | /* | ||
349 | * Setup offset into PCIE memory window. Address must be a | ||
350 | * MEMWIN0_APERTURE-byte-aligned address. (Read back MA register to | ||
351 | * ensure that changes propagate before we attempt to use the new | ||
352 | * values.) | ||
353 | */ | ||
354 | t4_write_reg(adap, PCIE_MEM_ACCESS_OFFSET, | ||
355 | addr & ~(MEMWIN0_APERTURE - 1)); | ||
356 | t4_read_reg(adap, PCIE_MEM_ACCESS_OFFSET); | ||
357 | |||
358 | /* Collecting data 4 bytes at a time upto MEMWIN0_APERTURE */ | ||
359 | for (i = 0; i < MEMWIN0_APERTURE; i = i+0x4) { | ||
360 | if (dir) | ||
361 | *data++ = t4_read_reg(adap, (MEMWIN0_BASE + i)); | ||
362 | else | ||
363 | t4_write_reg(adap, (MEMWIN0_BASE + i), *data++); | ||
364 | } | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | /** | ||
370 | * t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window | ||
371 | * @adap: the adapter | ||
372 | * @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC | ||
373 | * @addr: address within indicated memory type | ||
374 | * @len: amount of memory to transfer | ||
375 | * @buf: host memory buffer | ||
376 | * @dir: direction of transfer 1 => read, 0 => write | ||
377 | * | ||
378 | * Reads/writes an [almost] arbitrary memory region in the firmware: the | ||
379 | * firmware memory address, length and host buffer must be aligned on | ||
380 | * 32-bit boudaries. The memory is transferred as a raw byte sequence | ||
381 | * from/to the firmware's memory. If this memory contains data | ||
382 | * structures which contain multi-byte integers, it's the callers | ||
383 | * responsibility to perform appropriate byte order conversions. | ||
384 | */ | ||
385 | static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len, | ||
386 | __be32 *buf, int dir) | ||
387 | { | ||
388 | u32 pos, start, end, offset, memoffset; | ||
389 | int ret; | ||
390 | |||
391 | /* | ||
392 | * Argument sanity checks ... | ||
393 | */ | ||
394 | if ((addr & 0x3) || (len & 0x3)) | ||
395 | return -EINVAL; | ||
396 | |||
397 | /* | ||
398 | * Offset into the region of memory which is being accessed | ||
399 | * MEM_EDC0 = 0 | ||
400 | * MEM_EDC1 = 1 | ||
401 | * MEM_MC = 2 | ||
402 | */ | ||
403 | memoffset = (mtype * (5 * 1024 * 1024)); | ||
404 | |||
405 | /* Determine the PCIE_MEM_ACCESS_OFFSET */ | ||
406 | addr = addr + memoffset; | ||
407 | |||
408 | /* | ||
409 | * The underlaying EDC/MC read routines read MEMWIN0_APERTURE bytes | ||
410 | * at a time so we need to round down the start and round up the end. | ||
411 | * We'll start copying out of the first line at (addr - start) a word | ||
412 | * at a time. | ||
413 | */ | ||
414 | start = addr & ~(MEMWIN0_APERTURE-1); | ||
415 | end = (addr + len + MEMWIN0_APERTURE-1) & ~(MEMWIN0_APERTURE-1); | ||
416 | offset = (addr - start)/sizeof(__be32); | ||
417 | |||
418 | for (pos = start; pos < end; pos += MEMWIN0_APERTURE, offset = 0) { | ||
419 | __be32 data[MEMWIN0_APERTURE/sizeof(__be32)]; | ||
420 | |||
421 | /* | ||
422 | * If we're writing, copy the data from the caller's memory | ||
423 | * buffer | ||
424 | */ | ||
425 | if (!dir) { | ||
426 | /* | ||
427 | * If we're doing a partial write, then we need to do | ||
428 | * a read-modify-write ... | ||
429 | */ | ||
430 | if (offset || len < MEMWIN0_APERTURE) { | ||
431 | ret = t4_mem_win_rw(adap, pos, data, 1); | ||
432 | if (ret) | ||
433 | return ret; | ||
434 | } | ||
435 | while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) && | ||
436 | len > 0) { | ||
437 | data[offset++] = *buf++; | ||
438 | len -= sizeof(__be32); | ||
439 | } | ||
440 | } | ||
441 | |||
442 | /* | ||
443 | * Transfer a block of memory and bail if there's an error. | ||
444 | */ | ||
445 | ret = t4_mem_win_rw(adap, pos, data, dir); | ||
446 | if (ret) | ||
447 | return ret; | ||
448 | |||
449 | /* | ||
450 | * If we're reading, copy the data into the caller's memory | ||
451 | * buffer. | ||
452 | */ | ||
453 | if (dir) | ||
454 | while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) && | ||
455 | len > 0) { | ||
456 | *buf++ = data[offset++]; | ||
457 | len -= sizeof(__be32); | ||
458 | } | ||
459 | } | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len, | ||
465 | __be32 *buf) | ||
466 | { | ||
467 | return t4_memory_rw(adap, mtype, addr, len, buf, 0); | ||
468 | } | ||
469 | |||
333 | #define EEPROM_STAT_ADDR 0x7bfc | 470 | #define EEPROM_STAT_ADDR 0x7bfc |
334 | #define VPD_BASE 0 | 471 | #define VPD_BASE 0 |
335 | #define VPD_LEN 512 | 472 | #define VPD_LEN 512 |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h index c26b455f37de..f534ed7e10e9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | |||
@@ -58,6 +58,7 @@ enum { | |||
58 | 58 | ||
59 | enum { | 59 | enum { |
60 | SF_PAGE_SIZE = 256, /* serial flash page size */ | 60 | SF_PAGE_SIZE = 256, /* serial flash page size */ |
61 | SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */ | ||
61 | }; | 62 | }; |
62 | 63 | ||
63 | enum { RSP_TYPE_FLBUF, RSP_TYPE_CPL, RSP_TYPE_INTR }; /* response entry types */ | 64 | enum { RSP_TYPE_FLBUF, RSP_TYPE_CPL, RSP_TYPE_INTR }; /* response entry types */ |
@@ -137,4 +138,83 @@ struct rsp_ctrl { | |||
137 | #define QINTR_CNT_EN 0x1 | 138 | #define QINTR_CNT_EN 0x1 |
138 | #define QINTR_TIMER_IDX(x) ((x) << 1) | 139 | #define QINTR_TIMER_IDX(x) ((x) << 1) |
139 | #define QINTR_TIMER_IDX_GET(x) (((x) >> 1) & 0x7) | 140 | #define QINTR_TIMER_IDX_GET(x) (((x) >> 1) & 0x7) |
141 | |||
142 | /* | ||
143 | * Flash layout. | ||
144 | */ | ||
145 | #define FLASH_START(start) ((start) * SF_SEC_SIZE) | ||
146 | #define FLASH_MAX_SIZE(nsecs) ((nsecs) * SF_SEC_SIZE) | ||
147 | |||
148 | enum { | ||
149 | /* | ||
150 | * Various Expansion-ROM boot images, etc. | ||
151 | */ | ||
152 | FLASH_EXP_ROM_START_SEC = 0, | ||
153 | FLASH_EXP_ROM_NSECS = 6, | ||
154 | FLASH_EXP_ROM_START = FLASH_START(FLASH_EXP_ROM_START_SEC), | ||
155 | FLASH_EXP_ROM_MAX_SIZE = FLASH_MAX_SIZE(FLASH_EXP_ROM_NSECS), | ||
156 | |||
157 | /* | ||
158 | * iSCSI Boot Firmware Table (iBFT) and other driver-related | ||
159 | * parameters ... | ||
160 | */ | ||
161 | FLASH_IBFT_START_SEC = 6, | ||
162 | FLASH_IBFT_NSECS = 1, | ||
163 | FLASH_IBFT_START = FLASH_START(FLASH_IBFT_START_SEC), | ||
164 | FLASH_IBFT_MAX_SIZE = FLASH_MAX_SIZE(FLASH_IBFT_NSECS), | ||
165 | |||
166 | /* | ||
167 | * Boot configuration data. | ||
168 | */ | ||
169 | FLASH_BOOTCFG_START_SEC = 7, | ||
170 | FLASH_BOOTCFG_NSECS = 1, | ||
171 | FLASH_BOOTCFG_START = FLASH_START(FLASH_BOOTCFG_START_SEC), | ||
172 | FLASH_BOOTCFG_MAX_SIZE = FLASH_MAX_SIZE(FLASH_BOOTCFG_NSECS), | ||
173 | |||
174 | /* | ||
175 | * Location of firmware image in FLASH. | ||
176 | */ | ||
177 | FLASH_FW_START_SEC = 8, | ||
178 | FLASH_FW_NSECS = 8, | ||
179 | FLASH_FW_START = FLASH_START(FLASH_FW_START_SEC), | ||
180 | FLASH_FW_MAX_SIZE = FLASH_MAX_SIZE(FLASH_FW_NSECS), | ||
181 | |||
182 | /* | ||
183 | * iSCSI persistent/crash information. | ||
184 | */ | ||
185 | FLASH_ISCSI_CRASH_START_SEC = 29, | ||
186 | FLASH_ISCSI_CRASH_NSECS = 1, | ||
187 | FLASH_ISCSI_CRASH_START = FLASH_START(FLASH_ISCSI_CRASH_START_SEC), | ||
188 | FLASH_ISCSI_CRASH_MAX_SIZE = FLASH_MAX_SIZE(FLASH_ISCSI_CRASH_NSECS), | ||
189 | |||
190 | /* | ||
191 | * FCoE persistent/crash information. | ||
192 | */ | ||
193 | FLASH_FCOE_CRASH_START_SEC = 30, | ||
194 | FLASH_FCOE_CRASH_NSECS = 1, | ||
195 | FLASH_FCOE_CRASH_START = FLASH_START(FLASH_FCOE_CRASH_START_SEC), | ||
196 | FLASH_FCOE_CRASH_MAX_SIZE = FLASH_MAX_SIZE(FLASH_FCOE_CRASH_NSECS), | ||
197 | |||
198 | /* | ||
199 | * Location of Firmware Configuration File in FLASH. Since the FPGA | ||
200 | * "FLASH" is smaller we need to store the Configuration File in a | ||
201 | * different location -- which will overlap the end of the firmware | ||
202 | * image if firmware ever gets that large ... | ||
203 | */ | ||
204 | FLASH_CFG_START_SEC = 31, | ||
205 | FLASH_CFG_NSECS = 1, | ||
206 | FLASH_CFG_START = FLASH_START(FLASH_CFG_START_SEC), | ||
207 | FLASH_CFG_MAX_SIZE = FLASH_MAX_SIZE(FLASH_CFG_NSECS), | ||
208 | |||
209 | FLASH_FPGA_CFG_START_SEC = 15, | ||
210 | FLASH_FPGA_CFG_START = FLASH_START(FLASH_FPGA_CFG_START_SEC), | ||
211 | |||
212 | /* | ||
213 | * Sectors 32-63 are reserved for FLASH failover. | ||
214 | */ | ||
215 | }; | ||
216 | |||
217 | #undef FLASH_START | ||
218 | #undef FLASH_MAX_SIZE | ||
219 | |||
140 | #endif /* __T4_HW_H */ | 220 | #endif /* __T4_HW_H */ |