1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #ifndef _NPI_RX_RD64_H
27 #define _NPI_RX_RD64_H
28
29 #pragma ident "%Z%%M% %I% %E% SMI"
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 #include <npi.h>
36
37 /*
38 * RXDMA_REG_READ64
39 *
40 * Read a 64-bit value from a DMC register.
41 *
42 * This is the old, rather convoluted, macro:
43 *
44 * #define RXDMA_REG_READ64(handle, reg, channel, data_p) { \
45 * NXGE_REG_RD64(handle, (NXGE_RXDMA_OFFSET(reg, \
46 * handle.is_vraddr, channel)), (data_p))
47 *
48 * There are 4 versions of NXGE_REG_RD64:
49 * -------------------------------------------------------------
50 * #if defined(REG_TRACE)
51 * #define NXGE_REG_RD64(handle, offset, val_p) { \
52 * *(val_p) = NXGE_NPI_PIO_READ64(handle, offset); \
53 * npi_rtrace_update(handle, B_FALSE, &npi_rtracebuf, (uint32_t)offset, \
54 * (uint64_t)(*(val_p))); \
55 * }
56 * #elif defined(REG_SHOW)
57 * #define NXGE_REG_RD64(handle, offset, val_p) {\
58 * *(val_p) = NXGE_NPI_PIO_READ64(handle, offset);\
59 * rt_show_reg(0xbadbad, B_FALSE, (uint32_t)offset, (uint64_t)(*(val_p)));\
60 * }
61 * #elif defined(AXIS_DEBUG) && !defined(LEGION)
62 * #define NXGE_REG_RD64(handle, offset, val_p) {\
63 * int n; \
64 * for (n = 0; n < AXIS_WAIT_LOOP; n++) { \
65 * *(val_p) = 0; \
66 * *(val_p) = NXGE_NPI_PIO_READ64(handle, offset);\
67 * if (*(val_p) != (~0)) { \
68 * break; \
69 * } \
70 * drv_usecwait(AXIS_WAIT_PER_LOOP); \
71 * if (n < 20) { \
72 * cmn_err(CE_WARN, "NXGE_REG_RD64: loop %d " \
73 * "REG 0x%x(0x%llx)", \
74 * n, offset, *val_p);\
75 * } \
76 * } \
77 * if (n >= AXIS_WAIT_LOOP) { \
78 * cmn_err(CE_WARN, "(FATAL)NXGE_REG_RD64 on offset 0x%x " \
79 * "with -1!!!", offset); \
80 * } \
81 * }
82 * #else
83 * #define NXGE_REG_RD64(handle, offset, val_p) {\
84 * *(val_p) = NXGE_NPI_PIO_READ64(handle, offset);\
85 * }
86 * #endif
87 *
88 * There are 2 versions of NXGE_NPI_PIO_READ64:
89 * -------------------------------------------------------------
90 * #if defined(__i386)
91 * #define NXGE_NPI_PIO_READ64(npi_handle, offset) \
92 * (ddi_get64(NPI_REGH(npi_handle), \
93 * (uint64_t *)(NPI_REGP(npi_handle) + (uint32_t)offset)))
94 * #else
95 * #define NXGE_NPI_PIO_READ64(npi_handle, offset) \
96 * (ddi_get64(NPI_REGH(npi_handle), \
97 * (uint64_t *)(NPI_REGP(npi_handle) + offset)))
98 * #endif
99 *
100 * -------------------------------------------------------------
101 * #define NPI_REGH(npi_handle) (npi_handle.regh)
102 * #define NPI_REGP(npi_handle) (npi_handle.regp)
103 *
104 * Now let's tackle NXGE_RXDMA_OFFSET
105 * -------------------------------------------------------------
106 * #define NXGE_RXDMA_OFFSET(x, v, channel) (x + \
107 * (!v ? DMC_OFFSET(channel) : \
108 * RDMC_PIOVADDR_OFFSET(channel)))
109 *
110 * -------------------------------------------------------------
111 * #define DMC_OFFSET(channel) (DMA_CSR_SIZE * channel)
112 *
113 * #define TDMC_PIOVADDR_OFFSET(channel) (2 * DMA_CSR_SIZE * channel)
114 * -------------------------------------------------------------
115 * #define RDMC_PIOVADDR_OFFSET(channel) \
116 * (TDMC_OFFSET(channel) + DMA_CSR_SIZE)
117 * -------------------------------------------------------------
118 * #define DMA_CSR_SIZE 512
119 *
120 * #define TDMC_OFFSET(channel) (TX_RNG_CFIG + DMA_CSR_SIZE * channel)
121 * #define TX_RNG_CFIG (DMC + 0x40000)
122 * -------------------------------------------------------------
123 * This definition is clearly wrong! I think this was intended:
124 *
125 * #define RDMC_PIOVADDR_OFFSET(channel) \
126 * (TDMC_PIOVADDR__OFFSET(channel) + DMA_CSR_SIZE)
127 * -------------------------------------------------------------
128 *
129 * Finally, we have the full macro:
130 * -------------------------------------------------------------
131 * #define RXDMA_REG_READ64(handle, reg, channel, data_p) { \
132 * NXGE_REG_RD64(handle, (NXGE_RXDMA_OFFSET(reg, \
133 * handle.is_vraddr, channel)), (data_p))
134 *
135 * *data_p = ddi_get64(handle.regh, (uint64_t*)(handle.regp +
136 * ((0x600000+0x00000) +
137 * (!handle.is_vraddr ?
138 * (512 * channel) :
139 * 0x600000 + 0x40000 + (512 * channel) + 512)));
140 */
141
142 static void RXDMA_REG_READ64(npi_handle_t, uint64_t, int, uint64_t *);
143 #pragma inline(RXDMA_REG_READ64)
144
145 /*
146 * RXDMA_REG_READ64
147 *
148 * Read a 64-bit value from a DMC register.
149 *
150 * Arguments:
151 * handle The NPI handle to use.
152 * offset The offset into the DMA CSR (the register).
153 * channel The channel, which is used as a multiplicand.
154 * value Where to put the 64-bit value to be read.
155 *
156 * Notes:
157 * If handle.regp is a virtual address (the address of a VR),
158 * we have to subtract the value DMC right off the bat. DMC
159 * is defined as 0x600000, which works in a non-virtual address
160 * space, but not in a VR. In a VR, a DMA CSR's space begins
161 * at zero (0). So, since every call to RXMDA_REG_READ64 uses
162 * a register macro which adds in DMC, we have to subtract it.
163 *
164 * The rest of it is pretty straighforward. In a VR, a channel is
165 * logical, not absolute; and every DMA CSR is 512 bytes big;
166 * furthermore, a subpage of a VR is always ordered with the
167 * transmit CSRs first, followed by the receive CSRs. That is,
168 * a 512 byte space of Tx CSRs, followed by a 512 byte space of
169 * Rx CSRs. Hence this calculation:
170 *
171 * offset += ((channel << 1) + 1) << DMA_CSR_SLL;
172 *
173 * Here's an example:
174 *
175 * RXDMA_REG_READ64(handle, RX_DMA_CTL_STAT_REG, channel, value);
176 * Let's say channel is 3
177 * #define RX_DMA_CTL_STAT_REG (DMC + 0x00070)
178 * offset = 0x600070
179 * offset &= 0xff = 0x70
180 * offset += ((3 << 1) + 1) << 9
181 * 3 << 1 = 6
182 * 6 + 1 = 7
183 * 7 << 9 = 0xe00
184 * offset += 0xe00 = 0xe70
185 *
186 * Therefore, our register's (virtual) PIO address is 0xe70.
187 *
188 * cf. Table 10-6 on page 181 of the Neptune PRM, v 1.4:
189 *
190 * E00 - FFF CSRs for bound logical receive DMA channel 3.
191 *
192 * In a non-virtual environment, you simply multiply the absolute
193 * channel number by 512 bytes, and get the correct offset to
194 * the register you're looking for. That is, the RX_DMA_CTL_STAT CSR,
195 * is, as are all of these registers, in a table where each channel
196 * is offset 512 bytes from the previous channel (count 16 step 512).
197 *
198 * offset += (channel << DMA_CSR_SLL); // channel<<9 = channel*512
199 *
200 * Here's an example:
201 *
202 * RXDMA_REG_READ64(handle, RX_DMA_CTL_STAT_REG, channel, value);
203 * Let's say channel is 3
204 * #define RX_DMA_CTL_STAT_REG (DMC + 0x00070)
205 * offset = 0x600070
206 * offset += (3 << 9)
207 * 3 << 9 = 0x600
208 * offset += 0x600 = 0x600670
209 *
210 * Therefore, our register's PIO address is 0x600670.
211 *
212 * cf. Table 12-42 on page 234 of the Neptune PRM, v 1.4:
213 * RX_DMA_CTL_STAT (DMC + [0x]00070) (count 16 step [0x]200)
214 *
215 * Context:
216 * Guest domain
217 *
218 */
219 extern const char *nxge_rx2str(int);
220
221 void
RXDMA_REG_READ64(npi_handle_t handle,uint64_t offset,int channel,uint64_t * value)222 RXDMA_REG_READ64(
223 npi_handle_t handle,
224 uint64_t offset,
225 int channel,
226 uint64_t *value)
227 {
228 #if defined(NPI_REG_TRACE)
229 const char *name = nxge_rx2str((int)offset);
230 #endif
231 if (handle.is_vraddr) {
232 offset &= DMA_CSR_MASK;
233 offset += (((channel << 1) + 1) << DMA_CSR_SLL);
234 } else {
235 offset += (channel << DMA_CSR_SLL);
236 }
237
238 #if defined(__i386)
239 *value = ddi_get64(handle.regh,
240 (uint64_t *)(handle.regp + (uint32_t)offset));
241 #else
242 *value = ddi_get64(handle.regh, (uint64_t *)(handle.regp + offset));
243 #endif
244
245 #if defined(NPI_REG_TRACE)
246 npi_trace_update(handle, B_FALSE, &npi_rtracebuf,
247 name, (uint32_t)offset, *value);
248 #elif defined(REG_SHOW)
249 /*
250 * Since we don't have a valid RTBUF index to show, send 0xBADBAD.
251 */
252 rt_show_reg(0xbadbad, B_FALSE, (uint32_t)offset, *value);
253 #endif
254 }
255
256 #ifdef __cplusplus
257 }
258 #endif
259
260 #endif /* _NPI_RX_RD64_H */
261