aslrestype1i.c revision 250838
1/******************************************************************************
2 *
3 * Module Name: aslrestype1i - Small I/O-related resource descriptors
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2013, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions, and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    substantially similar to the "NO WARRANTY" disclaimer below
19 *    ("Disclaimer") and any redistribution must be conditioned upon
20 *    including a substantially similar Disclaimer requirement for further
21 *    binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 *    of any contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44
45#include <contrib/dev/acpica/compiler/aslcompiler.h>
46#include "aslcompiler.y.h"
47
48#define _COMPONENT          ACPI_COMPILER
49        ACPI_MODULE_NAME    ("aslrestype1i")
50
51/*
52 * This module contains the I/O-related small resource descriptors:
53 *
54 * DMA
55 * FixedDMA
56 * FixedIO
57 * IO
58 * IRQ
59 * IRQNoFlags
60 */
61
62/*******************************************************************************
63 *
64 * FUNCTION:    RsDoDmaDescriptor
65 *
66 * PARAMETERS:  Op                  - Parent resource descriptor parse node
67 *              CurrentByteOffset   - Offset into the resource template AML
68 *                                    buffer (to track references to the desc)
69 *
70 * RETURN:      Completed resource node
71 *
72 * DESCRIPTION: Construct a short "DMA" descriptor
73 *
74 ******************************************************************************/
75
76ASL_RESOURCE_NODE *
77RsDoDmaDescriptor (
78    ACPI_PARSE_OBJECT       *Op,
79    UINT32                  CurrentByteOffset)
80{
81    AML_RESOURCE            *Descriptor;
82    ACPI_PARSE_OBJECT       *InitializerOp;
83    ASL_RESOURCE_NODE       *Rnode;
84    UINT32                  i;
85    UINT8                   DmaChannelMask = 0;
86    UINT8                   DmaChannels = 0;
87
88
89    InitializerOp = Op->Asl.Child;
90    Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_DMA));
91
92    Descriptor = Rnode->Buffer;
93    Descriptor->Dma.DescriptorType  = ACPI_RESOURCE_NAME_DMA |
94                                        ASL_RDESC_DMA_SIZE;
95
96    /* Process all child initialization nodes */
97
98    for (i = 0; InitializerOp; i++)
99    {
100        switch (i)
101        {
102        case 0: /* DMA type */
103
104            RsSetFlagBits (&Descriptor->Dma.Flags, InitializerOp, 5, 0);
105            RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_DMATYPE,
106                CurrentByteOffset + ASL_RESDESC_OFFSET (Dma.Flags), 5, 2);
107            break;
108
109        case 1: /* Bus Master */
110
111            RsSetFlagBits (&Descriptor->Dma.Flags, InitializerOp, 2, 0);
112            RsCreateBitField (InitializerOp, ACPI_RESTAG_BUSMASTER,
113                CurrentByteOffset + ASL_RESDESC_OFFSET (Dma.Flags), 2);
114            break;
115
116        case 2: /* Xfer Type (transfer width) */
117
118            RsSetFlagBits (&Descriptor->Dma.Flags, InitializerOp, 0, 0);
119            RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_XFERTYPE,
120                CurrentByteOffset + ASL_RESDESC_OFFSET (Dma.Flags), 0, 2);
121            break;
122
123        case 3: /* Name */
124
125            UtAttachNamepathToOwner (Op, InitializerOp);
126            break;
127
128        default:
129
130            /* All DMA channel bytes are handled here, after flags and name */
131
132            if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)
133            {
134                /* Up to 8 channels can be specified in the list */
135
136                DmaChannels++;
137                if (DmaChannels > 8)
138                {
139                    AslError (ASL_ERROR, ASL_MSG_DMA_LIST,
140                        InitializerOp, NULL);
141                    return (Rnode);
142                }
143
144                /* Only DMA channels 0-7 are allowed (mask is 8 bits) */
145
146                if (InitializerOp->Asl.Value.Integer > 7)
147                {
148                    AslError (ASL_ERROR, ASL_MSG_DMA_CHANNEL,
149                        InitializerOp, NULL);
150                }
151
152                /* Build the mask */
153
154                DmaChannelMask |=
155                    (1 << ((UINT8) InitializerOp->Asl.Value.Integer));
156            }
157
158            if (i == 4) /* case 4: First DMA byte */
159            {
160                /* Check now for duplicates in list */
161
162                RsCheckListForDuplicates (InitializerOp);
163
164                /* Create a named field at the start of the list */
165
166                RsCreateByteField (InitializerOp, ACPI_RESTAG_DMA,
167                    CurrentByteOffset +
168                    ASL_RESDESC_OFFSET (Dma.DmaChannelMask));
169            }
170            break;
171        }
172
173        InitializerOp = RsCompleteNodeAndGetNext (InitializerOp);
174    }
175
176    /* Now we can set the channel mask */
177
178    Descriptor->Dma.DmaChannelMask = DmaChannelMask;
179    return (Rnode);
180}
181
182
183/*******************************************************************************
184 *
185 * FUNCTION:    RsDoFixedDmaDescriptor
186 *
187 * PARAMETERS:  Op                  - Parent resource descriptor parse node
188 *              CurrentByteOffset   - Offset into the resource template AML
189 *                                    buffer (to track references to the desc)
190 *
191 * RETURN:      Completed resource node
192 *
193 * DESCRIPTION: Construct a short "FixedDMA" descriptor
194 *
195 ******************************************************************************/
196
197ASL_RESOURCE_NODE *
198RsDoFixedDmaDescriptor (
199    ACPI_PARSE_OBJECT       *Op,
200    UINT32                  CurrentByteOffset)
201{
202    AML_RESOURCE            *Descriptor;
203    ACPI_PARSE_OBJECT       *InitializerOp;
204    ASL_RESOURCE_NODE       *Rnode;
205    UINT32                  i;
206
207
208    InitializerOp = Op->Asl.Child;
209    Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_FIXED_DMA));
210
211    Descriptor = Rnode->Buffer;
212    Descriptor->FixedDma.DescriptorType =
213        ACPI_RESOURCE_NAME_FIXED_DMA | ASL_RDESC_FIXED_DMA_SIZE;
214
215    /* Process all child initialization nodes */
216
217    for (i = 0; InitializerOp; i++)
218    {
219        switch (i)
220        {
221        case 0: /* DMA Request Lines [WORD] (_DMA) */
222
223            Descriptor->FixedDma.RequestLines = (UINT16) InitializerOp->Asl.Value.Integer;
224            RsCreateWordField (InitializerOp, ACPI_RESTAG_DMA,
225                CurrentByteOffset + ASL_RESDESC_OFFSET (FixedDma.RequestLines));
226            break;
227
228        case 1: /* DMA Channel [WORD] (_TYP) */
229
230            Descriptor->FixedDma.Channels = (UINT16) InitializerOp->Asl.Value.Integer;
231            RsCreateWordField (InitializerOp, ACPI_RESTAG_DMATYPE,
232                CurrentByteOffset + ASL_RESDESC_OFFSET (FixedDma.Channels));
233            break;
234
235        case 2: /* Transfer Width [BYTE] (_SIZ) */
236
237            Descriptor->FixedDma.Width = (UINT8) InitializerOp->Asl.Value.Integer;
238            RsCreateByteField (InitializerOp, ACPI_RESTAG_XFERTYPE,
239                CurrentByteOffset + ASL_RESDESC_OFFSET (FixedDma.Width));
240            break;
241
242        case 3: /* Descriptor Name (optional) */
243
244            UtAttachNamepathToOwner (Op, InitializerOp);
245            break;
246
247        default:    /* Ignore any extra nodes */
248
249            break;
250        }
251
252        InitializerOp = RsCompleteNodeAndGetNext (InitializerOp);
253    }
254
255    return (Rnode);
256}
257
258
259/*******************************************************************************
260 *
261 * FUNCTION:    RsDoFixedIoDescriptor
262 *
263 * PARAMETERS:  Op                  - Parent resource descriptor parse node
264 *              CurrentByteOffset   - Offset into the resource template AML
265 *                                    buffer (to track references to the desc)
266 *
267 * RETURN:      Completed resource node
268 *
269 * DESCRIPTION: Construct a short "FixedIO" descriptor
270 *
271 ******************************************************************************/
272
273ASL_RESOURCE_NODE *
274RsDoFixedIoDescriptor (
275    ACPI_PARSE_OBJECT       *Op,
276    UINT32                  CurrentByteOffset)
277{
278    AML_RESOURCE            *Descriptor;
279    ACPI_PARSE_OBJECT       *InitializerOp;
280    ACPI_PARSE_OBJECT       *AddressOp = NULL;
281    ASL_RESOURCE_NODE       *Rnode;
282    UINT32                  i;
283
284
285    InitializerOp = Op->Asl.Child;
286    Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_FIXED_IO));
287
288    Descriptor = Rnode->Buffer;
289    Descriptor->Io.DescriptorType  = ACPI_RESOURCE_NAME_FIXED_IO |
290                                      ASL_RDESC_FIXED_IO_SIZE;
291
292    /* Process all child initialization nodes */
293
294    for (i = 0; InitializerOp; i++)
295    {
296        switch (i)
297        {
298        case 0: /* Base Address */
299
300            Descriptor->FixedIo.Address =
301                (UINT16) InitializerOp->Asl.Value.Integer;
302            RsCreateWordField (InitializerOp, ACPI_RESTAG_BASEADDRESS,
303                CurrentByteOffset + ASL_RESDESC_OFFSET (FixedIo.Address));
304            AddressOp = InitializerOp;
305            break;
306
307        case 1: /* Length */
308
309            Descriptor->FixedIo.AddressLength =
310                (UINT8) InitializerOp->Asl.Value.Integer;
311            RsCreateByteField (InitializerOp, ACPI_RESTAG_LENGTH,
312                CurrentByteOffset + ASL_RESDESC_OFFSET (FixedIo.AddressLength));
313            break;
314
315        case 2: /* Name */
316
317            UtAttachNamepathToOwner (Op, InitializerOp);
318            break;
319
320        default:
321
322            AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL);
323            break;
324        }
325
326        InitializerOp = RsCompleteNodeAndGetNext (InitializerOp);
327    }
328
329    /* Error checks */
330
331    if (Descriptor->FixedIo.Address > 0x03FF)
332    {
333        AslError (ASL_WARNING, ASL_MSG_ISA_ADDRESS, AddressOp, NULL);
334    }
335
336    return (Rnode);
337}
338
339
340/*******************************************************************************
341 *
342 * FUNCTION:    RsDoIoDescriptor
343 *
344 * PARAMETERS:  Op                  - Parent resource descriptor parse node
345 *              CurrentByteOffset   - Offset into the resource template AML
346 *                                    buffer (to track references to the desc)
347 *
348 * RETURN:      Completed resource node
349 *
350 * DESCRIPTION: Construct a short "IO" descriptor
351 *
352 ******************************************************************************/
353
354ASL_RESOURCE_NODE *
355RsDoIoDescriptor (
356    ACPI_PARSE_OBJECT       *Op,
357    UINT32                  CurrentByteOffset)
358{
359    AML_RESOURCE            *Descriptor;
360    ACPI_PARSE_OBJECT       *InitializerOp;
361    ACPI_PARSE_OBJECT       *MinOp = NULL;
362    ACPI_PARSE_OBJECT       *MaxOp = NULL;
363    ACPI_PARSE_OBJECT       *LengthOp = NULL;
364    ACPI_PARSE_OBJECT       *AlignOp = NULL;
365    ASL_RESOURCE_NODE       *Rnode;
366    UINT32                  i;
367
368
369    InitializerOp = Op->Asl.Child;
370    Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_IO));
371
372    Descriptor = Rnode->Buffer;
373    Descriptor->Io.DescriptorType  = ACPI_RESOURCE_NAME_IO |
374                                      ASL_RDESC_IO_SIZE;
375
376    /* Process all child initialization nodes */
377
378    for (i = 0; InitializerOp; i++)
379    {
380        switch (i)
381        {
382        case 0: /* Decode size */
383
384            RsSetFlagBits (&Descriptor->Io.Flags, InitializerOp, 0, 1);
385            RsCreateBitField (InitializerOp, ACPI_RESTAG_DECODE,
386                CurrentByteOffset + ASL_RESDESC_OFFSET (Io.Flags), 0);
387            break;
388
389        case 1:  /* Min Address */
390
391            Descriptor->Io.Minimum =
392                (UINT16) InitializerOp->Asl.Value.Integer;
393            RsCreateWordField (InitializerOp, ACPI_RESTAG_MINADDR,
394                CurrentByteOffset + ASL_RESDESC_OFFSET (Io.Minimum));
395            MinOp = InitializerOp;
396            break;
397
398        case 2: /* Max Address */
399
400            Descriptor->Io.Maximum =
401                (UINT16) InitializerOp->Asl.Value.Integer;
402            RsCreateWordField (InitializerOp, ACPI_RESTAG_MAXADDR,
403                CurrentByteOffset + ASL_RESDESC_OFFSET (Io.Maximum));
404            MaxOp = InitializerOp;
405            break;
406
407        case 3: /* Alignment */
408
409            Descriptor->Io.Alignment =
410                (UINT8) InitializerOp->Asl.Value.Integer;
411            RsCreateByteField (InitializerOp, ACPI_RESTAG_ALIGNMENT,
412                CurrentByteOffset + ASL_RESDESC_OFFSET (Io.Alignment));
413            AlignOp = InitializerOp;
414            break;
415
416        case 4: /* Length */
417
418            Descriptor->Io.AddressLength =
419                (UINT8) InitializerOp->Asl.Value.Integer;
420            RsCreateByteField (InitializerOp, ACPI_RESTAG_LENGTH,
421                CurrentByteOffset + ASL_RESDESC_OFFSET (Io.AddressLength));
422            LengthOp = InitializerOp;
423            break;
424
425        case 5: /* Name */
426
427            UtAttachNamepathToOwner (Op, InitializerOp);
428            break;
429
430        default:
431
432            AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL);
433            break;
434        }
435
436        InitializerOp = RsCompleteNodeAndGetNext (InitializerOp);
437    }
438
439    /* Validate the Min/Max/Len/Align values */
440
441    RsSmallAddressCheck (ACPI_RESOURCE_NAME_IO,
442        Descriptor->Io.Minimum,
443        Descriptor->Io.Maximum,
444        Descriptor->Io.AddressLength,
445        Descriptor->Io.Alignment,
446        MinOp, MaxOp, LengthOp, AlignOp, Op);
447
448    return (Rnode);
449}
450
451
452/*******************************************************************************
453 *
454 * FUNCTION:    RsDoIrqDescriptor
455 *
456 * PARAMETERS:  Op                  - Parent resource descriptor parse node
457 *              CurrentByteOffset   - Offset into the resource template AML
458 *                                    buffer (to track references to the desc)
459 *
460 * RETURN:      Completed resource node
461 *
462 * DESCRIPTION: Construct a short "IRQ" descriptor
463 *
464 ******************************************************************************/
465
466ASL_RESOURCE_NODE *
467RsDoIrqDescriptor (
468    ACPI_PARSE_OBJECT       *Op,
469    UINT32                  CurrentByteOffset)
470{
471    AML_RESOURCE            *Descriptor;
472    ACPI_PARSE_OBJECT       *InitializerOp;
473    ASL_RESOURCE_NODE       *Rnode;
474    UINT32                  Interrupts = 0;
475    UINT16                  IrqMask = 0;
476    UINT32                  i;
477
478
479    InitializerOp = Op->Asl.Child;
480    Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_IRQ));
481
482    /* Length = 3 (with flag byte) */
483
484    Descriptor = Rnode->Buffer;
485    Descriptor->Irq.DescriptorType  = ACPI_RESOURCE_NAME_IRQ |
486                                      (ASL_RDESC_IRQ_SIZE + 0x01);
487
488    /* Process all child initialization nodes */
489
490    for (i = 0; InitializerOp; i++)
491    {
492        switch (i)
493        {
494        case 0: /* Interrupt Type (or Mode - edge/level) */
495
496            RsSetFlagBits (&Descriptor->Irq.Flags, InitializerOp, 0, 1);
497            RsCreateBitField (InitializerOp, ACPI_RESTAG_INTERRUPTTYPE,
498                CurrentByteOffset + ASL_RESDESC_OFFSET (Irq.Flags), 0);
499            break;
500
501        case 1: /* Interrupt Level (or Polarity - Active high/low) */
502
503            RsSetFlagBits (&Descriptor->Irq.Flags, InitializerOp, 3, 0);
504            RsCreateBitField (InitializerOp, ACPI_RESTAG_INTERRUPTLEVEL,
505                CurrentByteOffset + ASL_RESDESC_OFFSET (Irq.Flags), 3);
506            break;
507
508        case 2: /* Share Type - Default: exclusive (0) */
509
510            RsSetFlagBits (&Descriptor->Irq.Flags, InitializerOp, 4, 0);
511            RsCreateBitField (InitializerOp, ACPI_RESTAG_INTERRUPTSHARE,
512                CurrentByteOffset + ASL_RESDESC_OFFSET (Irq.Flags), 4);
513            break;
514
515        case 3: /* Name */
516
517            UtAttachNamepathToOwner (Op, InitializerOp);
518            break;
519
520        default:
521
522            /* All IRQ bytes are handled here, after the flags and name */
523
524            if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)
525            {
526                /* Up to 16 interrupts can be specified in the list */
527
528                Interrupts++;
529                if (Interrupts > 16)
530                {
531                    AslError (ASL_ERROR, ASL_MSG_INTERRUPT_LIST,
532                        InitializerOp, NULL);
533                    return (Rnode);
534                }
535
536                /* Only interrupts 0-15 are allowed (mask is 16 bits) */
537
538                if (InitializerOp->Asl.Value.Integer > 15)
539                {
540                    AslError (ASL_ERROR, ASL_MSG_INTERRUPT_NUMBER,
541                        InitializerOp, NULL);
542                }
543                else
544                {
545                    IrqMask |= (1 << (UINT8) InitializerOp->Asl.Value.Integer);
546                }
547            }
548
549            /* Case 4: First IRQ value in list */
550
551            if (i == 4)
552            {
553                /* Check now for duplicates in list */
554
555                RsCheckListForDuplicates (InitializerOp);
556
557                /* Create a named field at the start of the list */
558
559                RsCreateWordField (InitializerOp, ACPI_RESTAG_INTERRUPT,
560                    CurrentByteOffset + ASL_RESDESC_OFFSET (Irq.IrqMask));
561            }
562            break;
563        }
564
565        InitializerOp = RsCompleteNodeAndGetNext (InitializerOp);
566    }
567
568    /* Now we can set the channel mask */
569
570    Descriptor->Irq.IrqMask = IrqMask;
571    return (Rnode);
572}
573
574
575/*******************************************************************************
576 *
577 * FUNCTION:    RsDoIrqNoFlagsDescriptor
578 *
579 * PARAMETERS:  Op                  - Parent resource descriptor parse node
580 *              CurrentByteOffset   - Offset into the resource template AML
581 *                                    buffer (to track references to the desc)
582 *
583 * RETURN:      Completed resource node
584 *
585 * DESCRIPTION: Construct a short "IRQNoFlags" descriptor
586 *
587 ******************************************************************************/
588
589ASL_RESOURCE_NODE *
590RsDoIrqNoFlagsDescriptor (
591    ACPI_PARSE_OBJECT       *Op,
592    UINT32                  CurrentByteOffset)
593{
594    AML_RESOURCE            *Descriptor;
595    ACPI_PARSE_OBJECT       *InitializerOp;
596    ASL_RESOURCE_NODE       *Rnode;
597    UINT16                  IrqMask = 0;
598    UINT32                  Interrupts = 0;
599    UINT32                  i;
600
601
602    InitializerOp = Op->Asl.Child;
603    Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_IRQ_NOFLAGS));
604
605    Descriptor = Rnode->Buffer;
606    Descriptor->Irq.DescriptorType  = ACPI_RESOURCE_NAME_IRQ |
607                                      ASL_RDESC_IRQ_SIZE;
608
609    /* Process all child initialization nodes */
610
611    for (i = 0; InitializerOp; i++)
612    {
613        switch (i)
614        {
615        case 0: /* Name */
616
617            UtAttachNamepathToOwner (Op, InitializerOp);
618            break;
619
620        default:
621
622            /* IRQ bytes are handled here, after the flags and name */
623
624            if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)
625            {
626                /* Up to 16 interrupts can be specified in the list */
627
628                Interrupts++;
629                if (Interrupts > 16)
630                {
631                    AslError (ASL_ERROR, ASL_MSG_INTERRUPT_LIST,
632                        InitializerOp, NULL);
633                    return (Rnode);
634                }
635
636                /* Only interrupts 0-15 are allowed (mask is 16 bits) */
637
638                if (InitializerOp->Asl.Value.Integer > 15)
639                {
640                    AslError (ASL_ERROR, ASL_MSG_INTERRUPT_NUMBER,
641                        InitializerOp, NULL);
642                }
643                else
644                {
645                    IrqMask |= (1 << ((UINT8) InitializerOp->Asl.Value.Integer));
646                }
647            }
648
649            /* Case 1: First IRQ value in list */
650
651            if (i == 1)
652            {
653                /* Check now for duplicates in list */
654
655                RsCheckListForDuplicates (InitializerOp);
656
657                /* Create a named field at the start of the list */
658
659                RsCreateWordField (InitializerOp, ACPI_RESTAG_INTERRUPT,
660                    CurrentByteOffset + ASL_RESDESC_OFFSET (Irq.IrqMask));
661            }
662            break;
663        }
664
665        InitializerOp = RsCompleteNodeAndGetNext (InitializerOp);
666    }
667
668    /* Now we can set the interrupt mask */
669
670    Descriptor->Irq.IrqMask = IrqMask;
671    return (Rnode);
672}
673