C 将SKB复制到USART DMA

C 将SKB复制到USART DMA,c,network-programming,driver,device,usart,C,Network Programming,Driver,Device,Usart,你好,我正在写一个网络设备驱动程序。我已经安装了USART。 我在Probe funktion中注册了网络设备,如下所示: my_net = alloc_etherdev(sizeof(struct stm32_port)); if (my_net == NULL){ return ENOMEM; } /* Set MAC address */ eth_hw_addr_random(my_net); my_net -> n

你好,我正在写一个网络设备驱动程序。我已经安装了USART。 我在Probe funktion中注册了网络设备,如下所示:

my_net = alloc_etherdev(sizeof(struct stm32_port));
    if (my_net == NULL){
        return ENOMEM;
    }

    /* Set MAC address */
    eth_hw_addr_random(my_net);
    
    my_net -> netdev_ops = &my_net_ops;
    
    SET_NETDEV_DEV(my_net, &pdev->dev);    
    
    return register_netdev(my_net);
现在,在ndo_start_xmit方法中,当我试图将socketd puffer复制到CPU dma地址时,我的内核总是感到恐慌

    static int my_net_send(struct sk_buff *skb, struct net_device *ndev)
{
    //struct stm32_port *priv = netdev_priv(ndev);
    //unsigned int entry = TX_BUF_L;
    //unsigned int entry = tp->cur_tx;

    struct stm32_port *lp = netdev_priv(ndev);
    struct sk_buff *sk_buff;
    unsigned pktlen = skb->len;


    /* adjust the packet length to min. required
     * and hope that the buffer is large enough
     * to provide some random data.
     */
    if (pktlen < ETH_ZLEN)
    {
        if (skb_padto(skb, ETH_ZLEN))
            return NETDEV_TX_OK;
    pktlen = ETH_ZLEN;
    }
    
    //pr_info("do_start_xmit(skb=%p, ndev=%p) len=%u\n", skb, ndev, pktlen);

    netif_stop_queue(ndev);
    //send 
    if (lp->tx_dma_busy)
        return NETDEV_TX_BUSY;
    
    //pr_info("copy to usart: %s", skb->data);
    sk_buff = skb_get(skb);
    pr_info("copy to usart: %s", sk_buff->data);
    memcpy(&lp->tx_buf[0], sk_buff, pktlen);
    //dma_addr_t dma_addr = dma_map_single(ndev->d, skb->data, skb->len, DMA_TO_DEVICE);
    
    ndev->stats.tx_packets++;
    ndev->stats.tx_bytes += pktlen;
    dev_kfree_skb (skb);
    netif_start_queue(ndev);
    return NETDEV_TX_OK;
}

struct stm32_port {
    struct uart_port port;
    struct clk *clk;
    struct stm32_usart_info *info;
    struct dma_chan *rx_ch;  /* dma rx channel            */
    dma_addr_t rx_dma_buf;   /* dma rx buffer bus address */
    unsigned char *rx_buf;   /* dma rx buffer cpu address */
    struct dma_chan *tx_ch;  /* dma tx channel            */
    dma_addr_t tx_dma_buf;   /* dma tx buffer bus address */
    unsigned char *tx_buf;   /* dma tx buffer cpu address */
    u32 cr1_irq;         /* USART_CR1_RXNEIE or RTOIE */
    u32 cr3_irq;         /* USART_CR3_RXFTIE */
    int last_res;
    bool tx_dma_busy;    /* dma tx busy               */
    bool hw_flow_control;
    bool fifoen;
    int wakeirq;
    int rdr_mask;       /* receive data register mask */
    struct mctrl_gpios *gpios; /* modem control gpios */
};
static int my_net_send(struct sk_buff*skb,struct net_device*ndev)
{
//struct stm32_port*priv=netdev_priv(ndev);
//无符号整数项=TX_BUF_L;
//无符号整数项=tp->cur\u tx;
struct stm32_port*lp=netdev_priv(ndev);
结构sk_buff*sk_buff;
无符号pktlen=skb->len;
/*将数据包长度调整到所需的最小值
*希望缓冲区足够大
*提供一些随机数据。
*/
如果(pktlentx\U dma\U忙)
返回NETDEV_TX_BUSY;
//请购单信息(“复制到usart:%s”,skb->数据);
sk_buff=skb_get(skb);
pr_info(“复制到usart:%s”,sk_buff->data);
memcpy(&lp->tx_buf[0],sk_buff,pktlen);
//dma_addr_t dma_addr=dma_map_single(ndev->d,skb->data,skb->len,dma_TO_设备);
ndev->stats.tx_packets++;
ndev->stats.tx_bytes+=pktlen;
dev_kfree_skb(skb);
网络启动队列(ndev);
返回NETDEV_TX_OK;
}
结构stm32\u端口{
结构uart_端口;
结构时钟*时钟;
结构stm32_usart_info*info;
结构dma_chan*rx_ch;/*dma接收信道*/
dma_addr_t rx_dma_buf;/*dma rx缓冲区总线地址*/
无符号字符*rx_buf;/*dma接收缓冲区cpu地址*/
结构dma_chan*tx_ch;/*dma发送信道*/
dma_addr_t tx_dma_buf;/*dma tx缓冲区总线地址*/
无符号字符*tx_buf;/*dma tx缓冲区cpu地址*/
u32 cr1\u irq;/*USART\u cr1\u RXNEIE或RTOIE*/
u32 cr3\u irq;/*USART\u cr3\u RXFTIE*/
int last_res;
bool-tx\u-dma\u-busy;/*dma-tx-busy*/
bool硬件流量控制;
布尔费芬;
int wakeirq;
int rdr_掩码;/*接收数据寄存器掩码*/
结构mctrl_gpios*gpios;/*调制解调器控制gpios*/
};

复制袜子泡芙的正确方法是什么。对不起,我对设备驱动程序不熟悉。

为什么要使用
skb_data=skb_put(skb,pktlen)?如果我没记错的话,
skb_put
会移动
sk_buff
中的
data
字段。这将导致越界访问。仅供参考-您还使用
pr\u info
打印数据包内容。数据包内容是否保证以
\0
终止?很抱歉,这是错误的,我试图在复制之前用skb_get复制已插入的缓冲区。pr_信息只是供我查看的。好吧,现在随着更改,它应该是
memcpy(…,skb_buff->data,…)
(就像你在
pr_信息中所做的那样)。你真的能包括你试图编译/运行的代码,以便我们能够正确识别错误吗?