1/*-
2 * Copyright (c) 2007-2015 Solarflare Communications Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * The views and conclusions contained in the software and documentation are
27 * those of the authors and should not be interpreted as representing official
28 * policies, either expressed or implied, of the FreeBSD Project.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/efx_intr.c 299320 2016-05-10 07:01:06Z arybchik $");
33
34#include "efx.h"
35#include "efx_impl.h"
36
37
38#if EFSYS_OPT_SIENA
39
40static __checkReturn efx_rc_t
41falconsiena_intr_init(
42 __in efx_nic_t *enp,
43 __in efx_intr_type_t type,
44 __in efsys_mem_t *esmp);
45
46static void
47falconsiena_intr_enable(
48 __in efx_nic_t *enp);
49
50static void
51falconsiena_intr_disable(
52 __in efx_nic_t *enp);
53
54static void
55falconsiena_intr_disable_unlocked(
56 __in efx_nic_t *enp);
57
58static __checkReturn efx_rc_t
59falconsiena_intr_trigger(
60 __in efx_nic_t *enp,
61 __in unsigned int level);
62
63static void
64falconsiena_intr_fini(
65 __in efx_nic_t *enp);
66
67static void
68falconsiena_intr_status_line(
69 __in efx_nic_t *enp,
70 __out boolean_t *fatalp,
71 __out uint32_t *qmaskp);
72
73static void
74falconsiena_intr_status_message(
75 __in efx_nic_t *enp,
76 __in unsigned int message,
77 __out boolean_t *fatalp);
78
79static void
80falconsiena_intr_fatal(
81 __in efx_nic_t *enp);
82
83static __checkReturn boolean_t
84falconsiena_intr_check_fatal(
85 __in efx_nic_t *enp);
86
87
88#endif /* EFSYS_OPT_SIENA */
89
90
91#if EFSYS_OPT_SIENA
92static efx_intr_ops_t __efx_intr_siena_ops = {
93 falconsiena_intr_init, /* eio_init */
94 falconsiena_intr_enable, /* eio_enable */
95 falconsiena_intr_disable, /* eio_disable */
96 falconsiena_intr_disable_unlocked, /* eio_disable_unlocked */
97 falconsiena_intr_trigger, /* eio_trigger */
98 falconsiena_intr_status_line, /* eio_status_line */
99 falconsiena_intr_status_message, /* eio_status_message */
100 falconsiena_intr_fatal, /* eio_fatal */
101 falconsiena_intr_fini, /* eio_fini */
102};
103#endif /* EFSYS_OPT_SIENA */
104
105#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
106static efx_intr_ops_t __efx_intr_ef10_ops = {
107 ef10_intr_init, /* eio_init */
108 ef10_intr_enable, /* eio_enable */
109 ef10_intr_disable, /* eio_disable */
110 ef10_intr_disable_unlocked, /* eio_disable_unlocked */
111 ef10_intr_trigger, /* eio_trigger */
112 ef10_intr_status_line, /* eio_status_line */
113 ef10_intr_status_message, /* eio_status_message */
114 ef10_intr_fatal, /* eio_fatal */
115 ef10_intr_fini, /* eio_fini */
116};
117#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
118
119 __checkReturn efx_rc_t
120efx_intr_init(
121 __in efx_nic_t *enp,
122 __in efx_intr_type_t type,
123 __in efsys_mem_t *esmp)
124{
125 efx_intr_t *eip = &(enp->en_intr);
126 efx_intr_ops_t *eiop;
127 efx_rc_t rc;
128
129 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
130 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
131
132 if (enp->en_mod_flags & EFX_MOD_INTR) {
133 rc = EINVAL;
134 goto fail1;
135 }
136
137 eip->ei_esmp = esmp;
138 eip->ei_type = type;
139 eip->ei_level = 0;
140
141 enp->en_mod_flags |= EFX_MOD_INTR;
142
143 switch (enp->en_family) {
144#if EFSYS_OPT_SIENA
145 case EFX_FAMILY_SIENA:
146 eiop = (efx_intr_ops_t *)&__efx_intr_siena_ops;
147 break;
148#endif /* EFSYS_OPT_SIENA */
149
150#if EFSYS_OPT_HUNTINGTON
151 case EFX_FAMILY_HUNTINGTON:
152 eiop = (efx_intr_ops_t *)&__efx_intr_ef10_ops;
153 break;
154#endif /* EFSYS_OPT_HUNTINGTON */
155
156#if EFSYS_OPT_MEDFORD
157 case EFX_FAMILY_MEDFORD:
158 eiop = (efx_intr_ops_t *)&__efx_intr_ef10_ops;
159 break;
160#endif /* EFSYS_OPT_MEDFORD */
161
162 default:
163 EFSYS_ASSERT(B_FALSE);
164 rc = ENOTSUP;
165 goto fail2;
166 }
167
168 if ((rc = eiop->eio_init(enp, type, esmp)) != 0)
169 goto fail3;
170
171 eip->ei_eiop = eiop;
172
173 return (0);
174
175fail3:
176 EFSYS_PROBE(fail3);
177fail2:
178 EFSYS_PROBE(fail2);
179fail1:
180 EFSYS_PROBE1(fail1, efx_rc_t, rc);
181
182 return (rc);
183}
184
185 void
186efx_intr_fini(
187 __in efx_nic_t *enp)
188{
189 efx_intr_t *eip = &(enp->en_intr);
190 efx_intr_ops_t *eiop = eip->ei_eiop;
191
192 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
193 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
194 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
195
196 eiop->eio_fini(enp);
197
198 enp->en_mod_flags &= ~EFX_MOD_INTR;
199}
200
201 void
202efx_intr_enable(
203 __in efx_nic_t *enp)
204{
205 efx_intr_t *eip = &(enp->en_intr);
206 efx_intr_ops_t *eiop = eip->ei_eiop;
207
208 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
209 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
210
211 eiop->eio_enable(enp);
212}
213
214 void
215efx_intr_disable(
216 __in efx_nic_t *enp)
217{
218 efx_intr_t *eip = &(enp->en_intr);
219 efx_intr_ops_t *eiop = eip->ei_eiop;
220
221 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
222 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
223
224 eiop->eio_disable(enp);
225}
226
227 void
228efx_intr_disable_unlocked(
229 __in efx_nic_t *enp)
230{
231 efx_intr_t *eip = &(enp->en_intr);
232 efx_intr_ops_t *eiop = eip->ei_eiop;
233
234 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
235 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
236
237 eiop->eio_disable_unlocked(enp);
238}
239
240
241 __checkReturn efx_rc_t
242efx_intr_trigger(
243 __in efx_nic_t *enp,
244 __in unsigned int level)
245{
246 efx_intr_t *eip = &(enp->en_intr);
247 efx_intr_ops_t *eiop = eip->ei_eiop;
248
249 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
250 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
251
252 return (eiop->eio_trigger(enp, level));
253}
254
255 void
256efx_intr_status_line(
257 __in efx_nic_t *enp,
258 __out boolean_t *fatalp,
259 __out uint32_t *qmaskp)
260{
261 efx_intr_t *eip = &(enp->en_intr);
262 efx_intr_ops_t *eiop = eip->ei_eiop;
263
264 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
265 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
266
267 eiop->eio_status_line(enp, fatalp, qmaskp);
268}
269
270 void
271efx_intr_status_message(
272 __in efx_nic_t *enp,
273 __in unsigned int message,
274 __out boolean_t *fatalp)
275{
276 efx_intr_t *eip = &(enp->en_intr);
277 efx_intr_ops_t *eiop = eip->ei_eiop;
278
279 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
280 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
281
282 eiop->eio_status_message(enp, message, fatalp);
283}
284
285 void
286efx_intr_fatal(
287 __in efx_nic_t *enp)
288{
289 efx_intr_t *eip = &(enp->en_intr);
290 efx_intr_ops_t *eiop = eip->ei_eiop;
291
292 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
293 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
294
295 eiop->eio_fatal(enp);
296}
297
298
299/* ************************************************************************* */
300/* ************************************************************************* */
301/* ************************************************************************* */
302
303#if EFSYS_OPT_SIENA
304
305static __checkReturn efx_rc_t
306falconsiena_intr_init(
307 __in efx_nic_t *enp,
308 __in efx_intr_type_t type,
309 __in efsys_mem_t *esmp)
310{
311 efx_intr_t *eip = &(enp->en_intr);
312 efx_oword_t oword;
313
314 /*
315 * bug17213 workaround.
316 *
317 * Under legacy interrupts, don't share a level between fatal
318 * interrupts and event queue interrupts. Under MSI-X, they
319 * must share, or we won't get an interrupt.
320 */
321 if (enp->en_family == EFX_FAMILY_SIENA &&
322 eip->ei_type == EFX_INTR_LINE)
323 eip->ei_level = 0x1f;
324 else
325 eip->ei_level = 0;
326
327 /* Enable all the genuinely fatal interrupts */
328 EFX_SET_OWORD(oword);
329 EFX_SET_OWORD_FIELD(oword, FRF_AZ_ILL_ADR_INT_KER_EN, 0);
330 EFX_SET_OWORD_FIELD(oword, FRF_AZ_RBUF_OWN_INT_KER_EN, 0);
331 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TBUF_OWN_INT_KER_EN, 0);
332 if (enp->en_family >= EFX_FAMILY_SIENA)
333 EFX_SET_OWORD_FIELD(oword, FRF_CZ_SRAM_PERR_INT_P_KER_EN, 0);
334 EFX_BAR_WRITEO(enp, FR_AZ_FATAL_INTR_REG_KER, &oword);
335
336 /* Set up the interrupt address register */
337 EFX_POPULATE_OWORD_3(oword,
338 FRF_AZ_NORM_INT_VEC_DIS_KER, (type == EFX_INTR_MESSAGE) ? 1 : 0,
339 FRF_AZ_INT_ADR_KER_DW0, EFSYS_MEM_ADDR(esmp) & 0xffffffff,
340 FRF_AZ_INT_ADR_KER_DW1, EFSYS_MEM_ADDR(esmp) >> 32);
341 EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
342
343 return (0);
344}
345
346static void
347falconsiena_intr_enable(
348 __in efx_nic_t *enp)
349{
350 efx_intr_t *eip = &(enp->en_intr);
351 efx_oword_t oword;
352
353 EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
354
355 EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
356 EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 1);
357 EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
358}
359
360static void
361falconsiena_intr_disable(
362 __in efx_nic_t *enp)
363{
364 efx_oword_t oword;
365
366 EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
367 EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
368 EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
369
370 EFSYS_SPIN(10);
371}
372
373static void
374falconsiena_intr_disable_unlocked(
375 __in efx_nic_t *enp)
376{
377 efx_oword_t oword;
378
379 EFSYS_BAR_READO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
380 &oword, B_FALSE);
381 EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
382 EFSYS_BAR_WRITEO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
383 &oword, B_FALSE);
384}
385
386static __checkReturn efx_rc_t
387falconsiena_intr_trigger(
388 __in efx_nic_t *enp,
389 __in unsigned int level)
390{
391 efx_intr_t *eip = &(enp->en_intr);
392 efx_oword_t oword;
393 unsigned int count;
394 uint32_t sel;
395 efx_rc_t rc;
396
397 /* bug16757: No event queues can be initialized */
398 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
399
400 switch (enp->en_family) {
401 case EFX_FAMILY_FALCON:
402 if (level >= EFX_NINTR_FALCON) {
403 rc = EINVAL;
404 goto fail1;
405 }
406 break;
407
408 case EFX_FAMILY_SIENA:
409 if (level >= EFX_NINTR_SIENA) {
410 rc = EINVAL;
411 goto fail1;
412 }
413 break;
414
415 default:
416 EFSYS_ASSERT(B_FALSE);
417 break;
418 }
419
420 if (level > EFX_MASK32(FRF_AZ_KER_INT_LEVE_SEL))
421 return (ENOTSUP); /* avoid EFSYS_PROBE() */
422
423 sel = level;
424
425 /* Trigger a test interrupt */
426 EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
427 EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, sel);
428 EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER, 1);
429 EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
430
431 /*
432 * Wait up to 100ms for the interrupt to be raised before restoring
433 * KER_INT_LEVE_SEL. Ignore a failure to raise (the caller will
434 * observe this soon enough anyway), but always reset KER_INT_LEVE_SEL
435 */
436 count = 0;
437 do {
438 EFSYS_SPIN(100); /* 100us */
439
440 EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
441 } while (EFX_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER) && ++count < 1000);
442
443 EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
444 EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
445
446 return (0);
447
448fail1:
449 EFSYS_PROBE1(fail1, efx_rc_t, rc);
450
451 return (rc);
452}
453
454static __checkReturn boolean_t
455falconsiena_intr_check_fatal(
456 __in efx_nic_t *enp)
457{
458 efx_intr_t *eip = &(enp->en_intr);
459 efsys_mem_t *esmp = eip->ei_esmp;
460 efx_oword_t oword;
461
462 /* Read the syndrome */
463 EFSYS_MEM_READO(esmp, 0, &oword);
464
465 if (EFX_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT) != 0) {
466 EFSYS_PROBE(fatal);
467
468 /* Clear the fatal interrupt condition */
469 EFX_SET_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT, 0);
470 EFSYS_MEM_WRITEO(esmp, 0, &oword);
471
472 return (B_TRUE);
473 }
474
475 return (B_FALSE);
476}
477
478static void
479falconsiena_intr_status_line(
480 __in efx_nic_t *enp,
481 __out boolean_t *fatalp,
482 __out uint32_t *qmaskp)
483{
484 efx_intr_t *eip = &(enp->en_intr);
485 efx_dword_t dword;
486
487 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
488 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
489
490 /*
491 * Read the queue mask and implicitly acknowledge the
492 * interrupt.
493 */
494 EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE);
495 *qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
496
497 EFSYS_PROBE1(qmask, uint32_t, *qmaskp);
498
499 if (*qmaskp & (1U << eip->ei_level))
500 *fatalp = falconsiena_intr_check_fatal(enp);
501 else
502 *fatalp = B_FALSE;
503}
504
505static void
506falconsiena_intr_status_message(
507 __in efx_nic_t *enp,
508 __in unsigned int message,
509 __out boolean_t *fatalp)
510{
511 efx_intr_t *eip = &(enp->en_intr);
512
513 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
514 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
515
516 if (message == eip->ei_level)
517 *fatalp = falconsiena_intr_check_fatal(enp);
518 else
519 *fatalp = B_FALSE;
520}
521
522
523static void
524falconsiena_intr_fatal(
525 __in efx_nic_t *enp)
526{
527#if EFSYS_OPT_DECODE_INTR_FATAL
528 efx_oword_t fatal;
529 efx_oword_t mem_per;
530
531 EFX_BAR_READO(enp, FR_AZ_FATAL_INTR_REG_KER, &fatal);
532 EFX_ZERO_OWORD(mem_per);
533
534 if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0 ||
535 EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
536 EFX_BAR_READO(enp, FR_AZ_MEM_STAT_REG, &mem_per);
537
538 if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRAM_OOB_INT_KER) != 0)
539 EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_OOB, 0, 0);
540
541 if (EFX_OWORD_FIELD(fatal, FRF_AZ_BUFID_DC_OOB_INT_KER) != 0)
542 EFSYS_ERR(enp->en_esip, EFX_ERR_BUFID_DC_OOB, 0, 0);
543
544 if (EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
545 EFSYS_ERR(enp->en_esip, EFX_ERR_MEM_PERR,
546 EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
547 EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
548
549 if (EFX_OWORD_FIELD(fatal, FRF_AZ_RBUF_OWN_INT_KER) != 0)
550 EFSYS_ERR(enp->en_esip, EFX_ERR_RBUF_OWN, 0, 0);
551
552 if (EFX_OWORD_FIELD(fatal, FRF_AZ_TBUF_OWN_INT_KER) != 0)
553 EFSYS_ERR(enp->en_esip, EFX_ERR_TBUF_OWN, 0, 0);
554
555 if (EFX_OWORD_FIELD(fatal, FRF_AZ_RDESCQ_OWN_INT_KER) != 0)
556 EFSYS_ERR(enp->en_esip, EFX_ERR_RDESQ_OWN, 0, 0);
557
558 if (EFX_OWORD_FIELD(fatal, FRF_AZ_TDESCQ_OWN_INT_KER) != 0)
559 EFSYS_ERR(enp->en_esip, EFX_ERR_TDESQ_OWN, 0, 0);
560
561 if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVQ_OWN_INT_KER) != 0)
562 EFSYS_ERR(enp->en_esip, EFX_ERR_EVQ_OWN, 0, 0);
563
564 if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVF_OFLO_INT_KER) != 0)
565 EFSYS_ERR(enp->en_esip, EFX_ERR_EVFF_OFLO, 0, 0);
566
567 if (EFX_OWORD_FIELD(fatal, FRF_AZ_ILL_ADR_INT_KER) != 0)
568 EFSYS_ERR(enp->en_esip, EFX_ERR_ILL_ADDR, 0, 0);
569
570 if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0)
571 EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_PERR,
572 EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
573 EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
574#else
575 EFSYS_ASSERT(0);
576#endif
577}
578
579static void
580falconsiena_intr_fini(
581 __in efx_nic_t *enp)
582{
583 efx_oword_t oword;
584
585 /* Clear the interrupt address register */
586 EFX_ZERO_OWORD(oword);
587 EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
588}
589
590#endif /* EFSYS_OPT_SIENA */
2 * Copyright (c) 2007-2015 Solarflare Communications Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * The views and conclusions contained in the software and documentation are
27 * those of the authors and should not be interpreted as representing official
28 * policies, either expressed or implied, of the FreeBSD Project.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/efx_intr.c 299320 2016-05-10 07:01:06Z arybchik $");
33
34#include "efx.h"
35#include "efx_impl.h"
36
37
38#if EFSYS_OPT_SIENA
39
40static __checkReturn efx_rc_t
41falconsiena_intr_init(
42 __in efx_nic_t *enp,
43 __in efx_intr_type_t type,
44 __in efsys_mem_t *esmp);
45
46static void
47falconsiena_intr_enable(
48 __in efx_nic_t *enp);
49
50static void
51falconsiena_intr_disable(
52 __in efx_nic_t *enp);
53
54static void
55falconsiena_intr_disable_unlocked(
56 __in efx_nic_t *enp);
57
58static __checkReturn efx_rc_t
59falconsiena_intr_trigger(
60 __in efx_nic_t *enp,
61 __in unsigned int level);
62
63static void
64falconsiena_intr_fini(
65 __in efx_nic_t *enp);
66
67static void
68falconsiena_intr_status_line(
69 __in efx_nic_t *enp,
70 __out boolean_t *fatalp,
71 __out uint32_t *qmaskp);
72
73static void
74falconsiena_intr_status_message(
75 __in efx_nic_t *enp,
76 __in unsigned int message,
77 __out boolean_t *fatalp);
78
79static void
80falconsiena_intr_fatal(
81 __in efx_nic_t *enp);
82
83static __checkReturn boolean_t
84falconsiena_intr_check_fatal(
85 __in efx_nic_t *enp);
86
87
88#endif /* EFSYS_OPT_SIENA */
89
90
91#if EFSYS_OPT_SIENA
92static efx_intr_ops_t __efx_intr_siena_ops = {
93 falconsiena_intr_init, /* eio_init */
94 falconsiena_intr_enable, /* eio_enable */
95 falconsiena_intr_disable, /* eio_disable */
96 falconsiena_intr_disable_unlocked, /* eio_disable_unlocked */
97 falconsiena_intr_trigger, /* eio_trigger */
98 falconsiena_intr_status_line, /* eio_status_line */
99 falconsiena_intr_status_message, /* eio_status_message */
100 falconsiena_intr_fatal, /* eio_fatal */
101 falconsiena_intr_fini, /* eio_fini */
102};
103#endif /* EFSYS_OPT_SIENA */
104
105#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
106static efx_intr_ops_t __efx_intr_ef10_ops = {
107 ef10_intr_init, /* eio_init */
108 ef10_intr_enable, /* eio_enable */
109 ef10_intr_disable, /* eio_disable */
110 ef10_intr_disable_unlocked, /* eio_disable_unlocked */
111 ef10_intr_trigger, /* eio_trigger */
112 ef10_intr_status_line, /* eio_status_line */
113 ef10_intr_status_message, /* eio_status_message */
114 ef10_intr_fatal, /* eio_fatal */
115 ef10_intr_fini, /* eio_fini */
116};
117#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
118
119 __checkReturn efx_rc_t
120efx_intr_init(
121 __in efx_nic_t *enp,
122 __in efx_intr_type_t type,
123 __in efsys_mem_t *esmp)
124{
125 efx_intr_t *eip = &(enp->en_intr);
126 efx_intr_ops_t *eiop;
127 efx_rc_t rc;
128
129 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
130 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
131
132 if (enp->en_mod_flags & EFX_MOD_INTR) {
133 rc = EINVAL;
134 goto fail1;
135 }
136
137 eip->ei_esmp = esmp;
138 eip->ei_type = type;
139 eip->ei_level = 0;
140
141 enp->en_mod_flags |= EFX_MOD_INTR;
142
143 switch (enp->en_family) {
144#if EFSYS_OPT_SIENA
145 case EFX_FAMILY_SIENA:
146 eiop = (efx_intr_ops_t *)&__efx_intr_siena_ops;
147 break;
148#endif /* EFSYS_OPT_SIENA */
149
150#if EFSYS_OPT_HUNTINGTON
151 case EFX_FAMILY_HUNTINGTON:
152 eiop = (efx_intr_ops_t *)&__efx_intr_ef10_ops;
153 break;
154#endif /* EFSYS_OPT_HUNTINGTON */
155
156#if EFSYS_OPT_MEDFORD
157 case EFX_FAMILY_MEDFORD:
158 eiop = (efx_intr_ops_t *)&__efx_intr_ef10_ops;
159 break;
160#endif /* EFSYS_OPT_MEDFORD */
161
162 default:
163 EFSYS_ASSERT(B_FALSE);
164 rc = ENOTSUP;
165 goto fail2;
166 }
167
168 if ((rc = eiop->eio_init(enp, type, esmp)) != 0)
169 goto fail3;
170
171 eip->ei_eiop = eiop;
172
173 return (0);
174
175fail3:
176 EFSYS_PROBE(fail3);
177fail2:
178 EFSYS_PROBE(fail2);
179fail1:
180 EFSYS_PROBE1(fail1, efx_rc_t, rc);
181
182 return (rc);
183}
184
185 void
186efx_intr_fini(
187 __in efx_nic_t *enp)
188{
189 efx_intr_t *eip = &(enp->en_intr);
190 efx_intr_ops_t *eiop = eip->ei_eiop;
191
192 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
193 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
194 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
195
196 eiop->eio_fini(enp);
197
198 enp->en_mod_flags &= ~EFX_MOD_INTR;
199}
200
201 void
202efx_intr_enable(
203 __in efx_nic_t *enp)
204{
205 efx_intr_t *eip = &(enp->en_intr);
206 efx_intr_ops_t *eiop = eip->ei_eiop;
207
208 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
209 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
210
211 eiop->eio_enable(enp);
212}
213
214 void
215efx_intr_disable(
216 __in efx_nic_t *enp)
217{
218 efx_intr_t *eip = &(enp->en_intr);
219 efx_intr_ops_t *eiop = eip->ei_eiop;
220
221 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
222 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
223
224 eiop->eio_disable(enp);
225}
226
227 void
228efx_intr_disable_unlocked(
229 __in efx_nic_t *enp)
230{
231 efx_intr_t *eip = &(enp->en_intr);
232 efx_intr_ops_t *eiop = eip->ei_eiop;
233
234 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
235 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
236
237 eiop->eio_disable_unlocked(enp);
238}
239
240
241 __checkReturn efx_rc_t
242efx_intr_trigger(
243 __in efx_nic_t *enp,
244 __in unsigned int level)
245{
246 efx_intr_t *eip = &(enp->en_intr);
247 efx_intr_ops_t *eiop = eip->ei_eiop;
248
249 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
250 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
251
252 return (eiop->eio_trigger(enp, level));
253}
254
255 void
256efx_intr_status_line(
257 __in efx_nic_t *enp,
258 __out boolean_t *fatalp,
259 __out uint32_t *qmaskp)
260{
261 efx_intr_t *eip = &(enp->en_intr);
262 efx_intr_ops_t *eiop = eip->ei_eiop;
263
264 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
265 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
266
267 eiop->eio_status_line(enp, fatalp, qmaskp);
268}
269
270 void
271efx_intr_status_message(
272 __in efx_nic_t *enp,
273 __in unsigned int message,
274 __out boolean_t *fatalp)
275{
276 efx_intr_t *eip = &(enp->en_intr);
277 efx_intr_ops_t *eiop = eip->ei_eiop;
278
279 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
280 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
281
282 eiop->eio_status_message(enp, message, fatalp);
283}
284
285 void
286efx_intr_fatal(
287 __in efx_nic_t *enp)
288{
289 efx_intr_t *eip = &(enp->en_intr);
290 efx_intr_ops_t *eiop = eip->ei_eiop;
291
292 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
293 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
294
295 eiop->eio_fatal(enp);
296}
297
298
299/* ************************************************************************* */
300/* ************************************************************************* */
301/* ************************************************************************* */
302
303#if EFSYS_OPT_SIENA
304
305static __checkReturn efx_rc_t
306falconsiena_intr_init(
307 __in efx_nic_t *enp,
308 __in efx_intr_type_t type,
309 __in efsys_mem_t *esmp)
310{
311 efx_intr_t *eip = &(enp->en_intr);
312 efx_oword_t oword;
313
314 /*
315 * bug17213 workaround.
316 *
317 * Under legacy interrupts, don't share a level between fatal
318 * interrupts and event queue interrupts. Under MSI-X, they
319 * must share, or we won't get an interrupt.
320 */
321 if (enp->en_family == EFX_FAMILY_SIENA &&
322 eip->ei_type == EFX_INTR_LINE)
323 eip->ei_level = 0x1f;
324 else
325 eip->ei_level = 0;
326
327 /* Enable all the genuinely fatal interrupts */
328 EFX_SET_OWORD(oword);
329 EFX_SET_OWORD_FIELD(oword, FRF_AZ_ILL_ADR_INT_KER_EN, 0);
330 EFX_SET_OWORD_FIELD(oword, FRF_AZ_RBUF_OWN_INT_KER_EN, 0);
331 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TBUF_OWN_INT_KER_EN, 0);
332 if (enp->en_family >= EFX_FAMILY_SIENA)
333 EFX_SET_OWORD_FIELD(oword, FRF_CZ_SRAM_PERR_INT_P_KER_EN, 0);
334 EFX_BAR_WRITEO(enp, FR_AZ_FATAL_INTR_REG_KER, &oword);
335
336 /* Set up the interrupt address register */
337 EFX_POPULATE_OWORD_3(oword,
338 FRF_AZ_NORM_INT_VEC_DIS_KER, (type == EFX_INTR_MESSAGE) ? 1 : 0,
339 FRF_AZ_INT_ADR_KER_DW0, EFSYS_MEM_ADDR(esmp) & 0xffffffff,
340 FRF_AZ_INT_ADR_KER_DW1, EFSYS_MEM_ADDR(esmp) >> 32);
341 EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
342
343 return (0);
344}
345
346static void
347falconsiena_intr_enable(
348 __in efx_nic_t *enp)
349{
350 efx_intr_t *eip = &(enp->en_intr);
351 efx_oword_t oword;
352
353 EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
354
355 EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
356 EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 1);
357 EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
358}
359
360static void
361falconsiena_intr_disable(
362 __in efx_nic_t *enp)
363{
364 efx_oword_t oword;
365
366 EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
367 EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
368 EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
369
370 EFSYS_SPIN(10);
371}
372
373static void
374falconsiena_intr_disable_unlocked(
375 __in efx_nic_t *enp)
376{
377 efx_oword_t oword;
378
379 EFSYS_BAR_READO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
380 &oword, B_FALSE);
381 EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
382 EFSYS_BAR_WRITEO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
383 &oword, B_FALSE);
384}
385
386static __checkReturn efx_rc_t
387falconsiena_intr_trigger(
388 __in efx_nic_t *enp,
389 __in unsigned int level)
390{
391 efx_intr_t *eip = &(enp->en_intr);
392 efx_oword_t oword;
393 unsigned int count;
394 uint32_t sel;
395 efx_rc_t rc;
396
397 /* bug16757: No event queues can be initialized */
398 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
399
400 switch (enp->en_family) {
401 case EFX_FAMILY_FALCON:
402 if (level >= EFX_NINTR_FALCON) {
403 rc = EINVAL;
404 goto fail1;
405 }
406 break;
407
408 case EFX_FAMILY_SIENA:
409 if (level >= EFX_NINTR_SIENA) {
410 rc = EINVAL;
411 goto fail1;
412 }
413 break;
414
415 default:
416 EFSYS_ASSERT(B_FALSE);
417 break;
418 }
419
420 if (level > EFX_MASK32(FRF_AZ_KER_INT_LEVE_SEL))
421 return (ENOTSUP); /* avoid EFSYS_PROBE() */
422
423 sel = level;
424
425 /* Trigger a test interrupt */
426 EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
427 EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, sel);
428 EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER, 1);
429 EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
430
431 /*
432 * Wait up to 100ms for the interrupt to be raised before restoring
433 * KER_INT_LEVE_SEL. Ignore a failure to raise (the caller will
434 * observe this soon enough anyway), but always reset KER_INT_LEVE_SEL
435 */
436 count = 0;
437 do {
438 EFSYS_SPIN(100); /* 100us */
439
440 EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
441 } while (EFX_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER) && ++count < 1000);
442
443 EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
444 EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
445
446 return (0);
447
448fail1:
449 EFSYS_PROBE1(fail1, efx_rc_t, rc);
450
451 return (rc);
452}
453
454static __checkReturn boolean_t
455falconsiena_intr_check_fatal(
456 __in efx_nic_t *enp)
457{
458 efx_intr_t *eip = &(enp->en_intr);
459 efsys_mem_t *esmp = eip->ei_esmp;
460 efx_oword_t oword;
461
462 /* Read the syndrome */
463 EFSYS_MEM_READO(esmp, 0, &oword);
464
465 if (EFX_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT) != 0) {
466 EFSYS_PROBE(fatal);
467
468 /* Clear the fatal interrupt condition */
469 EFX_SET_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT, 0);
470 EFSYS_MEM_WRITEO(esmp, 0, &oword);
471
472 return (B_TRUE);
473 }
474
475 return (B_FALSE);
476}
477
478static void
479falconsiena_intr_status_line(
480 __in efx_nic_t *enp,
481 __out boolean_t *fatalp,
482 __out uint32_t *qmaskp)
483{
484 efx_intr_t *eip = &(enp->en_intr);
485 efx_dword_t dword;
486
487 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
488 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
489
490 /*
491 * Read the queue mask and implicitly acknowledge the
492 * interrupt.
493 */
494 EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE);
495 *qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
496
497 EFSYS_PROBE1(qmask, uint32_t, *qmaskp);
498
499 if (*qmaskp & (1U << eip->ei_level))
500 *fatalp = falconsiena_intr_check_fatal(enp);
501 else
502 *fatalp = B_FALSE;
503}
504
505static void
506falconsiena_intr_status_message(
507 __in efx_nic_t *enp,
508 __in unsigned int message,
509 __out boolean_t *fatalp)
510{
511 efx_intr_t *eip = &(enp->en_intr);
512
513 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
514 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
515
516 if (message == eip->ei_level)
517 *fatalp = falconsiena_intr_check_fatal(enp);
518 else
519 *fatalp = B_FALSE;
520}
521
522
523static void
524falconsiena_intr_fatal(
525 __in efx_nic_t *enp)
526{
527#if EFSYS_OPT_DECODE_INTR_FATAL
528 efx_oword_t fatal;
529 efx_oword_t mem_per;
530
531 EFX_BAR_READO(enp, FR_AZ_FATAL_INTR_REG_KER, &fatal);
532 EFX_ZERO_OWORD(mem_per);
533
534 if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0 ||
535 EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
536 EFX_BAR_READO(enp, FR_AZ_MEM_STAT_REG, &mem_per);
537
538 if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRAM_OOB_INT_KER) != 0)
539 EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_OOB, 0, 0);
540
541 if (EFX_OWORD_FIELD(fatal, FRF_AZ_BUFID_DC_OOB_INT_KER) != 0)
542 EFSYS_ERR(enp->en_esip, EFX_ERR_BUFID_DC_OOB, 0, 0);
543
544 if (EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
545 EFSYS_ERR(enp->en_esip, EFX_ERR_MEM_PERR,
546 EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
547 EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
548
549 if (EFX_OWORD_FIELD(fatal, FRF_AZ_RBUF_OWN_INT_KER) != 0)
550 EFSYS_ERR(enp->en_esip, EFX_ERR_RBUF_OWN, 0, 0);
551
552 if (EFX_OWORD_FIELD(fatal, FRF_AZ_TBUF_OWN_INT_KER) != 0)
553 EFSYS_ERR(enp->en_esip, EFX_ERR_TBUF_OWN, 0, 0);
554
555 if (EFX_OWORD_FIELD(fatal, FRF_AZ_RDESCQ_OWN_INT_KER) != 0)
556 EFSYS_ERR(enp->en_esip, EFX_ERR_RDESQ_OWN, 0, 0);
557
558 if (EFX_OWORD_FIELD(fatal, FRF_AZ_TDESCQ_OWN_INT_KER) != 0)
559 EFSYS_ERR(enp->en_esip, EFX_ERR_TDESQ_OWN, 0, 0);
560
561 if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVQ_OWN_INT_KER) != 0)
562 EFSYS_ERR(enp->en_esip, EFX_ERR_EVQ_OWN, 0, 0);
563
564 if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVF_OFLO_INT_KER) != 0)
565 EFSYS_ERR(enp->en_esip, EFX_ERR_EVFF_OFLO, 0, 0);
566
567 if (EFX_OWORD_FIELD(fatal, FRF_AZ_ILL_ADR_INT_KER) != 0)
568 EFSYS_ERR(enp->en_esip, EFX_ERR_ILL_ADDR, 0, 0);
569
570 if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0)
571 EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_PERR,
572 EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
573 EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
574#else
575 EFSYS_ASSERT(0);
576#endif
577}
578
579static void
580falconsiena_intr_fini(
581 __in efx_nic_t *enp)
582{
583 efx_oword_t oword;
584
585 /* Clear the interrupt address register */
586 EFX_ZERO_OWORD(oword);
587 EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
588}
589
590#endif /* EFSYS_OPT_SIENA */