element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Avnet Boards Forums
  • Products
  • Dev Tools
  • Avnet Boards Community
  • Avnet Boards Forums
  • More
  • Cancel
Avnet Boards Forums
Software Application Development Invalidating the data cache
  • Forum
  • Documents
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Avnet Boards Forums to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • State Not Answered
  • Replies 11 replies
  • Subscribers 329 subscribers
  • Views 3839 views
  • Users 0 members are here
Related

Invalidating the data cache

Former Member
Former Member over 10 years ago

I have a problem that I am trying to fix in a program I have written.

I receive internet packets, the Rx interrupt affects a bool so that in a loop I can to to then request the RxBD from the hardware. I then copy out the packets into some linked list containers that I have before returning the BDs to the hardware.


My problem is that when I go to read the data that the BD points to, the cached data is wrong, so I invalidate it. Except that using

void Xil_DCacheInvalidateRange(unsigned int adr, unsigned len)

invalidates a cache line but not necessarily where the packet information starts. It looks at the address I pass to it, then it moves from there to the start of the first cache line and only then begins invalidating the cache.


This leads to varying parts of my packet information being "chopped off". Anywhere from 0 to 28 bytes worth of data.


A solution to this, as stated in the Xilinxs documentation seems to be to cache align the... sections of memory that the BD point to. The problem is, I have no idea how to do this.


I have tried simply disabling the entire cache at the start of the program, however this doesn't seem to work. I don't know if it is my attempt that doesn't work, or if it simply doesn't fix the problem.

(Code used to try to disable the entire cache)
Xil_L2CacheDisable();
Xil_L1DCacheDisable();
Xil_L1ICacheDisable();
dsb();
isb();

  • Sign in to reply
  • Cancel
