/******************************************************************************* NAME $RCSfile: plxBS.c,v $ SUMMARY Board Stress for PLX Non-Transparent Bridge VERSION $Revision: 1.6 $ UPDATE DATE $Date: 2009/12/15 03:23:24 $ PROGRAMMER $Author: jim $ Copyright 2009 LSI Corporation. All Rights Reserved. DESCRIPTION: REFERENCE: *******************************************************************************/ #include #include #include #include #include #include #include //#include #include "plxDiag.h" /* FIXME: CB3 dma compare is not ready */ #define NO_DMA_COMPARE PUBLIC BOOLEAN dmaMemCompare(UINT64 addrPhySrc, UINT64 addrPhyDst, UINT32 len); extern void plxIpcExit(void); #ifdef PLX_NT_BACK_TO_BACK extern void plxNTBSetTransAddress(unsigned long long address); #endif /****************************************************** * Testing Memory Layout of two controllers * * _____________ _____________ * | | * | Kernel Memory | Kernel Memory * |_____________ |_____________ * | | * | (Local BAR2/3) | * LocalAddr ->|____________ TransAddr->|______________ * | | * | Local Memory | Remote Memory * |_____________ |______________ * | | * | | * ******************************************************/ struct PLX_BS_CB { struct task_struct *task; phys_addr_t localAddr; /* Local start physical address */ phys_addr_t transAddr; /* Translation peer physical address */ uint32_t size; /* Testing range */ }; static struct PLX_BS_CB plxBsCb; #define PATTERN_ARRAY_SIZE 8 static uint32_t plxBsPatternTable[] = { 0xFFFFFFFF, 0xAAAAAAAA, 0x55555555, 0x00000000, 0xC0C0C0C0, 0x0F0F0F0F, 0xF0F0F0F0, 0x03030303 }; #define BYTES_PER_LINE 16 static void plx_dgShowBuf(char *titleP, void *dataBufP, int count) { int done; int lineDone = 0; int i; unsigned char *bufP = (unsigned char *) dataBufP; unsigned char textBuf [BYTES_PER_LINE + 1]; unsigned char nextByte; unsigned char sepChar; printk ("%s\n", titleP); done = 0; while (done < count) { if (lineDone == 0) printk(" %.4X: ", done); if (lineDone == (BYTES_PER_LINE/2)) sepChar = '-'; else sepChar = ' '; nextByte = bufP[done]; printk ("%c%.2X", sepChar, nextByte); if ( (nextByte >= 0x20) && (nextByte <= 0x7F)) textBuf[lineDone] = nextByte; else textBuf[lineDone] = '.'; lineDone++; done++; if ((lineDone == BYTES_PER_LINE) || (done == count)) { for (i=lineDone; i= (region - DMA_BUFFER_SIZE)) // offset = 0; i++; } #ifdef NO_DMA_COMPARE if (virAddrPat) iounmap(virAddrPat); if (virAddrBack) iounmap(virAddrBack); if (virAddrRemote) iounmap(virAddrRemote); #endif } static int plxBsTask(void* data) { struct PLX_BS_CB *cb = data; struct pci_dev *pdev = NULL; int done = 0; phys_addr_t remotePhy = 0; /* * Find out NT Device and setup memory windows for this test */ while ((pdev = pci_get_device(0x10b5, PCI_ANY_ID, pdev))) { if ((pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) && ((pdev->class >> 8) == PCI_CLASS_BRIDGE_OTHER || (pdev->class >> 8) == PCI_CLASS_SYSTEM_OTHER) && (pdev->pcie_type == PCI_EXP_TYPE_ENDPOINT)) { uint32_t bl, bu; #ifndef PLX_NT_BACK_TO_BACK /* write translation address lower */ pci_write_config_dword(pdev, 0xc3c, (uint32_t) cb->transAddr); #else plxNTBSetTransAddress(cb->transAddr); #endif /* peer physical address */ pci_read_config_dword(pdev, 0x18, &bl); if (bl & 0x4) { /* address translation upper */ #ifndef PLX_NT_BACK_TO_BACK pci_write_config_dword(pdev, 0xc40, (uint32_t) (cb->transAddr >> 32)); #endif /* 64-bit address */ pci_read_config_dword(pdev, 0x1c, &bu); remotePhy = bu; remotePhy = remotePhy << 32; } remotePhy += (bl & 0xfff00000); done = 1; break; } } if (!done) { printk("PLX: can not find NT device\n"); return (-ENODEV); } plxBsRun(cb->localAddr, remotePhy, cb->size); return (0); } /******************************************************************************* * PROCEDURE * * NAME: plxBsStart * SUMMARY: Entry point to start stress test on NTB * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int plxBsStart(uint32_t localAddrMB, uint32_t transAddrMB, int sizeMB) { plxBsCb.localAddr = (phys_addr_t) localAddrMB * MB; plxBsCb.transAddr = (phys_addr_t) transAddrMB * MB; plxBsCb.size = sizeMB * MB; /* Clean up PLX IPC resource before this test */ plxIpcExit(); plxBsCb.task = kthread_run(plxBsTask, &plxBsCb, "plxBsTask"); if (IS_ERR(plxBsCb.task)) { printk("Create PLX BS Task Failed\n"); /* TODO */ return (-EFAULT); } return (0); } void plxBsStop(void) { if (plxBsCb.task) { kthread_stop(plxBsCb.task); plxBsCb.task = NULL; } } /******************************************************* * Debug & Testing *******************************************************/ void plxShowTransSettings(void) { struct pci_dev *pdev = NULL; int done = 0; phys_addr_t barAddress = 0; phys_addr_t transAddress = 0; while ((pdev = pci_get_device(0x10b5, PCI_ANY_ID, pdev))) { if ((pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) && ((pdev->class >> 8) == PCI_CLASS_BRIDGE_OTHER || (pdev->class >> 8) == PCI_CLASS_SYSTEM_OTHER) && (pdev->pcie_type == PCI_EXP_TYPE_ENDPOINT)) { uint32_t bl, bu; uint32_t ll, lu; /* read translation address lower */ pci_read_config_dword(pdev, 0xc3c, &ll); /* peer physical address */ pci_read_config_dword(pdev, 0x18, &bl); if (bl & 0x4) { #ifdef CONFIG_PHYS_ADDR_T_64BIT /* address translation upper */ pci_read_config_dword(pdev, 0xc40, &lu); /* 64-bit address */ pci_read_config_dword(pdev, 0x1c, &bu); barAddress = bu; barAddress = barAddress << 32; transAddress = lu; transAddress = transAddress << 32; #else BUG(); #endif } barAddress += (bl & 0xfff00000); transAddress += ll; done = 1; break; } } if (!done) { printk("PLX: can not find NT device\n"); return; } printk("PLX NTB: Translation Address = %016llx, BAR2/3 Address = %016llx\n", transAddress, barAddress); } void plxMemShow(uint32_t addrUpper, uint32_t addrLower, int size) { int i; phys_addr_t address; uint8_t *mem; address = (((phys_addr_t)addrUpper) << 32) + addrLower; mem = ioremap(address, size); if (mem == NULL) { printk("ioremap failed\n"); return; } for (i = 0; i < size; i++) { if ((i%32) == 0) printk("\n"); printk("%02x ", (volatile uint8_t) mem[i]); } printk("\n"); iounmap(mem); } /* void plxDmaCopy(uint32_t srcAddrUpper, uint32_t srcAddrLower, uint32_t desAddrUpper, uint32_t desAddrLower, int size) { phys_addr_t srcAddress; phys_addr_t desAddress; srcAddress = (((phys_addr_t)srcAddrUpper) << 32) + srcAddrLower; desAddress = (((phys_addr_t)desAddrUpper) << 32) + desAddrLower; dmaMemCopy(srcAddress, desAddress, size, 0); } void plxDmaSet(uint32_t addrUpper, uint32_t addrLower, int size, uint32_t value) { phys_addr_t address; address = (((phys_addr_t)addrUpper) << 32) + addrLower; dmaMemSet(address, size, value); } */ MODULE_AUTHOR( "lawrence.smith@netapp.com" ); MODULE_DESCRIPTION( "NetApp PLX Stress Code" ); MODULE_LICENSE( "GPL" ); MODULE_VERSION( "0.1" );