대학원/대회 준비 관련

[ZCU-104] DMA 기본적인 배경

오비루 2024. 4. 18. 17:55
728x90
728x90

[공부하면서 Notion에 적은 내용 그대로 복붙한 내용이라 미흡할 수 있습니다.]

Getting started with ZYNQ Ethernet using the Zybo board - Igor Freire

 

Getting started with ZYNQ Ethernet using the Zybo board - Igor Freire

This post shows how to make the ZYNQ Ethernet interface functional using a Zybo board and introduces basic Ethernet concepts that are involved.

igorfreire.com.br

Understanding the Gigabit Ethernet Controller's DMA on ZYNQ Devices - Igor Freire

 

Understanding the Gigabit Ethernet Controller's DMA on ZYNQ Devices - Igor Freire

This post explains the essential functionality of the DMA block that is present in the Gigabit Ethernet Controller in the Processing System (PS) of ZYNQ devices and also demonstrates a practical application.

igorfreire.com.br

Ethernet Interface

  • MAC Layer
    • 내장된 이더넷 MAC 주소를 사용한다.
    • Frame의 전송&수신을 담당한다.
    • 주로 PS영역에 구현되어있다.
  • PHY Layer
    • GEM & 외부 Ethernet Network 간의 물리적인 연결을 담당한다.
    • 주로 HW적으로 구현되어있다.

 

 

다음 두 인터페이스의 통신은 MII(Media Independent Interface)을 통해서 이루어진다.

 

 

GEM Ethernet Controller의 경우 MIO Pins이 비교적 적게 형성되어있는 RGMII(Reduced Gigabit MII)로 나타나며, PS에서 구현된 MAC은 RGMII를 통해서 연결된다.

ps)EMIO는 PL 내부의 PHY 하위 계층을 인스턴스화가 필요한 경우에만 사용한다.

PHY chip의 구성의 경우 MDIO(Management Data Input/Output)을 통해 관리된다.

데이터 송&수신

PS 내의 MAC 송&수신기 모듈은 FIFO에 연결되어 있으며, 이 FIFO는 다시 DMA Controller를 통해 메모리와 데이터를 교환한다.

여기서 사용되는 DMA는 산발적-수집 기능을 갖춘 SGDMA 블록을 특징으로 한다.

 

 

[수신]

MAC의 Rx(수신)은 수신된 데이터를 FIFO에 기록하고, DMA가 데이터를 메모리로 전송해준다.

  • 이더넷 PHY에서 받은 데이터가 Rx GMII를 통해 Rx MAC으로 이동
  • 수신된 Packet이 먼저 RX packet Buffer에 저장
  • RX DMA에 의해 AXI I/F를 통해 메모리로 전송

[송신]

송신의 경우 데이터가 저장되어 있을 메모리로부터 데이터를 가져와 FIFO에 기록을 한다.

이후 이 데이터를 MAC의 Tx(송신) Chain으로 전달한다.

  • 전송될 데이터는 AXI I/F를 통해 메모리에서 가져와 TX DMA 모듈에 의해 TX Packet Buffer에 쓰여짐
  • TX Packet Buffer에서 전체 프레임이 준비되면, MAC은 TX GMII I/F를 통해 PHY로 데이터를 전송 시작

GEM의 Buffer & Buffer Descriptors

Buffer

  • DMA를 통해 읽을 데이터 저장하기
  • DMA를 통해 쓰여진 데이터 받기

Buffer Descriptors

  • DMA R/W 전송을 프로그래밍 하기 위해 사용.
    • 둘 다 메모리에 저장되기에 별도의 메모리 영역이 할당되어 있어야 함
  • 메모리 영역의 초기 주소를 가리키는 포인터와 그 영역에서 읽거나 쓸 데이터 양을 결정하는 항목을 포함하는 데이터 구조
    • 메모리 영역의 길이
    • 데이터 전송의 길이
  • 버퍼 자체와 데이터 전송에 대한 추가 정보 포함
  • BD의 일반적인 항목 중 하나는 데이터 전송 완료 후 다음으로 처리해야 할 다른 BD를 카리키는 포인터 정보를 포함할 수 있다.
    • But, GEM에서 사용되는 BD는 이를 포함하지 않는다.

