← Documents Documentation/networking/device_drivers/ethernet/freescale/dpaa2/mac-phy-support.rst GitHub 원문 ↗

Linux 6.18.37 · Networking

DPAA2 MAC / PHY support

DPNI·DPMAC 연결에서 phylink와 MC firmware가 링크 상태를 나누어 관리하는 방식, DPNI-DPMAC 및 DPNI-DPNI 활성화 순서와 공개 API를 설명합니다.

Source pathDocumentation/networking/device_drivers/ethernet/freescale/dpaa2/mac-phy-support.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

mac-phy-support.rst:1-194

이 계층은 MC 객체 모델과 Linux PHYLINK 사이의 번역기 역할을 합니다. DPNI-DPMAC 연결에서는 phylink가 외부 PHY와 MAC callback을 관리하고, 고정 링크에서는 MC firmware가 PCS를 직접 polling합니다. DPNI끼리 연결될 때는 firmware IRQ를 통해 양쪽 carrier 상태를 맞춥니다.

객체와 소프트웨어 역할
요소역할
DPNI네트워크 인터페이스 추상화
DPMACMAC 추상화
dpaa2-eth·dpaa2-ethswnet_device와 endpoint 구동
phylinkPHY 연결과 MAC callback 조정
MC firmware객체 연결·고정 링크·IRQ 관리

링크 구성에 참여하는 객체와 계층입니다.

두 데이터 연결 유형
net_deviceDPNIDPMACPHY
net_deviceDPNIinternal linkDPNInet_device

DPNI는 외부 PHY 또는 다른 DPNI와 연결될 수 있습니다.

링크 상태 정보 경로
External MDIO·PHYphylinkdpaa2-ethnet_device
Internal MDIO·PCSMC firmware pollingDPMACDPNIdpaa2-eth

원문의 첫 번째 ASCII 도식을 외부 PHY와 내부 PCS 경로로 분리했습니다.

DPMAC 링크 모드
모드관리자phylink
DPMAC_LINK_TYPE_FIXEDMC firmware가 PCS polling불필요
DPMAC_LINK_TYPE_PHYdpaa2-mac과 net_device driver필요
TYPE_BACKPLANEphylink 경로, firmware는 PCS register 미접근필요

링크 상태를 누가 관리하는지가 가장 큰 차이입니다.

DPMAC 연결 준비
DPNI endpoint가 DPMAC인지 확인`phy-handle` 검색PHYLINK instance 생성`phylink_of_phy_connect()`PHY 연결

`dpaa2_mac_connect()`가 수행하는 세 단계입니다.

phylink MAC callback
callback동작
`.validate()``RGMII_*` capability 검증
`.mac_config()``dpmac_set_link_state()`로 새 구성 적용
`.mac_link_up/down()``dpmac_set_link_state()`로 링크 갱신

현재 지원 링크 형식과 firmware 호출을 정리했습니다.

연결 해제
DPNI-DPMAC 분리`dpaa2_mac_disconnect()`PHY 연결 해제PHYLINK instance 파괴

unbind 또는 endpoint 분리 때 PHYLINK 자원을 역순으로 정리합니다.

DPNI-DPMAC 활성화
`ip link set dev eth0 up``phylink_start()`MAC callback`dpmac_set_link_state()`HW MAC 구성`netif_carrier_on()`
`LINK_STATE_CHANGE` IRQdpaa2-ethpause 설정 반영Rx taildrop 조정

원문의 두 번째 ASCII 도식에 있는 1~6번 순서입니다.

DPNI-DPNI 활성화
eth0 upDPNI 0 enableinternal link
eth1 upDPNI 1 enableinternal link
link up양쪽 `LINK_STATE_CHANGED` IRQ양쪽 `netif_carrier_on()`

원문의 세 번째 ASCII 도식처럼 두 인터페이스가 대칭으로 활성화됩니다.

공개 API
API역할
`dpaa2_mac_connect()`DPMAC·PHYLINK 연결
`dpaa2_mac_disconnect()`PHY 연결과 instance 해제
`dpaa2_mac_is_type_phy()`phylink 필요 유형 판정

