aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
diff options
context:
space:
mode:
authorVipul Pandya <vipul@chelsio.com>2012-09-25 22:39:37 -0400
committerDavid S. Miller <davem@davemloft.net>2012-09-27 17:55:50 -0400
commit5afc8b84eb7b29e4646d6e8ca7e6d7196031d6f7 (patch)
tree34382fe914af703cbe1bf921c6a2ddac040f91e3 /drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
parent3eb4afbfceb44750d9afb832e6c992adec9fc571 (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>
Diffstat (limited to 'drivers/net/ethernet/chelsio/cxgb4/t4_hw.c')
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c137
1 files changed, 137 insertions, 0 deletions
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 */
344static 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 */
385static 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
464int 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