Queue Pointer Registers

GEM의 특정 경우에는 BD와 Buffer외에도 Tx & Rx에 각각 하나의 Queue Pointer Register가 존재한다. (FIFO인가?)

이는 다음에 처리될 대기열에 등록된 BD를 가리키는 Register이다.

지정된 BD의 트랜잭션이 완료된 후, Queue Pointer는 다음 BD를 가리키도록 Update된다. 이는 BD length만큼 증가하며, 현재 BD에 BD list의 마지막 BD임을 나타내는 조건이 있을시 리스트의 첫 번째 BD의 주소인 Queue 기본 주소로 되돌아간다.

728x90

 

위의 Diagram에 표시된 구성 요소는 GEM의 Tx와 Rx Chain 모두에 존재한다.

BD ⇒ Buffer를 가리키기

Queue Pointer ⇒ 다음에 처리될 현재 BD 가리키기

Queue BaseAddress ⇒ 항상 리스트의 첫 번째 BD (#1)를 가리킨다.

BD & Buffer = 메모리에 저장되어 있음 (그럼 이건 DDR을 의미??)

Queue Pointer & Queue Base-Address = GEM 내의 Register


Composition of Buffer Descriptors

BD (Ethernet Frame Data를 저장하는 Memory 영역, Buffer를 가리키는 역할)

  • Buffer Address (32bit)
  • Config / Status (32bit)
    • 여기서 Rx & Tx에 있는 상태/제어 단어는 다르지만, 공통적으로 둘 다 버퍼의 길이를 포함
    • wrap bit라고 불리는 비트 포함.
      • Hw가 BD list를 처리하다가 이 bit가 설정된 BD를 만나면, 첫 번째 BD 주소로 돌아간다.

 

 

DMA 작업에 필수적인 상태/제어 목록

⇒ 이는 프레임의 일부 또는 전체가 저장될 수 있는 메모리 영역의 시작 주소와 데이터 길이 등의 정보를 지니고 있다.

BD Sequence

  • 전체 프레임 데이터를 담고 있는 여러 메모리 영역을 순차적으로 가리키는 여러 BD들
  • 마지막 BD에는 wrap bit가 설정
  • wrap bit가 설정된 BD 처리 시, 해당 Sequence가 마지막 BD임을 알 수 있다. (시작 & 끝 명확히 알 수 있게 함)
  • 해당 신호를 기반으로 interrupt를 발생시켜 SW에게 처리 완료 알림

[ownership bit]

  • Rx BD에 설정된 bit
  • 특정 Rx BD가 가리키는 버퍼에 프레임 데이터 작성 시 DMA 컨트롤러는 ownership bit를 1로 설정한다.
    • 이는 버퍼가 사용되었음을 뜻하며, 이제는 SW가 해당 데이터를 갖고있으니 HW는 더 이상 사용 불가하다는 의미이다.

[used bit]

  • Tx에도 ownership과 비슷한 역할을 하는 것
  • HW는 버퍼 데이터가 성공적으로 전송 시 이 bit를 1로 설정해 버퍼가 사용되었는지 여부를 나타낸다.
  • SW는 전송을 요청하기 전에 이 비트를 지워야 함
    • “used” BD의 전송이 요청된 경우 HW는 오류 표시와 함께 interrupt 발생

“RX BD”의 경우, SOF(Start of Frame) & EOF(End of Frame) 비트와 같은 두 가지 중요한 지시 사항 존재.

프레임 수신 시, DMA Controller는 complete frame 저장을 위해 필요한 수의 BD를 사용한다. 이더넷 Frame length는 가변적이기에 Frame당 BD의 수도 다양하기에, SOF & EOF를 처음과 끝에 표시해 SW가 수신된 프레임 수를 이해할 수 있도록 한다.

명심해야 할 부분은 BD list에서 첫 번째 BD로 DMA 엔진을 되돌리게 하는 것은 EOF가 아닌 wrap bit이다.

“TX BD”의 경우, RX BD의 EOF와 유사한 last bit가 존재.

이는 BD가 현재 전송되고 있는 프레임의 마지막 buffer를 가리킬 때를 나타낸다.


BD State Machine

BD는 하단 이미지에 보이는 네 가지 다른 상태 중 하나로 존재한다.

이는 DMA 전송이 발생함에 따라 이러한 상태를 순환하는 것으로, 지금부터 그에 대한 내용을 설명한다.

 

320x100

[이건 추후에.. 개인적으로 이해하기 수월하도록 내 자료에 따로 적어둠]

Example Application

DMA Interrupts는 다음과 같이 이루어져 있다.

  • Tx Callback
  • Rx Callback
  • Error Callback

BD Ring Creation

이는 Zynq 장치에서 Ethernet Controller의 DMA Block을 사용할 때 BD ring을 제어하는 구조를 생성하는 과정을 말한다.

BD ring은 Tx & Rx의 데이터 이동을 위해 필요한 구조체임.

XEmacPS_CfgInitialize() 함수를 통해 생성된 XEmacPs 구조체는 기본적으로 두 개의 미할당 BD ring인 TxBdRing & RxBdRing을 포함한다.

⇒ XEmacPs 구조체에는 (Tx & Rx Ring) 이 포함되어 있다.

그 후 XEmacPs_BdRingCreate() 함수가 호출될 때 이 BD들이 정의된다.

Status = XEmacPs_BdRingCreate(&(XEmacPs_GetRxRing(EmacPsInstancePtr)),
                   (UINTPTR) RX_BD_LIST_START_ADDRESS,
                   (UINTPTR)RX_BD_LIST_START_ADDRESS,
                   XEMACPS_BD_ALIGNMENT,
                   RXBD_CNT);

여기서 RXBD_CNT는 ring이 몇 번 생성될 것인지를 나타내는 횟수 개념이다.

따라서 해당 인자가 선언되면 CNT 개수 만큼의 BD가 생성되며 이는 모두 Free 상태로 설정되어 있다. 또한 아직 memset으로 전체 데이터가 0으로 설정된 백지 상태이다.

XEmacPs_BdClear(&BdTemplate);
 
/*
 * Create the RxBD ring
 */
Status = XEmacPs_BdRingCreate(&(XEmacPs_GetRxRing(EmacPsInstancePtr)),
                   (UINTPTR) RX_BD_LIST_START_ADDRESS,
                   (UINTPTR)RX_BD_LIST_START_ADDRESS,
                   XEMACPS_BD_ALIGNMENT,
                   RXBD_CNT);
if (Status != XST_SUCCESS) {
    EmacPsUtilErrorTrap
        ("Error setting up RxBD space, BdRingCreate");
    return XST_FAILURE;
}
 
Status = XEmacPs_BdRingClone(&(XEmacPs_GetRxRing(EmacPsInstancePtr)),
                  &BdTemplate, XEMACPS_RECV);
if (Status != XST_SUCCESS) {
    EmacPsUtilErrorTrap
        ("Error setting up RxBD space, BdRingClone");
    return XST_FAILURE;
}

이후 BdRingClone을 통해서 비어있던 Bd 데이터 공간에 Template 내용을 복사하여 Rx데이터를 채워준다. 여기서 마지막 ring은 wrap으로 존재함.

  • 이러한 데이터 복사는 Free 상태였기에 가능한 것으로, 이외의 상태에서는 BD를 직접적으로 수정하는 것이 불가능하다.

다음 과정은 Tx에서도 동일하게 수행하지만, Tx의 모든 BD Template에는 used bit가 존재한다.

XEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK);

따라서, Ring을 생성하기 전에 다음과 같이 used bit를 설정해주는 과정을 수행한다.

→ SW에서 전송 활성화 전에 used bit clear 하는 것이 중요하기 때문에 used bit가 존재.

RX BD Ring State Transitions

상태도의 흐름을 보면 다음과 같음.

  1. BD 할당
  2. HW 등록
  3. BD가 HW에서 회수되어 해제됨
Status = XEmacPs_BdRingAlloc(&(XEmacPs_GetRxRing(EmacPsInstancePtr)), 1, &BdRxPtr);
  1. 단일 BD 할당 요청 : 사용자가 요청한 BD 수를 할당하려고 시도한다. 여기서 1은 단일 BD만 할당하고자 함을 의미함.
    1. 특정 Ethernet Frame을 수신하거나 전송하기 위한 메모리 공간을 준비하는 단계
  2. Free BD 검사 : 먼저 BD 링에 충분한 수의 “free” 상태인 BD가 있는지 확인. (이는 백지 상태의 BD를 의미함)
  3. BD 할당 및 “pre-process” 상태로 전환 : 충분한 수의 “free” BD가 있을 경우, 이 함수는 요청된 BD 수 만큼을 할당하고, 할당된 BD를 “pre-process” 상태로 전환한다. (= BD가 데이터 처리를 위해 준비되고, 사용자에 의해 구성될 수 있는 상태)
  4. 할당 결과 반환 : 할당 과정의 결과는 포인터 “&BdRxPtr”을 통해 반환된다. 이는 할당된 BD들 중 첫 번째 BD의 메모리 주소를 가리키며, 이후 단계(DMA)에서 해당 BD를 구성하고 사용하는데 필요하다.