endpoint 변경 IRQ 처리에서 사용하는 연결 API입니다.

phylink 필요 조건
유형phylinkPCS 접근
TYPE_FIXED불필요MC firmware
TYPE_PHY필요PHY 경로
TYPE_BACKPLANE필요MC firmware는 접근하지 않음

partner DPMAC 유형에 따른 통합 여부입니다.

연결 전 dpaa2_mac 준비
필드내용
net_device연관 Linux 네트워크 장치
MC portal pointerfirmware API 호출에 사용할 portal
fsl_mc_deviceDPMAC의 실제 MC 장치 객체

호출자가 구조체에 채워야 하는 필드입니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2 .. include:: <isonum.txt>
3
4 =======================
5 DPAA2 MAC / PHY support
6 =======================
7
8 :Copyright: |copy| 2019 NXP
9
10 Overview
11 --------
12
13 The DPAA2 MAC / PHY support consists of a set of APIs that help DPAA2 network
14 drivers (dpaa2-eth, dpaa2-ethsw) interact with the PHY library.
15
16 DPAA2 Software Architecture
17 ---------------------------
18
19 Among other DPAA2 objects, the fsl-mc bus exports DPNI objects (abstracting a
20 network interface) and DPMAC objects (abstracting a MAC). The dpaa2-eth driver
21 probes on the DPNI object and connects to and configures a DPMAC object with
22 the help of phylink.
23
24 Data connections may be established between a DPNI and a DPMAC, or between two
25 DPNIs. Depending on the connection type, the netif_carrier_[on/off] is handled
26 directly by the dpaa2-eth driver or by phylink.
27
28 .. code-block:: none
29
30 Sources of abstracted link state information presented by the MC firmware
31
32 +--------------------------------------+
33 +------------+ +---------+ | xgmac_mdio |
34 | net_device | | phylink |--| +-----+ +-----+ +-----+ +-----+ |
35 +------------+ +---------+ | | PHY | | PHY | | PHY | | PHY | |
36 | | | +-----+ +-----+ +-----+ +-----+ |
37 +------------------------------------+ | External MDIO bus |
38 | dpaa2-eth | +--------------------------------------+
39 +------------------------------------+
40 | | Linux
41 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42 | | MC firmware
43 | /| V
44 +----------+ / | +----------+
45 | | / | | |
46 | | | | | |
47 | DPNI |<------| |<------| DPMAC |
48 | | | | | |
49 | | \ |<---+ | |
50 +----------+ \ | | +----------+
51 \| |
52 |
53 +--------------------------------------+
54 | MC firmware polling MAC PCS for link |
55 | +-----+ +-----+ +-----+ +-----+ |
56 | | PCS | | PCS | | PCS | | PCS | |
57 | +-----+ +-----+ +-----+ +-----+ |
58 | Internal MDIO bus |
59 +--------------------------------------+
60
61
62 Depending on an MC firmware configuration setting, each MAC may be in one of two modes:
63
64 - DPMAC_LINK_TYPE_FIXED: the link state management is handled exclusively by
65 the MC firmware by polling the MAC PCS. Without the need to register a
66 phylink instance, the dpaa2-eth driver will not bind to the connected dpmac
67 object at all.
68
69 - DPMAC_LINK_TYPE_PHY: The MC firmware is left waiting for link state update
70 events, but those are in fact passed strictly between the dpaa2-mac (based on
71 phylink) and its attached net_device driver (dpaa2-eth, dpaa2-ethsw),
72 effectively bypassing the firmware.
73
74 Implementation
75 --------------
76
77 At probe time or when a DPNI's endpoint is dynamically changed, the dpaa2-eth
78 is responsible to find out if the peer object is a DPMAC and if this is the
79 case, to integrate it with PHYLINK using the dpaa2_mac_connect() API, which
80 will do the following:
81
82 - look up the device tree for PHYLINK-compatible of binding (phy-handle)
83 - will create a PHYLINK instance associated with the received net_device
84 - connect to the PHY using phylink_of_phy_connect()
85
86 The following phylink_mac_ops callback are implemented:
87
88 - .validate() will populate the supported linkmodes with the MAC capabilities
89 only when the phy_interface_t is RGMII_* (at the moment, this is the only
90 link type supported by the driver).
91
92 - .mac_config() will configure the MAC in the new configuration using the
93 dpmac_set_link_state() MC firmware API.
94
95 - .mac_link_up() / .mac_link_down() will update the MAC link using the same
96 API described above.
97
98 At driver unbind() or when the DPNI object is disconnected from the DPMAC, the
99 dpaa2-eth driver calls dpaa2_mac_disconnect() which will, in turn, disconnect
100 from the PHY and destroy the PHYLINK instance.
101
102 In case of a DPNI-DPMAC connection, an 'ip link set dev eth0 up' would start
103 the following sequence of operations:
104
105 (1) phylink_start() called from .dev_open().
106 (2) The .mac_config() and .mac_link_up() callbacks are called by PHYLINK.
107 (3) In order to configure the HW MAC, the MC Firmware API
108 dpmac_set_link_state() is called.
109 (4) The firmware will eventually setup the HW MAC in the new configuration.
110 (5) A netif_carrier_on() call is made directly from PHYLINK on the associated
111 net_device.
112 (6) The dpaa2-eth driver handles the LINK_STATE_CHANGE irq in order to
113 enable/disable Rx taildrop based on the pause frame settings.
114
115 .. code-block:: none
116
117 +---------+ +---------+
118 | PHYLINK |-------------->| eth0 |
119 +---------+ (5) +---------+
120 (1) ^ |
121 | |
122 | v (2)
123 +-----------------------------------+
124 | dpaa2-eth |
125 +-----------------------------------+
126 | ^ (6)
127 | |
128 v (3) |
129 +---------+---------------+---------+
130 | DPMAC | | DPNI |
131 +---------+ +---------+
132 | MC Firmware |
133 +-----------------------------------+
134 |
135 |
136 v (4)
137 +-----------------------------------+
138 | HW MAC |
139 +-----------------------------------+
140
141 In case of a DPNI-DPNI connection, a usual sequence of operations looks like
142 the following:
143
144 (1) ip link set dev eth0 up
145 (2) The dpni_enable() MC API called on the associated fsl_mc_device.
146 (3) ip link set dev eth1 up
147 (4) The dpni_enable() MC API called on the associated fsl_mc_device.
148 (5) The LINK_STATE_CHANGED irq is received by both instances of the dpaa2-eth
149 driver because now the operational link state is up.
150 (6) The netif_carrier_on() is called on the exported net_device from
151 link_state_update().
152
153 .. code-block:: none
154
155 +---------+ +---------+
156 | eth0 | | eth1 |
157 +---------+ +---------+
158 | ^ ^ |
159 | | | |
160 (1) v | (6) (6) | v (3)
161 +---------+ +---------+
162 |dpaa2-eth| |dpaa2-eth|
163 +---------+ +---------+
164 | ^ ^ |
165 | | | |
166 (2) v | (5) (5) | v (4)
167 +---------+---------------+---------+
168 | DPNI | | DPNI |
169 +---------+ +---------+
170 | MC Firmware |
171 +-----------------------------------+
172
173
174 Exported API
175 ------------
176
177 Any DPAA2 driver that drivers endpoints of DPMAC objects should service its
178 _EVENT_ENDPOINT_CHANGED irq and connect/disconnect from the associated DPMAC
179 when necessary using the below listed API::
180
181 - int dpaa2_mac_connect(struct dpaa2_mac *mac);
182 - void dpaa2_mac_disconnect(struct dpaa2_mac *mac);
183
184 A phylink integration is necessary only when the partner DPMAC is not of
185 ``TYPE_FIXED``. This means it is either of ``TYPE_PHY``, or of
186 ``TYPE_BACKPLANE`` (the difference being the two that in the ``TYPE_BACKPLANE``
187 mode, the MC firmware does not access the PCS registers). One can check for
188 this condition using the following helper::
189
190 - static inline bool dpaa2_mac_is_type_phy(struct dpaa2_mac *mac);
191
192 Before connection to a MAC, the caller must allocate and populate the
193 dpaa2_mac structure with the associated net_device, a pointer to the MC portal
194 to be used and the actual fsl_mc_device structure of the DPMAC.
195

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

