| /********************************************************************* |
| * |
| * (C) Copyright IBM Corp. 2007,2010 |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the |
| * Free Software Foundation; either version 2 of the License, or (at your |
| * option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * for more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, see <http://www.gnu.org/licenses>. |
| * |
| ********************************************************************/ |
| |
| #ifndef _DMA_COUNTER_H_ /* Prevent multiple inclusion */ |
| #define _DMA_COUNTER_H_ |
| |
| |
| /*! |
| * \file spi/DMA_Counter.h |
| * |
| * \brief DMA SPI Counter Definitions and Inline Functions |
| * |
| * This include file contains inline functions that are used to interface with |
| * BG/P DMA injection and reception counters at the lowest level. |
| * Functions include |
| * - set and get a counter's value and base address |
| * - enable and disable a counter or group of counters |
| * - query whether a counter or group of counters has hit zero |
| * - clear a counter's or group of counters' hit-zero state |
| * - set and get a reception counter's maximum address |
| * |
| * Definitions: |
| * - A counter is a 32-bit value containing the number of bytes being |
| * transferred from/to memory |
| * - Associated with a counter is a base address indicating where the data is |
| * being transferred from/to |
| * - Associated with a reception counter is a max address bounding the DMA |
| * transfer. |
| * - There are injection (iDMA) and reception (rDMA) counters |
| * - There are DMA_NUM_COUNTERS iDMA counters and DMA_NUM_COUNTERS rDMA |
| * counters |
| * - A counter group consists of DMA_NUM_COUNTERS_PER_GROUP counters |
| * - There are DMA_NUM_COUNTER_GROUPS iDMA counter groups and |
| * DMA_NUM_COUNTER_GROUPS rDMA counter groups |
| * - A subgroup consists of DMA_NUM_COUNTERS_PER_SUBGROUP counters. This is |
| * the unit of counter allocation. |
| * - The highest-level counter inlines in this include file work with virtual |
| * addresses. They are converted to physical addresses and placed into the |
| * counter. |
| * - The counter's base and max addresses reside in the DMA memory map (DMA |
| * SRAM). The DMA_CounterHw_t structure, known as the hardware counter |
| * structure maps a single counter in this storage. They are "shadowed" by |
| * these inline functions to a DMA_Counter_t structure in DDR memory, |
| * known as the software counter structure, and their associated virtual |
| * address is also stored in that structure for easy retrieval. The |
| * physical addresses really don't have to reside in this shadow structure, |
| * but it is faster to access them there than from the DMA's SRAM. |
| * - The counter's base and max addresses are stored in the DMA SRAM as |
| * 16B-aligned 4-bit shifted physical addresses. That is, the 36-bit |
| * physical address is right shifted 4 bits, aligning it on a 16B boundary |
| * leaving 32 bits. The following naming conventions are used to store |
| * addresses: |
| * - pa_xxxx: Physical address (32-bit, 16B-aligned 4-bit shifted) |
| * - va_xxxx: Virtual address (32 bits). |
| * |
| * \verbatim Picture of data structures: |
| |
| ========DDR MEMORY===================|==========DMA SRAM MEMORY============= |
| ------------------------------ | |
| | DMA_CounterGroup_t | | |
| | | | -------------------------------- |
| | status --------------------|-------|---->| DMA_CounterStatus_t | |
| | counter[0..63] | | -------------------------------- |
| | ------------------------ | | |
| | | DMA_Counter_t | | | ----------------------------- |
| | 0 | (software counter) | | | | DMA_CounterHw_t | |
| | | counter_hw_ptr-------|-|-------|---->| (hardware counter) | |
| | ------------------------ | | ----------------------------- |
| | . | | |
| | . | | |
| | . | | |
| | ------------------------ | | |
| | | DMA_Counter_t | | | ----------------------------- |
| |63 | (software counter) | | | | DMA_CounterHw_t | |
| | | counter_hw_ptr-------|-|-------|---->| (hardware counter) | |
| | ------------------------ | | ----------------------------- |
| | . | | |
| ------------------------------ | |
| |
| \endverbatim |
| * |
| * \note Memory consistency/coherency inside these inlines is achieved using |
| * mbar and msync. |
| * |
| * MBAR is used to make sure that all writes to memory issued by the |
| * calling core have been accepted by the memory system before |
| * continuing. This guarantees that writes and reads to/from different |
| * addresses to go in defined order. |
| * |
| * MBAR EXAMPLE 1: When a store is done to DMA SRAM, it may not complete |
| * for a period of time. If a counter value is set, and then an injection |
| * fifo tail pointer is set, DMA may see the tail pointer update and begin |
| * the operation before the counter value has been set. Inserting an mbar |
| * between the setting of the counter and the setting of the tail pointer |
| * guarantees that the counter will be set before the tail pointer is |
| * updated. |
| * |
| * MBAR EXAMPLE 2: A counter hits zero. We process the hit-zero and write |
| * a "clear hit zero" to DMA SRAM, and then go read that counter's hit-zero |
| * status (different address). The hit-zero status will still indicate |
| * that it hit zero, even though we have already processed it, unless an |
| * mbar is inserted between clearing the hit-zero and reading the hit-zero |
| * status. |
| * |
| * MBAR PHILOSOPHY: After DMA SRAM is updated in the DMA inline functions, |
| * they always do at least an mbar (possibly an msync instead...see below). |
| * |
| * MSYNC does what mbar does, plus ensures consistency across cores. That |
| * is, it waits for snoops (invalidations of L1 cache) on the other cores |
| * to complete before continuing. This guarantees that all of the cores |
| * will see a consistent view of memory after the msync. |
| * |
| * MSYNC EXAMPLE: When a reception counter has hit zero, we assume the |
| * DMA'd data is available to be read by any core. However, old copies of |
| * that data may still be in the L1 caches. Inserting an msync after |
| * detecting that a counter has hit zero guarantees that the old data has |
| * been removed from the L1 caches. |
| * |
| * MSYNC PHILOSOPHY: After the inline functions detect that a counter has |
| * hit zero, they always do an msync. |
| * |
| * SPECULATIVE EXECUTION OF MSYNC: There are cases where msync is done |
| * conditionally. The CPU will begin execution of both sides of the |
| * condition before the result of the condition has been determined. |
| * Then, it will cancel the execution of one side once the result of the |
| * condition has been determined. This speculation is unwanted when |
| * the first instruction on one side of the condition is msync because |
| * cancelling an msync is similar to executing the complete msync. |
| * To avoid this speculative execution of msync, we call |
| * _bgp_msync_nonspeculative(). This will trick the CPU so it won't begin |
| * the msync until the result of the condition is known. |
| * |
| * CALLER ADVICE: Users of these functions should not need to do |
| * mbar/msync themselves, unless they are doing something like the |
| * following: Read a counter and operate on the result when the counter |
| * hasn't reached zero. The caller will need to perform an msync after |
| * reading the counter in order to ensure that snoops have completed |
| * on all CPUs before operating on the DMA'd data. |
| * |
| */ |
| |
| |
| #include <common/namespace.h> |
| |
| |
| __BEGIN_DECLS |
| |
| |
| /*! |
| * \brief __INLINE__ definition |
| * |
| * Option 1: |
| * Make all functions be "static inline": |
| * - They are inlined if the compiler can do it |
| * - If the compiler does not inline it, a single copy of the function is |
| * placed in the translation unit (eg. xxx.c)for use within that unit. |
| * The function is not externalized for use by another unit...we want this |
| * so we don't end up with multiple units exporting the same function, |
| * which would result in linker errors. |
| * |
| * Option 2: |
| * A GNU C model: Use "extern inline" in a common header (this one) and provide |
| * a definition in a .c file somewhere, perhaps using macros to ensure that the |
| * same code is used in each case. For instance, in the header file: |
| * |
| * \verbatim |
| #ifndef INLINE |
| # define INLINE extern inline |
| #endif |
| INLINE int max(int a, int b) { |
| return a > b ? a : b; |
| } |
| \endverbatim |
| * |
| * ...and in exactly one source file (in runtime/SPI), that is included in a |
| * library... |
| * |
| * \verbatim |
| #define INLINE |
| #include "header.h" |
| \endverbatim |
| * |
| * This allows inlining, where possible, but when not possible, only one |
| * instance of the function is in storage (in the library). |
| */ |
| #ifndef __INLINE__ |
| #define __INLINE__ extern inline |
| #endif |
| |
| |
| #ifndef __LINUX_KERNEL__ |
| |
| #include <errno.h> |
| #include <bpcore/ppc450_inlines.h> /* For bgp_msync_nonspeculative() */ |
| |
| #endif /* ! __LINUX_KERNEL__ */ |
| |
| #include <spi/DMA_Assert.h> |
| #include <spi/bpcore_interface.h> /* For _BGP_IC_DMA_NFT_G3_HIER_POS*/ |
| #include <spi/kernel_interface.h> /* For Kernel_Virtual2Physical() */ |
| #include <spi/linux_kernel_spi.h> |
| #include <common/alignment.h> |
| |
| /* #include <asm/bluegene.h> */ |
| static inline unsigned bic_hw_to_irq(unsigned group, unsigned gint) |
| { |
| return ((group+1) << 5) | (gint & 0x1f); |
| } |
| |
| |
| /* |
| * ------------------------------------------------------------------------------ |
| * Definitions |
| * ------------------------------------------------------------------------------ |
| */ |
| |
| /*! |
| * \brief Number of DMA counter groups |
| * |
| * There are 4 counter groups. |
| * |
| */ |
| #define DMA_NUM_COUNTER_GROUPS 4 |
| |
| |
| /*! |
| * \brief Number of DMA counters in a counter group |
| * |
| * There are 64 counters in a counter group. |
| * |
| */ |
| #define DMA_NUM_COUNTERS_PER_GROUP 64 |
| |
| |
| /*! |
| * \brief Number of DMA counters in a counter subgroup |
| * |
| * There are 8 counters in a counter subgroup. |
| * |
| */ |
| #define DMA_NUM_COUNTERS_PER_SUBGROUP 8 |
| |
| |
| /*! |
| * \brief Number of DMA counter subgroups in a group |
| * |
| * There are 8 subgroups in a counter group. |
| * |
| */ |
| #define DMA_NUM_COUNTER_SUBGROUPS_PER_GROUP (DMA_NUM_COUNTERS_PER_GROUP / DMA_NUM_COUNTERS_PER_SUBGROUP) |
| |
| |
| /*! |
| * \brief Number of DMA counter subgroups, in total, across all groups |
| * |
| * There are 32 subgroups in total. |
| * |
| */ |
| #define DMA_NUM_COUNTER_SUBGROUPS (DMA_NUM_COUNTER_SUBGROUPS_PER_GROUP * DMA_NUM_COUNTER_GROUPS) |
| |
| |
| /*! |
| * \brief Initial value for a DMA counter |
| * |
| * This value is somewhat arbitrary, but is chosen to be different from zero, |
| * because zero means the counter has hit zero, and may cause false interupts. |
| * |
| */ |
| #define DMA_NUM_COUNTERS ( DMA_NUM_COUNTER_GROUPS * DMA_NUM_COUNTERS_PER_GROUP) |
| |
| |
| /*! |
| * \brief Initial value for a DMA counter |
| * |
| * This value is somewhat arbitrary, but is chosen to be different from zero, |
| * because zero means the counter has hit zero, and may cause false interupts. |
| * |
| */ |
| #define DMA_COUNTER_INIT_VAL 0xFFFFFFFF |
| |
| |
| /*! |
| * \brief Max Number of Cores Per Node |
| * |
| * This is the maximum number of cores that can run on a compute node. |
| */ |
| #define DMA_MAX_NUM_CORES 4 |
| |
| |
| /*! |
| * \brief Returns the word number that the specified counter is in |
| * |
| * \param[in] counter_id The ID of the counter (0 to |
| * DMA_NUM_COUNTERS_PER_GROUP-1) |
| * |
| * \return The number of the word that the specified counter is in (0 or 1) |
| * |
| * Used as an index in the "enabled", "enable", "disable", "hit_zero", and |
| * "clear_hit_zero" fields of the DMA_CounterStatus_t structure, and |
| * the permissions field of the DMA_CounterGroup_t structure. |
| * |
| */ |
| #define DMA_COUNTER_GROUP_WORD_ID(counter_id) ((counter_id)>>5) |
| |
| |
| /*! |
| * \brief Returns the bit within the word that the specified counter is in |
| * |
| * \param[in] counter_id The ID of the counter (0 to |
| * DMA_NUM_COUNTERS_PER_GROUP-1) |
| * |
| * \return The bit position within the word that the specified counter is |
| * in (0-31) |
| * |
| * Used with the "enabled", "enable", "disable", "hit_zero", and |
| * "clear_hit_zero" fields of the DMA_CounterStatus_t structure, and |
| * the permissions" field of the DMA_CounterGroup_t structure. |
| * |
| */ |
| #define DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id) ((counter_id) & 0x0000001F) |
| |
| |
| /* |
| * ----------------------------------------------------------------------------- |
| * Structures |
| * ----------------------------------------------------------------------------- |
| */ |
| |
| /*! |
| * \brief Hardware DMA Counter |
| * |
| * This maps a DMA counter as it is in the DMA memory map (DMA SRAM). |
| * |
| */ |
| typedef struct DMA_CounterHw_t |
| { |
| volatile unsigned counter; /*!< RW Value of the counter */ |
| volatile unsigned increment; /*!< W Increment the counter by this value */ |
| volatile unsigned pa_base; /*!< RW Base address of the counter, 32 bit |
| 16B-aligned 4-bit shifted address */ |
| volatile unsigned pa_max; /*!< RW Maximum payload address (rDMA only), |
| 16B-aligned 4-bit shifted address */ |
| } |
| DMA_CounterHw_t; |
| |
| |
| /*! |
| * \brief DMA Counter Hardware Status structure |
| * |
| * This structure maps the DMA SRAM for a particular group of |
| * DMA_NUM_COUNTERS_PER_GROUP counters. |
| * |
| * This is a common structure between iDMA and rDMA. |
| * |
| * \see DMA_COUNTER_GROUP_WORD_ID |
| * \see DMA_COUNTER_GROUP_WORD_BIT_ID |
| * |
| */ |
| typedef struct DMA_CounterStatus_t |
| { |
| volatile unsigned enabled[2]; /*!< R bitmask (1 bit/counter): |
| Counter is enabled (1=enabled) */ |
| volatile unsigned enable[2]; /*!< W bitmask (1 bit/counter): |
| Counter enable: writing a 1 to |
| bit i enables counter i. This |
| changes the corrresponding bit |
| in enabled. */ |
| volatile unsigned disable[2]; /*!< W bitmask (1 bit/counter): |
| Counter disble: writing a 1 to |
| bit i disbles counter i. This |
| changes the corrresponding bit |
| in enabled. */ |
| volatile unsigned reserved[2]; /*!< HOLE */ |
| volatile unsigned hit_zero[2]; /*!< R bitmask (1 bit/counter): |
| Counter hit zero |
| (1=counter hit zero) */ |
| volatile unsigned clear_hit_zero[2]; /*!< W bitmask (1 bit/counter): |
| Clear counter hit zero: writing |
| a 1 to bit i clears the |
| corresponding bit in hit_zero. */ |
| volatile unsigned grp_status; /*!< R bitmask (1 bit/subgroup): |
| bit i is 1 if or-reduce over |
| sub-group i of the hit_zero bits |
| anded with the enable bits. |
| Note this includes info about |
| all DMA_NUM_COUNTERS counters, |
| not just those in this group. */ |
| } |
| DMA_CounterStatus_t; |
| |
| |
| /*! |
| * \brief Software DMA Counter Structure |
| * |
| * This structure provides a shadow (recent copy) of the hardware counter's |
| * base and max. While accessing the actual hardware DMA counter's base and |
| * max is equivalent, it is slower than accessing them from here. |
| * |
| * Additionally, it stores the corresponding virtual addresses, for easy |
| * retrieval, since the hardware counter does not maintain the virtual |
| * address. |
| * |
| * Finally, it contains a pointer to the corresponding hardware counter in |
| * DMA SRAM. |
| * |
| */ |
| typedef struct DMA_Counter_t |
| { |
| void *va_base; /*!< Shadow virtual address of the base */ |
| unsigned int pa_base; /*!< Shadow physical address of the base. |
| 16B-aligned 4-bit shifted address. */ |
| void *va_max; /*!< Shadow virtual address of the max (rDMA only) */ |
| unsigned int pa_max; /*!< Shadow physical address of the max (rDMA only) |
| 16B-aligned 4-bit shifted address. */ |
| DMA_CounterHw_t *counter_hw_ptr; /*!< Pointer to the hardware counter */ |
| } |
| ALIGN_L1D_CACHE DMA_Counter_t; |
| /*! |
| * \todo Re-think whether we need to align this structure on a L1 cache line boundary |
| * |
| */ |
| |
| |
| /*! |
| * \enum DMA_Type_t |
| * \brief DMA type (injection/reception) enum |
| * |
| */ |
| typedef enum DMA_Type_t |
| { |
| DMA_Type_Injection = 0, /*!< Injection type of DMA */ |
| DMA_Type_Reception = 1 /*!< Reception type of DMA */ |
| |
| } |
| DMA_Type_t; |
| |
| |
| /*! |
| * \brief DMA Counter Group Structure |
| * |
| * This structure defines a DMA Counter Group. It is filled in by the kernel |
| * during the DMA_CounterGroupAllocate system call. It points to a |
| * DMA Counter Status structure, and contains up to DMA_NUM_COUNTERS_PER_GROUP |
| * software DMA Counter structures making up this group. |
| * |
| * It also contains permission bits to use the counters, one bit per counter. |
| * When the permission bit is on, the corresponding counter belongs to this |
| * group and can be used. Otherwise, the counter should not be used as part |
| * of this group. These permission bits are used as follows: |
| * 1. Inline functions will ASSERT when an attempt is made |
| * to use a counter that is not part of this group. |
| * 2. Inline functions will use the permission bits as a mask |
| * to return status information only for the counters allocated |
| * to this group. |
| * Use the DMA_COUNTER_GROUP_WORD_ID and DMA_COUNTER_GROUP_WORD_BIT_ID |
| * macros to locate the appropriate "permitted_counters" bit. |
| * |
| * Allocations are done in subgroups (groups of DMA_NUM_COUNTERS_PER_SUBGROUP |
| * counters). This structure contains a bit mask of the subgroups that belong |
| * to this group. |
| * |
| * \see DMA_COUNTER_GROUP_WORD_ID |
| * \see DMA_COUNTER_GROUP_WORD_BIT_ID |
| * |
| */ |
| typedef struct DMA_CounterGroup_t |
| { |
| |
| DMA_CounterStatus_t *status_ptr; /*!< Pointer to counter status */ |
| unsigned int permissions[2]; /*!< Bit i is 1 if permitted to use |
| counter i, 0 otherwise. One bit |
| per counter, |
| DMA_NUM_COUNTERS_PER_GROUP |
| counters. */ |
| unsigned int grp_permissions; /*!< Bit i is 1 if permitted to use |
| subgroup i, 0 otherwise. One |
| bit per subgroup, 8 subgroups. */ |
| unsigned int group_id; /*!< The id of this group (0 to |
| DMA_NUM_COUNTER_GROUPS-1). */ |
| DMA_Type_t type; /*!< The type of the DMA (injection |
| or reception) */ |
| DMA_Counter_t counter[DMA_NUM_COUNTERS_PER_GROUP]; /*!< |
| Software Counter Structures. |
| i-th structure's hardware |
| pointer is non-NULL if |
| permissions[i]=1, NULL if |
| permissions[i]=0. */ |
| } |
| DMA_CounterGroup_t; |
| |
| |
| /*! |
| * |
| * \brief Counter Application Segment |
| * |
| * A segment of user-addressible memory. |
| * Each segment consists of a virtual address, physical address, and length |
| * defining a contiguous segment of storage that is accessible from the |
| * application. |
| */ |
| typedef struct DMA_CounterAppSegment_t |
| { |
| unsigned int length; /*!< Length in bytes of the segment */ |
| uint32_t va_base; /*!< Virtual address of the segment base */ |
| uint32_t pa_base; /*!< Shifted physical address of the segment base */ |
| uint32_t va_max; /*!< Virtual address of the last byte of segment */ |
| } DMA_CounterAppSegment_t; |
| |
| |
| /*! |
| * |
| * \brief Counter Application Segments |
| * |
| * An array of application segments. There are N application segments per core |
| * on a node. Thus there are N * (number of cores on a node) application |
| * segments in this array. The first group of segments in the array correspond |
| * to core 0. The second group, core 1, etc. |
| */ |
| extern DMA_CounterAppSegment_t *DMA_CounterAppSegmentArray; |
| |
| |
| /*! |
| * \brief Number of application segments for a core |
| * |
| * The number of application segments is the same for all cores. |
| */ |
| extern uint32_t DMA_CounterNumAppSegments; |
| |
| |
| /*! |
| * \brief The index of the last application segment accessed for a core. |
| */ |
| extern int DMA_CounterCachedAppSegmentIndex[DMA_MAX_NUM_CORES]; |
| |
| |
| /*! |
| * \brief The Minimum 4-bit Shifted Physical Address Accessible From User Mode |
| */ |
| extern uint32_t DMA_CounterMinPaAccessibleFromUserMode[DMA_MAX_NUM_CORES]; |
| |
| /*! |
| * |
| * \brief Initialize Counter Application Segments |
| * |
| * Initialize the array of application segments and the global pointer to it. |
| * This identifies the memory regions that the application can access. |
| * |
| * Also, initialize the minimum physical address accessible from user mode |
| * for each core. |
| * |
| * \retval 0 Success |
| * \retval errorNumber Failure |
| */ |
| int DMA_CounterInitAppSegments(void); |
| |
| |
| /*! |
| * |
| * \brief Get Number of Counter Application Segments |
| * |
| * \returns Number of application segments for a core. |
| */ |
| __INLINE__ uint32_t DMA_CounterGetNumAppSegments( void ) |
| { |
| return ( DMA_CounterNumAppSegments ); |
| } |
| |
| |
| /*! |
| * |
| * \brief Get Pointer to Counter Application Segments |
| * |
| * \param[in] Core number whose application segments pointer is to be |
| * returned. |
| * |
| * \returns Pointer to application segments |
| */ |
| __INLINE__ DMA_CounterAppSegment_t * DMA_CounterGetAppSegments( unsigned int coreNum ) |
| { |
| SPI_assert ( coreNum >= 0 ); |
| SPI_assert ( coreNum <= DMA_MAX_NUM_CORES ); |
| |
| { |
| unsigned int index = coreNum * DMA_CounterGetNumAppSegments(); |
| return ( & ( DMA_CounterAppSegmentArray [ index ] ) ); |
| } |
| } |
| |
| |
| /*! |
| * |
| * \brief Get Virtual Addresses for the Min and Max Physical Addresses |
| * for User Space |
| * |
| * Based on information in the DMA_CounterAppSegments array, return the |
| * virtual addresses associated with the min and max physical addresses |
| * allowed for user space. |
| * |
| * \param[out] va_min Pointer to a pointer. Upon return, the pointer is |
| * set to the virtual address associated with the |
| * minimum physical address allowed for user space. |
| * \param[out] va_max Pointer to a pointer. Upon return, the pointer is |
| * set to the virtual address associated with the |
| * maximum physical address allowed for user space. |
| * |
| * If the DMA_CounterNumAppSegments array has not been initialized yet |
| * (it is initialized in DMA_CounterGroupAllocate()), a value of 0 for the |
| * min and 0xFFFFFFFF max is returned. |
| */ |
| __INLINE__ void DMA_CounterGetMinMaxVa(void ** va_min, |
| void ** va_max) |
| { |
| /* Determine the core we are running on so the correct application |
| * segments are consulted |
| */ |
| unsigned int coreNum = Kernel_PhysicalProcessorID(); |
| DMA_CounterAppSegment_t * appSegmentArray = DMA_CounterGetAppSegments(coreNum); |
| uint32_t numAppSegments = DMA_CounterGetNumAppSegments(); |
| |
| if ( appSegmentArray ) |
| { |
| uint32_t minPaBase=0xFFFFFFFF, maxPa=0; |
| uint32_t segmentPaBase, segmentPaMax; |
| uint32_t i, minIndex=0, maxIndex=0; |
| |
| for (i=0; i<numAppSegments; i++) |
| { |
| segmentPaBase = appSegmentArray[i].pa_base; |
| if ( segmentPaBase < minPaBase ) |
| { |
| minPaBase = segmentPaBase; |
| minIndex = i; |
| } |
| |
| segmentPaMax = appSegmentArray[i].pa_base + (appSegmentArray[i].length >> 4); |
| if ( segmentPaMax > maxPa ) |
| { |
| maxPa = segmentPaMax; |
| maxIndex = i; |
| } |
| } |
| |
| *va_min = (void*)(appSegmentArray[minIndex].va_base); |
| *va_max = (void*)(appSegmentArray[maxIndex].va_max); |
| |
| /* printf("coreNum=%d, va_min = 0x%08x, minIndex=%d, va_max = 0x%08x, maxIndex=%d, minPa=0x%08x maxPa=0x%08x\n",coreNum,(unsigned)*va_min, minIndex, (unsigned)*va_max, maxIndex, minPaBase, maxPa); */ |
| /* fflush(stdout); */ |
| } |
| else |
| { |
| *va_min = (void*)0; |
| *va_max = (void*)0xFFFFFFFF; |
| } |
| } |
| |
| |
| /*! |
| * \brief Convert a 32-bit virtual address to a 32-bit physical address |
| * |
| * This function is a wrapper around _bgp_Virtual2Physical(), only it combines |
| * its 36-bit output into a 32-bit physical address by right-shifting it 4 bits. |
| * Thus, the physical address returned corresponds to the input virtual address |
| * rounded down to the next lowest 16-byte boundary. |
| * |
| * \param[in] VA 32-bit virtual address to be converted |
| * \param[in] vsize Size in bytes of virtual range |
| * \param[out] pPA Pointer to 32-bit physical address. The output physical |
| * address is returned in the storage pointed to by pPA. |
| * |
| * \retval 0 Successful. The output physical address is in *pPA |
| * \retval -1 Invalid Virtual Address for this process. *pPA unmodified. |
| * \retval -2 The range from VA to (VA+vsize-1) is not physically |
| * contiguous |
| * \retval -3 Virtual Address is in Scratch, but no Scratch, or not enough |
| * Scratch, is enabled. *pPA unmodified. |
| * |
| */ |
| __INLINE__ int Kernel_VaTo4bitShiftedPa(void *VA, |
| size_t vsize, |
| uint32_t *pPA ) |
| { |
| int rc; |
| uint32_t ua_out, pa_out; |
| |
| SPI_assert( pPA != NULL ); |
| |
| rc = Kernel_Virtual2Physical(VA, |
| vsize, |
| &ua_out, |
| &pa_out ); |
| |
| if ( rc == 0 ) |
| { |
| *pPA = (ua_out << 28) | (pa_out >> 4); |
| } |
| |
| return (rc); |
| } |
| |
| |
| /* |
| *------------------------------------------------------------------------------ |
| * |
| * The following are inline function wrappers around system calls that |
| * operate on DMA counters. |
| * |
| *------------------------------------------------------------------------------ |
| */ |
| |
| |
| /*! |
| * \brief Query Free DMA Counter Subgroups within a Group |
| * |
| * This function is a wrapper around a system call that returns a list of the |
| * free (available) subgroups within the specified group. |
| * |
| * \param[in] type Specifies whether this is an injection or |
| * reception counter group (DMA_Type_Injection |
| * or DMA_Type_Reception) |
| * \param[in] grp Group number being queried (0 to |
| * DMA_NUM_COUNTER_GROUPS-1) |
| * \param[out] num_subgroups Pointer to an int where the number of free |
| * subgroups in the specified group is returned |
| * \param[out] subgroups Pointer to an array of num_subgroups ints where |
| * the list of num_subgroups subgroups is returned. |
| * Each int is the subgroup number |
| * (0 to DMA_NUM_COUNTERS_PER_SUBGROUP-1). The |
| * caller must provide space for |
| * DMA_NUM_COUNTERS_PER_SUBGROUP ints, in case the |
| * entire counter group is free. |
| * |
| * \retval 0 Successful. num_subgroups and subgroups array set as described. |
| * \retval -1 Unsuccessful. errno gives the reason. |
| * |
| * \note The kernel may need to synchronize with other cores performing |
| * allocate or free syscalls. |
| * |
| */ |
| __INLINE__ int DMA_CounterGroupQueryFree( |
| DMA_Type_t type, |
| int grp, |
| int *num_subgroups, |
| int *subgroups |
| ) |
| { |
| return Kernel_CounterGroupQueryFree( (uint32_t)type, |
| grp, |
| (uint32_t*)num_subgroups, |
| (uint32_t*)subgroups); |
| } |
| |
| |
| /*! |
| * \brief Allocate DMA Counters From A Group |
| * |
| * This function is a wrapper around a system call that allocates DMA counters |
| * from the specified group. Counters may be allocated in subgroups of |
| * DMA_NUM_COUNTERS_PER_SUBGROUP counters. Parameters specify how interrupts, |
| * generated when a counter hits zero, are to be handled. A |
| * DMA_CounterGroup_t structure is returned for use in other inline |
| * functions to operate on the allocated counters. |
| * |
| * \param[in] type Specifies whether this is an injection or |
| * reception counter group (DMA_Type_Injection |
| * or DMA_Type_Reception) |
| * \param[in] grp Group number whose counters are being allocated |
| * (0 to DMA_NUM_COUNTER_GROUPS-1) |
| * \param[in] num_subgroups Number of subgroups to be allocated from the group |
| * (1 to DMA_NUM_COUNTERS_PER_SUBGROUP) |
| * \param[in] subgroups Pointer to an array of num_subgroups ints where |
| * the list of subgroups to be allocated is provided. |
| * Each int is the subgroup number |
| * (0 to num_subgroups-1). |
| * \param[in] target The core that will receive the interrupt when a |
| * counter in this allocation hits zero |
| * (0 to DMA_NUM_COUNTER_GROUPS-1) |
| * \param[in] handler A pointer to the function to receive control in |
| * the I/O thread to handle the interrupt when a |
| * counter in this allocation hits zero. This |
| * function must be coded to take 4 uint32_t |
| * parameters: |
| * - A pointer to storage specific to this |
| * handler. This is the handler_parm |
| * specified on this allocation function. |
| * - Three unint32_t parameters that are not used. |
| * If handler is NULL, hit-zero interrupts will not |
| * be enabled for these counters. |
| * \param[in] handler_parm A pointer to storage that should be passed to the |
| * interrupt handling function (see handler |
| * parameter) |
| * \param[in] interruptGroup A InterruptGroup_t that identifies the |
| * group of interrupts that the counters being |
| * allocated will become part of. |
| * \param[out] cg_ptr Pointer to a structure that is filled in upon |
| * successful return for use in other inline |
| * functions to operate on the allocated counters. |
| * \li counter - Array of software counter |
| * structures. Each element |
| * points to the corresponding |
| * hardware counter in DMA SRAM. |
| * Pointers are null if not |
| * allocated). |
| * Counters are initialized to |
| * DMA_COUNTER_INIT_VAL, |
| * disabled, their hit_zero bit |
| * is off, base and max are NULL. |
| * \li status_ptr - Points to status area within the |
| * DMA memory map. |
| * \li permissions - Bits set for each allocated |
| * counter |
| * \li grp_permissions - Permissions for each |
| * subgroup |
| * \li group_id - The group number |
| * \li type - The type of DMA (injection or |
| * reception) |
| * |
| * \retval 0 Successful. Counters allocated and cg_ptr structure filled in as |
| * described. |
| * \retval -1 Unsuccessful. errno gives the reason. Nothing has been |
| * allocated. |
| * |
| * \note The kernel may need to synchronize with other cores performing queries |
| * or frees. |
| * |
| */ |
| __INLINE__ int DMA_CounterGroupAllocate( |
| DMA_Type_t type, |
| int grp, |
| int num_subgroups, |
| int *subgroups, |
| int target, |
| Kernel_CommThreadHandler handler, |
| void *handler_parm, |
| Kernel_InterruptGroup_t interruptGroup, |
| DMA_CounterGroup_t *cg_ptr |
| ) |
| { |
| int rc; |
| /* |
| * Initialize the Counter Application Segment array and its global pointer if |
| * it has not been initialized yet. |
| */ |
| if ( DMA_CounterAppSegmentArray == NULL ) |
| { |
| rc = DMA_CounterInitAppSegments(); |
| if (rc) return(rc); |
| } |
| |
| /* |
| * If an interrupt handler has been specified, invoke the system call |
| * to configure the kernel to invoke the handler when the hit zero |
| * interrupt fires. |
| */ |
| |
| if (handler) |
| { |
| /* |
| * Calculate the IRQ to be one of |
| * - 0: inj counter hit zero vector 0 |
| * - 1: inj counter hit zero vector 1 |
| * - 2: inj counter hit zero vector 2 |
| * - 3: inj counter hit zero vector 3 |
| * |
| * - 4: rec counter hit zero vector 0 |
| * - 5: rec counter hit zero vector 1 |
| * - 6: rec counter hit zero vector 2 |
| * - 7: rec counter hit zero vector 3 |
| * based on the counter type and the DMA group number. |
| */ |
| unsigned irqInGroup = (type == DMA_Type_Injection) ? 0 + grp : 4 + grp; |
| |
| /* |
| * Calculate an interrupt ID, which is the BIC interrupt group (3) |
| * combined with the IRQ number. |
| */ |
| /* int interruptID = Kernel_MkInterruptID(_BGP_IC_DMA_NFT_G3_HIER_POS, */ |
| /* irqInGroup); */ |
| int interruptID = bic_hw_to_irq(_BGP_IC_DMA_NFT_G3_HIER_POS, |
| irqInGroup); |
| |
| /* |
| * Calculate the opcode indicating |
| * - the target core for interrupt |
| * - to call the specified function when the interrupt fires |
| * - to disable interrupts before calling the specified function |
| * - to enable interrupts after callling the specified function |
| */ |
| int opcode = ( COMMTHRD_OPCODE_CORE0 + target ) | |
| COMMTHRD_OPCODE_CALLFUNC | |
| COMMTHRD_OPCODE_DISABLEINTONENTRY | |
| COMMTHRD_OPCODE_ENABLEINTONPOOF ; |
| |
| /* |
| * Configure this interrupt with the kernel. |
| */ |
| rc = Kernel_SetCommThreadConfig(interruptID, |
| opcode, |
| (uint32_t*)interruptGroup, |
| handler, |
| (uint32_t)handler_parm, |
| (uint32_t)NULL, |
| (uint32_t)NULL, |
| (uint32_t)NULL); |
| if (rc) return rc; |
| } |
| |
| /* |
| * Invoke the system call to allocate the counters. |
| * This system call also sets up the DMA DCRs to interrupt when the |
| * counters hit zero. |
| */ |
| rc = Kernel_CounterGroupAllocate( (uint32_t)type, |
| grp, |
| num_subgroups, |
| (uint32_t*)subgroups, |
| target, |
| (uint32_t) NULL, /* Handler. Not used */ |
| (uint32_t*)NULL, /* Handler_parm. Not used */ |
| (uint32_t) NULL, /* InterruptGroup. Not used */ |
| (uint32_t*)cg_ptr); |
| return rc; |
| } |
| |
| |
| /*! |
| * \brief Free DMA Counters From A Group |
| * |
| * This function is a wrapper around a system call that frees DMA counters |
| * from the specified group. Counters may be freed in subgroups of |
| * DMA_NUM_COUNTERS_PER_SUBGROUP counters. |
| * |
| * \param[in] grp Group number whose counters are being freed |
| * (0 to DMA_NUM_COUNTER_GROUPS-1) |
| * \param[in] num_subgroups Number of subgroups to be freed from the group |
| * (1-DMA_NUM_COUNTERS_PER_SUBGROUP) |
| * \param[in] subgroups Pointer to an array of num_subgroups ints where |
| * the list of subgroups to be freed is provided. |
| * Each int is the subgroup number |
| * (0 to DMA_NUM_COUNTERS_PER_SUBGROUP-1). |
| * \param[out] cg_ptr Pointer to the structure previously filled in when |
| * these counters were allocated. Upon successful |
| * return, this structure is updated to reflect the |
| * freed counters: |
| * \li counter[] - Counter structures Pointers to |
| * freed counters nulled. |
| * \li permissions - Bits cleared for each freed |
| * counter. |
| * |
| * \retval 0 Successful. Counters freed and cg_ptr structure updated as |
| * described. |
| * \retval -1 Unsuccessful. errno gives the reason. |
| * |
| * \note The kernel may need to synchronize with other cores performing allocates |
| * or queries. |
| */ |
| __INLINE__ int DMA_CounterGroupFree( |
| int grp, |
| int num_subgroups, |
| int *subgroups, |
| DMA_CounterGroup_t *cg_ptr |
| ) |
| { |
| return Kernel_CounterGroupFree( grp, |
| num_subgroups, |
| (uint32_t*)subgroups, |
| (uint32_t*)cg_ptr); |
| } |
| |
| |
| |
| /*! |
| * \brief Enable or Disable Counter Overflow and Underflow Interrupts |
| * |
| * This function is a wrapper around a system call that enables or disables |
| * the 4 counter overflow/underflow interrupts for all counters: |
| * 1. Injection counter overflow |
| * 2. Injection counter underflow |
| * 3. Reception counter overflow |
| * 4. Reception counter underflow |
| * |
| * \param[in] enable Specifies whether to enable or disable the interrupts |
| * 0 = Disable, 1 = Enable. |
| * |
| * \retval 0 Successful |
| * \retval error_value An error value defined in the _BGP_RAS_DMA_ErrCodes |
| * enum located in bgp/arch/include/common/bgp_ras.h |
| * |
| */ |
| __INLINE__ int DMA_CounterInterruptControl(unsigned int enable) |
| { |
| return Kernel_ChgCounterInterruptEnables( (uint32_t)enable ); |
| |
| } |
| |
| |
| |
| /* |
| * ----------------------------------------------------------------------------- |
| * The following inline functions operate directly on the Hardware DMA Counter. |
| * Note that MSYNC and MBAR are not performed by these hardware functions... |
| * it is up to the caller to perform them. |
| *------------------------------------------------------------------------------ |
| */ |
| |
| |
| /*! |
| * \brief Set DMA Hardware Counter Value |
| * |
| * Set a DMA hardware counter's value, given a pointer to the hardware counter. |
| * |
| * \param[in] c_hw Pointer to the hardware counter structure |
| * \param[in] value The value to be set into the counter |
| * |
| * \return None |
| * |
| * \note No MSYNC or MBAR is done in this function. It is the responsibility |
| * of the caller to do it. |
| * |
| */ |
| __INLINE__ void DMA_CounterSetValueHw( |
| DMA_CounterHw_t *c_hw, |
| unsigned int value |
| ) |
| { |
| SPI_assert( c_hw != NULL ); |
| |
| c_hw->counter = value; |
| } |
| |
| |
| /*! |
| * \brief Set DMA Hardware Counter Base |
| * |
| * Set a DMA hardware counter's base, given a pointer to the hardware counter. |
| * |
| * \param[in] c_hw Pointer to the hardware counter structure |
| * \param[in] pa_base The base physical address to be associated with the |
| * counter. 16B-aligned 4-bit shifted physical address. |
| * |
| * \return None |
| * |
| * \note No MSYNC or MBAR is done in this function. It is the responsibility |
| * of the caller to do it. |
| * |
| */ |
| __INLINE__ void DMA_CounterSetBaseHw( |
| DMA_CounterHw_t *c_hw, |
| unsigned int pa_base |
| ) |
| { |
| SPI_assert( c_hw != NULL ); |
| |
| c_hw->pa_base = pa_base; |
| } |
| |
| |
| /*! |
| * \brief Increment DMA Hardware Counter Value |
| * |
| * Increment a DMA hardware counter's value, given a pointer to the hardware |
| * counter. |
| * |
| * \param[in] c_hw Pointer to the hardware counter structure |
| * \param[in] incr The amount to increment the counter by |
| * |
| * \return None |
| * |
| * \note No MSYNC or MBAR is done in this function. It is the responsibility |
| * of the caller to do it. |
| * |
| */ |
| __INLINE__ void DMA_CounterIncrementHw( |
| DMA_CounterHw_t *c_hw, |
| unsigned int incr |
| ) |
| { |
| SPI_assert( c_hw != NULL ); |
| |
| c_hw->increment = incr; |
| } |
| |
| |
| /*! |
| * \brief Decrement DMA Hardware Counter Value |
| * |
| * Decrement a DMA hardware counter's value, given a pointer to the hardware |
| * counter. |
| * |
| * \param[in] c_hw Pointer to the hardware counter structure |
| * \param[in] decr The amount to decrement the counter by |
| * |
| * \return None |
| * |
| * \note No MSYNC or MBAR is done in this function. It is the responsibility |
| * of the caller to do it. |
| * |
| * \note The counter overflow interrupt will fire as a result of this operation. |
| * Consider disabling this interrupt. |
| * |
| */ |
| __INLINE__ void DMA_CounterDecrementHw( |
| DMA_CounterHw_t *c_hw, |
| unsigned int decr |
| ) |
| { |
| SPI_assert( c_hw != NULL ); |
| |
| /* Decrement the counter by incrementing with a large value, which will |
| * cause the counter to wrap. |
| */ |
| c_hw->increment = (0 - decr); |
| } |
| |
| |
| /*! |
| * \brief Set Reception DMA Hardware Counter Max |
| * |
| * Set a reception DMA hardware counter's maximum payload address, given a |
| * pointer to the hardware counter. |
| * |
| * \param[in] c_hw Pointer to the hardware counter structure |
| * \param[in] pa_max The max physical address to be associated with the |
| * counter. 16B-aligned 4-bit shifted physical address. |
| * |
| * \return None |
| * |
| * \pre The caller has ASSERTed that (c_hw != NULL) |
| * |
| * \note No MSYNC or MBAR is done in this function. It is the responsibility |
| * of the caller to do it. |
| * |
| */ |
| __INLINE__ void DMA_CounterSetMaxHw( |
| DMA_CounterHw_t *c_hw, |
| unsigned int pa_max |
| ) |
| { |
| c_hw->pa_max = pa_max; |
| } |
| |
| |
| /*! |
| * \brief Set DMA Hardware Counter Value and Base |
| * |
| * Set a DMA hardware counter's value and base, given a pointer to the hardware |
| * counter. |
| * |
| * \param[in] c_hw Pointer to the hardware counter structure |
| * \param[in] value The value to be set into the counter |
| * \param[in] pa_base The base physical address to be associated with the |
| * counter. 16B-aligned 4-bit shifted physical address. |
| * |
| * \return None |
| * |
| * \note No MSYNC or MBAR is done in this function. It is the responsibility |
| * of the caller to do it. |
| * |
| */ |
| __INLINE__ void DMA_CounterSetValueBaseHw( |
| DMA_CounterHw_t *c_hw, |
| unsigned int value, |
| unsigned int pa_base |
| ) |
| { |
| SPI_assert( c_hw != NULL ); |
| |
| c_hw->counter = value; |
| c_hw->pa_base = pa_base; |
| |
| } |
| |
| |
| /*! |
| * \brief Set Reception DMA Hardware Counter Value, Base, and Max |
| * |
| * Set a reception DMA hardware counter's value, base, and max, given a pointer |
| * to the hardware counter. |
| * |
| * \param[in] c_hw Pointer to the hardware counter structure |
| * \param[in] value The value to be set into the counter |
| * \param[in] pa_base The base physical address to be associated with the |
| * counter. 16B-aligned 4-bit shifted physical address. |
| * \param[in] pa_max The max physical address to be associated with the |
| * counter. 16B-aligned 4-bit shifted physical address. |
| * |
| * \return None |
| * |
| * \note No MSYNC or MBAR is done in this function. It is the responsibility |
| * of the caller to do it. |
| * |
| */ |
| __INLINE__ void DMA_CounterSetValueBaseMaxHw( |
| DMA_CounterHw_t *c_hw, |
| unsigned int value, |
| unsigned int pa_base, |
| unsigned int pa_max |
| ) |
| { |
| SPI_assert( c_hw != NULL ); |
| SPI_assert( pa_max >= pa_base); |
| |
| c_hw->counter = value; |
| c_hw->pa_base = pa_base; |
| c_hw->pa_max = pa_max; |
| } |
| |
| |
| /*! |
| * \brief Get DMA Hardware Counter Value |
| * |
| * Get a DMA hardware counter's value, given a pointer to the hardware counter. |
| * |
| * \param[in] c_hw Pointer to the hardware counter structure |
| * |
| * \retval value The current value of the counter |
| * |
| * \note No MSYNC or MBAR is done in this function. It is the responsibility |
| * of the caller to do it. |
| * |
| */ |
| __INLINE__ unsigned int DMA_CounterGetValueHw( |
| const DMA_CounterHw_t *c_hw |
| ) |
| { |
| SPI_assert( c_hw != NULL ); |
| |
| return( c_hw->counter ); |
| } |
| |
| |
| /*! |
| * \brief Get DMA Hardware Counter Base |
| * |
| * Get a DMA hardware counter's base, given a pointer to the hardware counter. |
| * |
| * \param[in] c_hw Pointer to the hardware counter structure |
| * |
| * \retval pa_base The base physical address associated with the counter. |
| * 16B-aligned 4-bit shifted physical address. |
| * |
| * \note No MSYNC or MBAR is done in this function. It is the responsibility |
| * of the caller to do it. |
| * |
| */ |
| __INLINE__ unsigned int DMA_CounterGetBaseHw( |
| const DMA_CounterHw_t *c_hw |
| ) |
| { |
| SPI_assert( c_hw != NULL ); |
| |
| return( c_hw->pa_base ); |
| } |
| |
| |
| /*! |
| * \brief Get Reception DMA Hardware Counter Max |
| * |
| * Get a reception DMA hardware counter's max payload address, given a pointer |
| * to the hardware counter. |
| * |
| * \param[in] c_hw Pointer to the hardware counter structure |
| * |
| * \retval pa_max The max physical address associated with the counter. |
| * 16B-aligned 4-bit shifted physical address. |
| * |
| * \note No MSYNC or MBAR is done in this function. It is the responsibility |
| * of the caller to do it. |
| * |
| */ |
| __INLINE__ unsigned int DMA_CounterGetMaxHw( |
| const DMA_CounterHw_t *c_hw |
| ) |
| { |
| SPI_assert( c_hw != NULL ); |
| |
| return( c_hw->pa_max ); |
| } |
| |
| |
| |
| |
| /* |
| * ----------------------------------------------------------------------------- |
| * The following inline functions operate indirectly on a hardware DMA counter |
| * through the Software DMA Counter structure. |
| *------------------------------------------------------------------------------ |
| */ |
| |
| |
| |
| |
| /*! |
| * \brief Set DMA Counter Value |
| * |
| * Set a DMA counter's value, given a pointer to the software DMA counter |
| * structure. |
| * |
| * \param[in] c_sw Pointer to the software counter structure |
| * \param[in] value The value to be set into the counter |
| * |
| * \return None |
| * |
| */ |
| __INLINE__ void DMA_CounterSetValue( |
| DMA_Counter_t *c_sw, |
| unsigned int value |
| ) |
| { |
| SPI_assert( c_sw != NULL ); |
| |
| DMA_CounterSetValueHw(c_sw->counter_hw_ptr, |
| value); |
| _bgp_mbar(); /* Make sure these writes have been accepted by the memory */ |
| /* system before continuing */ |
| |
| } |
| |
| |
| /*! |
| * \brief Set DMA Counter Base Address |
| * |
| * Set a DMA counter's base address, given a pointer to the software counter |
| * structure. |
| * |
| * \param[in] c_sw Pointer to the software counter structure |
| * \param[in] va_base_in The base virtual address to be associated with the |
| * counter. |
| * |
| * \retval 0 Success |
| * \retval -1 Failure. errno contains the reason. Most likely EFAULT due to |
| * the va_base_in being a bad virtual address. |
| * |
| * \post In the software counter structure, va_base and pa_base are set. |
| * In the hardware counter structure, pa_base is set. |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| * \note The va_base in the software counter structure is the va_base_in rounded |
| * down to the next lowest 16B-aligned address. The pa_base is the 4-bit |
| * shifted version of va_base. |
| * |
| */ |
| __INLINE__ int DMA_CounterSetBase( |
| DMA_Counter_t *c_sw, |
| void *va_base_in |
| ) |
| { |
| int rc; |
| |
| SPI_assert( c_sw != NULL ); |
| |
| /* |
| * 16-B align the virtual address and store result in software counter |
| * structure |
| */ |
| c_sw->va_base = (char*)( (unsigned)va_base_in & 0xFFFFFFF0 ); |
| |
| rc = Kernel_VaTo4bitShiftedPa(c_sw->va_base, |
| 1, |
| &(c_sw->pa_base) ); |
| if ( rc != 0 ) |
| { |
| errno = EFAULT; |
| return (-1); |
| } |
| |
| /* |
| * Write physical address to the hardware counter |
| */ |
| DMA_CounterSetBaseHw(c_sw->counter_hw_ptr, |
| c_sw->pa_base); |
| |
| _bgp_mbar(); /* Make sure these writes have been accepted by the memory */ |
| /* system before continuing */ |
| |
| return (0); |
| |
| } |
| |
| |
| /*! |
| * \brief Increment DMA Counter |
| * |
| * Increment a DMA counter's value, given a pointer to the software counter |
| * structure. |
| * |
| * \param[in] c_sw Pointer to the software counter structure |
| * \param[in] incr The amount to increment the counter by |
| * |
| * \return None |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ void DMA_CounterIncrement( |
| DMA_Counter_t *c_sw, |
| unsigned int incr |
| ) |
| { |
| SPI_assert( c_sw != NULL ); |
| |
| DMA_CounterIncrementHw(c_sw->counter_hw_ptr, |
| incr); |
| |
| _bgp_mbar(); /* Make sure these writes have been accepted by the memory */ |
| /* system before continuing */ |
| } |
| |
| |
| /*! |
| * \brief Decrement DMA Counter |
| * |
| * Decrement a DMA counter's value, given a pointer to the software counter |
| * structure. |
| * |
| * \param[in] c_sw Pointer to the software counter structure |
| * \param[in] decr The amount to decrement the counter by |
| * |
| * \return None |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ void DMA_CounterDecrement( |
| DMA_Counter_t *c_sw, |
| unsigned int decr |
| ) |
| { |
| SPI_assert( c_sw != NULL ); |
| |
| DMA_CounterDecrementHw(c_sw->counter_hw_ptr, |
| decr); |
| |
| _bgp_mbar(); /* Make sure these writes have been accepted by the memory */ |
| /* system before continuing */ |
| } |
| |
| |
| /*! |
| * \brief Set DMA Counter Max Address |
| * |
| * Set a DMA counter's max address, given a pointer to the software counter |
| * structure. |
| * |
| * \param[in] c_sw Pointer to the software counter structure |
| * \param[in] va_max_in The max virtual address to be associated with the |
| * counter. |
| * |
| * \retval 0 Success |
| * \retval -1 Failure. errno contains the reason. Most likely EFAULT due to |
| * the va_max_in being a bad virtual address. |
| * |
| * \post In the software counter structure, va_max and pa_max are set. |
| * In the hardware counter structure, pa_max is set. |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| * \note The va_max in the software counter structure is the va_max_in rounded |
| * up to the next highest 16B-aligned address. The pa_max is the 4-bit |
| * shifted version of va_max. |
| * |
| */ |
| __INLINE__ int DMA_CounterSetMax( |
| DMA_Counter_t *c_sw, |
| void *va_max_in |
| ) |
| { |
| int rc; |
| |
| SPI_assert( c_sw != NULL ); |
| |
| /* |
| * Round up to 16B boundary and 16-B align the virtual address and store |
| * result in software counter structure. |
| */ |
| c_sw->va_max = (char*) ( (unsigned)va_max_in & 0xFFFFFFF0 ); |
| if ( c_sw->va_max != va_max_in ) c_sw->va_max = (char*)c_sw->va_max + 0x00000010; |
| |
| /* |
| * Get the 16B-aligned 4-bit shifted physical address from the virtual address. |
| */ |
| rc = Kernel_VaTo4bitShiftedPa(c_sw->va_max, |
| 1, |
| &(c_sw->pa_max) ); |
| |
| if ( rc != 0 ) |
| { |
| errno = EFAULT; |
| return (-1); |
| } |
| |
| /* |
| * Write physical address to the hardware counter |
| */ |
| DMA_CounterSetMaxHw(c_sw->counter_hw_ptr, |
| c_sw->pa_max); |
| |
| _bgp_mbar(); /* Make sure these writes have been accepted by the memory */ |
| /* system before continuing */ |
| |
| return (0); |
| |
| } |
| |
| |
| /*! |
| * \brief Set DMA Counter Value and Base Address |
| * |
| * Set a DMA counter's value and base address, given a pointer to the software |
| * counter structure. |
| * |
| * \param[in] c_sw Pointer to the software counter structure |
| * \param[in] value The value to be set into the counter |
| * \param[in] va_base_in The base virtual address to be associated with the |
| * counter. |
| * |
| * \retval 0 Success |
| * \retval -1 Failure. errno contains the reason. Most likely EFAULT due to |
| * the va_base_in being a bad virtual address. |
| * |
| * \post In the software counter structure, va_base and pa_base are set. |
| * In the hardware counter structure, pa_base and value are set. |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| * \note The va_base in the software counter structure is the va_base_in rounded |
| * down to the next lowest 16B-aligned address. The pa_base is the 4-bit |
| * shifted version of va_base. |
| * |
| */ |
| __INLINE__ int DMA_CounterSetValueBase( |
| DMA_Counter_t *c_sw, |
| unsigned int value, |
| void *va_base_in |
| ) |
| { |
| int rc=0; |
| |
| SPI_assert( c_sw != NULL ); |
| |
| /* |
| * 16-B align the virtual address and store result in software counter |
| * structure |
| */ |
| c_sw->va_base = (char*) ( (unsigned)va_base_in & 0xFFFFFFF0 ); |
| |
| /* |
| * Get the 16B-aligned 4-bit shifted physical address from the virtual address. |
| */ |
| rc = Kernel_VaTo4bitShiftedPa(c_sw->va_base, |
| 1, |
| &(c_sw->pa_base) ); |
| if ( rc != 0 ) |
| { |
| errno = EFAULT; |
| return (-1); |
| } |
| |
| /* |
| * Write the value and physical address to the hardware counter |
| */ |
| DMA_CounterSetValueBaseHw(c_sw->counter_hw_ptr, |
| value, |
| c_sw->pa_base ); |
| |
| _bgp_mbar(); /* Make sure these writes have been accepted by the memory */ |
| /* system before continuing */ |
| |
| return (0); |
| } |
| |
| |
| /*! |
| * \brief Set DMA Counter Value, Base Address, and Max Address |
| * |
| * Set a reception DMA counter's value, base address, and max address, given a |
| * pointer to the software counter structure. |
| * |
| * \param[in] c_sw Pointer to the software counter structure |
| * \param[in] value The value to be set into the counter |
| * \param[in] va_base_in The base virtual address to be associated with the |
| * counter. |
| * \param[in] va_max_in The max virtual address to be associated with the |
| * counter. |
| * |
| * \retval 0 Success |
| * \retval -1 Failure. errno contains the reason. Most likely EFAULT due to |
| * the va_base_in or va_max_in being a bad virtual address. |
| * |
| * \post In the software counter structure, va_base, pa_base, va_max, and pa_max |
| * are set. In the hardware counter structure, pa_base, pa_max, and value |
| * are set. |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| * \note The va_base in the software counter structure is the va_base_in rounded |
| * down to the next lowest 16B-aligned address. The pa_base is the 4-bit |
| * shifted version of va_base. |
| * |
| * \note The va_max in the software counter structure is the va_max_in rounded |
| * up to the next highest 16B-aligned address. The pa_max is the 4-bit |
| * shifted version of va_max. |
| * |
| */ |
| __INLINE__ int DMA_CounterSetValueBaseMax( |
| DMA_Counter_t *c_sw, |
| unsigned int value, |
| void *va_base_in, |
| void *va_max_in |
| ) |
| { |
| int rc=0; |
| void *va_base, *va_max; |
| unsigned int pa_base, pa_max; |
| |
| SPI_assert( c_sw != NULL ); |
| |
| /* |
| * Process the base address: |
| * - 16-B align the virtual address and store result in software counter |
| * structure |
| * - Get the 16B-aligned 4-bit shifted physical address from the virtual |
| * address. |
| */ |
| va_base = c_sw->va_base = (char*) ( (unsigned)va_base_in & 0xFFFFFFF0 ); |
| |
| rc = Kernel_VaTo4bitShiftedPa(va_base, |
| 1, |
| &pa_base ); |
| if ( rc != 0 ) |
| { |
| errno = EFAULT; |
| return (-1); |
| } |
| |
| c_sw->pa_base = pa_base; |
| |
| /* |
| * Process the max address: |
| * - 16B align the virtual address and store result in software counter structure. |
| * Note: we can't round up or the address may be one byte out of range. |
| * - Get the 16B-aligned 4-bit shifted physical address from the virtual |
| * address. |
| */ |
| va_max = (char*) ( (unsigned)va_max_in & 0xFFFFFFF0 ); |
| |
| rc = Kernel_VaTo4bitShiftedPa(va_max, |
| 1, |
| &pa_max ); |
| /* printf("SetValueBaseMax: va_max_in=0x%08x, va_max=0x%08x, pa_max=0x%08x, rc=%d\n",(unsigned)va_max_in, (unsigned)va_max,pa_max,rc); */ |
| /* fflush(stdout); */ |
| if ( rc != 0 ) |
| { |
| errno = EFAULT; |
| return (-1); |
| } |
| |
| c_sw->pa_max = pa_max; |
| |
| /* |
| * Write the value, base, and max to the hardware counter |
| */ |
| DMA_CounterSetValueBaseMaxHw(c_sw->counter_hw_ptr, |
| value, |
| pa_base, |
| pa_max); |
| |
| _bgp_mbar(); /* Make sure these writes have been accepted by the memory */ |
| /* system before continuing */ |
| |
| return (0); |
| } |
| |
| |
| /*! |
| * \brief Get DMA Counter Value |
| * |
| * Get a DMA counter's value, given a pointer to the software counter |
| * structure. |
| * |
| * \param[in] c_sw Pointer to the software counter structure |
| * |
| * \retval value The value of the specified counter |
| * |
| * \note This function does an MSYNC after fetching the counter's value |
| * to ensure that the data that was just DMA'd is available to all |
| * cores. |
| * |
| */ |
| __INLINE__ unsigned int DMA_CounterGetValue( |
| const DMA_Counter_t *c_sw |
| ) |
| { |
| unsigned int val; |
| |
| SPI_assert( c_sw != NULL ); |
| |
| val = DMA_CounterGetValueHw( c_sw->counter_hw_ptr ); |
| |
| _bgp_msync(); |
| |
| return val; |
| |
| } |
| |
| |
| /*! |
| * \brief Get DMA Counter Value with No Msync |
| * |
| * Get a DMA counter's value, given a pointer to the software counter |
| * structure. No Msync is done. It is up to the caller to do it, |
| * if necessary. |
| * |
| * \param[in] c_sw Pointer to the software counter structure |
| * |
| * \retval value The value of the specified counter |
| * |
| */ |
| __INLINE__ unsigned int DMA_CounterGetValueNoMsync( |
| const DMA_Counter_t *c_sw |
| ) |
| { |
| unsigned int val; |
| |
| SPI_assert( c_sw != NULL ); |
| |
| val = DMA_CounterGetValueHw( c_sw->counter_hw_ptr ); |
| |
| return val; |
| |
| } |
| |
| |
| /*! |
| * \brief Get DMA Base Address |
| * |
| * Get a DMA counter's base virtual address, given a pointer to the software |
| * counter structure. |
| * |
| * \param[in] c_sw Pointer to the software counter structure |
| * |
| * \retval va_base The base virtual address associated with the specified |
| * counter |
| * |
| * \note This returns the shadow va_base directly out of the software counter |
| * structure. This should correspond with the physical address in the |
| * hardware counter, but it is a rounded-down-to-the-previous-16B-boundary |
| * version of the actual base virtual address of the buffer the caller is |
| * working with. |
| * |
| */ |
| __INLINE__ void * DMA_CounterGetBase( |
| const DMA_Counter_t *c_sw |
| ) |
| { |
| SPI_assert( c_sw != NULL ); |
| |
| return( c_sw->va_base ); |
| } |
| |
| |
| /*! |
| * \brief Get Reception DMA Max Address |
| * |
| * Get a reception DMA counter's max virtual address, given a pointer to |
| * the software counter structure. |
| * |
| * \param[in] c_sw Pointer to the software counter structure |
| * |
| * \retval va_max The max virtual address associated with the specified |
| * counter |
| * |
| * \note This returns the shadow va_max directly out of the software counter |
| * structure. This should correspond with the physical address in the |
| * hardware counter, but it is a rounded-up-to-the-next-16B-boundary |
| * version of the actual max virtual address of the buffer the caller is |
| * working with. |
| * |
| */ |
| __INLINE__ void *DMA_CounterGetMax( |
| const DMA_Counter_t *c_sw |
| ) |
| { |
| SPI_assert( c_sw != NULL ); |
| |
| return( c_sw->va_max ); |
| } |
| |
| |
| /*! |
| * \brief Get Offset from DMA Base Address |
| * |
| * Given a virtual address, get the offset from the base address associated with |
| * a counter. |
| * |
| * \param[in] c_sw Pointer to the software counter structure |
| * \param[in] va Virtual address whose offset from the counter's base is |
| * to be returned. |
| * \param[in] length The number of bytes in the buffer pointed to by va. |
| * \param[in] coreNum The number of the core in which the virtual |
| * address resides (0 to DMA_MAX_NUM_CORES). |
| * |
| * \retval offset The offset of the va from the counter's base. |
| * |
| * \note This uses the counter's physical base address and the application's |
| * memory segments (see DMA_CounterAppSegment_t). |
| * |
| * \note It is assumed that if the coreNum is not our core, then the counter's |
| * base address (used in calculating the offset) is the smallest physical |
| * address accessible from user space on coreNum |
| * (DMA_CounterMinPaAccessibleFromUserMode[coreNum]). |
| * |
| */ |
| __INLINE__ unsigned int DMA_CounterGetOffsetFromBase( |
| const DMA_Counter_t *c_sw, |
| void *va, |
| unsigned int length, |
| unsigned int coreNum |
| ) |
| { |
| SPI_assert( c_sw != NULL ); |
| SPI_assert( va != NULL ); |
| SPI_assert ( coreNum >= 0 ); |
| SPI_assert ( coreNum <= DMA_MAX_NUM_CORES ); |
| { |
| DMA_CounterAppSegment_t *appSegmentArray = DMA_CounterGetAppSegments( coreNum ); |
| uint32_t numAppSegments; |
| uint32_t i; |
| uint32_t segmentVaBase; |
| uint32_t offset; |
| uint32_t ourCoreNum = Kernel_PhysicalProcessorID(); |
| uint32_t counterPaBase; |
| |
| |
| /* Determine which application segment the virtual address is in. */ |
| /* First, check the last app segment accessed. */ |
| i = DMA_CounterCachedAppSegmentIndex[coreNum]; |
| segmentVaBase = appSegmentArray[i].va_base; |
| if ( ! ( ((uint32_t)va >= segmentVaBase) && |
| ((uint32_t)va - segmentVaBase < appSegmentArray[i].length) ) ) |
| { |
| /* It is not the last app segment accessed. Search them. */ |
| numAppSegments = DMA_CounterGetNumAppSegments(); |
| for (i=0; i<numAppSegments; i++) |
| { |
| segmentVaBase = appSegmentArray[i].va_base; |
| if ( ((uint32_t)va >= segmentVaBase) && |
| ((uint32_t)va - segmentVaBase < appSegmentArray[i].length) ) |
| break; |
| } |
| SPI_assert(i < numAppSegments); |
| DMA_CounterCachedAppSegmentIndex[coreNum] = i; |
| } |
| |
| /* |
| * Make sure buffer fits in app segment. |
| */ |
| if ( ( (uint32_t)va + length - 1 ) > appSegmentArray[i].va_max ) |
| { |
| printf("DMA_CounterGetOffsetFromBase: Buffer 0x%08x of length %d is out of bounds. Check length.\n", |
| (unsigned)va, length); |
| SPI_assert(0); |
| } |
| |
| /* |
| * If coreNum is our core, use the offset from our core's counter base to |
| * calculate the DMA offset. |
| * Otherwise, assume the counter base is the smallest physical address |
| * accessible from user space on coreNum and use that. |
| */ |
| if ( ourCoreNum == coreNum ) |
| counterPaBase = c_sw->pa_base; |
| else |
| counterPaBase = DMA_CounterMinPaAccessibleFromUserMode[coreNum]; |
| |
| /* |
| * If the base physical address of the application segment found above is |
| * greater than or equal to the counter's base physical address (typical |
| * case), proceed with the calculation based on that. |
| * |
| * Otherwise, use a slightly different calculation (see else leg). |
| */ |
| if ( appSegmentArray[i].pa_base >= counterPaBase ) |
| { |
| /* |
| * Calculate the offset from the counter base: |
| * - offset from app segment's virtual address base (va - segmentVaBase) + |
| * - segment's physical base (shifted) - counter's base (shifted) * 16 |
| */ |
| offset = |
| ((unsigned)va - segmentVaBase) + |
| ( (appSegmentArray[i].pa_base - counterPaBase) << 4 ); |
| |
| /* printf("GetOffsetFromBase: va=0x%08x, length=%d, offset=0x%08x, index=%d, segmentVaBase=0x%08x, appSegmentArrayPaBase=0x%08x, counterBase=0x%08x\n",(unsigned)va, length, offset, i, */ |
| /* segmentVaBase, appSegmentArray[i].pa_base, counterPaBase); */ |
| /* fflush(stdout); */ |
| } |
| /* |
| * Handle the case where the counter's base exceeds the app segment's base. |
| * This occurs when the counter's base is set to the base of the buffer |
| * rather than the min base of all the app segments. |
| */ |
| else |
| { |
| offset = |
| ((unsigned)va - segmentVaBase) - |
| ( (counterPaBase - appSegmentArray[i].pa_base) << 4 ); |
| |
| /* printf("GetOffsetFromBase2: va=0x%08x, length=%d, offset=0x%08x, index=%d, segmentVaBase=0x%08x, appSegmentArrayPaBase=0x%08x, counterBase=0x%08x\n",(unsigned)va, length, offset, i, */ |
| /* segmentVaBase, appSegmentArray[i].pa_base, counterPaBase); */ |
| /* fflush(stdout); */ |
| } |
| |
| return ( offset ); |
| } |
| } |
| |
| |
| |
| |
| /* |
| * ------------------------------------------------------------------------------ |
| * |
| * The following functions access counters by specifying the group pointer and |
| * counter_id. |
| * |
| * ------------------------------------------------------------------------------ |
| */ |
| |
| |
| |
| |
| /*! |
| * \brief Set DMA Counter Value using a Counter ID |
| * |
| * Set a DMA counter's value, given a counter group structure and counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when |
| * the counter was allocated |
| * \param[in] counter_id Identifier of the counter being set |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * \param[in] value The value to be set into the counter |
| * |
| * \return None |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ void DMA_CounterSetValueById( |
| DMA_CounterGroup_t *cg_ptr, |
| int counter_id, |
| unsigned int value |
| ) |
| { |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| |
| DMA_CounterSetValue( &cg_ptr->counter[counter_id], |
| value ); |
| |
| /* Note: it is assumed that the above function call performs an MBAR */ |
| } |
| |
| |
| /*! |
| * \brief Set DMA Counter Base Address using a Counter ID |
| * |
| * Set a DMA counter's base address, given a counter group structure and |
| * counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when |
| * the counter was allocated. |
| * \param[in] counter_id Identifier of the counter being set |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * \param[in] va_base_in The base virtual address to be associated with the |
| * counter. |
| * |
| * \retval 0 Success |
| * \retval -1 Failure. errno contains the reason. Most likely EFAULT due to |
| * the va_base_in being a bad virtual address. |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ int DMA_CounterSetBaseById( |
| DMA_CounterGroup_t *cg_ptr, |
| int counter_id, |
| void *va_base_in |
| ) |
| { |
| int rc; |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| |
| rc = DMA_CounterSetBase( &cg_ptr->counter[counter_id], |
| va_base_in ); |
| |
| /* Note: it is assumed that the above function call performs an MBAR */ |
| |
| return rc; |
| } |
| |
| |
| /*! |
| * \brief Increment DMA Counter using a Counter ID |
| * |
| * Increment a DMA counter's value, given a counter group structure and |
| * counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when |
| * the counter was allocated. |
| * \param[in] counter_id Identifier of the counter being incremented |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * \param[in] incr The amount to increment the counter by |
| * |
| * \return None |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ void DMA_CounterIncrementById( |
| DMA_CounterGroup_t *cg_ptr, |
| int counter_id, |
| unsigned int incr |
| ) |
| { |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| |
| DMA_CounterIncrement( &cg_ptr->counter[counter_id], |
| incr ); |
| |
| /* Note: it is assumed that the above function call performs an MBAR */ |
| } |
| |
| |
| /*! |
| * \brief Decrement DMA Counter using a Counter ID |
| * |
| * Decrement a DMA counter's value, given a counter group structure and |
| * counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when |
| * the counter was allocated. |
| * \param[in] counter_id Identifier of the counter being decremented |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * \param[in] decr The amount to decrement the counter by |
| * |
| * \return None |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ void DMA_CounterDecrementById( |
| DMA_CounterGroup_t *cg_ptr, |
| int counter_id, |
| unsigned int decr |
| ) |
| { |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| |
| DMA_CounterDecrement( &cg_ptr->counter[counter_id], |
| decr ); |
| |
| /* Note: it is assumed that the above function call performs an MBAR */ |
| } |
| |
| |
| /*! |
| * \brief Set Reception DMA Counter Max Address using a Counter ID |
| * |
| * Set a reception DMA counter's base address, given a counter group structure |
| * and counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when |
| * the counter was allocated. |
| * \param[in] counter_id Identifier of the counter being set |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * \param[in] va_max_in The max virtual address to be associated with the |
| * counter. |
| * |
| * \retval 0 Success |
| * \retval -1 Failure. errno contains the reason. Most likely EFAULT due to |
| * the va_max_in being a bad virtual address. |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ int DMA_CounterSetMaxById( |
| DMA_CounterGroup_t *cg_ptr, |
| int counter_id, |
| void *va_max_in |
| ) |
| { |
| int rc; |
| |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| |
| rc = DMA_CounterSetMax( &cg_ptr->counter[counter_id], |
| va_max_in ); |
| |
| /* Note: it is assumed that the above function call performs an MBAR */ |
| |
| return rc; |
| |
| } |
| |
| |
| /*! |
| * \brief Get DMA Counter Value using a Counter ID |
| * |
| * Get a DMA counter's value, given a counter group structure and counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when |
| * the counter was allocated. |
| * \param[in] counter_id Identifier of the counter |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * |
| * \retval value The value of the counter |
| * |
| */ |
| __INLINE__ unsigned int DMA_CounterGetValueById( |
| const DMA_CounterGroup_t *cg_ptr, |
| const int counter_id |
| ) |
| { |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| |
| return ( DMA_CounterGetValue( &cg_ptr->counter[counter_id] ) ); |
| } |
| |
| |
| /*! |
| * \brief Get DMA Counter Base Address using a Counter ID |
| * |
| * Get a DMA counter's base virtual address, given a counter group structure and |
| * counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counter was allocated. |
| * \param[in] counter_id Identifier of the counter |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * |
| * \retval va_base The base virtual address associated with the specified |
| * counter |
| * |
| * \note This returns the shadow va_base directly out of the software counter |
| * structure. This should correspond with the physical address in the |
| * hardware counter, but it is a rounded-down-to-the-previous-16B-boundary |
| * version of the actual base virtual address of the buffer the caller is |
| * working with. |
| * |
| */ |
| __INLINE__ void * DMA_CounterGetBaseById( |
| const DMA_CounterGroup_t *cg_ptr, |
| int counter_id |
| ) |
| { |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| |
| return( DMA_CounterGetBase( &cg_ptr->counter[counter_id] ) ); |
| } |
| |
| |
| /*! |
| * \brief Get Offset from DMA Base Address using a Counter ID |
| * |
| * Given a virtual address, get the offset from the base address associated with |
| * the specified counter. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when |
| * the counter was allocated |
| * \param[in] counter_id Identifier of the counter |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * \param[in] va Virtual address whose offset from the counter's base |
| * is to be returned. |
| * \param[in] length The number of bytes in the buffer pointed to by va. |
| * \param[in] coreNum The number of the core in which the virtual |
| * address resides (0 to DMA_MAX_NUM_CORES). |
| * |
| * \retval offset The offset of the va from the counter's base. |
| * |
| * \note This works with the shadow va_base directly out of the software counter |
| * structure. This should correspond with the physical address in the |
| * hardware counter, but it is a rounded-down-to-the-previous-16B-boundary |
| * version of the actual base virtual address of the buffer the caller is |
| * working with. |
| * |
| * \note No effort is given to flag the case where va is less than the base |
| * address. In that case, (va - va_base) is returned, whatever that is. |
| * |
| */ |
| __INLINE__ unsigned int DMA_CounterGetOffsetFromBaseById( |
| const DMA_CounterGroup_t *cg_ptr, |
| int counter_id, |
| void *va, |
| unsigned int length, |
| unsigned int coreNum |
| ) |
| { |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| /* printf("Getting offset from counter %d for core %d\n",counter_id,coreNum); */ |
| return( DMA_CounterGetOffsetFromBase( &cg_ptr->counter[counter_id], |
| va, |
| length, |
| coreNum ) ); |
| } |
| |
| |
| /*! |
| * \brief Get Reception DMA Counter Max Address Using a Counter ID |
| * |
| * Get a reception DMA counter's maximum virtual address, given a counter group |
| * structure and counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counter was allocated. |
| * \param[in] counter_id Identifier of the counter |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * |
| * \retval va_max The virtual address of the max of the counter |
| * |
| * \note This returns the shadow va_max directly out of the software counter |
| * structure. This should correspond with the physical address in the |
| * hardware counter, but it is a rounded-up-to-the-next-16B-boundary |
| * version of the actual max virtual address of the buffer the caller is |
| * working with. |
| * |
| */ |
| __INLINE__ void * DMA_CounterGetMaxById( |
| const DMA_CounterGroup_t *cg_ptr, |
| const int counter_id |
| ) |
| { |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| |
| return ( DMA_CounterGetMax( &cg_ptr->counter[counter_id] ) ); |
| } |
| |
| |
| /*! |
| * \brief Set DMA Counter Value and Base Address using a Counter ID |
| * |
| * Set a DMA counter's value and base address, given a counter group structure |
| * and counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counter was allocated. |
| * \param[in] counter_id Identifier of the counter being set |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * \param[in] value The value to be set into the counter |
| * \param[in] va_base_in The base virtual address to be associated with the |
| * counter. |
| * |
| * \retval 0 Success |
| * \retval -1 Failure. errno contains the reason. Most likely EFAULT due to |
| * the va_base_in being a bad virtual address. |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ int DMA_CounterSetValueBaseById( |
| DMA_CounterGroup_t *cg_ptr, |
| int counter_id, |
| unsigned int value, |
| void *va_base_in |
| ) |
| { |
| int rc; |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| |
| rc = DMA_CounterSetValueBase( &cg_ptr->counter[counter_id], |
| value, |
| va_base_in ); |
| |
| /* Note: it is assumed that the above function call performs an MBAR */ |
| |
| return rc; |
| } |
| |
| |
| |
| |
| /*! |
| * \brief Set Reception DMA Counter Value, Base Address, and Max Address using |
| * a Counter ID |
| * |
| * Set a reception DMA counter's value, base address, and max address, given a |
| * counter group structure and counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counter was allocated. |
| * \param[in] counter_id Identifier of the counter being set |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * \param[in] value The value to be set into the counter |
| * \param[in] va_base_in The base virtual address to be associated with the |
| * counter. |
| * \param[in] va_max_in The max virtual address to be associated with the |
| * counter. |
| * |
| * \retval 0 Success |
| * \retval -1 Failure. errno contains the reason. Most likely EFAULT due to |
| * the va_base_in or va_max_in being a bad virtual address. |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ int DMA_CounterSetValueBaseMaxById( |
| DMA_CounterGroup_t *cg_ptr, |
| int counter_id, |
| unsigned int value, |
| void *va_base_in, |
| void *va_max_in |
| ) |
| { |
| int rc; |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| |
| rc = DMA_CounterSetValueBaseMax( &cg_ptr->counter[counter_id], |
| value, |
| va_base_in, |
| va_max_in ); |
| |
| /* Note: it is assumed that the above function call performs an MBAR */ |
| |
| return rc; |
| |
| } |
| |
| |
| /*! |
| * \brief Enable DMA Counter using a Counter ID |
| * |
| * Enable a DMA counter, given a counter group structure and counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counter was allocated. |
| * \param[in] counter_id Identifier of the counter being enabled |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * |
| * \return None |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ void DMA_CounterSetEnableById( |
| DMA_CounterGroup_t *cg_ptr, |
| int counter_id |
| ) |
| { |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| SPI_assert( cg_ptr->status_ptr != 0); |
| |
| { |
| /* Enable the counter by writing 1 to the appropriate bit */ |
| int r = DMA_COUNTER_GROUP_WORD_ID(counter_id); |
| int c = DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id); |
| cg_ptr->status_ptr->enable[r] = _BN(c); |
| |
| _bgp_mbar(); /* Make sure these writes have been accepted by the memory */ |
| /* system before continuing */ |
| } |
| } |
| |
| |
| /*! |
| * \brief Disable DMA Counter using a Counter ID |
| * |
| * Disable a DMA counter, given a counter group structure and counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counter was allocated. |
| * \param[in] counter_id Identifier of the counter being disabled |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * |
| * \return None |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ void DMA_CounterSetDisableById( |
| DMA_CounterGroup_t *cg_ptr, |
| int counter_id |
| ) |
| { |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| SPI_assert( cg_ptr->status_ptr != 0); |
| |
| { |
| /* Disable the counter by writing 1 to the appropriate bit */ |
| int r = DMA_COUNTER_GROUP_WORD_ID(counter_id); |
| int c = DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id); |
| cg_ptr->status_ptr->disable[r] = _BN(c); |
| |
| _bgp_mbar(); /* Make sure these writes have been accepted by the memory */ |
| /* system before continuing */ |
| } |
| } |
| |
| |
| /*! |
| * \brief Determine Whether a DMA Counter is Enabled using a Counter ID |
| * |
| * Determine whether a DMA counter is enabled, given a counter group structure |
| * and counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counter was allocated. |
| * \param[in] counter_id Identifier of the counter being queried |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * |
| * \retval 0 The counter is disabled |
| * \retval 1 The counter is enabled |
| * |
| */ |
| __INLINE__ int DMA_CounterGetEnabledById( |
| const DMA_CounterGroup_t *cg_ptr, |
| int counter_id |
| ) |
| { |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| SPI_assert( cg_ptr->status_ptr != 0); |
| |
| { |
| /* Return 0 or 1 if counter is disabled/enabled */ |
| int r = DMA_COUNTER_GROUP_WORD_ID(counter_id); |
| int c = DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id); |
| if ( ( cg_ptr->status_ptr->enabled[r] & _BN(c) ) == 0 ) {return 0;} |
| else { return 1;} |
| } |
| } |
| |
| |
| /*! |
| * \brief Determine Whether a DMA Counter is Has Hit Zero using a Counter ID |
| * |
| * Determine whether a DMA counter has hit zero, given a counter group structure |
| * and counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counter was allocated. |
| * \param[in] counter_id Identifier of the counter being queried |
| * (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * |
| * \retval 0 The counter has not hit zero |
| * \retval 1 The counter has hit zero |
| * |
| * \note This function does an MSYNC after determining that the counter has hit |
| * zero to ensure that the data that was just DMA'd is available to all |
| * cores. The msync is only done if this is a reception counter group, |
| * since there is nothing to sync for injection counters that have hit zero. |
| * |
| */ |
| __INLINE__ int DMA_CounterGetHitZeroById( |
| const DMA_CounterGroup_t *cg_ptr, |
| int counter_id |
| ) |
| { |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| SPI_assert( cg_ptr->status_ptr != 0); |
| |
| { |
| /* Return 0 or 1 if counter has hit zero */ |
| int r = DMA_COUNTER_GROUP_WORD_ID(counter_id); |
| int c = DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id); |
| if ( ( cg_ptr->status_ptr->hit_zero[r] & _BN(c) ) == 0 ) {return 0;} |
| else { |
| /* By convention, we assume that if counter has hit zero, then it will be |
| * used. This requires an msync to ensure snoops from the DMA arbiter |
| * have hit the cores. That is, the data that was just DMA'd is available |
| * to all cores. |
| * |
| * Furthermore, If we just put a _bgp_msync() here, it could get |
| * speculatively executed and withdrawn even if the counter hasn't hit zero, |
| * so we call a special version of this function that ensures the speculation |
| * does not occur. |
| * |
| * It only needs to be done for reception counters since there is nothing |
| * to sync when sending data. |
| */ |
| if ( cg_ptr->type == DMA_Type_Reception ) _bgp_msync_nonspeculative(); |
| return 1; |
| } |
| } |
| } |
| |
| |
| /*! |
| * \brief Clear a DMA Counter's Hit Zero Status using a Counter ID |
| * |
| * Clear a DMA counter's "hit zero" status, given a counter group structure |
| * and counter ID. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counter was allocated. |
| * \param[in] counter_id Identifier of the counter whose "hit zero" status is |
| * being cleared (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * |
| * \return None |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ void DMA_CounterClearHitZeroById( |
| DMA_CounterGroup_t *cg_ptr, |
| int counter_id |
| ) |
| { |
| SPI_assert( (counter_id >= 0) && (counter_id < DMA_NUM_COUNTERS_PER_GROUP) ); |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( (cg_ptr->permissions[DMA_COUNTER_GROUP_WORD_ID(counter_id)] & |
| _BN(DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id))) != 0 ); |
| SPI_assert( cg_ptr->status_ptr != 0); |
| |
| { |
| /* Clear the hit zero bit of a counter */ |
| int r = DMA_COUNTER_GROUP_WORD_ID(counter_id); |
| int c = DMA_COUNTER_GROUP_WORD_BIT_ID(counter_id); |
| cg_ptr->status_ptr->clear_hit_zero[r] = _BN(c) ; |
| |
| _bgp_mbar(); /* Make sure these writes have been accepted by the memory */ |
| /* system before continuing */ |
| } |
| } |
| |
| |
| /* |
| * ------------------------------------------------------------------------------ |
| * |
| * The following functions manipulate or get the status of multiple counters |
| * |
| * ------------------------------------------------------------------------------ |
| */ |
| |
| |
| /*! |
| * \brief Enable Multiple DMA Counters |
| * |
| * Enable multiple DMA counters, given a counter group structure and mask. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counter was allocated. |
| * \param[in] reg Identifies the "word" (0 or 1) of the counters |
| * being manipulated. This is the index into the |
| * enable array. |
| * \param[in] counterBits Identifies which counters in the "word" are being |
| * manipulated. |
| * |
| * \return None |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ void DMA_CounterSetEnable( |
| DMA_CounterGroup_t *cg_ptr, |
| int reg, |
| unsigned int counterBits |
| ) |
| { |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( ( ( reg == 0 ) || ( reg == 1 ) ) ); |
| SPI_assert( counterBits == (counterBits & cg_ptr->permissions[reg]) ); |
| SPI_assert( cg_ptr->status_ptr != 0); |
| |
| cg_ptr->status_ptr->enable[reg] = counterBits; |
| |
| _bgp_mbar(); /* Make sure these writes have been accepted by the memory */ |
| /* system before continuing */ |
| } |
| |
| |
| /*! |
| * \brief Disable Multiple DMA Counters |
| * |
| * Disable multiple DMA counters, given a counter group structure and mask. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counter was allocated. |
| * \param[in] reg Identifies the "word" (0 or 1) of the counters |
| * being manipulated. This is the index into the |
| * disable array. |
| * \param[in] counterBits Identifies which counters in the "word" are being |
| * manipulated. |
| * |
| * \return None |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ void DMA_CounterSetDisable(DMA_CounterGroup_t *cg_ptr, |
| int reg, |
| unsigned int counterBits |
| ) |
| { |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( ( ( reg == 0 ) || ( reg == 1 ) ) ); |
| SPI_assert( counterBits == (counterBits & cg_ptr->permissions[reg]) ); |
| SPI_assert( cg_ptr->status_ptr != 0); |
| |
| cg_ptr->status_ptr->disable[reg] = counterBits; |
| |
| _bgp_mbar(); /* Make sure these writes have been accepted by the memory */ |
| /* system before continuing */ |
| } |
| |
| |
| /*! |
| * \brief Get Enabled DMA Counters |
| * |
| * Get the enabled status of DMA counters, given a counter group structure |
| * and "word". |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counter was allocated. |
| * \param[in] reg Identifies the "word" (0 or 1) of the counters |
| * being queried. This is the index into the |
| * enabled array. |
| * |
| * \return 32 bit mask indicating which counters in the specified word are enabled. |
| * Only the counters that the caller has allocated will have their status |
| * returned. The status for other counters will be 0. |
| * |
| */ |
| __INLINE__ unsigned int DMA_CounterGetEnabled( |
| const DMA_CounterGroup_t *cg_ptr, |
| int reg |
| ) |
| { |
| SPI_assert( ( ( cg_ptr != NULL ) && |
| ( ( reg == 0 ) || ( reg == 1 ) ) ) ); |
| SPI_assert( cg_ptr->status_ptr != 0); |
| |
| return (cg_ptr->permissions[reg] & cg_ptr->status_ptr->enabled[reg]); |
| } |
| |
| |
| /*! |
| * \brief Get Hit Zero Status of DMA Counters |
| * |
| * Get the "hit zero" status of DMA counters, given a counter group structure |
| * and "word". |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counter was allocated. |
| * \param[in] reg Identifies the "word" (0 or 1) of the counters |
| * being queried. This is the index into the |
| * hit zero array. |
| * |
| * \return 32 bit mask indicating which counters in the specified word hit zero. |
| * Only the counters that the caller has allocated will have their status |
| * returned. The status for other counters will be 0. |
| * |
| * \note This function does an MSYNC after determining that the counter has hit |
| * zero to ensure that the data that was just DMA'd is available to all |
| * cores. The msync is only done if this is a reception counter group, |
| * since there is nothing to sync for injection counters that have hit zero. |
| * |
| */ |
| __INLINE__ unsigned int DMA_CounterGetHitZero( |
| const DMA_CounterGroup_t *cg_ptr, |
| int reg |
| ) |
| { |
| unsigned int x; |
| |
| SPI_assert( ( ( cg_ptr != NULL ) && |
| ( ( reg == 0 ) || ( reg == 1 ) ) ) ); |
| SPI_assert( cg_ptr->status_ptr != 0); |
| |
| x = cg_ptr->status_ptr->hit_zero[reg]; |
| |
| if ( x != 0 ) { |
| |
| x &= cg_ptr->permissions[reg]; |
| |
| if ( ( cg_ptr->type == DMA_Type_Reception ) && |
| ( x != 0 ) ) |
| _bgp_msync_nonspeculative(); |
| |
| } |
| |
| return (x); |
| } |
| |
| |
| /*! |
| * \brief Get Hit Zero Status of All DMA Counters In the Specified Group |
| * |
| * Get the "hit zero" status of all DMA counters in the group specified by the |
| * counter group structure. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when |
| * the counter was allocated. |
| * \param[in,out] word0 Pointer to the first status word, for the first 32 |
| * counters. |
| * \param[in,out] word1 Pointer to the second status word, for the second 32 |
| * counters. |
| * |
| * \return word0 and word1 are set to the status of the counters. |
| * Only the counters that the caller has allocated will have their |
| * status returned. The status for other counters will be 0. |
| * |
| * \note This function does an MSYNC after determining that at least 1 counter |
| * has hit zero to ensure that the data that was just DMA'd is available |
| * to all cores. The msync is only done if this is a reception counter |
| * group, since there is nothing to sync for injection counters that have |
| * hit zero. |
| * |
| */ |
| __INLINE__ void DMA_CounterGetAllHitZero( |
| const DMA_CounterGroup_t *cg_ptr, |
| unsigned int *word0, |
| unsigned int *word1 |
| ) |
| { |
| unsigned int x,y; |
| |
| SPI_assert( ( cg_ptr != NULL ) && |
| ( word0 != NULL ) && |
| ( word1 != NULL ) ); |
| SPI_assert( cg_ptr->status_ptr != 0 ); |
| |
| x = cg_ptr->status_ptr->hit_zero[0]; |
| y = cg_ptr->status_ptr->hit_zero[1]; |
| |
| if ( (x | y) != 0 ) { |
| x &= cg_ptr->permissions[0]; |
| y &= cg_ptr->permissions[1]; |
| |
| if ( ( cg_ptr->type == DMA_Type_Reception ) && |
| ( (x | y) != 0 ) ) |
| _bgp_msync_nonspeculative(); |
| } |
| |
| *word0 = x; |
| *word1 = y; |
| |
| return; |
| } |
| |
| |
| /*! |
| * \brief Clear Hit Zero Status of DMA Counters |
| * |
| * Clear the "hit zero" status of DMA counters, given a counter group structure, |
| * a "word", and a mask of counters. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counter was allocated. |
| * \param[in] reg Identifies the "word" (0 or 1) of the counters |
| * being manipulated. This is the index into the |
| * clear_hit_zero array. |
| * \param[in] counterBits Identifies which counters in the "word" are being |
| * manipulated. |
| * |
| * \return None |
| * |
| * \note This function does an MBAR after setting the counter to ensure the |
| * writes have been accepted by the memory system before allowing other |
| * memory accesses to to occur. |
| * |
| */ |
| __INLINE__ void DMA_CounterGroupClearHitZero( |
| DMA_CounterGroup_t *cg_ptr, |
| int reg, |
| unsigned int counterBits |
| ) |
| { |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( ( ( reg == 0 ) || ( reg == 1 ) ) ); |
| SPI_assert( counterBits == (counterBits & cg_ptr->permissions[reg]) ); |
| SPI_assert( cg_ptr->status_ptr != 0); |
| |
| cg_ptr->status_ptr->clear_hit_zero[reg] = counterBits; |
| |
| _bgp_mbar(); /* Make sure these writes have been accepted by the memory */ |
| /* system before continuing */ |
| } |
| |
| |
| /*! |
| * \brief Get DMA Counter Group Status |
| * |
| * Get the DMA Counter Group Status, given a counter group structure. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counters were allocated. |
| * |
| * \return 32 bit mask indicating which subgroups have counters that are enabled and |
| * have hit zero. Only the subgroups that the caller has allocated will have |
| * their status returned. The status for other subgroups will be 0. |
| * |
| * \note This function does an MSYNC after determining that the counter has hit |
| * zero to ensure that the data that was just DMA'd is available to all |
| * cores. The msync is only done if this is a reception counter group, |
| * since there is nothing to sync for injection counters that have hit zero. |
| * |
| */ |
| __INLINE__ unsigned int DMA_CounterGetGroupStatus( |
| const DMA_CounterGroup_t *cg_ptr |
| ) |
| { |
| unsigned int x; |
| |
| SPI_assert( cg_ptr != NULL ); |
| SPI_assert( cg_ptr->status_ptr != 0); |
| |
| x = cg_ptr->status_ptr->grp_status; |
| |
| if ( x != 0 ) { |
| |
| x &= cg_ptr->grp_permissions; |
| |
| if ( ( cg_ptr->type == DMA_Type_Reception ) && |
| ( x != 0 ) ) |
| _bgp_msync_nonspeculative(); |
| |
| } |
| |
| return x; |
| } |
| |
| |
| /*! |
| * \brief Get DMA Counter Group Number |
| * |
| * Get the DMA Counter Group number, given a counter group structure. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counters were allocated. |
| * |
| * \return The DMA Counter Group number |
| * |
| */ |
| __INLINE__ int DMA_CounterGetGroupNum( |
| const DMA_CounterGroup_t *cg_ptr |
| ) |
| { |
| SPI_assert( cg_ptr != NULL ); |
| |
| return cg_ptr->group_id; |
| } |
| |
| |
| /*! |
| * \brief Get DMA Counter Global Id |
| * |
| * Get the global Id of a DMA Counter, given a counter group structure and a counter Id. |
| * |
| * \param[in] cg_ptr Pointer to the structure previously filled in when the |
| * counters were allocated. |
| * \param[in] counter_id Identifier of the counter |
| * |
| * \return The DMA Counter Global Id (0 to DMA_NUM_COUNTERS-1) |
| * |
| */ |
| __INLINE__ int DMA_CounterGetGlobalId( |
| const DMA_CounterGroup_t *cg_ptr, |
| int counter_id |
| ) |
| { |
| SPI_assert( ( cg_ptr != NULL ) && |
| ( counter_id >= 0 ) && |
| ( counter_id < DMA_NUM_COUNTERS_PER_GROUP ) ); |
| |
| return( counter_id + (DMA_NUM_COUNTERS_PER_GROUP * cg_ptr->group_id) ); |
| } |
| |
| |
| /*! |
| * \brief Get DMA Counter Local Id |
| * |
| * Get the local Id of a DMA Counter, given a counter group structure and a Global |
| * counter Id. |
| * |
| * \param[in] counter_id Global Identifier of the counter (0 to DMA_NUM_COUNTERS-1) |
| * |
| * \return The DMA Counter Local Id (0 to DMA_NUM_COUNTERS_PER_GROUP-1) |
| * |
| */ |
| __INLINE__ int DMA_CounterGetLocalId( |
| int counter_id |
| ) |
| { |
| return( counter_id % DMA_NUM_COUNTERS_PER_GROUP ); |
| } |
| |
| |
| |
| |
| __END_DECLS |
| |
| |
| #endif |