# HG changeset patch # User Louis Opter # Date 1375005043 25200 # Node ID 52402232483fca8156cf7fb15402e423b38d735a # Parent 6f600f83a7637655b6892217adde91c5dc02e117 WIP on the split up of e1000::set_up_device diff -r 6f600f83a763 -r 52402232483f rathaxes_samples_e1000_split_set_up_device.patch --- a/rathaxes_samples_e1000_split_set_up_device.patch Sat Jul 27 16:08:40 2013 -0700 +++ b/rathaxes_samples_e1000_split_set_up_device.patch Sun Jul 28 02:50:43 2013 -0700 @@ -1,20 +1,709 @@ # HG changeset patch -# Parent 069883bfa2ec71faaf7ab957bc35db087eacc3cc +# Parent d62a08753da7cec4d44246b747ff79847d9b4238 rathaxes: split and refactor e1000::set_up_device in {Rx,Tx}Ring methods - 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 -@@ -752,8 +752,10 @@ - */ - for (i = 0; i != ${config.rx_ring_size}; ++i) - { -+ /* XXX #46: */ -+ // hw_ctx->rx_ring.skbuffs[i].skbuff = ${rtx_ether_ctx.net_device.alloc_rx_skb(${config.rx_buffer_len})}; - hw_ctx->rx_ring.skbuffs[i].skbuff = (${Socket::AbstractSKBuff}*)netdev_alloc_skb( +@@ -1,4 +1,4 @@ +-with e1000, Ethernet, Socket, PCI, LKM, Log, Builtin ++with e1000, Ethernet, Socket, DMA, PCI, LKM, Log, Builtin + { + template type e1000::RxDescriptor() + { +@@ -96,8 +96,163 @@ + { + } + ++ chunk Ethernet::adapter_init_rx(Ethernet::Device rtx_ether_ctx) ++ { ++ { ++ ${e1000::Context.ref} hw_ctx = &${rtx_ether_ctx}->hw_ctx; ++ ++ /* ++ * Receive initialization (section 14.4): ++ * ++ * 1. Program the receive address, in RAL/RAH; ++ * 2. Initialize the Multicast Table Array; ++ * 3. Program the interrupt mask register (done in ++ * e1000::activate_device_interruption); ++ * 4. Allocate the receive descriptor ring and map it to make it ++ * accessible by the device; ++ * 5. Write the start address of the ring in RDBAL/RDBAH and set ++ * RDLEN (Receive Descriptor Length) to the size of the ring; ++ * 6. Set the RDH/RDT (Receive Descriptor Head/Tail) indexes to the ++ * beginning and end of the ring; ++ * 7. Make sure that RCTL.BSIZE and .BSEX are at 0 to configure the ++ * receive buffer size to 2048 bytes (e1000::rx_buffer_len). ++ * 8. Set RCTL.EN to enable the receiver. ++ * ++ * The ugly casts here are caused by the lack of CNorm unstrict. ++ */ ++ ++ int i; ++ ++ /* 1. Program the receive address */ ++ ++ /* (We should use uint{32,16}_t but CNorm doesn't know them yet) */ ++ rtx_e1000_register_write32(hw_ctx, E1000_RAL, ++ *(unsigned int *)(${rtx_ether_ctx.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 *)(&${rtx_ether_ctx.dev_addr}[4])); ++ rtx_e1000_register_set32(hw_ctx, E1000_RAH, E1000_RAH_AV); ++ ++ ${Log::info("adapter_init_rx: receive address programmed")}; ++ ++ /* 2. Initialize the MTA */ ++ ++ for (i = 0; i != 128; ++i) ++ rtx_e1000_register_write32(hw_ctx, E1000_MTA + i * 4, 0); ++ ++ ${Log::info("adapter_init_rx: MTA init done")}; ++ ++ /* 4. Setup the receive descriptor ring */ ++ ++ /* Allocate the descriptors */ ++ 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( ++ ${rtx_ether_ctx.device}, ++ hw_ctx->rx_ring.size, ++ &hw_ctx->rx_ring.dma_base, ++ GFP_KERNEL); ++ /* XXX ++ * The first arg is recognized as Ethernet::Device instead of ++ * Device::AbstractDevice. ++ */ ++ hw_ctx->rx_ring.base = ${DMA::alloc_coherent( ++ rtx_ether_ctx.device, local.hw_ctx.rx_ring.size, local.hw_ctx.rx_ring.dma_base.dma_handle ++ )}; ++ if (!hw_ctx->rx_ring.base) ++ { ++ ${Log::info("adapter_init_rx: cannot allocate the descriptors for the rx ring")}; ++ goto err_rx_ring_alloc; ++ } ++ ++ ${Log::info("adapter_init_rx: rx descriptors allocated")}; ++ ++ /* ++ * Allocate the skbuffs, map them for DMA, and write their address ++ * in the corresponding descriptor. ++ */ ++ for (i = 0; i != ${config.rx_ring_size}; ++i) ++ { ++ // XXX #46: ${Socket::SKBuff.ref} skbuff = ${rtx_ether_ctx.net_device.alloc_rx_skbuff(config.rx_buffer_len)}; ++ ${Socket::AbstractSKBuff.ref} k_sk_buff = (${Socket::AbstractSKBuff.ref})netdev_alloc_skb( ++ ${rtx_ether_ctx.net_device.k_net_dev}, ${config.rx_buffer_len} ++ ); ++ if (!k_sk_buff) ++ { ++ ${Log::info("adapter_init_rx: cannot allocate a skbuff for the rx ring")}; ++ goto err_skbuffs_alloc; ++ } ++ ${Socket::SKBuff.ref} skbuff = &hw_ctx->rx_ring.skbuffs[i]; ++ // XXX breaks rtxGen: ${local.skbuff.init(local.k_sk_buff)}; ++ skbuff->skbuff = k_sk_buff; ++ skbuff->dma_handle = 0; ++ // XXX #46: ${local.skbuff.map_from(rtx_ether_ctx.device)}; ++ if (rtx_socket_skbuff_map(${local.skbuff}, ${rtx_ether_ctx.device}, RTX_DMA_FROM_DEVICE)) ++ { ++ ${Log::info("adapter_init_rx: cannot dma-map a skbuff for the rx ring")}; ++ goto err_skbuffs_map; ++ } ++ hw_ctx->rx_ring.base[i].buff_addr = cpu_to_le64(${local.skbuff.sk_buff}); ++ } ++ ++ ${Log::info("adapter_init_rx: skbuffs allocated")}; ++ ++ /* 5. Save the emplacement and the size of the ring in RDBA/RDLEN */ ++ rtx_e1000_register_write32(hw_ctx, E1000_RDBAL, hw_ctx->rx_ring.dma_base & 0xffffffff); ++ rtx_e1000_register_write32(hw_ctx, E1000_RDBAH, hw_ctx->rx_ring.dma_base >> 32); ++ rtx_e1000_register_write32(hw_ctx, E1000_RDLEN, hw_ctx->rx_ring.size); ++ ++ /* 6. Setup RDH/RDT */ ++ rtx_e1000_register_write32(hw_ctx, E1000_RDH, 0); ++ rtx_e1000_register_write32(hw_ctx, E1000_RDT, ${config.rx_ring_size} - 1); ++ ++ /* 7. Configure the buffer size, */ ++ rtx_e1000_register_set32(hw_ctx, E1000_RCTL, E1000_RCTL_BSIZE_${config.rx_buffer_len}); ++ ++ /* 8. Enable the receiver */ ++ rtx_e1000_register_set32(hw_ctx, E1000_RCTL, E1000_RCTL_EN); ++ ++ ${Log::info("adapter_init_rx: receive registers configured and receiver enabled")}; ++ ++ /* ++ * XXX: We can't return here since we are not in a function but ++ * in a chunk of code (injected in a function). ++ */ ++ goto init_rx_ok; ++ ++ err_skbuffs_alloc: ++ while (i--) ++ { ++ dma_unmap_single( ++ ${rtx_ether_ctx.device}, ++ hw_ctx->rx_ring.skbuffs[i].dma_handle, ++ ${config.rx_buffer_len}, ++ DMA_FROM_DEVICE); ++ err_skbuffs_map: ++ /* XXX leaking cast: */ ++ dev_kfree_skb((struct sk_buff *)hw_ctx->rx_ring.skbuffs[i].skbuff); ++ } ++ ++ dma_free_coherent(${rtx_ether_ctx.device}, hw_ctx->rx_ring.size, ++ hw_ctx->rx_ring.base, hw_ctx->rx_ring.dma_base); ++ err_rx_ring_alloc: ++ /* ++ * XXX: Likewise, if there is something else to rollback in the ++ * enclosing function, this won't be done. ++ */ ++ return -ENOMEM; ++ ++ init_rx_ok: (void)0; /* NOP, to make this a valid label. */ ++ } ++ } ++ + map + { ++ size: ((${self}).size); ++ dma_base: ((${self}).dma_base); + } + } + +@@ -208,7 +363,62 @@ + } + } + +- method clean() ++ chunk Ethernet::adapter_init_tx(Ethernet::Device rtx_ether_ctx) ++ { ++ { ++ ${e1000::Context.ref} hw_ctx = &${rtx_ether_ctx}->hw_ctx; ++ ++ /* ++ * Transmission initialization (section 14.5): ++ * ++ * 1. Allocate the transmit descriptors ring and map it to make it ++ * accessible by the device; ++ * 2. Write the start address of the ring in TDBAL/TDBAH and set ++ * TDLEN to the size of the ring; ++ * 3. Set the TDH/TDT indexes to the beginning and end of the ring; ++ * 4. Set TCTL.PSP to pad short packets and TCTL.EN to enable the ++ * transmitter. ++ */ ++ ++ /* 1. Allocate the tx ring */ ++ hw_ctx->tx_ring.size = ${config.tx_ring_size} * sizeof(*hw_ctx->tx_ring.base); ++ hw_ctx->tx_ring.size = ALIGN(hw_ctx->tx_ring.size, 4096); ++ hw_ctx->tx_ring.base = dma_alloc_coherent( ++ ${rtx_ether_ctx.device}, ++ hw_ctx->tx_ring.size, ++ &hw_ctx->tx_ring.dma_base, ++ GFP_KERNEL); ++ if (!hw_ctx->rx_ring.base) ++ { ++ ${Log::info("adapter_init_tx: cannot allocate the descriptors for the tx ring")}; ++ /* ++ * XXX: If there is something else to rollback in the enclosing ++ * function, this won't be done. ++ */ ++ return -ENOMEM; ++ } ++ ++ ${Log::info("adapter_init_tx: tx descriptors allocated")}; ++ ++ /* 2. Save the emplacement and the size of the ring in TDBA/TDLEN */ ++ rtx_e1000_register_write32(hw_ctx, E1000_TDBAL, hw_ctx->tx_ring.dma_base & 0xffffffff); ++ rtx_e1000_register_write32(hw_ctx, E1000_TDBAH, hw_ctx->tx_ring.dma_base >> 32); ++ rtx_e1000_register_write32(hw_ctx, E1000_TDLEN, hw_ctx->tx_ring.size); ++ ++ /* 3. Setup TDH/TDT to zero: the queue is empty */ ++ rtx_e1000_register_write32(hw_ctx, E1000_TDH, 0); ++ rtx_e1000_register_write32(hw_ctx, E1000_TDT, 0); ++ hw_ctx->tx_ring.head = 0; ++ hw_ctx->tx_ring.tail = 0; ++ ++ /* 4. Set TCTL.PSP and enable the transmitter */ ++ rtx_e1000_register_set32(hw_ctx, E1000_TCTL, E1000_TCTL_PSP|E1000_TCTL_EN); ++ ++ ${Log::info("adapter_init_tx: transmit registers configured and transmitter enabled")}; ++ } ++ } ++ ++ method clean() + { + rtx_e1000_tx_ring_clean(${self}); + } +@@ -247,9 +457,8 @@ + { + int bars; + unsigned char /* __iomem */ *ioaddr; +- +- ${e1000::RxRing} rx_ring; +- ${e1000::TxRing} tx_ring; ++ ${e1000::RxRing.scalar} rx_ring; ++ ${e1000::TxRing.scalar} tx_ring; + } + + chunk Ethernet::HardwareContext() +@@ -309,10 +518,53 @@ + } + } + ++ chunk Ethernet::adapter_setup(Ethernet::Device rtx_ether_ctx) ++ { ++ { ++ ${e1000::Context.ref} hw_ctx = &${rtx_ether_ctx}->hw_ctx; ++ ++ /* ++ * "General Configuration" (section 14.3): ++ * ++ * - CTRL.ASDE/CTRL.SLU: Let the PHY handle the speed detection & ++ * negociation; ++ * - CTRL.LRST/FRCSPD: Unset them to initiate the auto-negociation; ++ * - CTRL.PHY_RST: Unset it; ++ * - CTRL.ILOS: Unset it (ILOS is Invert Loss Of Signal); ++ * - CTRL.VME: Make sure it's not set to disable VLAN support; ++ * - Set the control flow registers to 0; ++ * - Finally, initialize all the statistic registers from ++ * E1000_CRCERRS to E1000_TSCTFC. ++ */ ++ rtx_e1000_register_set32(hw_ctx, E1000_CTRL, ++ E1000_CMD_ASDE | ++ E1000_CMD_SLU); ++ 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(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); ++ /* ++ * XXX: Using int i clashes with another int i from the ++ * "parent" chunk: ++ */ ++ for (int j = 0; j != 64; ++j) ++ rtx_e1000_register_write32(hw_ctx, E1000_CRCERRS + j * 4, 0); ++ ++ ${Log::info("adapter_setup: general configuration done")}; ++ } ++ } ++ + map + { ++ rx_ring: ((${self})->rx_ring); ++ //tx_ring: ((${self})->tx_ring); + } +- + } + + template type e1000::Register() +@@ -615,269 +867,6 @@ + } + } + +- /* TODO: refactor +- * +- * Split into two method methods: +- * - e1000::RxRing::init_rx() +- * - e1000::TxRing::init_tx() +- * +- * Also it should use the new methods in Socket::SKbuff. +- */ +- template sequence set_up_device(Ethernet::Device rtx_ether_ctx) +- { +- chunk ::CALL() +- { +- /* +- * 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.ref} hw_ctx; +- hw_ctx = &${rtx_ether_ctx}->hw_ctx; +- +- /* +- * "General Configuration" (section 14.3): +- * +- * - CTRL.ASDE/CTRL.SLU: Let the PHY handle the speed detection & +- * negociation; +- * - CTRL.LRST/FRCSPD: Unset them to initiate the auto-negociation; +- * - CTRL.PHY_RST: Unset it; +- * - CTRL.ILOS: Unset it (ILOS is Invert Loss Of Signal); +- * - CTRL.VME: Make sure it's not set to disable VLAN support; +- * - Set the control flow registers to 0; +- * - Finally, initialize all the statistic registers from +- * E1000_CRCERRS to E1000_TSCTFC. +- */ +- +- int i; +- +- rtx_e1000_register_set32(hw_ctx, E1000_CTRL, +- E1000_CMD_ASDE | +- E1000_CMD_SLU); +- 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(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); +- for (i = 0; i != 64; ++i) +- rtx_e1000_register_write32(hw_ctx, E1000_CRCERRS + i * 4, 0); +- +- { +- ${Log::info("setup_device: general configuration done")}; +- } +- +- /* +- * Receive initialization (section 14.4): +- * +- * 1. Program the receive address, in RAL/RAH; +- * 2. Initialize the Multicast Table Array; +- * 3. Program the interrupt mask register (done in +- * e1000::activate_device_interruption); +- * 4. Allocate the receive descriptor ring and map it to make it +- * accessible by the device; +- * 5. Write the start address of the ring in RDBAL/RDBAH and set +- * RDLEN (Receive Descriptor Length) to the size of the ring; +- * 6. Set the RDH/RDT (Receive Descriptor Head/Tail) indexes to the +- * beginning and end of the ring; +- * 7. Make sure that RCTL.BSIZE and .BSEX are at 0 to configure the +- * receive buffer size to 2048 bytes (e1000::rx_buffer_len). +- * 8. Set RCTL.EN to enable the receiver. +- * +- * The ugly casts here are caused by the lack of CNorm unstrict. +- */ +- +- /* 1. Program the receive address */ +- +- /* (We should use uint{32,16}_t but CNorm doesn't know them yet) */ +- rtx_e1000_register_write32(hw_ctx, E1000_RAL, +- *(unsigned int *)(${rtx_ether_ctx.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 *)(&${rtx_ether_ctx.dev_addr}[4])); +- rtx_e1000_register_set32(hw_ctx, E1000_RAH, E1000_RAH_AV); +- +- { +- ${Log::info("setup_device: receive address programmed")}; +- } +- +- /* 2. Initialize the MTA */ +- +- for (i = 0; i != 128; ++i) +- rtx_e1000_register_write32(hw_ctx, E1000_MTA + i * 4, 0); +- +- { +- ${Log::info("setup_device: MTA init done")}; +- } +- +- /* 4. Setup the receive descriptor ring */ +- +- /* Allocate the descriptors */ +- 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( +- ${rtx_ether_ctx.device}, +- 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; +- } +- +- { +- ${Log::info("setup_device: rx descriptors allocated")}; +- } +- +- /* +- * Allocate the skbuffs, map them for DMA, and write their address +- * in the corresponding descriptor. +- */ +- for (i = 0; i != ${config.rx_ring_size}; ++i) +- { +- hw_ctx->rx_ring.skbuffs[i].skbuff = (${Socket::AbstractSKBuff}*)netdev_alloc_skb( - ${rtx_ether_ctx.net_device.k_net_dev}, /* XXX: .k_net_dev isn't expanded here */ -+ ${rtx_ether_ctx.net_device.k_net_dev}, - ${config.rx_buffer_len}); - if (!hw_ctx->rx_ring.skbuffs[i].skbuff) - { +- ${config.rx_buffer_len}); +- if (!hw_ctx->rx_ring.skbuffs[i].skbuff) +- { +- ${Log::info("cannot allocate a skbuff for the rx ring")}; +- goto err_skbuffs_alloc; +- } +- hw_ctx->rx_ring.skbuffs[i].dma_handle = dma_map_single( +- ${rtx_ether_ctx.device}, +- (struct sk_buff *)hw_ctx->rx_ring.skbuffs[i].skbuff, /* XXX leaking cast */ +- ${config.rx_buffer_len}, +- DMA_FROM_DEVICE); +- int dma_error = dma_mapping_error(${rtx_ether_ctx.device}, +- hw_ctx->rx_ring.skbuffs[i].dma_handle); +- if (dma_error) +- { +- ${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.skbuffs[i].skbuff); +- } +- +- ${Log::info("setup_device: skbuffs allocated")}; +- +- /* 5. Save the emplacement and the size of the ring in RDBA/RDLEN */ +- rtx_e1000_register_write32(hw_ctx, E1000_RDBAL, hw_ctx->rx_ring.dma_base & 0xffffffff); +- rtx_e1000_register_write32(hw_ctx, E1000_RDBAH, hw_ctx->rx_ring.dma_base >> 32); +- rtx_e1000_register_write32(hw_ctx, E1000_RDLEN, hw_ctx->rx_ring.size); +- +- /* 6. Setup RDH/RDT */ +- rtx_e1000_register_write32(hw_ctx, E1000_RDH, 0); +- rtx_e1000_register_write32(hw_ctx, E1000_RDT, ${config.rx_ring_size} - 1); +- +- /* 7. Configure the buffer size, */ +- rtx_e1000_register_set32(hw_ctx, E1000_RCTL, E1000_RCTL_BSIZE_${config.rx_buffer_len}); +- +- /* 8. Enable the receiver */ +- rtx_e1000_register_set32(hw_ctx, E1000_RCTL, E1000_RCTL_EN); +- +- ${Log::info("setup_device: receive registers configured and receiver enabled")}; +- +- /* +- * Transmission initialization (section 14.5): +- * +- * 1. Allocate the transmit descriptors ring and map it to make it +- * accessible by the device; +- * 2. Write the start address of the ring in TDBAL/TDBAH and set +- * TDLEN to the size of the ring; +- * 3. Set the TDH/TDT indexes to the beginning and end of the ring; +- * 4. Set TCTL.PSP to pad short packets and TCTL.EN to enable the +- * transmitter. +- */ +- +- /* +- * XXX: at this point we must be careful to not fuck up with i, or +- * we are going go have surprises in `err_skbuffs_alloc`. Maybe it's +- * time to separate the rx and tx initialization in two functions. +- */ +- +- /* 1. Allocate the tx ring */ +- hw_ctx->tx_ring.size = ${config.tx_ring_size} * sizeof(*hw_ctx->tx_ring.base); +- hw_ctx->tx_ring.size = ALIGN(hw_ctx->tx_ring.size, 4096); +- hw_ctx->tx_ring.base = dma_alloc_coherent( +- ${rtx_ether_ctx.device}, +- hw_ctx->tx_ring.size, +- &hw_ctx->tx_ring.dma_base, +- GFP_KERNEL); +- if (!hw_ctx->rx_ring.base) +- { +- ${Log::info("cannot allocate the descriptors for the tx ring")}; +- goto err_tx_ring_alloc; +- } +- +- ${Log::info("setup_device: tx descriptors allocated")}; +- +- /* 2. Save the emplacement and the size of the ring in TDBA/TDLEN */ +- rtx_e1000_register_write32(hw_ctx, E1000_TDBAL, hw_ctx->tx_ring.dma_base & 0xffffffff); +- rtx_e1000_register_write32(hw_ctx, E1000_TDBAH, hw_ctx->tx_ring.dma_base >> 32); +- rtx_e1000_register_write32(hw_ctx, E1000_TDLEN, hw_ctx->tx_ring.size); +- +- /* 3. Setup TDH/TDT to zero: the queue is empty */ +- rtx_e1000_register_write32(hw_ctx, E1000_TDH, 0); +- rtx_e1000_register_write32(hw_ctx, E1000_TDT, 0); +- hw_ctx->tx_ring.head = 0; +- hw_ctx->tx_ring.tail = 0; +- +- /* 4. Set TCTL.PSP and enable the transmitter */ +- rtx_e1000_register_set32(hw_ctx, E1000_TCTL, E1000_TCTL_PSP|E1000_TCTL_EN); +- +- ${Log::info("transmit registers configured and transmitter enabled")}; +- +- /* +- * XXX: We can't return here since we are not in a function but in +- * a chunk of code (injected in a function). +- */ +- goto ok; +- +- err_tx_ring_alloc: +- /* +- * Likewise, 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( +- ${rtx_ether_ctx.device}, +- hw_ctx->rx_ring.skbuffs[i].dma_handle, +- ${config.rx_buffer_len}, +- DMA_FROM_DEVICE); +- err_skbuffs_map: +- /* XXX leaking cast: */ +- dev_kfree_skb((struct sk_buff *)hw_ctx->rx_ring.skbuffs[i].skbuff); +- } +- +- dma_free_coherent(${rtx_ether_ctx.device}, hw_ctx->rx_ring.size, +- hw_ctx->rx_ring.base, hw_ctx->rx_ring.dma_base); +- err_rx_ring_alloc: +- return -ENOMEM; +- +- ok: +- } +- } +- + /* TODO: + * + * Refactor into two methods (one in RxRing and one in TxRing) and make use +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,23 +1,10 @@ +-interface e1000 : Socket, Ethernet, PCI, LKM, Builtin ++interface e1000 : Socket, Ethernet, DMA, PCI, LKM, Builtin + { + required variable Builtin::number rx_ring_size; + required variable Builtin::number tx_ring_size; + required variable Builtin::number rx_buffer_len; + required variable Builtin::number tx_max_data_per_desc; + +- provided type Context +- { +- chunk Ethernet::HardwareContext(); +- decl data_types(); +- +- /* Callbacks/Hooks which should probably be in the front-end: */ +- chunk Ethernet::adapter_init_context(Ethernet::Device, +- Builtin::number, +- Builtin::symbol); +- chunk Ethernet::adapter_reset(Ethernet::Device); +- chunk Ethernet::adapter_load_mac_address(Ethernet::Device); +- } +- + provided type RxDescriptor + { + chunk LKM::includes(); +@@ -35,6 +22,32 @@ + { + decl data_types(); + method init(); ++ ++ /* XXX: Callback that should be in the front-end: */ ++ chunk Ethernet::adapter_init_rx(Ethernet::Device); ++ ++ attribute DMA::DMAHandle.scalar dma_base; ++ attribute Builtin::number.scalar size; ++ } ++ ++ provided type Context ++ { ++ chunk Ethernet::HardwareContext(); ++ decl data_types(); ++ ++ /* XXX: ++ * These callbacks/Hooks which should probably be in the front-end. ++ * Also, I'm not too happy about the names, it's difficult to make ++ * the difference between the probe and open parts. ++ */ ++ chunk Ethernet::adapter_init_context(Ethernet::Device, ++ Builtin::number, ++ Builtin::symbol); ++ chunk Ethernet::adapter_reset(Ethernet::Device); ++ chunk Ethernet::adapter_load_mac_address(Ethernet::Device); ++ chunk Ethernet::adapter_setup(Ethernet::Device); ++ ++ attribute RxRing.scalar rx_ring; + } + + provided type TxRing +@@ -44,6 +57,9 @@ + decl data_types(); + method init(); + ++ /* XXX: Callback that should be in the front-end: */ ++ chunk Ethernet::adapter_init_tx(Ethernet::Device); ++ + /* Clean the ring (i.e: move the head closer to the tail): */ + method clean(); + /* Return the number of clean descriptors left in the ring: */ +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 +@@ -170,6 +170,9 @@ + ${Log::info("Cannot register the interrupt handler")}; + return error; + } ++ ${pointcut Ethernet::adapter_setup(local.rtx_ether_ctx)}; ++ ${pointcut Ethernet::adapter_init_rx(local.rtx_ether_ctx)}; ++ ${pointcut Ethernet::adapter_init_tx(local.rtx_ether_ctx)}; + ${pointcut ::IMPLEMENTATION(local.rtx_ether_ctx)}; + + return 0; +diff --git a/rathaxes/samples/e1000/ethernet.rti b/rathaxes/samples/e1000/ethernet.rti +--- a/rathaxes/samples/e1000/ethernet.rti ++++ b/rathaxes/samples/e1000/ethernet.rti +@@ -52,6 +52,15 @@ + provided chunk LKM::includes(); + provided chunk LKM::prototypes(); + provided chunk LKM::code(); ++ ++ /* ++ * For e1000, this part is documented in the Intel Gigabit Ethernet ++ * Controller Software Developper manual. (You can find it in the ++ * doc/hardware directory). ++ */ ++ provided pointcut Ethernet::adapter_setup(Ethernet::Device); ++ provided pointcut Ethernet::adapter_init_rx(Ethernet::Device); ++ provided pointcut Ethernet::adapter_init_tx(Ethernet::Device); + } + + required sequence send(Ethernet::Device, Socket::AbstractSKBuff) +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 +@@ -4,10 +4,6 @@ + { + Log::info("opening the device"); + +- +- e1000::set_up_device(dev); +- Log::info("device activated"); +- + e1000::activate_device_interruption(dev); + Log::info("interruption enabled"); + +diff --git a/rathaxes/samples/e1000/socket.rti b/rathaxes/samples/e1000/socket.rti +--- a/rathaxes/samples/e1000/socket.rti ++++ b/rathaxes/samples/e1000/socket.rti +@@ -15,6 +15,10 @@ + decl data_types(); + method init(Socket::AbstractSKBuff); + method dump_infos(); ++ /* ++ * map_to and map_from return a non-zero value on failure (which ++ * doesn't correspond to an errno value): ++ */ + method map_to(Device::AbstractDevice); + method map_from(Device::AbstractDevice); + method unmap_to_and_free(Device::AbstractDevice);