개요와 DPAA2 소프트웨어 아키텍처

1-26

이 문서는 `GPL-2.0` 라이선스를 따르며 저작권은 © 2019 NXP에 있습니다.

DPAA2 MAC/PHY 지원

개요

DPAA2 MAC/PHY 지원은 `dpaa2-eth`, `dpaa2-ethsw` 같은 DPAA2 네트워크 드라이버가 PHY library와 상호 작용하도록 돕는 API 집합입니다.

DPAA2 소프트웨어 아키텍처

`fsl-mc` bus는 여러 DPAA2 객체 중 네트워크 인터페이스를 추상화한 DPNI 객체와 MAC을 추상화한 DPMAC 객체를 노출합니다.

`dpaa2-eth` 드라이버는 DPNI 객체를 probe하고 `phylink`의 도움으로 DPMAC 객체에 연결해 이를 구성합니다.

데이터 연결은 DPNI와 DPMAC 사이 또는 두 DPNI 사이에 만들 수 있습니다. 연결 유형에 따라 `netif_carrier_on()`과 `netif_carrier_off()` 처리는 `dpaa2-eth` 드라이버가 직접 수행하거나 `phylink`가 담당합니다.

.. SPDX-License-Identifier: GPL-2.0
.. include:: <isonum.txt>

