1 /* Copyright 2015 IBM Corp.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12 * implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <skiboot.h>
18 #include <chip.h>
19 #include <xscom.h>
20 #include <io.h>
21 #include <cpu.h>
22 #include <nx.h>
23 #include <vas.h>
24 #include <opal.h>
25
nx_cfg_umac_tx_wc(u32 gcid,u64 xcfg)26 static int nx_cfg_umac_tx_wc(u32 gcid, u64 xcfg)
27 {
28 int rc = 0;
29 u64 cfg;
30
31 cfg = vas_get_wcbs_bar(gcid);
32 if (!cfg) {
33 prerror("NX%d: ERROR finding WC Backing store BAR\n", gcid);
34 return -ENOMEM;
35 }
36
37 /*
38 * NOTE: Write the entire bar address to SCOM. VAS/NX will extract
39 * the relevant (NX_P9_UMAC_TX_WINDOW_CONTEXT_ADDR) bits.
40 * IOW, _don't_ just write the bit field like:
41 *
42 * cfg = SETFIELD(NX_P9_UMAC_TX_WINDOW_CONTEXT_ADDR, 0ULL, cfg);
43 */
44 rc = xscom_write(gcid, xcfg, cfg);
45
46 if (rc)
47 prerror("NX%d: ERROR: UMAC SEND WC BAR, %d\n", gcid, rc);
48 else
49 prlog(PR_DEBUG, "NX%d: UMAC SEND WC BAR, 0x%016lx, "
50 "xcfg 0x%llx\n",
51 gcid, (unsigned long)cfg, xcfg);
52
53 return rc;
54 }
55
nx_cfg_dma_vas_mmio(u32 gcid,u64 xcfg)56 static int nx_cfg_dma_vas_mmio(u32 gcid, u64 xcfg)
57 {
58 int rc = 0;
59 u64 cfg;
60
61 cfg = vas_get_hvwc_mmio_bar(gcid);
62 /*
63 * NOTE: Write the entire bar address to SCOM. VAS/NX will extract
64 * the relevant (NX_P9_UMAC_VAS_MMIO_ADDR) bits. IOW, _don't_
65 * just write the bit field like:
66 *
67 * cfg = SETFIELD(NX_P9_DMA_VAS_MMIO_ADDR, 0ULL, cfg);
68 */
69 rc = xscom_write(gcid, xcfg, cfg);
70
71 if (rc)
72 prerror("NX%d: ERROR: DMA VAS MMIO BAR, %d\n", gcid, rc);
73 else
74 prlog(PR_DEBUG, "NX%d: DMA VAS MMIO BAR, 0x%016lx, xcfg 0x%llx\n",
75 gcid, (unsigned long)cfg, xcfg);
76
77 return rc;
78 }
79
nx_cfg_umac_vas_mmio(u32 gcid,u64 xcfg)80 static int nx_cfg_umac_vas_mmio(u32 gcid, u64 xcfg)
81 {
82 int rc = 0;
83 u64 cfg;
84
85 cfg = vas_get_hvwc_mmio_bar(gcid);
86 /*
87 * NOTE: Write the entire bar address to SCOM. VAS/NX will extract
88 * the relevant (NX_P9_UMAC_VAS_MMIO_ADDR) bits. IOW, _don't_
89 * just write the bit field like:
90 *
91 * cfg = SETFIELD(NX_P9_UMAC_VAS_MMIO_ADDR, 0ULL, cfg);
92 */
93 rc = xscom_write(gcid, xcfg, cfg);
94
95 if (rc)
96 prerror("NX%d: ERROR: UMAC VAS MMIO BAR, %d\n", gcid, rc);
97 else
98 prlog(PR_DEBUG, "NX%d: UMAC VAS MMIO BAR, 0x%016lx, "
99 "xcfg 0x%llx\n",
100 gcid, (unsigned long)cfg, xcfg);
101
102 return rc;
103 }
104
nx_cfg_umac_status_ctrl(u32 gcid,u64 xcfg)105 static int nx_cfg_umac_status_ctrl(u32 gcid, u64 xcfg)
106 {
107 u64 uctrl;
108 int rc;
109 #define CRB_ENABLE 1
110
111 rc = xscom_read(gcid, xcfg, &uctrl);
112 if (rc)
113 return rc;
114
115 uctrl = SETFIELD(NX_P9_UMAC_STATUS_CTRL_CRB_ENABLE, uctrl, CRB_ENABLE);
116 rc = xscom_write(gcid, xcfg, uctrl);
117 if (rc)
118 prerror("NX%d: ERROR: Setting UMAC Status Control failure %d\n",
119 gcid, rc);
120 else
121 prlog(PR_DEBUG, "NX%d: Setting UMAC Status Control 0x%016lx\n",
122 gcid, (unsigned long)uctrl);
123
124 return rc;
125 }
126
nx_cfg_rx_fifo(struct dt_node * node,const char * compat,const char * priority,u32 gcid,u32 pid,u32 tid,u64 umac_bar,u64 umac_notify)127 int nx_cfg_rx_fifo(struct dt_node *node, const char *compat,
128 const char *priority, u32 gcid, u32 pid, u32 tid,
129 u64 umac_bar, u64 umac_notify)
130 {
131 u64 cfg;
132 int rc, size;
133 uint64_t fifo;
134 u32 lpid = 0xfff; /* All 1's for 12 bits in UMAC notify match reg */
135 #define MATCH_ENABLE 1
136
137 fifo = (uint64_t) local_alloc(gcid, RX_FIFO_SIZE, RX_FIFO_SIZE);
138 assert(fifo);
139
140 /*
141 * When configuring the address of the Rx FIFO into the Receive FIFO
142 * BAR, we should _NOT_ shift the address into bits 8:53. Instead we
143 * should copy the address as is and VAS/NX will extract relevant bits.
144 */
145 /*
146 * Section 5.21 of P9 NX Workbook Version 2.42 shows Receive FIFO BAR
147 * 54:56 represents FIFO size
148 * 000 = 1KB, 8 CRBs
149 * 001 = 2KB, 16 CRBs
150 * 010 = 4KB, 32 CRBs
151 * 011 = 8KB, 64 CRBs
152 * 100 = 16KB, 128 CRBs
153 * 101 = 32KB, 256 CRBs
154 * 110 = 111 reserved
155 */
156 size = RX_FIFO_SIZE / 1024;
157 cfg = SETFIELD(NX_P9_RX_FIFO_BAR_SIZE, fifo, ilog2(size));
158
159 rc = xscom_write(gcid, umac_bar, cfg);
160 if (rc) {
161 prerror("NX%d: ERROR: Setting UMAC FIFO bar failure %d\n",
162 gcid, rc);
163 return rc;
164 } else
165 prlog(PR_DEBUG, "NX%d: Setting UMAC FIFO bar 0x%016lx\n",
166 gcid, (unsigned long)cfg);
167
168 rc = xscom_read(gcid, umac_notify, &cfg);
169 if (rc)
170 return rc;
171
172 /*
173 * VAS issues asb_notify with the unique ID to identify the target
174 * co-processor/engine. Logical partition ID (lpid), process ID (pid),
175 * and thread ID (tid) combination is used to define the unique ID
176 * in the system. Export these values in device-tree such that the
177 * driver configure RxFIFO with VAS. Set these values in RxFIFO notify
178 * match register for each engine which compares the ID with each
179 * request.
180 * To define unique indentification, 0xfff (1's for 12 bits),
181 * co-processor type, and counter within coprocessor type are used
182 * for lpid, pid, and tid respectively.
183 */
184 cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_LPID, cfg, lpid);
185 cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_PID, cfg, pid);
186 cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_TID, cfg, tid);
187 cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_MATCH_ENABLE, cfg,
188 MATCH_ENABLE);
189
190 rc = xscom_write(gcid, umac_notify, cfg);
191 if (rc) {
192 prerror("NX%d: ERROR: Setting UMAC notify match failure %d\n",
193 gcid, rc);
194 return rc;
195 } else
196 prlog(PR_DEBUG, "NX%d: Setting UMAC notify match 0x%016lx\n",
197 gcid, (unsigned long)cfg);
198
199 dt_add_property_string(node, "compatible", compat);
200 dt_add_property_string(node, "priority", priority);
201 dt_add_property_u64(node, "rx-fifo-address", fifo);
202 dt_add_property_cells(node, "rx-fifo-size", RX_FIFO_SIZE);
203 dt_add_property_cells(node, "lpid", lpid);
204 dt_add_property_cells(node, "pid", pid);
205 dt_add_property_cells(node, "tid", tid);
206
207 return 0;
208 }
209
nx_init_fifo_ctrl(u32 gcid,u64 fifo_ctrl)210 static int nx_init_fifo_ctrl(u32 gcid, u64 fifo_ctrl)
211 {
212 u64 cfg;
213 int rc = 0;
214
215 rc = xscom_read(gcid, fifo_ctrl, &cfg);
216 if (rc)
217 return rc;
218
219 cfg = SETFIELD(NX_P9_RX_FIFO_CTRL_READ_OFFSET, cfg, 0);
220 cfg = SETFIELD(NX_P9_RX_FIFO_CTRL_QUEUED, cfg, 0);
221
222 rc = xscom_write(gcid, fifo_ctrl, cfg);
223
224 return rc;
225 }
226
227
opal_nx_coproc_init(u32 gcid,u32 ct)228 static int opal_nx_coproc_init(u32 gcid, u32 ct)
229 {
230 struct proc_chip *chip;
231 u64 fifo, fifo_hi;
232 u32 nx_base;
233 int rc;
234
235 if (proc_gen < proc_gen_p9)
236 return OPAL_UNSUPPORTED;
237
238 chip = get_chip(gcid);
239 if (!chip)
240 return OPAL_PARAMETER;
241
242 nx_base = chip->nx_base;
243 if (!nx_base)
244 return OPAL_PARAMETER;
245
246 switch (ct) {
247 case NX_CT_842:
248 fifo_hi = nx_base + NX_P9_842_HIGH_PRI_RX_FIFO_CTRL;
249 fifo = nx_base + NX_P9_842_NORMAL_PRI_RX_FIFO_CTRL;
250 break;
251 case NX_CT_GZIP:
252 fifo_hi = nx_base + NX_P9_GZIP_HIGH_PRI_RX_FIFO_CTRL;
253 fifo = nx_base + NX_P9_GZIP_NORMAL_PRI_RX_FIFO_CTRL;
254 break;
255 default:
256 prlog(PR_EMERG, "OPAL: Unknown NX coprocessor type\n");
257 return OPAL_PARAMETER;
258 }
259
260 rc = nx_init_fifo_ctrl(gcid, fifo_hi);
261
262 if (!rc)
263 rc = nx_init_fifo_ctrl(gcid, fifo);
264
265 return rc;
266 }
267
268 opal_call(OPAL_NX_COPROC_INIT, opal_nx_coproc_init, 2);
269
nx_create_compress_node(struct dt_node * node)270 void nx_create_compress_node(struct dt_node *node)
271 {
272 u32 gcid, pb_base;
273 struct proc_chip *chip;
274 int rc;
275
276 gcid = dt_get_chip_id(node);
277 pb_base = dt_get_address(node, 0, NULL);
278
279 chip = get_chip(gcid);
280 chip->nx_base = pb_base;
281
282 prlog(PR_INFO, "NX%d: 842 at 0x%x\n", gcid, pb_base);
283
284 if (dt_node_is_compatible(node, "ibm,power9-nx")) {
285 u64 cfg_mmio, cfg_txwc, cfg_uctrl, cfg_dma;
286
287 prlog(PR_DEBUG, "Found ibm,power9-nx\n");
288 cfg_mmio = pb_base + NX_P9_UMAC_VAS_MMIO_BAR;
289 cfg_dma = pb_base + NX_P9_DMA_VAS_MMIO_BAR;
290 cfg_txwc = pb_base + NX_P9_UMAC_TX_WINDOW_CONTEXT_BAR;
291 cfg_uctrl = pb_base + NX_P9_UMAC_STATUS_CTRL;
292
293 rc = nx_cfg_umac_vas_mmio(gcid, cfg_mmio);
294 if (rc)
295 return;
296
297 rc = nx_cfg_dma_vas_mmio(gcid, cfg_dma);
298 if (rc)
299 return;
300
301 rc = nx_cfg_umac_tx_wc(gcid, cfg_txwc);
302 if (rc)
303 return;
304
305 rc = nx_cfg_umac_status_ctrl(gcid, cfg_uctrl);
306 if (rc)
307 return;
308
309 p9_nx_enable_842(node, gcid, pb_base);
310 p9_nx_enable_gzip(node, gcid, pb_base);
311 } else
312 nx_enable_842(node, gcid, pb_base);
313 }
314