1 /******************************************************************************************
2 * FILE PURPOSE: Boot queue manager driver
3 ******************************************************************************************
4 * FILE NAME: qm.c
5 *
6 * DESCRIPTION: The boot loader queue manager driver. This driver uses a very simple
7 * setup on the queue manager, with a single link ram and a single
8 * memory region. The descriptors are configured as host descriptors
9 * and have the minimum 32 byte size.
10 *
11 * For the boot driver queue register C is not written. It is important
12 * to the boot loader if packets are pushed/popped from the head or
13 * tail of a queue.
14 *
15 ******************************************************************************************/
16 #include "types.h"
17 #include "platform.h"
18 #include "qm_loc.h"
19 #include "qm_api.h"
20 #include "target.h"
21 #include <string.h>
23 /*******************************************************************************************
24 * FUNCTION PURPOSE: Pop a descriptor off of a queue
25 *******************************************************************************************
26 * DESCRIPTION: The descriptor is read from queue register D.
27 *******************************************************************************************/
28 qmHostDesc_t *hwQmQueuePop (uint32_t qnum)
29 {
30 qmHostDesc_t *hd;
31 uint32_t uhd;
33 /* Strip the descriptor size info */
34 uhd = DEVICE_REG32_R (DEVICE_QM_MANAGER_QUEUES_BASE + QM_REG_QUEUE_REGD(qnum));
35 uhd = uhd & ~0xf;
36 hd = (qmHostDesc_t *)uhd;
38 return (hd);
39 } /* hwQmQueuePop */
41 /*******************************************************************************************
42 * FUNCTION PURPOSE: Return the number of descriptors on a queue
43 *******************************************************************************************
44 * DESCRIPTION: The queue count is returned
45 *******************************************************************************************/
46 uint32_t hwQmQueueCount (uint32_t qnum)
47 {
48 uint32_t rega;
50 rega = DEVICE_REG32_R (DEVICE_QM_QUEUE_STATUS_BASE + QM_REG_QUEUE_REGA(qnum));
51 rega = BOOT_READ_BITFIELD (rega, QM_QA_ENTRY_COUNT_MSB, QM_QA_ENTRY_COUNT_LSB);
52 return (rega);
54 } /* hwQmQueueCount */
56 /*******************************************************************************************
57 * FUNCTION PURPOSE: Set a queue threshold
58 *******************************************************************************************
59 * DESCRIPTION: The queue threshold is enabled. Only high threshold is set, with a threshold
60 * value of 1.
61 *******************************************************************************************/
62 int16_t hwQmInitThreshold (uint32_t qnum)
63 {
64 DEVICE_REG32_W (DEVICE_QM_QUEUE_STATUS_BASE + QM_REG_STAT_CFG_REGD(qnum), 0x81);
66 return (0);
68 } /* hwQmInitThreshold */
71 /*******************************************************************************************
72 * FUNCTION PURPOSE: Push a descriptor onto a queue
73 *******************************************************************************************
74 * DESCRIPTION: The descriptor is written to queue register D. No check is made to see
75 * if the queue number is valid.
76 *******************************************************************************************/
77 void hwQmQueuePush (qmHostDesc_t *hd, uint32_t qnum, uint32_t descrSize)
78 {
79 uint32_t regd;
81 regd = ((uint32_t) hd | ((descrSize >> 4) - 1));
83 /* Push the descriptor onto the queue */
84 DEVICE_REG32_W (DEVICE_QM_MANAGER_QUEUES_BASE + QM_REG_QUEUE_REGD(qnum), regd);
86 } /* hwQmQueuePush */
88 /*******************************************************************************************
89 * FILE PURPOSE: Setup the queue manager
90 *******************************************************************************************
91 * DESCRIPTION: The queue manager is setup using a single linking ram and memory region,
92 * with fixed descriptor initialization.
93 *
94 * Since the linking ram and descriptor regions are configured, it is assumed
95 * that all queues are currently empty.
96 *
97 ********************************************************************************************/
98 int16_t hwQmSetup (qmConfig_t *cfg)
99 {
100 uint32_t v;
101 uint32_t w;
102 uint32_t x;
103 uint32_t i;
104 qmHostDesc_t *hd;
106 /* Verify that alignment requirements */
107 if ( (cfg->linkRamBase & (QM_LINKRAM_ALIGN-1)) != 0 )
108 return (QM_INVALID_LINKRAM_ALIGNMENT);
110 if ( (cfg->memRegionBase & (QM_MEMR_ALIGN-1)) != 0 )
111 return (QM_INVALID_MEMREGION_ALIGNMENT);
113 /* Verify linkram sizing is in range */
114 if ( (cfg->linkRamSize & ~QM_REG_LINKRAM_SIZE_MAX_MASK) != 0 )
115 return (QM_INVALID_LINKRAM_SIZE);
117 /* Verify there is enough linkram to cover the single memory region */
118 if (cfg->linkRamSize < cfg->memRegNumDescriptors)
119 return (QM_INVALID_LINKRAM_RAM_SIZE);
122 /* Linking RAM info */
123 DEVICE_REG32_W (DEVICE_QM_MANAGER_BASE + QM_REG_LINKRAM_BASE(0), cfg->linkRamBase);
124 DEVICE_REG32_W (DEVICE_QM_MANAGER_BASE + QM_REG_LINKRAM_SIZE(0), cfg->linkRamSize);
125 DEVICE_REG32_W (DEVICE_QM_MANAGER_BASE + QM_REG_LINKRAM_BASE(1), 0);
127 /* Memory region 0 info */
128 DEVICE_REG32_W (DEVICE_QM_DESC_SETUP_BASE + QM_REG_MEMR_BASE_ADDR(0), cfg->memRegionBase);
129 DEVICE_REG32_W (DEVICE_QM_DESC_SETUP_BASE + QM_REG_MEMR_START_IDX(0), 0);
131 /* Calculate the 2 fields in the descriptor setup register. Bits 0-3 specifiy
132 * the total memory size rounded up to the next higher power of two, and
133 * is expresses as 2^(n - 5). So for example if you have 20 descriptors
134 * The next higher power of 2 that exceeds this is 32, which is 2^5, so the value 0 (5-5)
135 * is placed in this field */
136 v = (31 - chipLmbd (1, cfg->memRegNumDescriptors));
137 if (v >= 4)
138 v = v - 4;
139 else
140 v = 0;
142 /* Add the descriptor size field */
143 QM_REG_VAL_DESC_SETUP_SET_DESC_SIZE(v, QM_DESC_SIZE_BYTES);
145 DEVICE_REG32_W (DEVICE_QM_DESC_SETUP_BASE + QM_REG_MEMR_DESC_SETUP(0), v);
148 /* Now format the descriptors and put them in a queue */
149 for (i = 0, v = cfg->memRegionBase; i < cfg->memRegNumDescriptors; i++, v += QM_DESC_SIZE_BYTES) {
151 hd = (qmHostDesc_t *)v;
152 memset (hd, 0, sizeof(qmHostDesc_t));
154 hd->descInfo = QM_DESC_DEFAULT_DESCINFO;
155 hd->packetInfo = QM_DESC_DEFAULT_PINFO;
157 if (QM_DESC_INFO_GET_PSINFO_LOC(hd->descInfo) == QM_DESC_PSINFO_IN_DESCR) {
158 if (QM_PKT_INFO_GET_EPIB(hd->packetInfo) == QM_DESC_PINFO_EPIB)
159 w = QM_DESC_SIZE_BYTES - 32 - 16; /* 32 bytes min descriptor size, 16 bytes extended info */
160 else
161 w = QM_DESC_SIZE_BYTES - 32;
162 } else
163 w = 0;
165 QM_PKT_INFO_SET_PSINFO_SIZE(hd->packetInfo, (w >> 2));
168 /* Push the descriptor onto the queue */
169 x = deviceLocalAddrToGlobal (v);
171 DEVICE_REG32_W (DEVICE_QM_MANAGER_QUEUES_BASE + QM_REG_QUEUE_REGD(cfg->destQ), x);
173 }
175 return (QM_OK);
177 } /* hwQmSetup */
180 /****************************************************************************************
181 * FUNCTION PURPOSE: Disable the QM
182 ****************************************************************************************
183 * DESCRIPTION: The QM is reset by clearing the linking ram and region 0 information
184 ****************************************************************************************/
185 void hwQmTeardown (void)
186 {
187 uint32_t i;
189 /* Linking RAM info */
190 for (i = 0; i < DEVICE_QM_NUM_LINKRAMS; i++) {
191 DEVICE_REG32_W (DEVICE_QM_MANAGER_BASE + QM_REG_LINKRAM_BASE(i), 0);
192 DEVICE_REG32_W (DEVICE_QM_MANAGER_BASE + QM_REG_LINKRAM_SIZE(i), 0);
193 }
195 /* Memory region info */
196 for (i = 0; i < DEVICE_QM_NUM_MEMREGIONS; i++) {
197 DEVICE_REG32_W (DEVICE_QM_DESC_SETUP_BASE + QM_REG_MEMR_BASE_ADDR(i), 0);
198 DEVICE_REG32_W (DEVICE_QM_DESC_SETUP_BASE + QM_REG_MEMR_START_IDX(i), 0);
199 DEVICE_REG32_W (DEVICE_QM_DESC_SETUP_BASE + QM_REG_MEMR_DESC_SETUP(i), 0);
200 }
202 } /* hwQmTeardown */