=======================
DPAA2 MAC / PHY support
=======================

:Copyright: |copy| 2019 NXP

Overview
--------

The DPAA2 MAC / PHY support consists of a set of APIs that help DPAA2 network
drivers (dpaa2-eth, dpaa2-ethsw) interact with the PHY library.

DPAA2 Software Architecture
---------------------------

Among other DPAA2 objects, the fsl-mc bus exports DPNI objects (abstracting a
network interface) and DPMAC objects (abstracting a MAC). The dpaa2-eth driver
probes on the DPNI object and connects to and configures a DPMAC object with
the help of phylink.

Data connections may be established between a DPNI and a DPMAC, or between two
DPNIs. Depending on the connection type, the netif_carrier_[on/off] is handled
directly by the dpaa2-eth driver or by phylink.

연결 구현, phylink callback과 해제

74-100

구현

probe 시점이나 DPNI endpoint가 동적으로 바뀔 때 `dpaa2-eth`는 peer 객체가 DPMAC인지 확인해야 합니다.

peer가 DPMAC이면 `dpaa2_mac_connect()` API로 이를 PHYLINK와 통합합니다. 이 API는 다음 작업을 수행합니다.

  • device tree에서 PHYLINK 호환 `of` binding인 `phy-handle` 검색
  • 전달받은 `net_device`와 연결된 PHYLINK instance 생성
  • `phylink_of_phy_connect()`로 PHY에 연결

다음 `phylink_mac_ops` callback이 구현되어 있습니다.

callback동작
`.validate()``phy_interface_t`가 `RGMII_*`일 때만 MAC capability로 지원 link mode를 채웁니다. 현재 드라이버가 지원하는 링크 유형은 이것뿐입니다.
`.mac_config()``dpmac_set_link_state()` MC firmware API로 MAC을 새 구성에 맞춥니다.
`.mac_link_up()` / `.mac_link_down()`같은 `dpmac_set_link_state()` API로 MAC 링크 상태를 갱신합니다.

드라이버 `unbind()` 시점이나 DPNI 객체가 DPMAC에서 분리될 때 `dpaa2-eth`는 `dpaa2_mac_disconnect()`를 호출합니다. 이 함수는 PHY 연결을 끊고 PHYLINK instance를 파괴합니다.

Implementation
--------------

At probe time or when a DPNI's endpoint is dynamically changed, the dpaa2-eth
is responsible to find out if the peer object is a DPMAC and if this is the
case, to integrate it with PHYLINK using the dpaa2_mac_connect() API, which
will do the following:

 - look up the device tree for PHYLINK-compatible of binding (phy-handle)
 - will create a PHYLINK instance associated with the received net_device
 - connect to the PHY using phylink_of_phy_connect()