Parents
  • Former Member
    0 Former Member over 10 years ago

    I'm not sure about the alignment of your 2-dimensional array
    u8 RxBuf[32][1540]__attribute__((aligned(32)));
    Maybe the whole array will be 32-aligned, not every element.
    Better try it this way:
    typedef u8 ethernetFrameData[XEMACPS_MAX_VLAN_FRAME_SIZE] __attribute__ ((aligned(32)));
    ethernetFrameData RxBuf[32];

    I now understand what you mean by direction and error word. You can use this error handler, to check for your errors:
    void ethernetError_handler(void *Callback, u8 Direction, u32 ErrorWord) {
    t//XEmacPs *EmacPsInstancePtr = (XEmacPs *) Callback;

    tu32* availableBuffer_l = availableBuffer;
    tu32* receiveBdCount_l = receiveBdCount;

    tXEmacPs *emacPsInstancePtr = (XEmacPs *) Callback;

    tswitch (Direction) {
    tcase XEMACPS_RECV:
    ttif (ErrorWord & XEMACPS_RXSR_HRESPNOK_MASK) {
    tttdebug_ReportError("Receive DMA error");
    tt}
    ttif (ErrorWord & XEMACPS_RXSR_RXOVR_MASK) {
    tttdebug_ReportError("Receive over run");
    tt}
    ttif (ErrorWord & XEMACPS_RXSR_BUFFNA_MASK) {
    tttdebug_ReportError("Receive buffer not available");
    tt}
    ttbreak;
    tcase XEMACPS_SEND:
    ttif (ErrorWord & XEMACPS_TXSR_HRESPNOK_MASK) {
    tttdebug_ReportError("Transmit DMA error");
    tt}
    ttif (ErrorWord & XEMACPS_TXSR_URUN_MASK) {
    tttdebug_ReportError("Transmit under run");
    tt}
    ttif (ErrorWord & XEMACPS_TXSR_BUFEXH_MASK) {
    tttdebug_ReportError("Transmit buffer exhausted");
    tt}
    ttif (ErrorWord & XEMACPS_TXSR_RXOVR_MASK) {
    tttdebug_ReportError("Transmit retry exceeded limits");
    ttt//todo: maybe restart transmission
    tt}
    ttif (ErrorWord & XEMACPS_TXSR_FRAMERX_MASK) {
    tttdebug_ReportError("Transmit collision");
    tt}
    ttif (ErrorWord & XEMACPS_TXSR_USEDREAD_MASK) {
    tttdebug_ReportError("Transmit buffer not available");
    tt}
    ttbreak;
    t}
    }

    register the handler by
    XEmacPs_SetHandler(EmacPsInstancePtr, XEMACPS_HANDLER_ERROR, (void *) ethernetError_handler, EmacPsInstancePtr);

    the defines are in xemacps_hw.h


    It is very important, that you place your BD-list in non-cacheable memory.
    Beware: Using Xil_SetTlbAttributes you must assure, that the first argument is a multiple of 0x100000, because otherwise this function maps your virtual memory to another physical address (and thus you get into trouble).
    To get into cacheing (especially important with arm1) I recommend reading http://www.silica.com/fileadmin/02_Products/Productdetails/Xilinx/Zynq_MMU_caches_control_ver1.0.pdf

    Instead of using the linker I recommend using a custom memory layout. Search yourself for an appropriate part of your memory and place there your BD-lists and frame buffers (and make them all uncacheable). Then you will not suffer from all that problems.
    e.g. my layout looks as follows:
    I use the Linker skript just to manage my personal layout. Thus I define the symbols:
    _EthernetFramesStorage_startAddress = 0x0F018000;
    _EthernetFramesStorage_maxLength = 0x9E8000;

    _txBDList_startAddress = 0x0F0C000;
    _txBDList_maxLength = 0xC000;

    _rxBDList_startAddress = 0x0F000000;
    _rxBDList_maxLength = 0xC000;

    Then in a .h I define
    /*
    * Buffer descriptors and frames are allocated in uncached memory. The memory is made
    * uncached by setting the attributes appropriately in the MMU table.
    */
    extern u32 _rxBDList_startAddress;
    extern u32 _txBDList_startAddress;
    extern u32 _EthernetFramesStorage_startAddress;
    #define RX_BD_LIST_START_ADDRESSt((size_t)&_rxBDList_startAddress)
    #define TX_BD_LIST_START_ADDRESSt((size_t)&_txBDList_startAddress)
    #define ETHERNET_FRAMES_STORAGE_START_ADDRESSt((size_t)&_EthernetFramesStorage_startAddress)

    extern u32 _rxBDList_maxLength;
    extern u32 _txBDList_maxLength;
    extern u32 _EthernetFramesStorage_maxLength;
    #define RX_BD_LIST_MAX_LENGTHt((u32)&_rxBDList_maxLength)
    #define TX_BD_LIST_MAX_LENGTHt((u32)&_txBDList_maxLength)
    #define ETHERNET_FRAMES_STORAGE_MAX_LENGTH ((u32)&_EthernetFramesStorage_maxLength)

    typedef u8 ethernetFrameData[XEMACPS_MAX_VLAN_FRAME_SIZE] __attribute__ ((aligned(32)));
    typedef struct {
    tethernetFrameData data;
    tu32 length;
    } ethernetFrame;


    in a .c I define
    static ethernetFrame* ethernetFrames = ETHERNET_FRAMES_STORAGE_START_ADDRESS;

    static int initBDRings(void) {
    tint status;

    tXEmacPs_Bd BdTemplate;

    t/*
    t * Setup RxBD space.
    t *
    t * Setup a BD template for the Rx channel. This template will be
    t * copied to every RxBD. We will not have to explicitly set these
    t * again.
    t */
    tXEmacPs_BdClear(&BdTemplate);

    t/*
    t * Create the RxBD ring with 2*RECEIVE_FIFO_ATTENDENCE BDs, so that there are always enough BDs to be allocated, even if not all have been returned yet
    t */
    tstatus = XEmacPs_BdRingCreate(&(XEmacPs_GetRxRing(usedEmacPsInstancePtr)), RX_BD_LIST_START_ADDRESS, RX_BD_LIST_START_ADDRESS, XEMACPS_BD_ALIGNMENT,
    ttt2 * RECEIVE_FIFO_ATTENDENCE);
    tif (status != XST_SUCCESS) {
    ttdebug_ReportError("Error setting up RxBD space, BdRingCreate");
    ttreturn XST_FAILURE;
    t}

    tstatus = XEmacPs_BdRingClone(&(XEmacPs_GetRxRing(usedEmacPsInstancePtr)), &BdTemplate, XEMACPS_RECV);
    tif (status != XST_SUCCESS) {
    ttdebug_ReportError("Error setting up RxBD space, BdRingClone");
    ttreturn XST_FAILURE;
    t}



    t/*
    t * Setup TxBD space.
    t *
    t * Like RxBD space, we have already defined a properly aligned area
    t * of memory to use.
    t *
    t * Also like the RxBD space, we create a template.
    t * The "last" attribute is set, s.t. every BD contains a full frame.
    t */
    tXEmacPs_BdClear(&BdTemplate);
    tXEmacPs_BdSetLast(&BdTemplate);
    tXEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK);

    t/*
    t * Create the TxBD ring
    t */
    tstatus = XEmacPs_BdRingCreate(&(XEmacPs_GetTxRing(usedEmacPsInstancePtr)), TX_BD_LIST_START_ADDRESS, TX_BD_LIST_START_ADDRESS, XEMACPS_BD_ALIGNMENT,
    tttETHERNET_FRAME_RESERVE);
    tif (status != XST_SUCCESS) {
    ttdebug_ReportError("Error setting up TxBD space, BdRingCreate");
    ttreturn XST_FAILURE;
    t}
    tstatus = XEmacPs_BdRingClone(&(XEmacPs_GetTxRing(usedEmacPsInstancePtr)), &BdTemplate, XEMACPS_SEND);
    tif (status != XST_SUCCESS) {
    ttdebug_ReportError("Error setting up TxBD space, BdRingClone");
    ttreturn XST_FAILURE;
    t}

    treturn XST_SUCCESS;
    }

    For cacheing I use a wrapper, to make changing the page table save (with defines from the Link I posted):
    #define L1_NON_CACHEABLE 0x00  //  C = b0, B = b0
    #define L1_WRITEBACK_WRITEALLOCATE  0x0004  //  C = b0, B = b1
    #define L1_WRITETHROUGH_NO_WRITEALLOCATE 0x0008  // C = b1, B = b0
    #define L1_WRITEBACK_NO_WRITEALLOCATE 0x000C  //  C = b1, B = b1


    #define L2_NON_CACHEABLE 0x00  // TEX(1:0) = b00, C = b0, B = b0
    #define L2_WRITEBACK_WRITEALLOCATE  0x1000  // TEX(1:0) = b01, C = b0, B = b1
    #define L2_WRITETHROUGH_NO_WRITEALLOCATE 0x2000  // TEX(1:0) = b10, C = b1, B = b0
    #define L2_WRITEBACK_NO_WRITEALLOCATE 0x3000  // TEX(1:0) = b11, C = b1, B = b1


    //L1 and L2
    #define NON_CACHEABLE  (L1_NON_CACHEABLE | L2_NON_CACHEABLE)
    #define WRITEBACK_WRITEALLOCATE   (L1_WRITEBACK_WRITEALLOCATE | L2_WRITEBACK_WRITEALLOCATE)
    #define WRITETHROUGH_NO_WRITEALLOCATE  (L1_WRITETHROUGH_NO_WRITEALLOCATE | L2_WRITETHROUGH_NO_WRITEALLOCATE)
    #define WRITEBACK_NO_WRITEALLOCATE  (L1_WRITEBACK_NO_WRITEALLOCATE | L2_WRITEBACK_NO_WRITEALLOCATE)


    #define NON_GLOBAL 0x20000  // nG = b1

    #define EXECUTE_NEVER 0x10  // XN = b1

    #define SHAREABLE 0x10000  // S = b1

    #define AP_PERMISSIONFAULT 0x00  // AP(2) = b0, AP(1:0) = b00
    #define AP_PRIVIEGED_ACCESS_ONLY 0x400  // AP(2) = b0, AP(1:0) = b01
    #define AP_NO_USERMODE_WRITE 0x800  // AP(2) = b0, AP(1:0) = b10
    #define AP_FULL_ACCESS 0xC00  // AP(2) = b0, AP(1:0) = b11
    #define AP_PRIVILEGED_READ_ONLY 0x8800  // AP(2) = b1, AP(1:0) = b10

    void adjustMmuMode_1MBGranularity(u32 address, u32 length, u32 features) {
    tunsigned int mmu_attributes = 0;

    t/* Declare the part of the page table value that gets written to the */
    t/* MMU Table, which is always fixed. */
    t/* NS = b0, Bit 18 = b0, TEX(2) = b1, Bit 9 = b0, Domain = b1111, */
    t/* Bits(1:0) = b10 ... Equivalent hex value = 0x41e2 */
    tconst u32 fixed_values = 0x41e2;

    t// Calculate the value that will be written to the MMU Page Table
    tmmu_attributes = fixed_values | features;

    t// Write the value to the TLB
    tu32 onePastLastAddress = address + length;
    tu32 roundedAddress = address & 0xFFF00000;
    tfor (; roundedAddress < onePastLastAddress; roundedAddress += 0x100000) {
    ttXil_SetTlbAttributes(roundedAddress, mmu_attributes);
    t}
    }


    When running the program, first assure changing the page table settings:
    adjustMmuMode_1MBGranularity(RX_BD_LIST_START_ADDRESS, RX_BD_LIST_MAX_LENGTH, NON_CACHEABLE | AP_FULL_ACCESS | SHAREABLE);
    tadjustMmuMode_1MBGranularity(TX_BD_LIST_START_ADDRESS, TX_BD_LIST_MAX_LENGTH, NON_CACHEABLE | AP_FULL_ACCESS | SHAREABLE);
    tadjustMmuMode_1MBGranularity(ETHERNET_FRAMES_STORAGE_START_ADDRESS, ETHERNET_FRAMES_STORAGE_MAX_LENGTH, NON_CACHEABLE | AP_FULL_ACCESS | SHAREABLE);



    I do not know how you configure your PHY, but try
    #define PHY_REG0_RESET    0x8000
    #define PHY_REG0_10       0x0100
    #define PHY_REG0_100      0x2100
    #define PHY_REG0_1000     0x0140
    #define PHY_REG21_10      0x0030
    #define PHY_REG21_100     0x2030
    #define PHY_REG21_1000    0x0070
    static int initPhy(XEmacPs * EmacPsInstancePtr) {
    tint Status;
    tu32 PhyAddr = 0;
    tu16 PhyReg0 = PHY_REG0_1000; //gigabit (no meore)
    tu16 PhyReg21  = PHY_REG21_1000;
    tu16 PhyReg22  = 0;

    tStatus = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0);
    t/*
    t * Make sure new configuration is in effect
    t */
    tStatus = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0);
    tif (Status != XST_SUCCESS) {
    ttdebug_ReportError("Error setup phy speed");
    ttreturn XST_FAILURE;
    t}



    t/*
    t * Switching to PAGE2
    t */
    tPhyReg22 = 0x2;
    tStatus = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 22, PhyReg22);

    t/*
    t * Adding Tx and Rx delay. Configuring loopback speed.
    t */
    tStatus = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 21, PhyReg21);
    t/*
    t * Make sure new configuration is in effect
    t */
    tStatus = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 21, &PhyReg21);
    tif (Status != XST_SUCCESS) {
    ttdebug_ReportError("Error setting Reg 21 in Page 2");
    ttreturn XST_FAILURE;
    t}
    t/*
    t * Switching to PAGE0
    t */
    tPhyReg22 = 0x0;
    tStatus = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 22, PhyReg22);





    t/*
    t * Issue a reset to phy
    t */
    tStatus = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0);
    tPhyReg0 |= PHY_REG0_RESET;
    tStatus = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0);

    tStatus = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0);
    tif (Status != XST_SUCCESS) {
    ttdebug_ReportError("Error reset phy");
    ttreturn XST_FAILURE;
    t}

    t/*
    t * Delay loop
    t */
    tsleep(EMACPS_PHY_DELAY_SEC);

    treturn XST_SUCCESS;

    }


    I think that it schould not be a problem to run the MAC from arm1, but there could be problems, if your arm0 writes to memory, where he shouldn't write to. And much more important, there will be huge problems, if you use cacheing with both arms and the one invalidates or flushes cachelines of L2 with not aligned memory. Normally only arm0 should have control over the L2 cache and arm1 should ask arm0 to savely flush or invalidate the cache.
    There really are a lot of pitfalls. If you do not exactly know what you are doing, turn your caches of. Otherwise you will loose random bytes (depending on race conditions)
    A wise guy said, there are only two hard things in Computer Science: cache invalidation and naming things.



    Now to your second post:
    I think you messed it up with SetTlbAttributes.
    And then disabling the cache from arm1 can cause problems. On arm1 you can not use the Xil_DCacheInvalidateRange or the Xil_DCacheDisable function, since arm0 controls L2 cache, too. You better should just switch cacheing off in the page table (mmu table) by Xil_SetTlbAttributes.
    You should try to run your program from arm0 alone. When it works, you can think about porting it to arm1 and clearify all that cache and mmu stuff.



    Man... that's a lot... I admit that I did not read the text twice, because I have written it for an hour and have to go to sleep now. So if there are some mistakes, be merciful

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
Reply
  • Former Member
    0 Former Member over 10 years ago

    I'm not sure about the alignment of your 2-dimensional array
    u8 RxBuf[32][1540]__attribute__((aligned(32)));
    Maybe the whole array will be 32-aligned, not every element.
    Better try it this way:
    typedef u8 ethernetFrameData[XEMACPS_MAX_VLAN_FRAME_SIZE] __attribute__ ((aligned(32)));
    ethernetFrameData RxBuf[32];

    I now understand what you mean by direction and error word. You can use this error handler, to check for your errors:
    void ethernetError_handler(void *Callback, u8 Direction, u32 ErrorWord) {
    t//XEmacPs *EmacPsInstancePtr = (XEmacPs *) Callback;

    tu32* availableBuffer_l = availableBuffer;
    tu32* receiveBdCount_l = receiveBdCount;

    tXEmacPs *emacPsInstancePtr = (XEmacPs *) Callback;

    tswitch (Direction) {
    tcase XEMACPS_RECV:
    ttif (ErrorWord & XEMACPS_RXSR_HRESPNOK_MASK) {
    tttdebug_ReportError("Receive DMA error");
    tt}
    ttif (ErrorWord & XEMACPS_RXSR_RXOVR_MASK) {
    tttdebug_ReportError("Receive over run");
    tt}
    ttif (ErrorWord & XEMACPS_RXSR_BUFFNA_MASK) {
    tttdebug_ReportError("Receive buffer not available");
    tt}
    ttbreak;
    tcase XEMACPS_SEND:
    ttif (ErrorWord & XEMACPS_TXSR_HRESPNOK_MASK) {
    tttdebug_ReportError("Transmit DMA error");
    tt}
    ttif (ErrorWord & XEMACPS_TXSR_URUN_MASK) {
    tttdebug_ReportError("Transmit under run");
    tt}
    ttif (ErrorWord & XEMACPS_TXSR_BUFEXH_MASK) {
    tttdebug_ReportError("Transmit buffer exhausted");
    tt}
    ttif (ErrorWord & XEMACPS_TXSR_RXOVR_MASK) {
    tttdebug_ReportError("Transmit retry exceeded limits");
    ttt//todo: maybe restart transmission
    tt}
    ttif (ErrorWord & XEMACPS_TXSR_FRAMERX_MASK) {
    tttdebug_ReportError("Transmit collision");
    tt}
    ttif (ErrorWord & XEMACPS_TXSR_USEDREAD_MASK) {
    tttdebug_ReportError("Transmit buffer not available");
    tt}
    ttbreak;
    t}
    }

    register the handler by
    XEmacPs_SetHandler(EmacPsInstancePtr, XEMACPS_HANDLER_ERROR, (void *) ethernetError_handler, EmacPsInstancePtr);

    the defines are in xemacps_hw.h


    It is very important, that you place your BD-list in non-cacheable memory.
    Beware: Using Xil_SetTlbAttributes you must assure, that the first argument is a multiple of 0x100000, because otherwise this function maps your virtual memory to another physical address (and thus you get into trouble).
    To get into cacheing (especially important with arm1) I recommend reading http://www.silica.com/fileadmin/02_Products/Productdetails/Xilinx/Zynq_MMU_caches_control_ver1.0.pdf

    Instead of using the linker I recommend using a custom memory layout. Search yourself for an appropriate part of your memory and place there your BD-lists and frame buffers (and make them all uncacheable). Then you will not suffer from all that problems.
    e.g. my layout looks as follows:
    I use the Linker skript just to manage my personal layout. Thus I define the symbols:
    _EthernetFramesStorage_startAddress = 0x0F018000;
    _EthernetFramesStorage_maxLength = 0x9E8000;

    _txBDList_startAddress = 0x0F0C000;
    _txBDList_maxLength = 0xC000;

    _rxBDList_startAddress = 0x0F000000;
    _rxBDList_maxLength = 0xC000;

    Then in a .h I define
    /*
    * Buffer descriptors and frames are allocated in uncached memory. The memory is made
    * uncached by setting the attributes appropriately in the MMU table.
    */
    extern u32 _rxBDList_startAddress;
    extern u32 _txBDList_startAddress;
    extern u32 _EthernetFramesStorage_startAddress;
    #define RX_BD_LIST_START_ADDRESSt((size_t)&_rxBDList_startAddress)
    #define TX_BD_LIST_START_ADDRESSt((size_t)&_txBDList_startAddress)
    #define ETHERNET_FRAMES_STORAGE_START_ADDRESSt((size_t)&_EthernetFramesStorage_startAddress)

    extern u32 _rxBDList_maxLength;
    extern u32 _txBDList_maxLength;
    extern u32 _EthernetFramesStorage_maxLength;
    #define RX_BD_LIST_MAX_LENGTHt((u32)&_rxBDList_maxLength)
    #define TX_BD_LIST_MAX_LENGTHt((u32)&_txBDList_maxLength)
    #define ETHERNET_FRAMES_STORAGE_MAX_LENGTH ((u32)&_EthernetFramesStorage_maxLength)

    typedef u8 ethernetFrameData[XEMACPS_MAX_VLAN_FRAME_SIZE] __attribute__ ((aligned(32)));
    typedef struct {
    tethernetFrameData data;
    tu32 length;
    } ethernetFrame;


    in a .c I define
    static ethernetFrame* ethernetFrames = ETHERNET_FRAMES_STORAGE_START_ADDRESS;

    static int initBDRings(void) {
    tint status;

    tXEmacPs_Bd BdTemplate;

    t/*
    t * Setup RxBD space.
    t *
    t * Setup a BD template for the Rx channel. This template will be
    t * copied to every RxBD. We will not have to explicitly set these
    t * again.
    t */
    tXEmacPs_BdClear(&BdTemplate);

    t/*
    t * Create the RxBD ring with 2*RECEIVE_FIFO_ATTENDENCE BDs, so that there are always enough BDs to be allocated, even if not all have been returned yet
    t */
    tstatus = XEmacPs_BdRingCreate(&(XEmacPs_GetRxRing(usedEmacPsInstancePtr)), RX_BD_LIST_START_ADDRESS, RX_BD_LIST_START_ADDRESS, XEMACPS_BD_ALIGNMENT,
    ttt2 * RECEIVE_FIFO_ATTENDENCE);
    tif (status != XST_SUCCESS) {
    ttdebug_ReportError("Error setting up RxBD space, BdRingCreate");
    ttreturn XST_FAILURE;
    t}

    tstatus = XEmacPs_BdRingClone(&(XEmacPs_GetRxRing(usedEmacPsInstancePtr)), &BdTemplate, XEMACPS_RECV);
    tif (status != XST_SUCCESS) {
    ttdebug_ReportError("Error setting up RxBD space, BdRingClone");
    ttreturn XST_FAILURE;
    t}



    t/*
    t * Setup TxBD space.
    t *
    t * Like RxBD space, we have already defined a properly aligned area
    t * of memory to use.
    t *
    t * Also like the RxBD space, we create a template.
    t * The "last" attribute is set, s.t. every BD contains a full frame.
    t */
    tXEmacPs_BdClear(&BdTemplate);
    tXEmacPs_BdSetLast(&BdTemplate);
    tXEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK);

    t/*
    t * Create the TxBD ring
    t */
    tstatus = XEmacPs_BdRingCreate(&(XEmacPs_GetTxRing(usedEmacPsInstancePtr)), TX_BD_LIST_START_ADDRESS, TX_BD_LIST_START_ADDRESS, XEMACPS_BD_ALIGNMENT,
    tttETHERNET_FRAME_RESERVE);
    tif (status != XST_SUCCESS) {
    ttdebug_ReportError("Error setting up TxBD space, BdRingCreate");
    ttreturn XST_FAILURE;
    t}
    tstatus = XEmacPs_BdRingClone(&(XEmacPs_GetTxRing(usedEmacPsInstancePtr)), &BdTemplate, XEMACPS_SEND);
    tif (status != XST_SUCCESS) {
    ttdebug_ReportError("Error setting up TxBD space, BdRingClone");
    ttreturn XST_FAILURE;
    t}

    treturn XST_SUCCESS;
    }

    For cacheing I use a wrapper, to make changing the page table save (with defines from the Link I posted):
    #define L1_NON_CACHEABLE 0x00  //  C = b0, B = b0
    #define L1_WRITEBACK_WRITEALLOCATE  0x0004  //  C = b0, B = b1
    #define L1_WRITETHROUGH_NO_WRITEALLOCATE 0x0008  // C = b1, B = b0
    #define L1_WRITEBACK_NO_WRITEALLOCATE 0x000C  //  C = b1, B = b1


    #define L2_NON_CACHEABLE 0x00  // TEX(1:0) = b00, C = b0, B = b0
    #define L2_WRITEBACK_WRITEALLOCATE  0x1000  // TEX(1:0) = b01, C = b0, B = b1
    #define L2_WRITETHROUGH_NO_WRITEALLOCATE 0x2000  // TEX(1:0) = b10, C = b1, B = b0
    #define L2_WRITEBACK_NO_WRITEALLOCATE 0x3000  // TEX(1:0) = b11, C = b1, B = b1


    //L1 and L2
    #define NON_CACHEABLE  (L1_NON_CACHEABLE | L2_NON_CACHEABLE)
    #define WRITEBACK_WRITEALLOCATE   (L1_WRITEBACK_WRITEALLOCATE | L2_WRITEBACK_WRITEALLOCATE)
    #define WRITETHROUGH_NO_WRITEALLOCATE  (L1_WRITETHROUGH_NO_WRITEALLOCATE | L2_WRITETHROUGH_NO_WRITEALLOCATE)
    #define WRITEBACK_NO_WRITEALLOCATE  (L1_WRITEBACK_NO_WRITEALLOCATE | L2_WRITEBACK_NO_WRITEALLOCATE)


    #define NON_GLOBAL 0x20000  // nG = b1

    #define EXECUTE_NEVER 0x10  // XN = b1

    #define SHAREABLE 0x10000  // S = b1

    #define AP_PERMISSIONFAULT 0x00  // AP(2) = b0, AP(1:0) = b00
    #define AP_PRIVIEGED_ACCESS_ONLY 0x400  // AP(2) = b0, AP(1:0) = b01
    #define AP_NO_USERMODE_WRITE 0x800  // AP(2) = b0, AP(1:0) = b10
    #define AP_FULL_ACCESS 0xC00  // AP(2) = b0, AP(1:0) = b11
    #define AP_PRIVILEGED_READ_ONLY 0x8800  // AP(2) = b1, AP(1:0) = b10

    void adjustMmuMode_1MBGranularity(u32 address, u32 length, u32 features) {
    tunsigned int mmu_attributes = 0;

    t/* Declare the part of the page table value that gets written to the */
    t/* MMU Table, which is always fixed. */
    t/* NS = b0, Bit 18 = b0, TEX(2) = b1, Bit 9 = b0, Domain = b1111, */
    t/* Bits(1:0) = b10 ... Equivalent hex value = 0x41e2 */
    tconst u32 fixed_values = 0x41e2;

    t// Calculate the value that will be written to the MMU Page Table
    tmmu_attributes = fixed_values | features;

    t// Write the value to the TLB
    tu32 onePastLastAddress = address + length;
    tu32 roundedAddress = address & 0xFFF00000;
    tfor (; roundedAddress < onePastLastAddress; roundedAddress += 0x100000) {
    ttXil_SetTlbAttributes(roundedAddress, mmu_attributes);
    t}
    }


    When running the program, first assure changing the page table settings:
    adjustMmuMode_1MBGranularity(RX_BD_LIST_START_ADDRESS, RX_BD_LIST_MAX_LENGTH, NON_CACHEABLE | AP_FULL_ACCESS | SHAREABLE);
    tadjustMmuMode_1MBGranularity(TX_BD_LIST_START_ADDRESS, TX_BD_LIST_MAX_LENGTH, NON_CACHEABLE | AP_FULL_ACCESS | SHAREABLE);
    tadjustMmuMode_1MBGranularity(ETHERNET_FRAMES_STORAGE_START_ADDRESS, ETHERNET_FRAMES_STORAGE_MAX_LENGTH, NON_CACHEABLE | AP_FULL_ACCESS | SHAREABLE);



    I do not know how you configure your PHY, but try
    #define PHY_REG0_RESET    0x8000
    #define PHY_REG0_10       0x0100
    #define PHY_REG0_100      0x2100
    #define PHY_REG0_1000     0x0140
    #define PHY_REG21_10      0x0030
    #define PHY_REG21_100     0x2030
    #define PHY_REG21_1000    0x0070
    static int initPhy(XEmacPs * EmacPsInstancePtr) {
    tint Status;
    tu32 PhyAddr = 0;
    tu16 PhyReg0 = PHY_REG0_1000; //gigabit (no meore)
    tu16 PhyReg21  = PHY_REG21_1000;
    tu16 PhyReg22  = 0;

    tStatus = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0);
    t/*
    t * Make sure new configuration is in effect
    t */
    tStatus = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0);
    tif (Status != XST_SUCCESS) {
    ttdebug_ReportError("Error setup phy speed");
    ttreturn XST_FAILURE;
    t}



    t/*
    t * Switching to PAGE2
    t */
    tPhyReg22 = 0x2;
    tStatus = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 22, PhyReg22);

    t/*
    t * Adding Tx and Rx delay. Configuring loopback speed.
    t */
    tStatus = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 21, PhyReg21);
    t/*
    t * Make sure new configuration is in effect
    t */
    tStatus = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 21, &PhyReg21);
    tif (Status != XST_SUCCESS) {
    ttdebug_ReportError("Error setting Reg 21 in Page 2");
    ttreturn XST_FAILURE;
    t}
    t/*
    t * Switching to PAGE0
    t */
    tPhyReg22 = 0x0;
    tStatus = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 22, PhyReg22);





    t/*
    t * Issue a reset to phy
    t */
    tStatus = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0);
    tPhyReg0 |= PHY_REG0_RESET;
    tStatus = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0);

    tStatus = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0);
    tif (Status != XST_SUCCESS) {
    ttdebug_ReportError("Error reset phy");
    ttreturn XST_FAILURE;
    t}

    t/*
    t * Delay loop
    t */
    tsleep(EMACPS_PHY_DELAY_SEC);

    treturn XST_SUCCESS;

    }


    I think that it schould not be a problem to run the MAC from arm1, but there could be problems, if your arm0 writes to memory, where he shouldn't write to. And much more important, there will be huge problems, if you use cacheing with both arms and the one invalidates or flushes cachelines of L2 with not aligned memory. Normally only arm0 should have control over the L2 cache and arm1 should ask arm0 to savely flush or invalidate the cache.
    There really are a lot of pitfalls. If you do not exactly know what you are doing, turn your caches of. Otherwise you will loose random bytes (depending on race conditions)
    A wise guy said, there are only two hard things in Computer Science: cache invalidation and naming things.



    Now to your second post:
    I think you messed it up with SetTlbAttributes.
    And then disabling the cache from arm1 can cause problems. On arm1 you can not use the Xil_DCacheInvalidateRange or the Xil_DCacheDisable function, since arm0 controls L2 cache, too. You better should just switch cacheing off in the page table (mmu table) by Xil_SetTlbAttributes.
    You should try to run your program from arm0 alone. When it works, you can think about porting it to arm1 and clearify all that cache and mmu stuff.



    Man... that's a lot... I admit that I did not read the text twice, because I have written it for an hour and have to go to sleep now. So if there are some mistakes, be merciful

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
Children
No Data
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube