# HG changeset patch # User Louis Opter # Date 1388942501 -3600 # Node ID f2e4dd91dc6f219b3897f2c68640274fad70cf84 # Parent c209851a82de75e31bde2ae65a4f9926558714cb Wip, leave some "functions" empty but start some build tests diff -r c209851a82de -r f2e4dd91dc6f rathaxes_sample_e1000_rewrite_device_dependent_code.patch --- a/rathaxes_sample_e1000_rewrite_device_dependent_code.patch Fri Jan 03 15:01:47 2014 +0100 +++ b/rathaxes_sample_e1000_rewrite_device_dependent_code.patch Sun Jan 05 18:21:41 2014 +0100 @@ -6,7 +6,9 @@ new file mode 100644 --- /dev/null +++ b/notes.txt -@@ -0,0 +1,9 @@ +@@ -0,0 +1,26 @@ ++Remarks for David & Lionel: ++ +- Too much changes to not start over; +- Lack of methods is extremely annoying and requires a lot of workarounds (e.g: + see the register read/write/set/unset methods on e1000::Context); @@ -15,24 +17,35 @@ + because the ethernet subsystem isn't aware of the type of the field (so I + can't write an attribute). Being able to just inject a type (instead of a + whole structure field) might not be the best solution but would solve this -+ issue/use case. ++ issue/use case; ++- Can I use the same name for a pointcut and a sequence (e.g: Ethernet::send ++ bot a sequence name and a pointcut same thing for the interrupt handler); ++- Lack of support for circular dependencies make some code annoying or ++ incorrect (circular dependencies between abstract and concrete types via the ++ attribute or circular dependencies between the rings and the hardware ++ context). ++ ++Todo/Totry: ++ ++- Use the rtx_ether_ctx attribute on AbstractDevice to initialize Device ++ objects in ethernet.bl; ++- Worry about the code being executed concurrently, e.g: what happens if the ++ interrupt handler is called right before we disable it in the close path? ++ ++Questions: diff --git a/rathaxes/samples/e1000/CMakeLists.txt b/rathaxes/samples/e1000/CMakeLists.txt +old mode 100755 +new mode 100644 --- a/rathaxes/samples/e1000/CMakeLists.txt +++ b/rathaxes/samples/e1000/CMakeLists.txt -@@ -9,7 +9,6 @@ - pci.rti - socket.rti - ethernet.rti -- e1000.rti - BLT - log.blt - lkm.blt -@@ -17,9 +16,8 @@ +@@ -17,9 +17,9 @@ dma.blt pci.blt socket.blt - e1000.blt - ethernet.blt) +- ethernet.blt) ++ ethernet.blt ++ e1000.blt) -IF (LINUX_KBUILD_DIR) - ADD_RATHAXES_LKM(e1000 e1000_src) @@ -40,38 +53,24 @@ +#IF (LINUX_KBUILD_DIR) +# ADD_RATHAXES_LKM(e1000 e1000_src) +#ENDIF (LINUX_KBUILD_DIR) +diff --git a/rathaxes/samples/e1000/dma.blt b/rathaxes/samples/e1000/dma.blt +old mode 100755 +new mode 100644 +diff --git a/rathaxes/samples/e1000/dma.rti b/rathaxes/samples/e1000/dma.rti +old mode 100755 +new mode 100644 diff --git a/rathaxes/samples/e1000/e1000.blt b/rathaxes/samples/e1000/e1000.blt +old mode 100755 +new mode 100644 --- a/rathaxes/samples/e1000/e1000.blt +++ b/rathaxes/samples/e1000/e1000.blt -@@ -170,14 +170,15 @@ - for (i = 0; i != ${config.rx_ring_size}; ++i) - { - ${Socket::SKBuff.ref} skbuff = &hw_ctx->rx_ring.skbuffs[i]; -- // XXX #46: ${rtx_ether_ctx.init_rx_skbuff(local.skbuff, config.rx_buffer_len)}; -- if (rtx_ethernet_init_rx_skbuff(${local.skbuff}, ${config.rx_buffer_len})) -+ // XXX #46: ${rtx_ether_ctx.alloc_rx_skbuff(local.skbuff, config.rx_buffer_len)}; -+ if (rtx_ethernet_alloc_rx_skbuff(${local.skbuff}, ${config.rx_buffer_len})) - { - ${Log::info("adapter_init_rx: cannot allocate a skbuff for the rx ring")}; - goto err_skbuffs_alloc; - } -- // 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)) -+ /* XXX: recuperer le dma handle et le placer correctement dans le descripteur. */ -+ ${DMA::map(local.rtx_ether_ctx.device, local.skbuff.data, local.skbuff.len, RTX_DMA_FROM_DEVICE)} -+ if (${DMA::map(local.rtx_ether_ctx.device, local.skbuff.data, local.skbuff.len, RTX_DMA_FROM_DEVICE)}) - { - ${Log::info("adapter_init_rx: cannot dma-map a skbuff for the rx ring")}; - goto err_skbuffs_map; -diff --git a/rathaxes/samples/e1000/e1000ng.blt b/rathaxes/samples/e1000/e1000ng.blt -new file mode 100755 ---- /dev/null -+++ b/rathaxes/samples/e1000/e1000ng.blt -@@ -0,0 +1,717 @@ -+with e1000ng, Ethernet, Socket, DMA, PCI, LKM, Log, Builtin -+{ +@@ -1,8 +1,148 @@ + with e1000, Ethernet, Socket, DMA, PCI, LKM, Log, Builtin + { +- template type e1000::RxDescriptor() + template type e1000::Register() -+ { + { +- decl data_types() + decl data_types() + { + E1000_CTRL = 0x00000, /* Device Control - RW */ @@ -213,20 +212,21 @@ + template type e1000::RxDescriptor() + { + decl data_types() -+ { -+ __le64 buff_addr; -+ __le16 length; -+ __le16 csum; -+ unsigned char status; -+ unsigned char errors; -+ __le16 special; -+ } -+ + { + __le64 buff_addr; + __le16 length; +@@ -12,13 +152,39 @@ + __le16 special; + } + +- chunk LKM::includes() + map -+ { -+ } + { +- #include + } + } -+ + +- method init() + // This is a generic tx descriptor for the e1000. When you use TCP + // Segmentation Offload (TSO) the hardware actually uses two types of + // tx descriptors in its tx ring: @@ -237,7 +237,7 @@ + template type e1000::TxDescriptor() + { + decl data_types() -+ { + { + __le64 buff_addr; + union { + __le32 data; @@ -255,23 +255,56 @@ + __le16 special; + } fields; + } upper; -+ } -+ -+ map -+ { -+ } -+ } -+ + } + + map +@@ -26,44 +192,131 @@ + } + } + +- /* +- * This is a generic tx descriptor for the e1000. When you use TCP +- * Segmentation Offload (TSO) the hardware actually uses two types of +- * tx descriptors in its tx ring: +- * - context descriptors: this descriptor doesn't actually point to data to +- * send but initialize the offloading engine for the data descriptor that +- * follow; +- * - data descriptors: this descriptor points to data from the skbuffs. +- */ +- template type e1000::TxDescriptor() + template type e1000::Buffer() -+ { + { +- decl data_types() + decl data_types() -+ { + { +- __le64 buff_addr; +- union +- { +- __le32 data; +- struct +- { +- __le16 length; +- unsigned char csum_offset; /* CSO */ +- unsigned char cmd; +- } fields; +- } lower; +- union +- { +- __le32 data; +- struct +- { +- unsigned char status; +- unsigned char csum_start; /* CSS */ +- __le16 special; +- } fields; +- } upper; + ${Socket::SKBuff} sk_buff; + ${DMA::DMAHandle} dma; -+ } -+ + } + +- method init() + method init(Socket::SKBuff sk_buff, DMA::DMAHandle dma) -+ { + { + ${self.sk_buff} = ${sk_buff}; + ${self.dma} = ${dma}; + } @@ -283,7 +316,7 @@ + } + } + -+ template type e1000::MMIO ++ template type e1000::MMIO() + { + decl data_types() + { @@ -328,22 +361,22 @@ + ${self.io} = ${io}; + } + -+ method read32(${e1000::Register} reg) ++ method read32(e1000::Register reg) + { + ioread32(${self.io} + ${local.reg}); + } + -+ method write32(${e1000::Register} reg, ${Builtin::number} value) ++ method write32(e1000::Register reg, Builtin::number value) + { + iowrite32(${local.value}, ${self.io} + ${local.reg}); + } + -+ method set32(${e1000::Register} reg, ${Builtin::number} value) ++ method set32(e1000::Register reg, Builtin::number value) + { + iowrite32(ioread32(${self.io} + ${local.reg}) | value, ${self.io} + ${local.reg}); + } + -+ method unset32(${e1000::Register} reg, ${Builtin::number} value) ++ method unset32(e1000::Register reg, Builtin::number value) + { + iowrite32(ioread32(${self.io} + ${local.reg}) & ~value, ${self.io} + ${local.reg}); + } @@ -387,21 +420,44 @@ + method init(e1000::MMIO io, Builtin::number desc_count, Builtin::number desc_size) + { + rtx_e1000_ring_init(&${self}, ${io}, ${desc_count}, ${desc_size}); -+ } -+ } -+ + } + + map +@@ -71,32 +324,27 @@ + } + } + +- /* +- * Ring of e1000::RxDescriptors and their corresponding skbuffs. +- * +- * - size: total size of the ring in bytes. +- * - base: address of the ring (we can't use the typedef here until we get +- * CNorm unstrict); +- * - dma_base: (physical) address of the ring where the device can access +- * the different descriptors; +- * - skbuffs: array of the skbuffs and their dma (physical) address +- * associated with each descriptor. +- */ +- template type e1000::RxRing() + template type e1000::RxRing() -+ { + { +- decl data_types() + decl data_types() -+ { + { +- unsigned int size; +- ${e1000::RxDescriptor.ref} base; +- dma_addr_t dma_base; +- ${Socket::SKBuff} skbuffs[${config.rx_ring_size}]; + ${e1000::Ring} ring; -+ } -+ + } + +- method init() + chunk LKM::prototypes() -+ { + { + static int rtx_e1000_alloc_rx_ressources(${e1000::RxRing.ref}); -+ } -+ + } + +- chunk Ethernet::adapter_init_rx(Ethernet::Device rtx_ether_ctx) + chunk LKM::code() + { + static int rtx_e1000_alloc_rx_ressources(${e1000::RxRing.ref} self) @@ -411,264 +467,652 @@ + } + + 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, -+ 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) -+ { -+ ${Socket::SKBuff.ref} skbuff = &hw_ctx->rx_ring.skbuffs[i]; + { + { + ${e1000::Context.ref} hw_ctx = &${rtx_ether_ctx}->hw_ctx; +@@ -167,18 +415,16 @@ + * Allocate the skbuffs, map them for DMA, and write their address + * in the corresponding descriptor. + */ +- for (i = 0; i != ${config.rx_ring_size}; ++i) +- { ++ for (i = 0; i != ${config.rx_ring_size}; ++i) { + ${Socket::SKBuff.ref} skbuff = &hw_ctx->rx_ring.skbuffs[i]; +- // XXX #46: ${rtx_ether_ctx.init_rx_skbuff(local.skbuff, config.rx_buffer_len)}; +- if (rtx_ethernet_init_rx_skbuff(${local.skbuff}, ${config.rx_buffer_len})) +- { + // XXX #46: ${rtx_ether_ctx.alloc_rx_skbuff(local.skbuff, config.rx_buffer_len)}; -+ if (rtx_ethernet_alloc_rx_skbuff(${local.skbuff}, ${config.rx_buffer_len})) -+ { -+ ${Log::info("adapter_init_rx: cannot allocate a skbuff for the rx ring")}; -+ goto err_skbuffs_alloc; -+ } ++ if (rtx_ethernet_alloc_rx_skbuff(${local.skbuff}, ${config.rx_buffer_len})) { + ${Log::info("adapter_init_rx: cannot allocate a skbuff for the rx ring")}; + goto err_skbuffs_alloc; + } +- // 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)) +- { + /* XXX: recuperer le dma handle et le placer correctement dans le descripteur. */ + ${DMA::map(local.rtx_ether_ctx.device, local.skbuff.data, local.skbuff.len, RTX_DMA_FROM_DEVICE)} -+ if (${DMA::map(local.rtx_ether_ctx.device, local.skbuff.data, local.skbuff.len, 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}; -+ pr_info("rtx_e1k: adapter_init_rx: skbuffs allocated, headlen=%d", skb_headlen((struct sk_buff *)hw_ctx->rx_ring.skbuffs[i - 1].skbuff)); -+ -+ /* 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: ++ if (${DMA::map(local.rtx_ether_ctx.device, local.skbuff.data, local.skbuff.len, RTX_DMA_FROM_DEVICE)}) { + ${Log::info("adapter_init_rx: cannot dma-map a skbuff for the rx ring")}; + goto err_skbuffs_map; + } +@@ -212,8 +458,7 @@ + goto init_rx_ok; + + err_skbuffs_alloc: +- while (i--) +- { + while (i--) { -+ dma_unmap_single( -+ ${rtx_ether_ctx.device}, -+ /* XXX Leaking cast because of the array: */ -+ *((dma_addr_t *)&(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. */ -+ } -+ } -+ + dma_unmap_single( + ${rtx_ether_ctx.device}, + /* XXX Leaking cast because of the array: */ +@@ -238,487 +483,87 @@ + } + } + +- map + method init(e1000::MMIO io, Builtin::number desc_count) -+ { + { +- size: ((${self}).size); +- dma_base: ((${self}).dma_base); +- } +- } +- +- /* +- * Ring of e1000::TxDescriptors, this is a bit similar to the Rx ring except +- * that we don't really have to manage the skbuffs themselves (they are +- * given to use by the kernel). +- * +- * - size: total size of the ring in bytes. +- * - base: address of the ring (we can't use the typedef here until we get +- * CNorm unstrict); +- * - dma_base: (physical) address of the ring where the device can access +- * the different descriptors; +- * - skbuffs: the skbuffs associated with each descriptor of the ring; +- * - head: index on the head of the ring; +- * - tail: index on the tail of the ring. +- * +- * Keep in mind that the head and tail fields are, obviously, not +- * synchronized with TDT/TDH on the device. +- */ +- template type e1000::TxRing() +- { +- decl data_types() +- { +- unsigned int size; +- /* XXX: can't use ${e1000::TxDescriptor} here: */ +- ${e1000::TxDescriptor.ref} base; /* rename to descs */ +- dma_addr_t dma_base; +- ${Socket::SKBuff} skbuffs[${config.tx_ring_size}]; +- unsigned short head; +- unsigned short tail; + ${self.ring.init(local.io, local.desc_count, self.desc_size)}; -+ } -+ + } + +- chunk LKM::prototypes() + method alloc() -+ { + { +- static void rtx_e1000_tx_ring_clean(${e1000::TxRing.ref}); +- static unsigned int rtx_e1000_tx_ring_descriptors_remaining(${e1000::TxRing.ref}); +- static int rtx_e1000_tx_ring_tso_cksum_offload(${e1000::TxRing.ref}, ${Socket::SKBuff.ref}); +- static void rtx_e1000_tx_ring_put(${e1000::TxRing.ref}, ${Socket::SKBuff.ref}); +- /* FIXME: See issue #54 */ +- static void rtx_e1000_tx_ring_start_xmit(${e1000::TxRing.ref}, /*const*/ ${e1000::Context.ref}); +- } +- +- chunk LKM::code() +- { +- static void rtx_e1000_tx_ring_clean(${e1000::TxRing.ref} self) +- { +- ${e1000::TxDescriptor.ref} tx_desc; +- bool done; +- +- for (; self->head != self->tail; self->head++) +- { +- tx_desc = &self->base[self->head]; +- done = tx_desc->upper.fields.status & E1000_TXD_STAT_DD; +- if (!done) +- break ; +- } +- +- pr_info("%s: tx_ring_clean: moving head to %d/%d", ${config.name}, self->head, ${config.tx_ring_size}); +- } +- +- static unsigned int rtx_e1000_tx_ring_descriptors_remaining(${e1000::TxRing.ref} self) +- { +- if (self->tail == self->head) /* ring is empty */ +- return 256; /* XXX: ${config.tx_ring_size}; */ +- if (self->tail > self->head) +- /* XXX: ${config.tx_ring_size} */ +- return 256 - (self->tail - self->head); +- return self->head - self->tail; +- } +- +- static int rtx_e1000_tx_ring_tso_cksum_offload(${e1000::TxRing.ref} self, ${Socket::SKBuff.ref} skb) +- { +- ${Socket::AbstractSKBuff.ref} k_skb = skb->skbuff; +- return skb_is_gso(${local.k_skb.k_sk_buff}) || ${local.k_skb.k_sk_buff}->ip_summed == CHECKSUM_PARTIAL; +- } +- +- static void rtx_e1000_tx_ring_put(${e1000::TxRing.ref} self, ${Socket::SKBuff.ref} skb) +- { +- WARN_ON(!skb); +- +- /* +- * Mark it as the last buffer (EOP) and ask the card to +- * insert the Ethernet FCS (Frame Check Sequence). +- * +- * XXX: it sucks to use skb_headlen() here (this part of the +- * code shouldn't be aware of it and use something more +- * abstract. +- */ +- ${Socket::AbstractSKBuff.ref} k_skb = skb->skbuff; +- ${e1000::TxDescriptor.ref} tx_desc = &self->base[self->tail]; +- tx_desc->lower.data = cpu_to_le32( +- E1000_TXD_CMD_EOP | +- E1000_TXD_CMD_IFCS | +- E1000_TXD_CMD_RS | +- skb_headlen(${local.k_skb.k_sk_buff})); +- tx_desc->upper.data = 0; +- tx_desc->buff_addr = cpu_to_le64(${local.skb.dma_handle.k_dma_handle}); +- memcpy(&self->skbuffs[self->tail], ${local.k_skb.k_sk_buff}, sizeof(*${local.k_skb.k_sk_buff})); +- self->tail = (self->tail + 1) % ${config.tx_ring_size}; +- } +- +- /* FIXME: See issue #54 */ +- static void rtx_e1000_tx_ring_start_xmit(${e1000::TxRing.ref} self, /*const*/ ${e1000::Context.ref} hw_ctx) +- { +- pr_info("%s: start_xmit: moving tail to %d/%d", ${config.name}, self->tail, ${config.tx_ring_size}); +- rtx_e1000_register_write32(hw_ctx, E1000_TDT, self->tail); +- } +- } +- +- 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}); +- } +- +- method descriptors_remaining() +- { +- rtx_e1000_tx_ring_descriptors_remaining(${self}); +- } +- +- method tso_cksum_offload(Socket::SKBuff skb) +- { +- } +- +- method put(Socket::SKBuff skb) +- { +- rtx_e1000_tx_ring_put(${self}, &${skb}); +- } +- +- method start_xmit(e1000::Context ctx) +- { +- rtx_e1000_tx_ring_start_xmit(${self}, ${ctx}); +- } +- +- method init() +- { + rtx_e1000_alloc_rx_ressources(${self}); -+ } -+ -+ map -+ { + } + + map + { + descs: ((${self})->descs); // TODO: fix cast pour directement avoir les descs + desc_size: sizeof(/* XXX ${e1000::RxDescriptor} */int); -+ } -+ } -+ + } + } + +- template type e1000::Context() + template type e1000::TxRing() -+ { + { +- decl data_types() + decl data_types() -+ { + { +- int bars; +- unsigned char /* __iomem */ *ioaddr; +- ${e1000::RxRing.scalar} rx_ring; +- ${e1000::TxRing.scalar} tx_ring; + ${e1000::Ring} ring; -+ } -+ + } + +- chunk Ethernet::HardwareContext() + chunk LKM::prototypes() -+ { + { +- /* +- * Force the generation of the structure in the "headers" part, we +- * have to do this since we do not use the structure in this blt +- * (we hacked a bit and used it in ethernet.blt directly). +- */ +- ${e1000::Context} hw_ctx; + static int rtx_e1000_alloc_tx_ressources(${e1000::TxRing.ref}); -+ } -+ + } + +- chunk Ethernet::adapter_init_context(Ethernet::Device rtx_ether_ctx, +- Builtin::number bars, +- Builtin::symbol ioaddr) + chunk LKM::code() -+ { + { + static int rtx_e1000_alloc_tx_ressources(${e1000::TxRing.ref} self) -+ { + { +- ${e1000::Context.ref} hw_ctx = &${rtx_ether_ctx}->hw_ctx; +- hw_ctx->bars = ${bars}; +- hw_ctx->ioaddr = ${ioaddr}; + return 0; -+ } -+ } -+ + } + } + +- chunk Ethernet::adapter_reset(Ethernet::Device rtx_ether_ctx) + method init(e1000::MMIO io, Builtin::number desc_count) -+ { + { +- { +- /* XXX Naming this variable 'hw_ctx' kicks the decl out of the generated code */ +- ${e1000::Context.ref} tmp_hw_ctx = &${rtx_ether_ctx}->hw_ctx; +- rtx_e1000_register_write32(tmp_hw_ctx, E1000_CTRL, E1000_CMD_RST); +- udelay(10); +- } + ${self.ring.init(local.io, local.desc_count, self.desc_size)}; -+ } -+ + } + +- chunk Ethernet::adapter_load_mac_address(Ethernet::Device rtx_ether_ctx) + method alloc() -+ { + { +- { +- ${e1000::Context.ref} hw_ctx = &${rtx_ether_ctx}->hw_ctx; +- /* Shamelessly borrowed from Minix */ +- for (int i = 0; i < 3; ++i) +- { +- rtx_e1000_register_write32(hw_ctx, E1000_EEPROM_READ, (i << 8) | 1); +- int value; +- do +- value = rtx_e1000_register_read32(hw_ctx, E1000_EEPROM_READ); +- while ((value & (1 << 4)) == 0); +- value >>= 16; +- /* +- * NOTE: I'm not sure if Ethernet::Device should be +- * accessed directly here. But since we need to take it in +- * parameter (so we can get back our e1000::Context) it +- * seems inadequate to set this in another way: +- */ +- ${rtx_ether_ctx.dev_addr}[i * 2] = value & 0xff; +- ${rtx_ether_ctx.dev_addr}[i * 2 + 1] = (value >> 8) & 0xff; +- } +- ${Log::info("e1000::create: mac address loaded from the EEPROM")}; +- } +- } +- +- 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")}; +- } + rtx_e1000_alloc_tx_ressources(${self}); -+ } -+ -+ map -+ { + } + + map + { +- rx_ring: ((${self})->rx_ring); +- //tx_ring: ((${self})->tx_ring); XXX Circular dep with Context + descs: ((${self})->descs); // TODO: fix cast pour directement avoir les descs + desc_size: sizeof(/* XXX ${e1000::TxDescriptor} */int); -+ } -+ } -+ + } + } + +- template type e1000::Register() + template type e1000::Context() -+ { + { +- decl data_types() + decl data_types() -+ { + { +- E1000_CTRL = 0x00000, /* Device Control - RW */ +- E1000_CTRL_DUP = 0x00004, /* Device Control Duplicate (Shadow) - RW */ +- E1000_STATUS = 0x00008, /* Device Status - RO */ +- E1000_EEPROM_FLASH = 0x00010, /* EEPROM/Flash Control - RW */ +- E1000_EEPROM_READ = 0x00014, /* EEPROM Read - RW */ +- E1000_CTRL_EXT = 0x00018, /* Extended Device Control - RW */ +- E1000_FLA = 0x0001C, /* Flash Access - RW */ +- E1000_MDIC = 0x00020, /* MDI Control - RW */ +- E1000_IMS = 0x000D0, /* Interrupt Mask Set */ +- E1000_IMC = 0x000D8, /* Interrupt Mask Clear */ +- E1000_ICR = 0x000C0, /* Interrupt Cause Read - R/clr */ +- E1000_FCAL = 0x00028, /* Flow Control Address Low */ +- E1000_FCAH = 0x0002c, /* Flow Control Address High */ +- E1000_FCT = 0x00030, /* Flow Control Type */ +- E1000_RCTL = 0x00100, /* Receive Control */ +- E1000_FCTTV = 0x00170, /* Flow Control Transmit Timer Value */ +- E1000_TCTL = 0x00400, /* Transmit Control */ +- 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 */ +- E1000_RDBAL = 0x02800, /* Receive Descriptor Base Address (Low 32 bits) */ +- E1000_RDBAH = 0x02804, /* Receive Descriptor Base Address (High 32 bits) */ +- E1000_RDLEN = 0x02808, /* Receive Descriptor Length */ +- E1000_RDH = 0x02810, /* Receive Descriptor Head */ +- E1000_RDT = 0x02818, /* Receive Descriptor Tail */ +- E1000_TDBAL = 0x03800, /* Transmit Descriptor Base Address (Low 32 bits) */ +- E1000_TDBAH = 0x03804, /* Transmit Descriptor Base Address (High 33 bits) */ +- E1000_TDLEN = 0x03808, /* Transmit Descriptor Length */ +- E1000_TDH = 0x03810, /* Transmit Descriptor Head */ +- E1000_TDT = 0x03818, /* Transmit Descriptor Tail */ + ${e1000::MMIO} io; + ${e1000::TxRing} tx_ring; + ${e1000::RxRing} rx_ring; -+ } -+ + } + +- method init(Builtin::number value) + chunk LKM::includes() -+ { + { +- ${self} = ${value}; + #include -+ } -+ + } + +- map +- { +- } +- } +- +- template type e1000::Commands() +- { +- decl data_types() +- { +- E1000_CMD_FD = 0x00000001, /* Full duplex.0=half; 1=full */ +- E1000_CMD_BEM = 0x00000002, /* Endian Mode.0=little,1=big */ +- E1000_CMD_PRIOR = 0x00000004, /* Priority on PCI. 0=rx,1=fair */ +- E1000_CMD_GIO_MASTER_DISABLE = 0x00000004, /* Blocks new Master requests */ +- E1000_CMD_LRST = 0x00000008, /* Link reset. 0=normal,1=reset */ +- E1000_CMD_TME = 0x00000010, /* Test mode. 0=normal,1=test */ +- E1000_CMD_SLE = 0x00000020, /* Serial Link on 0=dis,1=en */ +- E1000_CMD_ASDE = 0x00000020, /* Auto-speed detect enable */ +- E1000_CMD_SLU = 0x00000040, /* Set link up (Force Link) */ +- E1000_CMD_ILOS = 0x00000080, /* Invert Loss-Of Signal */ +- E1000_CMD_SPD_SEL = 0x00000300, /* Speed Select Mask */ +- E1000_CMD_SPD_10 = 0x00000000, /* Force 10Mb */ +- E1000_CMD_SPD_100 = 0x00000100, /* Force 100Mb */ +- E1000_CMD_SPD_1000 = 0x00000200, /* Force 1Gb */ +- E1000_CMD_BEM32 = 0x00000400, /* Big Endian 32 mode */ +- E1000_CMD_FRCSPD = 0x00000800, /* Force Speed */ +- E1000_CMD_FRCDPX = 0x00001000, /* Force Duplex */ +- E1000_CMD_D_UD_EN = 0x00002000, /* Dock/Undock enable */ +- E1000_CMD_D_UD_POLARITY = 0x00004000, /* Defined polarity of Dock/Undock indication in SDP[0] */ +- E1000_CMD_FORCE_PHY_RESET = 0x00008000, /* Reset both PHY ports, through PHYRST_N pin */ +- E1000_CMD_EXT_LINK_EN = 0x00010000, /* enable link status from external LINK_0 and LINK_1 pins */ +- E1000_CMD_SWDPIN0 = 0x00040000, /* SWDPIN 0 value */ +- E1000_CMD_SWDPIN1 = 0x00080000, /* SWDPIN 1 value */ +- E1000_CMD_SWDPIN2 = 0x00100000, /* SWDPIN 2 value */ +- E1000_CMD_SWDPIN3 = 0x00200000, /* SWDPIN 3 value */ +- E1000_CMD_SWDPIO0 = 0x00400000, /* SWDPIN 0 Input or output */ +- E1000_CMD_SWDPIO1 = 0x00800000, /* SWDPIN 1 input or output */ +- E1000_CMD_SWDPIO2 = 0x01000000, /* SWDPIN 2 input or output */ +- E1000_CMD_SWDPIO3 = 0x02000000, /* SWDPIN 3 input or output */ +- E1000_CMD_RST = 0x04000000, /* Global reset */ +- E1000_CMD_RFCE = 0x08000000, /* Receive Flow Control enable */ +- E1000_CMD_TFCE = 0x10000000, /* Transmit flow control enable */ +- E1000_CMD_RTE = 0x20000000, /* Routing tag enable */ +- E1000_CMD_VME = 0x40000000, /* IEEE VLAN mode enable */ +- E1000_CMD_PHY_RST = 0x80000000, /* PHY Reset */ +- E1000_CMD_SW2FW_INT = 0x02000000, /* Initiate an interrupt to manageability engine */ +- E1000_INTR_TXDW = 0x00000001, /* Transmit desc written back */ +- E1000_INTR_TXQE = 0x00000002, /* Transmit Queue empty */ +- E1000_INTR_LSC = 0x00000004, /* Link Status Change */ +- E1000_INTR_RXSEQ = 0x00000008, /* rx sequence error */ +- 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_RAH_AV = (1 << 31), /* Set the MAC Address as Valid */ +- E1000_RCTL_EN = (1 << 1), /* Receiver Enable */ +- E1000_RCTL_BSEX = (1 << 25), /* Buffer Size Extension */ +- E1000_RCTL_BSIZE_256 = ((1 << 16) | (1 << 17)), +- E1000_RCTL_BSIZE_512 = (1 << 17), +- E1000_RCTL_BSIZE_1024 = (1 << 16), +- E1000_RCTL_BSIZE_2048 = 0, +- E1000_RCTL_BSIZE_4096 = (E1000_RCTL_BSEX | (1 << 16) | (1 << 17)), +- E1000_RCTL_BSIZE_8192 = (E1000_RCTL_BSEX | (1 << 17)), +- E1000_RCTL_BSIZE_16384 = (E1000_RCTL_BSEX | (1 << 16)), +- E1000_TCTL_EN = (1 << 1), /* Transmitter Enable */ +- E1000_TCTL_PSP = (1 << 3), /* Pad Short Packet */ +- } +- +- map +- { +- } +- } +- +- template type e1000::TxDescriptorFlags() +- { +- decl data_types() +- { +- E1000_TXD_DTYP_D = 0x00100000, /* Data Descriptor */ +- E1000_TXD_DTYP_C = 0x00000000, /* Context Descriptor */ +- E1000_TXD_POPTS_IXSM = 0x01, /* Insert IP checksum */ +- E1000_TXD_POPTS_TXSM = 0x02, /* Insert TCP/UDP checksum */ +- E1000_TXD_CMD_EOP = 0x01000000, /* End of Packet */ +- E1000_TXD_CMD_IFCS = 0x02000000, /* Insert FCS (Ethernet CRC) */ +- E1000_TXD_CMD_IC = 0x04000000, /* Insert Checksum */ +- E1000_TXD_CMD_RS = 0x08000000, /* Report Status */ +- E1000_TXD_CMD_RPS = 0x10000000, /* Report Packet Sent */ +- E1000_TXD_CMD_DEXT = 0x20000000, /* Descriptor extension (0 = legacy) */ +- E1000_TXD_CMD_VLE = 0x40000000, /* Add VLAN tag */ +- E1000_TXD_CMD_IDE = 0x80000000, /* Enable Tidv register */ +- E1000_TXD_STAT_DD = 0x00000001, /* Descriptor Done */ +- E1000_TXD_STAT_EC = 0x00000002, /* Excess Collisions */ +- E1000_TXD_STAT_LC = 0x00000004, /* Late Collisions */ +- E1000_TXD_STAT_TU = 0x00000008, /* Transmit underrun */ +- E1000_TXD_CMD_TCP = 0x01000000, /* TCP packet */ +- E1000_TXD_CMD_IP = 0x02000000, /* IP packet */ +- E1000_TXD_CMD_TSE = 0x04000000, /* TCP Seg enable */ +- E1000_TXD_STAT_TC = 0x00000004, /* Tx Underrun */ +- } +- +- map +- { +- } +- } +- +- /* TODO: make that a method of e1000::Context */ +- template sequence e1000::print_status(Ethernet::Device rtx_ether_ctx) +- { +- chunk LKM::prototypes() + chunk LKM::prototypes() -+ { -+ static void rtx_e1000_print_status(${e1000::Context.ref}); -+ } -+ + { + static void rtx_e1000_print_status(${e1000::Context.ref}); + } + +- chunk LKM::code() + chunk LKM::code() -+ { -+ static void rtx_e1000_print_status(${e1000::Context.ref} hw_ctx) -+ { + { + static void rtx_e1000_print_status(${e1000::Context.ref} hw_ctx) + { +- unsigned int status = rtx_e1000_register_read32(hw_ctx, E1000_STATUS); +- ${Log::info("card status:")}; +- /* +- * we can't use Log::info below because it just accept a string +- * (as opposed to a format string with its parameters). +- */ + unsigned int status = rtx_e1000_reg_read32(hw_ctx, E1000_STATUS); + ${Log::info("card status:")}; + // XXX We can't use Log::info below because it just accept a + // string (as opposed to a format string with its parameters): -+ pr_info("\tRegister value: 0x%x\n", status); -+ pr_info("\tMode: %s\n", (status & 1) ? "Full": "Half"); -+ pr_info("\tLink: %s\n", (status & 2) ? "Up" : "Down"); -+ pr_info("\tTransmission: %s\n", (status & 4) ? "Paused" : "Ok"); -+ pr_info("\tInterface: %s\n", (status & 3) == 3 ? "Up" : "Down"); -+ } -+ } -+ + pr_info("\tRegister value: 0x%x\n", status); + pr_info("\tMode: %s\n", (status & 1) ? "Full": "Half"); + pr_info("\tLink: %s\n", (status & 2) ? "Up" : "Down"); +@@ -727,300 +572,178 @@ + } + } + +- chunk ::CALL() + chunk Ethernet::HardwareContext() -+ { + { +- rtx_e1000_print_status(&${rtx_ether_ctx}->hw_ctx); +- } +- } +- +- /* +- * We should have been able to do something along those lines, but +- * it didn't work so we made the call manually. +- * +- * Ideally: +- * ${e1000::register_read32(rtx_ether_ctx->hw_ctx, E1000_STATUS)}; +- * +- * Ideally2, not sure about the syntax on the register parameter: +- * ${e1000::register_read32(rtx_ether_ctx->hw_ctx, ${e1000::Register.E1000_STATUS})}; +- * +- * "Acceptable": +- * ${e1000::Register} reg_status; +- * ${e1000.init(E1000_STATUS); // didn't work, so we used the next line +- * reg_status = E1000_STATUS; +- * ${e1000::register_read32(rtx_ether_ctx->hw_ctx, reg_status)}; +- * +- * TODO: make them methods of e1000::Context +- */ +- template sequence e1000::register_read32(e1000::Context ctx, e1000::Register reg_offset) +- { +- chunk LKM::prototypes() +- { +- /* FIXME: See issue #54 */ +- static unsigned int rtx_e1000_register_read32(/*const*/ ${e1000::Context.ref}, unsigned int); + ${e1000::Context} hw_ctx; -+ } -+ + } + +- chunk LKM::code() + chunk Ethernet::adapter_init_context(Ethernet::Device rtx_ether_ctx, Builtin::symbol ioaddr) -+ { -+ { + { +- /* FIXME: See issue #54 */ +- static unsigned int rtx_e1000_register_read32(/*const*/ ${e1000::Context.ref} ctx, unsigned int reg_offset) + { +- return ioread32(ctx->ioaddr + reg_offset); + ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx; + ${local.hw_ctx.io.init(local.ioaddr)}; + ${local.hw_ctx.rx_ring.init(local.hw_ctx.io, config.rx_ring_size)}; + ${local.hw_ctx.tx_ring.init(local.hw_ctx.io, config.tx_ring_size)}; -+ } -+ } -+ + } + } + +- chunk ::CALL() + chunk Ethernet::adapter_reset(Ethernet::Device rtx_ether_ctx) -+ { -+ { + { +- rtx_e1000_register_read32(${ctx}, ${reg_offset}); +- } +- } +- +- template sequence e1000::register_write32(e1000::Context ctx, e1000::Register reg_offset, ::number value) +- { +- chunk LKM::prototypes() +- { +- /* FIXME: See issue #54 */ +- static void rtx_e1000_register_write32(/*const*/ ${e1000::Context.ref}, unsigned int, unsigned int); +- } +- +- chunk LKM::code() +- { +- /* FIXME: See issue #54 */ +- static void rtx_e1000_register_write32(/*const*/ ${e1000::Context.ref} ctx, unsigned int reg_offset, unsigned int value) + { +- iowrite32(value, ctx->ioaddr + reg_offset); + ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx; + // XXX #46: ${local.hw_ctx.io.write32(E1000_CTRL, E1000_CMD_RST)}; + rtx_e1000_reg_write32(hw_ctx, E1000_CTRL, E1000_CMD_RST); + udelay(10); // TODO: abstract this too... + ${Log::info("adapter has been reset")}; -+ } -+ } -+ + } + } + +- chunk ::CALL() + chunk Ethernet::adapter_load_mac_address(Ethernet::Device rtx_ether_ctx) -+ { + { +- rtx_e1000_register_write32(${ctx}, ${reg_offset}, ${value}); +- } +- } + { + ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx; + // Shamelessly borrowed from Minix @@ -686,16 +1130,44 @@ + ${local.rtx_ether_ctx.dev_addr}[i * 2] = value & 0xff; + ${local.rtx_ether_ctx.dev_addr}[i * 2 + 1] = (value >> 8) & 0xff; + } -+ + +- template sequence e1000::register_set32(e1000::Context ctx, e1000::Register reg_offset, ::number value) +- { +- chunk LKM::prototypes() +- { +- /* FIXME: See issue #54 */ +- static void rtx_e1000_register_set32(/*const*/ ${e1000::Context.ref}, unsigned int, unsigned int); +- } +- +- chunk LKM::code() +- { +- /* FIXME: See issue #54 */ +- static void rtx_e1000_register_set32(/*const*/ ${e1000::Context.ref} ctx, unsigned int reg_offset, unsigned int value) +- { +- iowrite32(rtx_e1000_register_read32(ctx, reg_offset) | value, ctx->ioaddr + reg_offset); + ${Log::info("mac address loaded from the EEPROM")}; -+ } -+ } -+ + } + } + +- chunk ::CALL() ++ // For e1000, this part is documented in the Intel Gigabit Ethernet ++ // Controller Software Developper manual. (You can find it in the ++ // doc/hardware directory). + chunk Ethernet::adapter_setup_rx_tx(Ethernet::Device rtx_ether_ctx) -+ { + { +- rtx_e1000_register_set32(${ctx}, ${reg_offset}, ${value}); +- } +- } + { + ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx; -+ + +- template sequence e1000::register_unset32(e1000::Context ctx, e1000::Register reg_offset, ::number value) +- { +- chunk LKM::prototypes() +- { +- /* FIXME: See issue #54 */ +- static void rtx_e1000_register_unset32(/*const*/ ${e1000::Context.ref}, unsigned int, unsigned int); +- } + // "General Configuration" (section 14.3): + // + // - CTRL.ASDE/CTRL.SLU: Let the PHY handle the speed detection & @@ -722,13 +1194,23 @@ + rtx_e1000_reg_write32(hw_ctx, E1000_FCTTV, 0); + for (int i = 0; i != 64; ++i) + rtx_e1000_reg_write32(hw_ctx, E1000_CRCERRS + i * 4, 0); -+ + +- chunk LKM::code() +- { +- /* FIXME: See issue #54 */ +- static void rtx_e1000_register_unset32(/*const*/ ${e1000::Context.ref} ctx, unsigned int reg_offset, unsigned int value) +- { +- iowrite32(rtx_e1000_register_read32(ctx, reg_offset) & ~value, ctx->ioaddr + reg_offset); + ${Log::info("adapter_setup: general configuration done")}; -+ } -+ } -+ + } + } + +- chunk ::CALL() + chunk Ethernet::adapter_enable_interrupts(Ethernet::Device) -+ { + { +- rtx_e1000_register_unset32(${ctx}, ${reg_offset}, ${value}); +- } +- } + { + ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx; + rtx_e1000_reg_write32( @@ -737,15 +1219,129 @@ + E1000_INTR_TXDW|E1000_INTR_TXQE|E1000_INTR_LSC| + E1000_INTR_RXO|E1000_INTR_RXT0 + ); -+ + +- template sequence activate_device_interruption(Ethernet::Device rtx_ether_ctx) +- { +- chunk ::CALL() +- { +- rtx_e1000_register_write32(&${rtx_ether_ctx}->hw_ctx, E1000_IMS, +- E1000_INTR_TXDW | +- E1000_INTR_TXQE | +- E1000_INTR_LSC | +- E1000_INTR_RXO | +- E1000_INTR_RXT0); +- } +- } +- +- /* TODO: +- * +- * Refactor into two methods (one in RxRing and one in TxRing) and make use +- * of the new methods in Socket::SKBuff. +- */ +- template sequence free_rx_tx(Ethernet::Device rtx_ether_ctx) +- { +- chunk ::CALL() +- { +- /* +- * XXX: Not generated if named "hw_ctx" (which is funny because +- * it's used and works in the template right above this one): +- */ +- ${e1000::Context.ref} hw_ctx_; +- hw_ctx_ = &${rtx_ether_ctx}->hw_ctx; +- +- /* +- * Free the rx ring: +- * - Unmap and free the skbuffs; +- * - Free the descriptors array. +- */ +- for (int i = 0; i != ${config.rx_ring_size}; ++i) +- { +- /* +- * XXX Leaking casts: +- * +- * We should go through the rtx types (Socket::SKBuff, +- * AbstractSKBuff), but we can't because of the array here, +- * which is not supported by the compiler. +- */ +- dma_unmap_single( +- ${rtx_ether_ctx.device}, +- *((dma_addr_t *)&(hw_ctx_->rx_ring.skbuffs[i].dma_handle)), +- ${config.rx_buffer_len}, +- DMA_FROM_DEVICE); +- 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); +- ${Log::info("free_rx_tx: rx ring free'ed")}; +- +- /* +- * Free the tx ring: +- * - Free the descriptors array. +- */ +- dma_free_coherent(${rtx_ether_ctx.device}, hw_ctx_->tx_ring.size, +- hw_ctx_->tx_ring.base, hw_ctx_->tx_ring.dma_base); +- ${Log::info("free_rx_tx: tx ring free'ed")}; +- } +- } +- +- template sequence handle_interrupt(Ethernet::Device rtx_ether_ctx) +- { +- chunk ::CALL() +- { +- unsigned int icr = rtx_e1000_register_read32(&${rtx_ether_ctx}->hw_ctx, E1000_ICR); +- pr_info("%s: interrupt received, ICR: 0x%x", ${config.name}, icr); +- if (icr) +- { +- if (icr & E1000_INTR_LSC) +- { +- ${Log::info("handle_interrupt: cable link status changed, dumping card status:")}; +- ${e1000::print_status(rtx_ether_ctx)}; +- } +- if (icr & (E1000_INTR_TXQE|E1000_INTR_TXDW)) +- { +- ${Log::info("handle_interrupt: TxRing: packet(s) sent")}; +- /* +- * XXX Do a Rathaxes call (how can I bind +- * "&${rtx_ether_ctx}->hw_ctx.tx_ring" to e1000::TxRing easily?) +- */ +- rtx_e1000_tx_ring_clean(&${rtx_ether_ctx}->hw_ctx.tx_ring); +- } +- if (icr & E1000_INTR_RXT0) +- { +- ${Log::info("handle_interrupt: RxRing: packet(s) received")}; +- } +- if (icr & E1000_INTR_RXO) +- { +- ${Log::info("handle_interrupt: RxRing: overrun")}; +- } +- +- return IRQ_HANDLED; + // XXX We should probably move that elsewhere (it just used to + // be done right after we enabled interrupts when this was + // still in lkm.rtx): -+ ${local.hw_ctx.print_status()}; -+ } ++ // XXX #46: ${local.hw_ctx.print_status()}; ++ rtx_e1000_print_status(hw_ctx); + } + } +- } + +- template sequence e1000::xmit(Ethernet::Device rtx_ether_ctx, Socket::AbstractSKBuff kernel_skb) +- { +- chunk ::CALL() ++ chunk Ethernet::disable_interrupts(Ethernet::Device rtx_ether_ctx) + { +- /* +- * Put packets on the TX ring, must return NETDEV_TX_OK or +- * NETDEV_TX_BUSY. +- */ ++ { ${Log::info("adapter_disable_interrupts: TBD...")}; } + } -+ -+ chunk Ethernet::handle_interrupt(Ethernet::Device rtx_ether_ctx) + +- ${Socket::SKBuff} skb; +- ${e1000::Context.ref} hw_ctx; +- ${e1000::TxRing.ref} tx_ring; +- ${Device::AbstractDevice.ref} devp; ++ chunk Ethernet::adapter_handle_interrupt(Ethernet::Device rtx_ether_ctx) + { + { + ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx; @@ -754,7 +1350,8 @@ + if (icr) { + if (icr & E1000_INTR_LSC) { + ${Log::info("handle_interrupt: cable link status changed, dumping card status:")}; -+ ${local.hw_ctx.print_status()}; ++ // XXX #46: ${local.hw_ctx.print_status()}; ++ rtx_e1000_print_status(hw_ctx); + } + if (icr & (E1000_INTR_TXQE|E1000_INTR_TXDW)) { + ${Log::info("handle_interrupt: TxRing: packet(s) sent")}; @@ -765,38 +1362,122 @@ + if (icr & E1000_INTR_RXO) { + ${Log::info("handle_interrupt: RxRing: overrun")}; + } -+ + +- ${local.skb.init(kernel_skb)}; +- hw_ctx = &${rtx_ether_ctx}->hw_ctx; +- tx_ring = &hw_ctx->tx_ring; +- devp = (${Device::AbstractDevice.ref})${rtx_ether_ctx.device}; + // XXX: This sucks since we don't know the pointcut context: + return IRQ_HANDLED; + } + } + } -+ + +- ${Log::info("xmit: skbuff details:")}; +- /* +- * skb does not expand on the bound C variable (should be +- * rtx_skbuff), which is funny because it works for the +- * sequence template call right after. +- */ +- /* +- * XXX: doesn't work (I tried to pass self explicitely too): +- * ${local.skb.dump_infos()}; +- */ +- rtx_socket_skbuff_dump_infos(&skb); ++ chunk Ethernet::adapter_xmit(Ethernet::Device rtx_ether_ctx, Socket::SKBuff rtx_skb) ++ { ++ { ${Log::info("adapter_xmit: TBD...")}; } ++ } + +- /* +- * The transmission is going to be several steps: +- * 1. TCP Segmentation Offload & Checksum Offloading: pick a +- * descriptor from the tx ring and fill it as a context +- * descriptor to allow the card to slice into several packets +- * according to the MSS; +- * 2. DMA Map the skbuff data as slices of 4096; +- * 3. Signal the hardware that data is available via a tx desc. +- */ ++ chunk Ethernet::adapter_disable_rx(Ethernet::Device rtx_ether_ctx) ++ { ++ { ${Log::info("adapter_disable_rx: TBD..")}; } ++ } + +- /* XXX: same thing wanted to use: ${local.tx_ring.descriptors_remaining()} */ +- if (!rtx_e1000_tx_ring_descriptors_remaining(tx_ring)) +- return NETDEV_TX_BUSY; ++ chunk Ethernet::adpater_disable_tx(Ethernet::Device rtx_ether_ctx) ++ { ++ { ${Log::info("adapter_disable_tx: TBD..")}; } ++ } + +- /* 1. Offloading */ ++ chunk Ethernet::adapter_free_rx_tx(Ethernet::Device rtx_ether_ctx) ++ { ++ { ${Log::info("adapter_free_rx_tx: TBD..")}; } ++ } + +- /* XXX: ${local.tx_ring.tso_cksum_offload(skb)}; */ +- if (rtx_e1000_tx_ring_tso_cksum_offload(tx_ring, &skb)) +- { +- ${Log::info("xmit: the packet needs to be fragmented and/or checksummed but this not implemented yet!")}; +- goto err_offload; +- } + +- /* 2. Map the data */ + method print_status() + { + rtx_e1000_print_status(${self}); + } -+ + +- /* XXX: ${local.skb.map_to(devp.k_device)}; */ +- if (rtx_socket_skbuff_map(&skb, ${devp.k_device}, DMA_TO_DEVICE)) +- { +- ${Log::info("xmit: can't DMA map a SKbuff")}; +- goto err_skb_map_to; +- } +- +- /* 3. Update the TX Ring and signal the hardware */ +- +- /* XXX: ${local.tx_ring.put(skb)}; */ +- rtx_e1000_tx_ring_put(tx_ring, &skb); +- +- /* XXX: ${local.tx_ring.start_xmit(hw_ctx)}; */ +- rtx_e1000_tx_ring_start_xmit(tx_ring, hw_ctx); +- +- return NETDEV_TX_OK; +- +- err_offload: +- err_skb_map_to: +- /* XXX: ${local.skb.unmap_to_and_free(local.dev)}; */ +- rtx_socket_skbuff_unmap_and_free(&skb, ${devp.k_device}, DMA_TO_DEVICE); +- return NETDEV_TX_OK; + map + { + io: ${self}->io; + rx_ring: ${self}->rx_ring; + tx_ring: ${self}->tx_ring; -+ } -+ } -+} -diff --git a/rathaxes/samples/e1000/e1000ng.rti b/rathaxes/samples/e1000/e1000ng.rti -new file mode 100755 ---- /dev/null -+++ b/rathaxes/samples/e1000/e1000ng.rti -@@ -0,0 +1,122 @@ -+interface e1000ng : Socket, Ethernet, DMA, PCI, LKM, Builtin -+{ + } + } + } +diff --git a/rathaxes/samples/e1000/e1000.rti b/rathaxes/samples/e1000/e1000.rti +old mode 100755 +new mode 100644 +--- a/rathaxes/samples/e1000/e1000.rti ++++ b/rathaxes/samples/e1000/e1000.rti +@@ -1,157 +1,115 @@ + 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; + 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 RxDescriptor + // Hardware values/data structures, should probably be in the front-end: + provided type Register { decl data_types(); } + provided type Command { decl data_types(); } @@ -805,21 +1486,25 @@ + provided type TxDescriptor { decl data_types(); } + + provided type Buffer -+ { -+ decl data_types(); + { +- chunk LKM::includes(); + decl data_types(); +- method init(); + + method init(Socket::SKBuff, DMA::DMAHandle); + + attribute Socket::SKBuff.ref sk_buff; + attribute DMA::DMAHandle.ref dma; -+ } -+ + } + +- provided type TxDescriptor + // I wish we could just leave those methods in the Context type but we also + // need them from the rings and that would mean a circular dependency + // between the context and the rings and Rathaxes can't handle it. + provided type MMIO -+ { -+ decl data_types(); + { + decl data_types(); +- method init(); + + chunk LKM::prototypes(); + chunk LKM::code(); @@ -830,7 +1515,7 @@ + method set32(Register, Builtin::number); + method unset32(Register, Builtin::number); + -+ attribute Builtin::symbol io; ++ attribute Builtin::symbol.scalar io; + } + + provided type Ring @@ -842,24 +1527,29 @@ + + method init(MMIO, Builtin::number, Builtin::number); + -+ attribute MMIO io; -+ attribute DMA:DMAHandle dma; -+ attribute Builtin::number size; // Total size in bytes -+ attribute Builtin::symbol.ref descs; -+ attribute Buffer.ref buffs; -+ } -+ -+ provided type RxRing -+ { -+ decl data_types(); -+ ++ attribute MMIO.scalar io; ++ attribute DMA::DMAHandle.scalar dma; ++ attribute Builtin::number.scalar size; // Total size in bytes ++ attribute Builtin::symbol.ref descs; ++ attribute Buffer.ref buffs; + } + + provided type RxRing + { + decl data_types(); +- method init(); + +- /* XXX: Callback that should be in the front-end: */ +- chunk Ethernet::adapter_init_rx(Ethernet::Device); + chunk LKM::prototypes(); + chunk LKM::code(); -+ + +- attribute DMA::DMAHandle.scalar dma_base; +- attribute Builtin::number.scalar size; + method init(MMIO, Builtin::number); + method alloc(); // Returns != 0 on failure + -+ attribute RxDescriptor descs; ++ attribute RxDescriptor.scalar descs; + } + + provided type TxRing @@ -872,13 +1562,22 @@ + method init(MMIO, Builtin::number); + method alloc(); // Returns != 0 on failure + -+ attribute TxDescriptor descs; -+ } -+ -+ provided type Context -+ { -+ decl data_types(); -+ ++ attribute TxDescriptor.scalar descs; + } + + 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 LKM::includes(); + chunk LKM::prototypes(); + chunk LKM::code(); @@ -886,45 +1585,177 @@ + + // NOTE: Those callbacks/hooks should probably be in the front-end: + -+ // Init the hardware context structure, doesn't allocate anything. + chunk Ethernet::adapter_init_context(Ethernet::Device, Builtin::symbol); -+ -+ // Reset the adapter -+ chunk Ethernet::adapter_reset(Ethernet::Device); -+ -+ // Load the MAC address from the EEPROM and save it into the -+ // dev_addr field/attribute of Ethernet::Device. -+ chunk Ethernet::adapter_load_mac_address(Ethernet::Device); -+ -+ // Prepare the device and the resources for rx/tx. + chunk Ethernet::adapter_reset(Ethernet::Device); + chunk Ethernet::adapter_load_mac_address(Ethernet::Device); +- chunk Ethernet::adapter_setup(Ethernet::Device); + chunk Ethernet::adapter_setup_rx_tx(Ethernet::Device); -+ -+ // Enable interrupts. + chunk Ethernet::adapter_enable_interrupts(Ethernet::Device); -+ -+ // Interrupt handler. -+ chunk Ethernet::handle_interrupt(Ethernet::Device); -+ ++ chunk Ethernet::adapter_disable_interrupts(Ethernet::Device); ++ chunk Ethernet::adapter_handle_interrupt(Ethernet::Device); ++ chunk Ethernet::adapter_xmit(Ethernet::Device, Socket::SKBuff); ++ chunk Ethernet::adapter_disable_rx(Ethernet::Device); ++ chunk Ethernet::adapter_disable_tx(Ethernet::Device); ++ chunk Ethernet::adapter_free_rx_tx(Ethernet::Device); + + method print_status(); + -+ attribute MMIO io; -+ attribute RxRing.scalar rx_ring; ++ attribute MMIO.scalar io; + attribute RxRing.scalar rx_ring; +- /* XXX: circular dependency with Contex: */ +- //attribute TxRing.scalar tx_ring; +- } +- +- provided type TxRing +- { +- chunk LKM::prototypes(); +- chunk LKM::code(); +- 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: */ +- method descriptors_remaining(); +- method tso_cksum_offload(Socket::SKBuff); +- method put(Socket::SKBuff); +- /* Signal the device that new dirty descriptors are on the ring: */ +- method start_xmit(e1000::Context); +- } +- +- /* +- * These two types should actually be registers definitions in the frontend: +- */ +- provided type Register +- { +- decl data_types(); +- method init(Builtin::number); +- } +- +- provided type Commands +- { +- decl data_types(); +- } +- +- provided type TxDescriptorFlags +- { +- decl data_types(); +- } +- +- /* +- * This should take an e1000::Context as the first argument but this was +- * not working as wished. +- */ +- provided sequence print_status(Ethernet::Device) +- { +- provided chunk LKM::prototypes(); +- provided chunk LKM::code(); +- provided chunk ::CALL(); +- } +- +- provided sequence activate_device_interruption(Ethernet::Device) +- { +- provided chunk ::CALL(); +- } +- +- provided sequence set_up_device(Ethernet::Device) +- { +- provided chunk ::CALL(); +- } +- +- provided sequence free_rx_tx(Ethernet::Device dev) +- { +- provided chunk ::CALL(); +- } +- +- provided sequence handle_interrupt(Ethernet::Device) +- { +- provided chunk ::CALL(); +- } +- +- provided sequence xmit(Ethernet::Device, Socket::AbstractSKBuff) +- { +- provided chunk ::CALL(); +- } +- +- provided sequence register_read32(e1000::Context, e1000::Register) +- { +- provided chunk LKM::prototypes(); +- provided chunk LKM::code(); +- provided chunk ::CALL(); +- } +- +- provided sequence register_write32(e1000::Context, e1000::Register, ::number) +- { +- provided chunk LKM::prototypes(); +- provided chunk LKM::code(); +- provided chunk ::CALL(); +- } +- +- provided sequence register_set32(e1000::Context, e1000::Register, ::number) +- { +- provided chunk LKM::prototypes(); +- provided chunk LKM::code(); +- provided chunk ::CALL(); +- } +- +- provided sequence register_unset32(e1000::Context, e1000::Register, ::number) +- { +- provided chunk LKM::prototypes(); +- provided chunk LKM::code(); +- provided chunk ::CALL(); + attribute TxRing.scalar tx_ring; -+ } -+} + } + } diff --git a/rathaxes/samples/e1000/ethernet.blt b/rathaxes/samples/e1000/ethernet.blt +old mode 100755 +new mode 100644 --- a/rathaxes/samples/e1000/ethernet.blt +++ b/rathaxes/samples/e1000/ethernet.blt -@@ -106,7 +106,7 @@ +@@ -1,4 +1,4 @@ +-with Ethernet, PCI, LKM, Log, Builtin ++with Ethernet, Socket, PCI, LKM, Log, Builtin + { + template type Ethernet::ProtocolId() + { +@@ -61,7 +61,7 @@ + + method init(Builtin::symbol dev) + { +- ${self} = (${Ethernet::AbstractDevice} *)${dev}; ++ ${self} = (${Ethernet::AbstractDevice.ref})${dev}; + } + + map +@@ -104,9 +104,12 @@ + { + static int rtx_ethernet_alloc_rx_skbuff(${Ethernet::Device.ref} self, ${Socket::SKBuff.ref} sk_buff, ${Builtin::number} size) { - ${Socket::AbstractSKBuff} k_sk_buff = netdev_alloc_skb(${local.self.net_device.k_net_dev}, ${local.size}); - if (${local.k_sk_buff) { +- ${Socket::AbstractSKBuff} k_sk_buff = netdev_alloc_skb(${local.self.net_device.k_net_dev}, ${local.size}); +- if (${local.k_sk_buff) { - ${local.sk_buff.init(local.k_sk_buff, local.size)}; -+ ${local.sk_buff.init(local.k_sk_buff)}; ++ ${Socket::AbstractSKBuff.ref} k_skb = netdev_alloc_skb(${local.self.net_device.k_net_dev}, ${local.size}); ++ if (${local.k_skb}) { ++ // XXX meh, can't use the init method since we get a copy ++ // of the pointer, so we have to do this which is ++ // inconsistent with the rest of code: ++ sk_buff->skbuff = k_skb; return 0; } return 1; -@@ -164,34 +164,30 @@ +@@ -148,7 +151,7 @@ + } + } + +- template sequence Ethernet::open(Ethernet::Device dev) ++ template sequence Ethernet::open() + { + chunk LKM::includes() + { +@@ -164,60 +167,68 @@ { static int rtx_ethernet_open(struct net_device *dev) { @@ -939,12 +1770,9 @@ ${Ethernet::Device.ref} rtx_ether_ctx = ${local.rtx_net_dev.rtx_ether_ctx}; - int error; -+ ${pointcut Ethernet::adapter_setup_rx_tx(local.rtx_ether_ctx)}; -+ - { +- { - ${Log::info("installing the interrupt handler")}; -+ ${Log::info("Installing the interrupt handler")}; - } +- } - error = request_irq(${local.rtx_ether_ctx.irq}, - rtx_ethernet_interrupt_handler, - IRQF_SHARED, @@ -952,6 +1780,9 @@ - dev); - if (error) - { ++ ${pointcut Ethernet::adapter_setup_rx_tx(local.rtx_ether_ctx)}; ++ ++ ${Log::info("Installing the interrupt handler")}; + int error = request_irq( + ${local.rtx_ether_ctx.irq}, + rtx_ethernet_interrupt_handler, @@ -972,16 +1803,123 @@ return 0; } -@@ -269,7 +265,7 @@ + } ++ ++ /* XXX This chunk should be removed (see #26) */ ++ chunk ::CALL() ++ { ++ } + } + +- template sequence Ethernet::send(Ethernet::Device dev, Socket::AbstractSKBuff skb) ++ template sequence Ethernet::send() + { + chunk LKM::prototypes() + { +- static int rtx_ethernet_xmit(struct sk_buff* skb, struct net_device *dev); ++ static int rtx_ethernet_xmit(struct sk_buff *skb, struct net_device *dev); + } + + chunk LKM::code() + { +- static int rtx_ethernet_xmit(struct sk_buff* kernel_skb, struct net_device *net_dev) ++ static int rtx_ethernet_xmit(struct sk_buff *k_skb, struct net_device *net_dev) + { + ${Ethernet::Device.ref} rtx_ether_ctx = netdev_priv(net_dev); +- ${Socket::AbstractSKBuff.ref} rtx_skb = (${Socket::AbstractSKBuff.ref}) kernel_skb; ++ ${Socket::SKBuff.ref} rtx_skb; + +- ${pointcut ::IMPLEMENTATION(local.rtx_ether_ctx, local.rtx_skb)}; ++ ${cast local.k_skb as Socket::AbstractSKBuff.ref}; ++ ${local.rtx_skb.init(local.k_skb)}; ++ ++ ${Log::info("we have one packet to transmit!")}; ++ ${pointcut Ethernet::adapter_xmit(local.rtx_ether_ctx, local.rtx_skb)}; + } + } ++ ++ /* XXX This chunk should be removed (see #26) */ ++ chunk ::CALL() ++ { ++ } + } + +- template sequence Ethernet::close(Ethernet::Device dev) ++ template sequence Ethernet::close() + { + chunk LKM::prototypes() + { +@@ -226,31 +237,37 @@ + + chunk LKM::code() + { +- static int rtx_ethernet_close(struct net_device *dev) ++ static int rtx_ethernet_close(struct net_device *net_dev) + { +- ${Ethernet::AbstractDevice.ref} rtx_net_dev; +- { /* XXX: I end up with a placeholder if I don't open a scope */ +- ${local.rtx_net_dev.init(local.dev)}; +- } ++ ${cast local.net_dev as Ethernet::AbstractDevice.ref}; ++ ${Ethernet::Device.ref} rtx_ether_ctx = ${local.net_dev.rtx_ether_ctx}; + +- ${Ethernet::Device.ref} rtx_ether_ctx = ${local.rtx_net_dev.rtx_ether_ctx}; ++ ${pointcut Ethernet::adapter_disable_rx(local.rtx_ether_ctx)}; + +- /* TODO: change this pointcut into a pointcut/adapter/callback: */ +- { +- ${pointcut ::IMPLEMENTATION(local.rtx_ether_ctx)}; +- } ++ netif_tx_disable(net_dev); ++ ${pointcut Ethernet::adapter_disable_tx(local.rtx_ether_ctx)}; + ++ ${pointcut Ethernet::adapter_disable_interrupts(local.rtx_ether_ctx)}; + free_irq(${local.rtx_ether_ctx.irq}, dev); +- { +- ${Log::info("interrupt handler free'ed")}; +- } ++ ${Log::info("interrupt handler free'ed")}; ++ ++ // TODO/XXX: There is definitely more stuff to do around here ++ // (e.g: clean the rings, flush some stuff...) ++ ++ ${pointcut Ethernet::adapter_reset(local.rtx_ether_ctx)}; ++ ${pointcut Ethernet::adapter_free_rx_tx(local.rtx_ether_ctx)}; + + return 0; + } + } ++ ++ /* XXX This chunk should be removed (see #26) */ ++ chunk ::CALL() ++ { ++ } + } + +- template sequence Ethernet::interrupt_handler(Ethernet::Device dev) ++ template sequence Ethernet::interrupt_handler() + { + /* + * We can't use the irqreturn_t type here because CNornm doesn't know +@@ -269,11 +286,16 @@ ${Ethernet::Device.ref} rtx_ether_ctx; rtx_ether_ctx = ${local.rtx_net_dev.rtx_ether_ctx}; - ${pointcut ::IMPLEMENTATION(local.rtx_ether_ctx)}; -+ ${pointcut Ethernet::handle_interrupt(local.rtx_ether_ctx)}; ++ ${pointcut Ethernet::adapter_handle_interrupt(local.rtx_ether_ctx)}; return IRQ_NONE; } -@@ -342,12 +338,8 @@ + } ++ ++ /* XXX This chunk should be removed (see #26) */ ++ chunk ::CALL() ++ { ++ } + } + + template sequence Ethernet::init() +@@ -342,12 +364,8 @@ * XXX: the asssignments/casts are here to circumvent * typing issues in the compiler (see previous XXX). */ @@ -995,10 +1933,56 @@ ${pointcut Ethernet::adapter_reset(local.rtx_ether_ctx)}; ${pointcut Ethernet::adapter_load_mac_address(local.rtx_ether_ctx)}; memcpy(${local.rtx_ether_ctx.perm_addr}, +@@ -355,7 +373,7 @@ + ${local.rtx_net_dev.k_net_dev}->addr_len); + } + +- /* This chunk should be removed (see #26) */ ++ /* XXX This chunk should be removed (see #26) */ + chunk ::CALL() + { + } +@@ -377,7 +395,7 @@ + free_netdev(${local.rtx_net_dev.k_net_dev}); + } + +- /* This chunk should be removed (see #26) */ ++ /* XXX This chunk should be removed (see #26) */ + chunk ::CALL() + { + } diff --git a/rathaxes/samples/e1000/ethernet.rti b/rathaxes/samples/e1000/ethernet.rti +old mode 100755 +new mode 100644 --- a/rathaxes/samples/e1000/ethernet.rti +++ b/rathaxes/samples/e1000/ethernet.rti -@@ -28,8 +28,12 @@ +@@ -2,16 +2,16 @@ + { + required variable Builtin::string ifname; + +- provided type ProtocolId +- { +- chunk LKM::prototypes(); +- chunk LKM::data(); +- chunk LKM::code(); +- decl data_types(); ++ provided type ProtocolId ++ { ++ chunk LKM::prototypes(); ++ chunk LKM::data(); ++ chunk LKM::code(); ++ decl data_types(); + +- attribute Builtin::number.scalar id; +- attribute Builtin::string.scalar str; +- } ++ attribute Builtin::number.scalar id; ++ attribute Builtin::string.scalar str; ++ } + + provided type AbstractDevice + { +@@ -28,72 +28,88 @@ provided type Device { @@ -1012,56 +1996,123 @@ pointcut Ethernet::HardwareContext(); method init(Ethernet::AbstractDevice, PCI::AbstractDevice); -@@ -51,7 +55,7 @@ +- /* +- * Alloc (the AbstractSKBuff inside) the given SKBuff and initialize +- * the SKBuff, return 1 if the allocation failed, 0 on success. +- */ ++ ++ // Alloc (the AbstractSKBuff inside) the given SKBuff and initialize ++ // the SKBuff, return 1 if the allocation failed, 0 on success: + method alloc_rx_skbuff(Socket::SKBuff, Builtin::number); + + attribute Device::AbstractDevice.ref device; + attribute PCI::AbstractDevice.ref pci_device; + attribute Ethernet::AbstractDevice.ref net_device; +- /* +- * I'd like to use better names here, but I'd like to understand the +- * difference between the two first: +- */ ++ ++ // I'd like to use better names here, but I'd like to understand the ++ // difference between the two first: + attribute Builtin::symbol.ref perm_addr; + attribute Builtin::symbol.ref dev_addr; attribute Builtin::symbol.scalar irq; } - required sequence open(Ethernet::Device) -+ provided sequence open(Ethernet::Device) ++ provided sequence open() { - provided chunk LKM::includes(); - provided chunk LKM::prototypes(); -@@ -62,9 +66,8 @@ - * Controller Software Developper manual. (You can find it in the - * doc/hardware directory). - */ +- provided chunk LKM::includes(); +- provided chunk LKM::prototypes(); +- provided chunk LKM::code(); ++ 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); ++ // Prepare the device and the resources for rx/tx: + provided pointcut Ethernet::adapter_setup_rx_tx(Ethernet::Device); ++ ++ // Enable interrupts: + provided pointcut Ethernet::adapter_enable_interrupts(Ethernet::Device); } - required sequence send(Ethernet::Device, Socket::AbstractSKBuff) -@@ -79,10 +82,12 @@ - provided chunk LKM::code(); +- required sequence send(Ethernet::Device, Socket::AbstractSKBuff) ++ provided sequence send() + { +- provided chunk LKM::prototypes(); +- provided chunk LKM::code(); ++ provided chunk LKM::prototypes(); ++ provided chunk LKM::code(); ++ ++ // Put a packet on the tx ring and signal the device: ++ provided pointcut Ethernet::adapter_xmit(Ethernet::Device, Socket::SKBuff); + } + +- required sequence close(Ethernet::Device) ++ provided sequence close() + { +- provided chunk LKM::prototypes(); +- provided chunk LKM::code(); ++ provided chunk LKM::prototypes(); ++ provided chunk LKM::code(); ++ ++ provided pointcut Ethernet::adapter_disable_rx(Ethernet::Device); ++ provided pointcut Ethernet::adapter_disable_tx(Ethernet::Device); ++ provided pointcut Ethernet::adapter_disable_interrupts(Ethernet::Device); ++ ++ // Clean and free all resources on the rx/tx rings: ++ provided pointcut Ethernet::adapter_free_rx_tx(Ethernet::Device); } - required sequence interrupt_handler(Ethernet::Device) -+ provided sequence interrupt_handler(Ethernet::Device) ++ provided sequence interrupt_handler() { - provided chunk LKM::prototypes(); - provided chunk LKM::code(); +- provided chunk LKM::prototypes(); +- provided chunk LKM::code(); ++ provided chunk LKM::prototypes(); ++ provided chunk LKM::code(); + -+ provided pointcut Ethernet::handle_interrupt(Ethernet::Device); ++ // Interrupt handler: ++ provided pointcut Ethernet::adapter_handle_interrupt(Ethernet::Device); } - provided sequence init() -@@ -90,9 +95,7 @@ - provided chunk LKM::data(); - provided chunk PCI::pci_probe_hook(PCI::Device); +- provided sequence init() ++ provided sequence init() + { +- provided chunk LKM::data(); +- provided chunk PCI::pci_probe_hook(PCI::Device); ++ provided chunk LKM::data(); ++ provided chunk PCI::pci_probe_hook(PCI::Device); - provided pointcut Ethernet::adapter_init_context(Ethernet::Device, - Builtin::number, - Builtin::symbol); ++ // Init the hardware context structure, doesn't allocate anything: + provided pointcut Ethernet::adapter_init_context(Ethernet::Device, Builtin::symbol); ++ ++ // Reset the adapter: provided pointcut Ethernet::adapter_reset(Ethernet::Device); ++ ++ // Load the MAC address from the EEPROM and save it into the ++ // dev_addr field/attribute of Ethernet::Device: provided pointcut Ethernet::adapter_load_mac_address(Ethernet::Device); } + diff --git a/rathaxes/samples/e1000/lkm.rtx b/rathaxes/samples/e1000/lkm.rtx +old mode 100755 +new mode 100644 --- a/rathaxes/samples/e1000/lkm.rtx +++ b/rathaxes/samples/e1000/lkm.rtx -@@ -1,34 +1,5 @@ +@@ -1,40 +1,5 @@ device LKM use LKM, PCI, Ethernet, Log, Socket { - Ethernet::open(Ethernet::Device dev) @@ -1093,10 +2144,59 @@ - e1000::handle_interrupt(dev); - } - - Ethernet::send(Ethernet::Device dev, Socket::AbstractSKBuff skb) +- Ethernet::send(Ethernet::Device dev, Socket::AbstractSKBuff skb) +- { +- Log::info("we have one packet to transmit!"); +- e1000::xmit(dev, skb); +- } +- + LKM::init() { - Log::info("we have one packet to transmit!"); + Log::info("loading module"); +@@ -50,7 +15,7 @@ + { + LKM::name = "rtx_e1k"; + LKM::author = "Rathaxes"; +- LKM::description = "Hello World Loadable Kernel Module (LKM)"; ++ LKM::description = "Rathaxes Intel PCI Gigabit NIC sample driver"; + LKM::license = "GPL"; + + /* +diff --git a/rathaxes/samples/e1000/e1000.blt b/rathaxes/samples/e1000/old_e1000.blt +old mode 100755 +new mode 100644 +copy from rathaxes/samples/e1000/e1000.blt +copy to rathaxes/samples/e1000/old_e1000.blt +--- a/rathaxes/samples/e1000/e1000.blt ++++ b/rathaxes/samples/e1000/old_e1000.blt +@@ -170,14 +170,15 @@ + for (i = 0; i != ${config.rx_ring_size}; ++i) + { + ${Socket::SKBuff.ref} skbuff = &hw_ctx->rx_ring.skbuffs[i]; +- // XXX #46: ${rtx_ether_ctx.init_rx_skbuff(local.skbuff, config.rx_buffer_len)}; +- if (rtx_ethernet_init_rx_skbuff(${local.skbuff}, ${config.rx_buffer_len})) ++ // XXX #46: ${rtx_ether_ctx.alloc_rx_skbuff(local.skbuff, config.rx_buffer_len)}; ++ if (rtx_ethernet_alloc_rx_skbuff(${local.skbuff}, ${config.rx_buffer_len})) + { + ${Log::info("adapter_init_rx: cannot allocate a skbuff for the rx ring")}; + goto err_skbuffs_alloc; + } +- // 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)) ++ /* XXX: recuperer le dma handle et le placer correctement dans le descripteur. */ ++ ${DMA::map(local.rtx_ether_ctx.device, local.skbuff.data, local.skbuff.len, RTX_DMA_FROM_DEVICE)} ++ if (${DMA::map(local.rtx_ether_ctx.device, local.skbuff.data, local.skbuff.len, RTX_DMA_FROM_DEVICE)}) + { + ${Log::info("adapter_init_rx: cannot dma-map a skbuff for the rx ring")}; + goto err_skbuffs_map; +diff --git a/rathaxes/samples/e1000/e1000.rti b/rathaxes/samples/e1000/old_e1000.rti +old mode 100755 +new mode 100644 +copy from rathaxes/samples/e1000/e1000.rti +copy to rathaxes/samples/e1000/old_e1000.rti diff --git a/rathaxes/samples/e1000/socket.blt b/rathaxes/samples/e1000/socket.blt +old mode 100755 +new mode 100644 --- a/rathaxes/samples/e1000/socket.blt +++ b/rathaxes/samples/e1000/socket.blt @@ -22,16 +22,12 @@ @@ -1117,8 +2217,28 @@ } chunk LKM::code() -@@ -63,85 +59,6 @@ - shinfo->nr_frags, shinfo->gso_size, shinfo->gso_segs, shinfo->gso_type +@@ -52,98 +48,29 @@ + * arguments yet. + */ + pr_info( +- "\t protocol = %#-5x (%s) ip_summed = %d (%s)\n" +- "\t len = %-5u data_len = %-5u head_len = %-5u\n" +- "\t nr_frags = %u\n" +- "\t gso_size = %-5u gso_segs = %-5u gso_type = %-5u", +- /* XXX: can't use ${local.ethernet_proto.id} here (issue #52): */ +- ethernet_proto.id, ${local.ethernet_proto.str}, +- ${local.self.sk_buff.k_sk_buff}->ip_summed, ip_summed_values[${local.self.sk_buff.k_sk_buff}->ip_summed], +- ${local.self.sk_buff.k_sk_buff}->len, ${local.self.sk_buff.k_sk_buff}->data_len, skb_headlen(${local.self.sk_buff.k_sk_buff}), +- shinfo->nr_frags, shinfo->gso_size, shinfo->gso_segs, shinfo->gso_type ++ "\t protocol = %#-5x (%s) ip_summed = %d (%s)\n" ++ "\t len = %-5u data_len = %-5u head_len = %-5u\n" ++ "\t nr_frags = %u\n" ++ "\t gso_size = %-5u gso_segs = %-5u gso_type = %-5u", ++ /* XXX: can't use ${local.ethernet_proto.id} here (issue #52): */ ++ ethernet_proto.id, ${local.ethernet_proto.str}, ++ ${local.self.sk_buff.k_sk_buff}->ip_summed, ip_summed_values[${local.self.sk_buff.k_sk_buff}->ip_summed], ++ ${local.self.sk_buff.k_sk_buff}->len, ${local.self.sk_buff.k_sk_buff}->data_len, skb_headlen(${local.self.sk_buff.k_sk_buff}), ++ shinfo->nr_frags, shinfo->gso_size, shinfo->gso_segs, shinfo->gso_type ); } - @@ -1163,25 +2283,28 @@ - dev_kfree_skb_any(${local.self.sk_buff.k_sk_buff}); - ${local.self.sk_buff} = NULL; - } -- } -- + } + - /* - * XXX: the rathaxes argument kernel_skb is not actually bound to the - * correct C variable from Ethernet::send() (so I named it as the C - * variable I needed) - */ - method init(Socket::AbstractSKBuff kernel_skb, Builtin::number size) -- { ++ method init(Socket::AbstractSKBuff k_skb) + { - ${self.sk_buff} = ${kernel_skb}; - ${self.size} = ${size}; - ${self.dma_handle} = 0; -- } -- ++ ${self} = (${Socket::SKBuff.ref})(${k_skb}); + } + - method dump_infos() -- { -- rtx_socket_skbuff_dump_infos(${self}); -- } -- ++ method dump_infos() + { + rtx_socket_skbuff_dump_infos(${self}); + } + - method map_to(Device::AbstractDevice dev) - { - rtx_socket_skbuff_map(${self}, ${dev}, RTX_DMA_TO_DEVICE); @@ -1200,10 +2323,12 @@ - method unmap_from_and_free(Device::AbstractDevice dev) - { - rtx_socket_skbuff_unmap_and_free(${self}, ${dev}, RTX_DMA_FROM_DEVICE); - } - +- } +- map -@@ -151,13 +68,9 @@ + { + // Some work may have to be done here in order to access to some +@@ -151,13 +78,9 @@ // management can be abstracted from the user. But this is at least // useful for internal use: sk_buff: (${self})->skbuff; @@ -1221,6 +2346,8 @@ } } diff --git a/rathaxes/samples/e1000/socket.rti b/rathaxes/samples/e1000/socket.rti +old mode 100755 +new mode 100644 --- a/rathaxes/samples/e1000/socket.rti +++ b/rathaxes/samples/e1000/socket.rti @@ -12,20 +12,14 @@