The following phylink_mac_ops callback are implemented:

 - .validate() will populate the supported linkmodes with the MAC capabilities
   only when the phy_interface_t is RGMII_* (at the moment, this is the only
   link type supported by the driver).

 - .mac_config() will configure the MAC in the new configuration using the
   dpmac_set_link_state() MC firmware API.

 - .mac_link_up() / .mac_link_down() will update the MAC link using the same
   API described above.

At driver unbind() or when the DPNI object is disconnected from the DPMAC, the
dpaa2-eth driver calls dpaa2_mac_disconnect() which will, in turn, disconnect
from the PHY and destroy the PHYLINK instance.

DPNI-DPMAC 링크 활성화 순서

101-140

DPNI-DPMAC 연결에서 `ip link set dev eth0 up`을 실행하면 다음 순서로 동작합니다.

  • (1) `.dev_open()`에서 `phylink_start()`를 호출합니다.
  • (2) PHYLINK가 `.mac_config()`와 `.mac_link_up()` callback을 호출합니다.
  • (3) 하드웨어 MAC 구성을 위해 MC firmware API `dpmac_set_link_state()`를 호출합니다.
  • (4) firmware가 최종적으로 하드웨어 MAC을 새 구성으로 설정합니다.
  • (5) PHYLINK가 연결된 `net_device`에서 직접 `netif_carrier_on()`을 호출합니다.
  • (6) `dpaa2-eth` 드라이버가 `LINK_STATE_CHANGE` IRQ를 처리하고 pause frame 설정에 따라 Rx taildrop을 활성화하거나 비활성화합니다.
DPNI-DPMAC 활성화
`eth0`(1) `phylink_start()`PHYLINK(2) MAC callback`dpaa2-eth`(3) `dpmac_set_link_state()`DPMAC·MC firmware(4) HW MAC
PHYLINK(5) `netif_carrier_on()``eth0`
DPNI·MC firmware(6) `LINK_STATE_CHANGE` IRQ`dpaa2-eth`Rx taildrop 조정

원문의 두 번째 ASCII 도식에 표시된 1~6번 호출과 event 경로를 다시 구성했습니다.


In case of a DPNI-DPMAC connection, an 'ip link set dev eth0 up' would start
the following sequence of operations:

(1) phylink_start() called from .dev_open().
(2) The .mac_config() and .mac_link_up() callbacks are called by PHYLINK.
(3) In order to configure the HW MAC, the MC Firmware API
    dpmac_set_link_state() is called.
(4) The firmware will eventually setup the HW MAC in the new configuration.
(5) A netif_carrier_on() call is made directly from PHYLINK on the associated
    net_device.
(6) The dpaa2-eth driver handles the LINK_STATE_CHANGE irq in order to
    enable/disable Rx taildrop based on the pause frame settings.

.. code-block:: none

  +---------+               +---------+
  | PHYLINK |-------------->|  eth0   |
  +---------+           (5) +---------+
  (1) ^  |
      |  |
      |  v (2)
  +-----------------------------------+
  |             dpaa2-eth             |
  +-----------------------------------+
         |                    ^ (6)
         |                    |
         v (3)                |
  +---------+---------------+---------+
  |  DPMAC  |               |  DPNI   |
  +---------+               +---------+
  |            MC Firmware            |
  +-----------------------------------+
         |
         |
         v (4)
  +-----------------------------------+
  |             HW MAC                |
  +-----------------------------------+

DPNI-DPNI 내부 링크 활성화 순서

141-173

DPNI-DPNI 연결의 일반적인 동작 순서는 다음과 같습니다.

  • (1) `ip link set dev eth0 up`을 실행합니다.
  • (2) 연결된 `fsl_mc_device`에서 `dpni_enable()` MC API를 호출합니다.
  • (3) `ip link set dev eth1 up`을 실행합니다.
  • (4) 두 번째 `fsl_mc_device`에서 `dpni_enable()` MC API를 호출합니다.
  • (5) operational link state가 이제 up이므로 두 `dpaa2-eth` instance가 모두 `LINK_STATE_CHANGED` IRQ를 받습니다.
  • (6) `link_state_update()`가 외부에 노출한 각 `net_device`에서 `netif_carrier_on()`을 호출합니다.
