aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/cxl/pci.c
diff options
context:
space:
mode:
authorVaibhav Jain <vaibhav@linux.vnet.ibm.com>2015-05-22 01:26:05 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2015-06-02 23:27:15 -0400
commite36f6fe1f7aa4238478d4b253aac7d3fcfff6ee0 (patch)
tree6ce1500973c137d3b642bc46f0fb4654d323969a /drivers/misc/cxl/pci.c
parent27d4dc7116eed98775902627ba61b70e9045e321 (diff)
cxl: Export AFU error buffer via sysfs
Export the "AFU Error Buffer" via sysfs attribute (afu_err_buf). AFU error buffer is used by the AFU to report application specific errors. The contents of this buffer are AFU specific and are intended to be interpreted by the application interacting with the afu. Suggested-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Vaibhav Jain <vaibhav@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'drivers/misc/cxl/pci.c')
-rw-r--r--drivers/misc/cxl/pci.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
index 1ef01647265f..c3671b3c4dcd 100644
--- a/drivers/misc/cxl/pci.c
+++ b/drivers/misc/cxl/pci.c
@@ -593,6 +593,22 @@ static int cxl_read_afu_descriptor(struct cxl_afu *afu)
593 afu->crs_len = AFUD_CR_LEN(val) * 256; 593 afu->crs_len = AFUD_CR_LEN(val) * 256;
594 afu->crs_offset = AFUD_READ_CR_OFF(afu); 594 afu->crs_offset = AFUD_READ_CR_OFF(afu);
595 595
596
597 /* eb_len is in multiple of 4K */
598 afu->eb_len = AFUD_EB_LEN(AFUD_READ_EB(afu)) * 4096;
599 afu->eb_offset = AFUD_READ_EB_OFF(afu);
600
601 /* eb_off is 4K aligned so lower 12 bits are always zero */
602 if (EXTRACT_PPC_BITS(afu->eb_offset, 0, 11) != 0) {
603 dev_warn(&afu->dev,
604 "Invalid AFU error buffer offset %Lx\n",
605 afu->eb_offset);
606 dev_info(&afu->dev,
607 "Ignoring AFU error buffer in the descriptor\n");
608 /* indicate that no afu buffer exists */
609 afu->eb_len = 0;
610 }
611
596 return 0; 612 return 0;
597} 613}
598 614
@@ -672,6 +688,50 @@ static int sanitise_afu_regs(struct cxl_afu *afu)
672 return 0; 688 return 0;
673} 689}
674 690
691#define ERR_BUFF_MAX_COPY_SIZE PAGE_SIZE
692/*
693 * afu_eb_read:
694 * Called from sysfs and reads the afu error info buffer. The h/w only supports
695 * 4/8 bytes aligned access. So in case the requested offset/count arent 8 byte
696 * aligned the function uses a bounce buffer which can be max PAGE_SIZE.
697 */
698ssize_t cxl_afu_read_err_buffer(struct cxl_afu *afu, char *buf,
699 loff_t off, size_t count)
700{
701 loff_t aligned_start, aligned_end;
702 size_t aligned_length;
703 void *tbuf;
704 const void __iomem *ebuf = afu->afu_desc_mmio + afu->eb_offset;
705
706 if (count == 0 || off < 0 || (size_t)off >= afu->eb_len)
707 return 0;
708
709 /* calculate aligned read window */
710 count = min((size_t)(afu->eb_len - off), count);
711 aligned_start = round_down(off, 8);
712 aligned_end = round_up(off + count, 8);
713 aligned_length = aligned_end - aligned_start;
714
715 /* max we can copy in one read is PAGE_SIZE */
716 if (aligned_length > ERR_BUFF_MAX_COPY_SIZE) {
717 aligned_length = ERR_BUFF_MAX_COPY_SIZE;
718 count = ERR_BUFF_MAX_COPY_SIZE - (off & 0x7);
719 }
720
721 /* use bounce buffer for copy */
722 tbuf = (void *)__get_free_page(GFP_TEMPORARY);
723 if (!tbuf)
724 return -ENOMEM;
725
726 /* perform aligned read from the mmio region */
727 memcpy_fromio(tbuf, ebuf + aligned_start, aligned_length);
728 memcpy(buf, tbuf + (off & 0x7), count);
729
730 free_page((unsigned long)tbuf);
731
732 return count;
733}
734
675static int cxl_init_afu(struct cxl *adapter, int slice, struct pci_dev *dev) 735static int cxl_init_afu(struct cxl *adapter, int slice, struct pci_dev *dev)
676{ 736{
677 struct cxl_afu *afu; 737 struct cxl_afu *afu;