Data transmission on the link layer of the linux protocol stack - data reception

  

data reception in order to understand the process of NIC data reception. It is necessary to discuss the specific process of DMA first. The DMA transfer data can be divided into the following steps: First, the CPU sends commands to the DMA, such as DMA mode, main memory address, number of words transferred, etc., after which the CPU executes the original program. Then the DMA controls the I/O device and the main memory. Exchange data between. After receiving the data, send a DMA request to the CPU, obtain the bus control right, perform data transfer, modify the main memory address on the card, modify the word counter and check whether the value is zero, if it is not zero, continue to transmit, if it is zero , then send an interrupt request to the CPU. In other words, when the NIC receives the packet, it is placed in the current skb->data. When you come back to a package. The DMA will modify the main memory address on the card, go to skb->next, and put the data into it. That is why a skb->data stores a packet. Ok, now you can see the specific code implementation. When the network data arrives, the network card puts it into the DMA memory, and then the DMA reports the interrupt to the CPU. The CPU finds the interrupt processing routine according to the interrupt vector, which is the e100_intr() registered by us. Static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs){struct net_device *netdev = dev_id;struct nic *nic = netdev_priv(netdev);u8 stat_ack = readb(&nic->csr->scb .stat_ack);DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\ ", stat_ack);if(stat_ack == stat_ack_not_ours | |  /* Not our interrupt */stat_ack == stat_ack_not_present) /* Hardware is ejected */return IRQ_NONE;/* Ack interrupt(s) *///Send interrupt ACK. The CPU sends an ACK to the device. Indicates that this interrupt has been processed for writeb(stat_ack, &nic->csr->scb.stat_ack);/* We hit Receive No Resource (RNR); restart RU after cleaning */if(stat_ack & stat_ack_rnr)nic- >ru_running = 0; //disable interrupt e100_disable_irq (nic); //CPU began to schedule this device. Instead, running netdev->pollnetif_rx_schedule(netdev);return IRQ_HANDLED;}netif_rx_schedule(netdev), the cpu starts scheduling the device and polls the device for data to process. After the call, call the netdev->poll function, ie: e100_poll() static int e100_poll(struct net_device *netdev, int *budget){struct nic *nic = netdev_priv(netdev);unsigned int work_to_do = min(netdev->quota , *budget);unsigned int work_done = 0;int tx_cleaned;//Start NIC, DMA data processing e100_rx_clean(nic, &work_done, work_to_do);tx_cleaned = e100_tx_clean(nic);/* If no Rx and Tx Cleanup work was done, exit polling mode. */if((!tx_cleaned && (work_done == 0)) | |  !netif_running(netdev)) {netif_rx_complete(netdev);e100_enable_irq(nic);return 0;}*budget -= work_done;netdev->quota -= work_done;return 1;}Track into e100_rx_clean():static inline void e100_rx_clean (struct nic *nic, unsigned int *work_done, unsigned int work_to_do){struct rx *rx;/* Indicated newly arrived packets *///traverse the data in the ring DMA, call e100_rx_indicate() for processing for(rx = nic- >rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {if(e100_rx_indicate(nic, rx, work_done, work_to_do))break; /* No more to clean */}/* Alloc new skbs to refill list */for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {if(un100ly_ex_alloc_skb(nic, rx )))break; /* Better luck next time (see watchdog) */}e100_start_receiver(nic);} Here, it will traverse the data in the ring DMA, that is, the data starting from nic->rx_to_clean until the data is all Processed into the handler: e100_rx_indicate() static inline int e100_rx_indicate(struct nic *nic, struct Rx *rx,unsigned int *work_done, unsigned int work_to_do){struct sk_buff *skb = rx->skb;//Get rfd from here. It includes some received information, but not valid data from the link struct rfd *rfd = (struct rfd *)skb->data;u16 rfd_status, actual_size;if(unlikely(work_done && *work_done >= work_to_do))return -EAGAIN;//synchronous DMA cache pci_dma_sync_single_for_cpu(nic-> ;pdev, rx->dma_addr,sizeof(struct rfd), PCI_DMA_FROMDEVICE);//Get the receive status rfd_status = le16_to_cpu(rfd->status);DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\ " , rfd_status);/* If data isn't ready, nothing to indicate *///No reception is complete, return

Copyright © Windows knowledge All Rights Reserved