DPNI-DPNI 활성화
`eth0` up(1)`dpaa2-eth`(2) `dpni_enable()`DPNI 0MC firmware internal link
`eth1` up(3)`dpaa2-eth`(4) `dpni_enable()`DPNI 1MC firmware internal link
두 DPNI link up(5) `LINK_STATE_CHANGED` IRQ두 `dpaa2-eth` instance(6) `netif_carrier_on()``eth0`·`eth1`

원문의 세 번째 ASCII 도식에 표시된 양쪽 인터페이스의 대칭 동작을 다시 구성했습니다.

In case of a DPNI-DPNI connection, a usual sequence of operations looks like
the following:

(1) ip link set dev eth0 up
(2) The dpni_enable() MC API called on the associated fsl_mc_device.
(3) ip link set dev eth1 up
(4) The dpni_enable() MC API called on the associated fsl_mc_device.
(5) The LINK_STATE_CHANGED irq is received by both instances of the dpaa2-eth
    driver because now the operational link state is up.
(6) The netif_carrier_on() is called on the exported net_device from
    link_state_update().

.. code-block:: none

  +---------+               +---------+
  |  eth0   |               |  eth1   |
  +---------+               +---------+
      |  ^                     ^  |
      |  |                     |  |
  (1) v  | (6)             (6) |  v (3)
  +---------+               +---------+
  |dpaa2-eth|               |dpaa2-eth|
  +---------+               +---------+
      |  ^                     ^  |
      |  |                     |  |
  (2) v  | (5)             (5) |  v (4)
  +---------+---------------+---------+
  |  DPNI   |               |  DPNI   |
  +---------+               +---------+
  |            MC Firmware            |
  +-----------------------------------+

외부 공개 API와 연결 전제 조건

174-194

외부 공개 API

DPMAC 객체의 endpoint를 구동하는 모든 DPAA2 드라이버는 `_EVENT_ENDPOINT_CHANGED` IRQ를 처리해야 합니다. 필요할 때 다음 API로 연결된 DPMAC에 접속하거나 연결을 해제합니다.

int dpaa2_mac_connect(struct dpaa2_mac *mac);
void dpaa2_mac_disconnect(struct dpaa2_mac *mac);

partner DPMAC이 `TYPE_FIXED`가 아닐 때만 phylink 통합이 필요합니다. 즉 `TYPE_PHY` 또는 `TYPE_BACKPLANE`이어야 합니다.

`TYPE_BACKPLANE`에서는 MC firmware가 PCS register에 접근하지 않는다는 점이 `TYPE_PHY`와 다릅니다.

다음 helper로 이 조건을 확인할 수 있습니다.

static inline bool dpaa2_mac_is_type_phy(struct dpaa2_mac *mac);

MAC에 연결하기 전에 호출자는 `dpaa2_mac` 구조체를 할당해야 합니다. 연관된 `net_device`, 사용할 MC portal pointer, DPMAC의 실제 `fsl_mc_device` 구조체를 채워야 합니다.

Exported API
------------

Any DPAA2 driver that drivers endpoints of DPMAC objects should service its
_EVENT_ENDPOINT_CHANGED irq and connect/disconnect from the associated DPMAC
when necessary using the below listed API::

 - int dpaa2_mac_connect(struct dpaa2_mac *mac);
 - void dpaa2_mac_disconnect(struct dpaa2_mac *mac);

A phylink integration is necessary only when the partner DPMAC is not of
``TYPE_FIXED``. This means it is either of ``TYPE_PHY``, or of
``TYPE_BACKPLANE`` (the difference being the two that in the ``TYPE_BACKPLANE``
mode, the MC firmware does not access the PCS registers). One can check for
this condition using the following helper::

 - static inline bool dpaa2_mac_is_type_phy(struct dpaa2_mac *mac);

Before connection to a MAC, the caller must allocate and populate the
dpaa2_mac structure with the associated net_device, a pointer to the MC portal
to be used and the actual fsl_mc_device structure of the DPMAC.