Mercurial > archived > louis > epitech > mq > rathaxes
view e1000_initialize_reception.patch @ 77:892b3bc7e43b
Wip on the RX init in the e1000 sample
author | Louis Opter <louis@lse.epitech.net> |
---|---|
date | Sun, 04 Mar 2012 18:35:43 +0100 |
parents | 51bea596df7f |
children | 501bf9cf65dc |
line wrap: on
line source
# HG changeset patch # Parent 40e5b7402e64e301b898fa4da1056a5348522fbb rathaxes: initialize reception on the e1000 sample: - This is documented in details in the sections 14.4 and 3.2 of the Intel Gigabit Controller Software Developer manual; - "Address filtering" is set up, address filters just tell the hardware which packets they should accept (unicast/multicast/vlan/promisc), we simply configure the hardware to accept packet for its own mac address (receive address); - It involves setting up a ring of receive descriptors (their format is documented in section 3.2.3) and an internal data structure to keep track of the ring; - Each descriptor of the ring correspond to an skbuff (skbuff are allocated individually). diff --git a/rathaxes/samples/e1000/e1000.blt b/rathaxes/samples/e1000/e1000.blt --- a/rathaxes/samples/e1000/e1000.blt +++ b/rathaxes/samples/e1000/e1000.blt @@ -21,9 +21,12 @@ */ typedef struct rtx_e1000_ctx { - int bars; - unsigned char /* __iomem */ *ioaddr; - int irq; + int bars; + unsigned char /* __iomem */ *ioaddr; + int irq; + + /* we can't use the Rathaxes type here (#8) */ + struct rtx_e1000_rx_ring rx_ring; } *rtx_e1000_ctx_p; } @@ -36,6 +39,78 @@ } } + template type e1000::RxDescriptor() + { + chunk LKM::includes() + { + typedef int ${e1000::RxDescriptor}; + + #include <linux/types.h> + } + + chunk ::decl() + { + typedef struct rtx_e1000_rx_descriptor + { + /* actual types are in comments */ + unsigned long int /* __le64 */ buff_addr; + unsigned short /* __le16 */ length; + unsigned short /* __le16 */ csum; + unsigned char status; + unsigned char errors; + unsigned short /* __le16 */ special; + } *rtx_e1000_rx_descriptor_p; + } + + chunk ::init() + { + } + + map + { + } + } + + template type e1000::RxRing() + { + chunk LKM::includes() + { + typedef int ${e1000::RxRing}; + } + + chunk ::decl() + { + /* + * - size: total size of the ring in bytes. + * - base: address of the ring; + * - dma_base: (physical) address of the ring where the device + * can access it; + * - skbuffs: array of the skbuffs associated with + * each descriptor; + * - dma_skbuffs: (physical) address of each skbuff + * where the device can write the received + * packets; + */ + struct rtx_e1000_rx_ring + { + unsigned int size; + rtx_e1000_rx_descriptor_p base; + void *dma_base; + + struct sk_buff *skbuffs[256 /* ${config.rx_ring_size} */]; + void *dma_skbuffs[256 /* ${config.rx_ring_size} */]; + }; + } + + chunk ::init() + { + } + + map + { + } + } + template type e1000::Register() { chunk LKM::includes() @@ -64,6 +139,9 @@ E1000_FCT = 0x00030, /* Flow Control Type */ E1000_FCTTV = 0x00170, /* Flow Control Transmit Timer Value */ E1000_CRCERRS = 0x04000, /* CRC Error Count (base address of the statistic register spaces) */ + E1000_RAL = 0x05400, /* Receive Address Low */ + E1000_RAH = 0x05404, /* Receive Address High */ + E1000_MTA = 0x05200, /* Multicast Table Array */ }; } @@ -132,7 +210,8 @@ E1000_INTR_RXDMT0 = 0x00000010, /* rx desc min. threshold (0) */ E1000_INTR_RXO = 0x00000040, /* rx overrun */ E1000_INTR_RXT0 = 0x00000080, /* rx timer intr (ring 0) */ - E1000_INTR_MDAC = 0x00000200 /* MDIO access complete */ + E1000_INTR_MDAC = 0x00000200, /* MDIO access complete */ + E1000_RAH_AV = (1 << 31), /* Set the MAC Address as Valid */ }; } @@ -458,14 +537,23 @@ chunk ::CALL { /* - * This is documented in the Intel Gigabit Ethernet Controller - * Software Developper manual. + * This part is documented in the Intel Gigabit Ethernet Controller + * Software Developper manual. (You can find it in the doc/hardware + * directory). * * Since this part is actually completely device specific it should * not be written here. (but in the front-end). */ /* + * shortcut hw_ctx... maybe we should directly take an + * e1000::Context? (but we would need to make it point back to + * the struct net_device) + */ + ${e1000::Context} hw_ctx; + hw_ctx = &${ctx}->hw_ctx; + + /* * "General Configuration" (section 14.3): * * - CTRL.ASDE/CTRL.SLU: Let the PHY handle the speed detection & @@ -478,22 +566,111 @@ * - Finally, initialize all the statistic registers from * E1000_CRCERRS to E1000_TSCTFC. */ - rtx_e1000_register_set32(&${ctx}->hw_ctx, E1000_CTRL, + + rtx_e1000_register_set32(hw_ctx, E1000_CTRL, E1000_CMD_ASDE | E1000_CMD_SLU); - rtx_e1000_register_unset32(&${ctx}->hw_ctx, E1000_CTRL, + rtx_e1000_register_unset32(hw_ctx, E1000_CTRL, E1000_CMD_LRST | E1000_CMD_FRCSPD | E1000_CMD_PHY_RST | E1000_CMD_ILOS | E1000_CMD_VME); - rtx_e1000_register_write32(&${ctx}->hw_ctx, E1000_FCAH, 0); - rtx_e1000_register_write32(&${ctx}->hw_ctx, E1000_FCAL, 0); - rtx_e1000_register_write32(&${ctx}->hw_ctx, E1000_FCT, 0); - rtx_e1000_register_write32(&${ctx}->hw_ctx, E1000_FCTTV, 0); - int i = 0; + rtx_e1000_register_write32(hw_ctx, E1000_FCAH, 0); + rtx_e1000_register_write32(hw_ctx, E1000_FCAL, 0); + rtx_e1000_register_write32(hw_ctx, E1000_FCT, 0); + rtx_e1000_register_write32(hw_ctx, E1000_FCTTV, 0); + int i = 0; /* CNorm workaround, the init part of for isn't generated */ for (i = 0; i != 64; ++i) - rtx_e1000_register_write32(&${ctx}->hw_ctx, E1000_CRCERRS + i * 4, 0); + rtx_e1000_register_write32(hw_ctx, E1000_CRCERRS + i * 4, 0); + + /* + * Receive initialization + * + * - Program the receive address, in RAL/RAH; + * - Initialize the Multicast Table Array; + * - Program the interrupt mask register (done in + * e1000::activate_device_interruption); + * - Allocate the receive descriptor ring and map it to make it + * accessible by the device. + */ + + /* (We should use uint{32,16}_t but CNorm doesn't know them yet) */ + rtx_e1000_register_write32(hw_ctx, E1000_RAL, + *(unsigned int *)(${ctx}->net_dev->dev_addr)); + /* + * The 16 upper bits of RAH also store the AS bits (which should be + * 0) and the AV bit (should be 1 to set the address as valid). + */ + rtx_e1000_register_write32(hw_ctx, E1000_RAH, + *(unsigned short *)(&${ctx}->net_dev->dev_addr[4])); + rtx_e1000_register_set32(hw_ctx, E1000_RAH, E1000_RAH_AV); + + i = 0; /* CNorm workaround, the init part of for isn't generated */ + for (i = 0; i != 128; ++i) + rtx_e1000_register_write32(hw_ctx, E1000_MTA + i * 4, 0); + + hw_ctx->rx_ring.size = ${config.rx_ring_size} * sizeof(*hw_ctx->rx_ring.base); + hw_ctx->rx_ring.size = ALIGN(hw_ctx->rx_ring.size, 4096); + hw_ctx->rx_ring.base = dma_alloc_coherent(&${ctx}->pci_dev->dev, + hw_ctx->rx_ring.size, &hw_ctx->rx_ring.dma_base, GFP_KERNEL); + if (!hw->ctx->rx_ring.base) + { + ${Log::info("cannot allocate the descriptors for the Rx ring")}; + goto err_rx_ring_alloc; + } + + i = 0; + for (i = 0; i != ${config.rx_ring_size}; ++i) + { + hw_ctx->rx_ring.skbuffs[i] = netdev_allock_skb(${ctx}->net_device, + ${config.rx_buffer_len}); + if (!hw_ctx->rx_ring.skbuffs[i]) + { + ${Log::info("cannot allocate a skbuff for the Rx ring")}; + goto err_skbuffs_alloc; + } + hw_ctx->rx_ring.dma_skbuffs[i] = dma_map_single(&${ctx}->pci_dev->dev, + hw_ctx->rx_ring.skbuffs[i]->data, + ${config.rx_buffer_len}, + DMA_FROM_DEVICE); + if (dma_mapping_error(&${ctx}->pci_dev->dev, + hw_ctx->rx_ring.dma_skbuffs[i])) + { + ${Log::info("cannot dma-map a skbuff for the Rx ring")}; + goto err_skbuffs_map; + } + hw_ctx->rx_ring.base[i].buff_addr = cpu_to_le64(hw_ctx->rx_ring.dma_skbuffs[i]); + } + + /* + * Always the same problem with error handling, we don't know where + * we are at in the "parent context": + */ + + err_skbuffs_alloc: + while (i--) + { + dma_unmap_single(&${ctx}->pci_dev->dev, + hw_ctx->rx_ring.dma_skbuffs[i], + ${config.rx_buffer_len}, + DMA_FROM_DEVICE); + err_skbuffs_map: + dev_kfree_skb(hw_ctx->rx_ring.skbuffs[i]); + } + + dma_free_coherent(&${ctx}->pci_dev->dev, hw_ctx->rx_ring.size, + hw_ctx->rx_ring.base, hw_ctx->rx_ring.dma_base); + err_rx_ring_alloc: + return -ENOMEM; + } + } + + template sequence e1000::free_rx_tx(Ethernet::Device ctx) + { + chunk ::CALL + { + } } diff --git a/rathaxes/samples/e1000/e1000.rti b/rathaxes/samples/e1000/e1000.rti --- a/rathaxes/samples/e1000/e1000.rti +++ b/rathaxes/samples/e1000/e1000.rti @@ -1,6 +1,9 @@ interface e1000 : Socket, Ethernet, PCI, LKM { provided type e1000::Context; + provided type e1000::RxDescriptor; + provided type e1000::RxRing; + /* * These two types should actually be registers definitions in the frontend: */ @@ -57,6 +60,11 @@ provided chunk ::CALL; } + provided sequence e1000::free_rx_tx(Ethernet::Device dev) + { + provided chunk ::CALL; + } + provided sequence e1000::handle_interrupt(Ethernet::Device) { provided chunk ::CALL; diff --git a/rathaxes/samples/e1000/ethernet.blt b/rathaxes/samples/e1000/ethernet.blt --- a/rathaxes/samples/e1000/ethernet.blt +++ b/rathaxes/samples/e1000/ethernet.blt @@ -102,7 +102,7 @@ { static int rtx_ethernet_close(struct net_device *dev) { - struct rtx_ethernet_dev* rtx_ether_dev = netdev_priv(dev); + struct rtx_ethernet_dev* rtx_ether_dev = netdev_priv(dev); struct rtx_e1000_ctx* ctx = &rtx_ether_dev->hw_ctx; ${pointcut ::IMPLEMENTATION(local.rtx_ether_dev)}; diff --git a/rathaxes/samples/e1000/lkm.rtx b/rathaxes/samples/e1000/lkm.rtx --- a/rathaxes/samples/e1000/lkm.rtx +++ b/rathaxes/samples/e1000/lkm.rtx @@ -24,7 +24,17 @@ Ethernet::close(Ethernet::Device dev) { Log::info("closing the device"); + + /* + * Note: some calls to release resources must be done when IRQs are + * enabled (dma_free_coherent() for example). So we have to cleanup our + * stuff before free_interrupt_handler(). + */ + e1000::free_rx_tx(dev); + Log::info("free'ed up skbuffs"); + e1000::free_interrupt_handler(dev); + Log::info("interrupt handler free'ed"); } Ethernet::interrupt_handler(Ethernet::Device dev) @@ -61,4 +71,11 @@ PCI::set_master = true; Ethernet::ifname = "rtx%d"; + + e1000::rx_ring_size = 256; /* Number of incoming packets we can buffer */ + /* + * The e1000 supports seven receive buffer sizes: 256, 512, 1024, 2048, + * 4096, 8192 and 16384 bytes: + */ + e1000::rx_buffer_len = 2048; }