실제로 바로 다음 함수에서 Rx 프레임에 할당된 주소가 첫 번째 BD 변수에 작성되어, 수신 데이터가 저장될 메모리 영역을 가리킨다.

XEmacPs_BdSetAddressRx(BdRxPtr, (UINTPTR)&RxFrame);

이후 할당된 BD(이 경우에는 1개 설정해서 1개만 존재)가 HW에 등록된다.

/*
 * Enqueue to HW
 */
Status = XEmacPs_BdRingToHw(&(XEmacPs_GetRxRing(EmacPsInstancePtr)),
                1, BdRxPtr);

Bd는 Hw 상태에 존재하기에 DMA Controller에 의해 직접 제어되고 있다. 즉 이 상태에서 BD는 Network에서 수신되는 데이터 처리 준비 완료 상태임을 의미한다.

“turn on” 상태에서 DMA는 이러한 BD를 사용해서 Ethernet I/F를 통해 수신된 데이터를 처리한다.

데이터 수신 준비가 완료되면, XEmacPs_Start()를 통해 Ethernet MAC의 수신 체인을 활성화함. 이를 통해 Network I/F를 통해 들어오는 데이터를 실제로 수신하고 처리할 준비가 끝남.

/*
 * Start the device
 */
XEmacPs_Start(EmacPsInstancePtr);

수신 체인이 활성화되면, 네트워크에서 데이터 packet이 들어올 때 이 packet은 DMA를 통해 BD가 가리키는 메모리 위치에 저장된다. 이는 HW에 의해 자동으로 수행됨.

프레임이 성공적으로 수신되면, 해당하는 인터럽트가 발생하고, FrameRx 변수 값을 증가시키며 수신된 프레임 수를 기록한다. (이는 SW가 데이터 수신을 얼마나 했는지 확인하기 위한 것)

while (!FramesRx);

이후 수신된 데이터를 기다리며 상단의 함수를 통해 busy waiting 상태에 들어간다. 이는 FramesRx가 0이 아닌 값을 가지면 while loop 탈출함을 나타낸다. (frame 1개 이상 수신을 위해)

Loop를 나오면 Application은 이전 Hw(DMA)에 등록된 BD를 하단의 함수를 통해 다시 제어한다.

NumRxBuf = XEmacPs_BdRingFromHwRx(&(XEmacPs_GetRxRing(EmacPsInstancePtr)), 1, &BdRxPtr);

Hw에 의해 처리된 BD를 검색하고, 처리된 BD의 수를 return한다.

이는 SW가 수신된 데이터를 접근하고 처리할 준비가 되었음을 의미한다.

만약, 모든 BD가 사용된 경우 return 값은 함수 내의 2번째 변수 값과 같다. (BD 개수)

또한, Hw → Post-process 상태로 이동한 첫 번째 BD 주소를 3번째 변수(BdRxPtr)에 저장한다.

이러한 주소값을 하단의 함수에 넣어서 BD를 해제할 수 있다.

Status = XEmacPs_BdRingFree(&(XEmacPs_GetRxRing(EmacPsInstancePtr)), NumRxBuf, BdRxPtr);

이는 BD가 다음 DMA를 다시 사용할 수 있도록 도와준다.

TX BD Ring State Transitions

TX BD Ring에 대해서도 비슷한 순서로 진행된다.

먼저, 1개의 TX BD 할당

Status = XEmacPs_BdRingAlloc(&(XEmacPs_GetTxRing(EmacPsInstancePtr)),
                      1, &Bd1Ptr);

이후 BD가 가리키는 주소(전송할 데이터가 위치한 곳), 전송 length, used bit 삭제, 현재 frame과 관련된 마지막 BD를 나타내는 last 비트 설정

XEmacPs_BdSetAddressTx(Bd1Ptr, (UINTPTR)&TxFrame);
XEmacPs_BdSetLength(Bd1Ptr, TxFrameLength);
XEmacPs_BdClearTxUsed(Bd1Ptr);
XEmacPs_BdSetLast(Bd1Ptr);

이후 BD가 HW에 등록

Status = XEmacPs_BdRingToHw(&(XEmacPs_GetTxRing(EmacPsInstancePtr)),
                     1, Bd1Ptr);

DMA 전송 엔진이 다음과 같이 활성화 되면,

/*
 * Start the device
 */
XEmacPs_Start(EmacPsInstancePtr);
 
/* Start transmit */
XEmacPs_Transmit(EmacPsInstancePtr);

SW는 전송 Interrupt handler를 통해 증가하는 전송된 frame 수에 대해 빠르게 증가한다.

while (!FramesTx);

frame이 전송되면, 해당 BD는 post-process 상태로 이동한다.

XEmacPs_BdRingFromHwTx(&(XEmacPs_GetTxRing(EmacPsInstancePtr)),
                    1, &Bd1Ptr)

마지막으로, BD가 다시 free 상태로 이동 된다.

Status = XEmacPs_BdRingFree(&(XEmacPs_GetTxRing(EmacPsInstancePtr)),
                 1, Bd1Ptr);

Queue Pointers

Queue Pointer는 Zynq의 GEM 내에서 DMA transaction을 위해 처리해야 할 BD를 관리하는 데 사용된다.

이는 현재 처리해야 할 BD의 위치를 가리키며, DMA 엔진이 데이터 전송 수행 시 이 포인터를 참조한다.

본 함수는 Queue Pointer를 설정하여 특정 BD의 시작 주소를 지정한다. 이는 DMA가 BD들을 순차적으로 처리할 시작점을 알려주는 역할을 하며 function(MAC 인스턴스 포인터, 기본 주소, 큐 번호, 큐 type<수신/전송>)을 인자로 받는다.

DMA Tx 및 Rx를 활성화하기 전에, 다음 함수를 호출하여 큐 기본 주소를 만든다.

XEmacPs_SetQueuePtr(EmacPsInstancePtr, EmacPsInstancePtr->RxBdRing.BaseBdAddr, 0, XEMACPS_RECV);
XEmacPs_SetQueuePtr(EmacPsInstancePtr, EmacPsInstancePtr->TxBdRing.BaseBdAddr, 1, XEMACPS_SEND);

이를 통해 DMA 컨트롤러가 데이터 수신 혹은 전송 시 어느 BD부터 처리할 지 알 수 있도록 하며 모든 transaction이 완료되면, Queue Pointer는 자동으로 다음 BD로 이동하거나, 설정에 따라 Queue의 시작점으로 돌아가서 순환 가능하다.

728x90
반응형