uclinux-W5500 network device kernel driver based on stm32f429
uclinux-W5500 network device kernel driver based on stm32f429
0
Project description
int w5100_probe(struct device *dev, const struct w5100_ops *ops,int sizeof_ops_priv, const void *mac_addr, int irq,int link_gpio)
- 1
static const struct ethtool_ops w5100_ethtool_ops = {
.get_drvinfo = w5100_get_drvinfo,
.get_msglevel = w5100_get_msglevel,
.set_msglevel = w5100_set_msglevel,
.get_link = w5100_get_link,
.get_regs_len = w5100_get_regs_len,
.get_regs = w5100_get_regs,
};
The ethtool_ops member function corresponds to the various command options of the user space ethol tool.?ethtool provides network card and network card driver management capabilities, which can provide Linux network developers and administrators with network access.?card hardware and drivers, and network protocol stack configuration, display and debugging functions.
4、 netif_napi_add(ndev, &priv->napi, w5100_napi_poll, 16);
This function is used to initialize a NAPI, the poll parameter of netif_napi_add() is the poll function that will be scheduled and executed by NAPI
Data reception process:
static int w5100_napi_poll(struct napi_struct *napi, int budget)
{
struct w5100_priv *priv = container_of(napi, struct w5100_priv, napi);
int rx_count;
for (rx_count = 0; rx_count < budget; rx_count++) {
struct sk_buff *skb = w5100_rx_skb(priv->ndev); // Obtener los datos de recibir skb
if (skb)
netif_receive_skb(skb);// Analizar los datos en el bufer de recepcion de la red
else
break;
}
if (rx_count < budget) {
napi_complete(napi);// Elimina el dispositivo napi de la lista de sondeo
w5100_enable_intr(priv); // Habilitar interrupcion
}
return rx_count;
}
The method of receiving data is NAPI (New API) In short, NAPI is a technology that integrates interrupt and poll methods.
Its data receiving process is:
Receive Interrupt is coming ?? "Receive Interrupt Disable ??" Receive all data packets in polling mode until empty ?? "Receive Interrupt Enable ??" Reception outage is coming
Register interrupt function:
err = request_irq(priv->irq, w5100_interrupt,IRQF_TRIGGER_LOW, ndev->name, ndev);
priv-> irq: hardware interrupt number to apply
w5100_interrupt: The interrupt processing function registered with the system is a callback function.?When an interrupt occurs, this function is called by the system and passed the parameter ndev
IRQF_TRIGGER_LOW: Specified interrupt trigger type: active low
ndev-> name: the name of the device driver
ndev: The interrupt name can be used as an interrupt-distinguishing parameter when sharing an interrupt, or it can be used to specify the data address that the interrupt service function should refer to
Interrupt function:
static irqreturn_t w5100_interrupt(int irq, void *ndev_instance)
{
struct net_device *ndev = ndev_instance;
struct w5100_priv *priv = netdev_priv(ndev);
int ir = w5100_read(priv, W5100_S0_IR(priv));
if (!ir)
return IRQ_NONE;
w5100_write(priv, W5100_S0_IR(priv), ir);
if (ir & S0_IR_SENDOK) {
// netif_dbg(priv, tx_done, ndev, "tx donen");
netif_wake_queue(ndev);
}
if (ir & S0_IR_RECV) {
w5100_disable_intr(priv);
if (priv->ops->may_sleep)
queue_work(priv->xfer_wq, &priv->rx_work); // Programa para ejecutar una tarea en una cola de trabajo especifica. Parametros de entrada:
@ workqueue_struct: el puntero de la cola de trabajo especificado
@work_struct: puntero a un objeto de tarea especifico
else if (napi_schedule_prep(&priv->napi)) // Verifica si es posible programar napi
__napi_schedule(&priv->napi);// Llame a napi_schedule () en la funcion de procesamiento de interrupciones del controlador de la tarjeta de red para usar NAPI
}
return IRQ_HANDLED;
}
static int w5100_start_tx(struct sk_buff *skb, struct net_device *ndev)
{
struct w5100_priv *priv = netdev_priv(ndev);
netif_stop_queue(ndev);// Detener el paquete de transmision del dispositivo
if (priv->ops->may_sleep) {
WARN_ON(priv->tx_skb);
priv->tx_skb = skb;
queue_work(priv->xfer_wq, &priv->tx_work);// Abrir la tarea de envio de datos
} else {
w5100_tx_skb(ndev, skb);
}
return NETDEV_TX_OK;
}
static void w5100_tx_skb(struct net_device *ndev, struct sk_buff *skb)
{
struct w5100_priv *priv = netdev_priv(ndev);
u16 offset;
offset = w5100_read16(priv, W5100_S0_TX_WR(priv));// Leer socket0 enviar offset de bufer de w5500
w5100_writebuf(priv, offset, skb->data, skb->len);
w5100_write16(priv, W5100_S0_TX_WR(priv), offset + skb->len);// Escribe datos en w5500
ndev->stats.tx_bytes += skb->len;
ndev->stats.tx_packets++; // Registra la cantidad de paquetes enviados
dev_kfree_skb(skb);
w5100_command(priv, S0_CR_SEND);
}
The effect of the final execution:
