# HG changeset patch # User Louis Opter # Date 1389202953 28800 # Node ID dbb4a3b383cb321169fa6ce01f59596b138216b6 # Parent f2e4dd91dc6f219b3897f2c68640274fad70cf84 Wip on build diff -r f2e4dd91dc6f -r dbb4a3b383cb rathaxes_sample_e1000_rewrite_device_dependent_code.patch --- a/rathaxes_sample_e1000_rewrite_device_dependent_code.patch Sun Jan 05 18:21:41 2014 +0100 +++ b/rathaxes_sample_e1000_rewrite_device_dependent_code.patch Wed Jan 08 09:42:33 2014 -0800 @@ -1,12 +1,12 @@ # HG changeset patch -# Parent 7d00455945ec97c5851ac0d735da7c3cfbd8e39c +# Parent 53d3ca9da9c4cd680cf5982b9e972903fb4d3231 rathaxes: rewrite/refactor all the e1000 device dependent code diff --git a/notes.txt b/notes.txt new file mode 100644 --- /dev/null +++ b/notes.txt -@@ -0,0 +1,26 @@ +@@ -0,0 +1,40 @@ +Remarks for David & Lionel: + +- Too much changes to not start over; @@ -23,7 +23,14 @@ +- 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). ++ context); ++- It would be really cool to passthrough the comments; ++- Not being able to use a Rathaxes type in the attributes is really annoying ++ and forces me to hardcode a lot of stuff; ++- Pointcuts are scoped by subsystems which is kinda weird because different ++ subsystems are going to share the same pointcuts (i.e: the PCI and USB ++ susystem are going to expose the same pointcuts that can be used by the ++ Ethernet subsystem). + +Todo/Totry: + @@ -31,11 +38,42 @@ + 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? ++- Why the DMA sequences are taking an AbstractDMAHandle instead of a DMAHandle? + +Questions: ++ ++Compiler bugs: ++ ++- Trying to expand a type that doesn't exists crashes the compiler instead of ++ displaying something more useful (took me 15 minutes to figure out that I ++ typed 3 colons instead of 2 in a placeholder). +diff --git a/rathaxes/compiler/passes/back/rtxIntrospect.inc.cws b/rathaxes/compiler/passes/back/rtxIntrospect.inc.cws +--- a/rathaxes/compiler/passes/back/rtxIntrospect.inc.cws ++++ b/rathaxes/compiler/passes/back/rtxIntrospect.inc.cws +@@ -890,6 +890,8 @@ + local to_remove; + foreach placeHolder in local_node.body.compile + { ++ if (!placeHolder.node.body.type) ++ traceLine(RED + "BUG: placeHolder.node.body.type is missing in rtxIntrospect_walk<\"__rtx_chunk__\">" + DEFAULT_COLOR); + if (rtxIntrospect_InferPlaceHolderTypes(placeHolder.node.body, local_node) == false) + { + pushItem to_remove; +diff --git a/rathaxes/compiler/passes/back/rtxPlaceHolders.inc.cws b/rathaxes/compiler/passes/back/rtxPlaceHolders.inc.cws +--- a/rathaxes/compiler/passes/back/rtxPlaceHolders.inc.cws ++++ b/rathaxes/compiler/passes/back/rtxPlaceHolders.inc.cws +@@ -394,7 +394,10 @@ + { rtxPH_mapPlaceHolder(local_node.expr.id, compile, node_idx, "target_pointcut"); } + } + else ++ { ++ traceLine(CYAN + "LOUIS: local_node.expr: " + toString(local_node.expr) + DEFAULT_COLOR); + rtxPH_compile(local_node.expr, compile, node_idx); ++ } + } + // Label + if (existVariable(local_node.label) && rtxPH_havePlaceHolder(local_node.label)) 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 @@ -17,9 +17,9 @@ @@ -53,215 +91,40 @@ +#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 -@@ -1,8 +1,148 @@ - with e1000, Ethernet, Socket, DMA, PCI, LKM, Log, Builtin +@@ -1,564 +1,8 @@ +-with e1000, Ethernet, Socket, DMA, PCI, LKM, Log, Builtin ++with e1000, Ethernet, Socket, Device, 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 */ -+ 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 */ -+ } -+ -+ 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::TxDescriptorFlag() -+ { -+ 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 -+ { -+ } -+ } -+ -+ template type e1000::RxDescriptor() -+ { -+ decl data_types() - { - __le64 buff_addr; - __le16 length; -@@ -12,13 +152,39 @@ - __le16 special; - } - +- { +- __le64 buff_addr; +- __le16 length; +- __le16 csum; +- unsigned char status; +- unsigned char errors; +- __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: -+ // - 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() -+ { -+ 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; - } - - map -@@ -26,44 +192,131 @@ - } - } - +- { +- } +- +- map +- { +- } +- } +- - /* - * This is a generic tx descriptor for the e1000. When you use TCP - * Segmentation Offload (TSO) the hardware actually uses two types of @@ -272,11 +135,9 @@ - * - 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 - { @@ -298,135 +159,17 @@ - __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}; -+ } -+ -+ map -+ { -+ sk_buff: ${self}->sk_buff; -+ dma: ${self}->dma; -+ } -+ } -+ -+ template type e1000::MMIO() -+ { -+ decl data_types() -+ { -+ unsigned char *io; -+ } -+ -+ // XXX: we'll need those functions until we get working methods (#46): -+ -+ chunk LKM::prototypes() -+ { -+ static unsigned int rtx_e1000_reg_read32(${e1000::MMIO}, ${e1000::Register}); -+ static void rtx_e1000_reg_write32(${e1000:::MMIO}, ${e1000::Register}, ${Builtin::number}); -+ static void rtx_e1000_reg_set32(${e1000:::MMIO}, ${e1000::Register}, ${Builtin::number}); -+ static void rtx_e1000_reg_unset32(${e1000:::MMIO}, ${e1000::Register}, ${Builtin::number}); -+ } -+ -+ chunk LKM::code() -+ { -+ static unsigned int rtx_e1000_reg_read32(${e1000::MMIO} io, ${e1000::Register} reg) -+ { -+ return ioread32(${local.io.io} + reg); -+ } -+ -+ static void rtx_e1000_reg_write32(${e1000:::MMIO} io, ${e1000::Register} reg, ${Builtin::number} value) -+ { -+ return iowrite32(value, ${local.io.io} + reg); -+ } -+ -+ static void rtx_e1000_reg_set32(${e1000:::MMIO} io, ${e1000::Register} reg, ${Builtin::number} value) -+ { -+ return iowrite32(rtx_e1000_reg_read32(io, reg) | value, ${local.io.io} + reg); -+ } -+ -+ static void rtx_e1000_reg_unset32(${e1000:::MMIO} io, ${e1000::Register} reg, ${Builtin::number} value) -+ { -+ return iowrite32(rtx_e1000_reg_read32(io, reg) & ~value, ${local.io.io} + reg); -+ } -+ } -+ -+ method init(Builtin::symbol io) -+ { -+ ${self.io} = ${io}; -+ } -+ -+ method read32(e1000::Register reg) -+ { -+ ioread32(${self.io} + ${local.reg}); -+ } -+ -+ method write32(e1000::Register reg, Builtin::number value) -+ { -+ iowrite32(${local.value}, ${self.io} + ${local.reg}); -+ } -+ -+ 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) -+ { -+ iowrite32(ioread32(${self.io} + ${local.reg}) & ~value, ${self.io} + ${local.reg}); -+ } -+ -+ map -+ { -+ io: ((unsigned char *)(${self})); -+ } -+ } -+ -+ template type e1000::Ring() -+ { -+ decl data_types() -+ { -+ ${e1000::MMIO} io; -+ ${DMA::DMAHandle} dma; -+ ${Builtin::symbol.ref} descs; -+ ${Builtin::number} size; -+ ${e1000::Buffer.ref} buffs; -+ } -+ -+ chunk LKM::prototypes() -+ { -+ static void rtx_e1000_ring_init(${e1000::Ring.ref}, ${e1000::MMIO}, -+ ${Builtin::number}, ${Builtin::number}); -+ } -+ -+ chunk LKM::code() -+ { -+ static void rtx_e1000_ring_init(${e1000::Ring.ref} self, -+ ${e1000::MMIO} io, -+ ${Builtin::number} desc_count, -+ ${Builtin::number} desc_size) -+ { -+ memset(self, 0, sizeof(*self)); -+ self->size = ALIGN(desc_count * desc_size, 4096); -+ self->io = io; -+ } -+ } -+ -+ 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 @@ - } - } - +- { +- } +- +- map +- { +- } +- } +- - /* - * Ring of e1000::RxDescriptors and their corresponding skbuffs. - * @@ -439,79 +182,163 @@ - * 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) -+ { -+ return 0; -+ } -+ } -+ -+ chunk Ethernet::adapter_init_rx(Ethernet::Device rtx_ether_ctx) - { - { - ${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. - */ +- { +- { +- ${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) - { -+ for (i = 0; i != ${config.rx_ring_size}; ++i) { - ${Socket::SKBuff.ref} skbuff = &hw_ctx->rx_ring.skbuffs[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; - } +- ${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; - } -@@ -212,8 +458,7 @@ - goto init_rx_ok; - - err_skbuffs_alloc: +- ${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: - while (i--) - { -+ while (i--) { - dma_unmap_single( - ${rtx_ether_ctx.device}, - /* XXX Leaking cast because of the array: */ -@@ -238,487 +483,87 @@ - } - } - +- 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. */ +- } +- } +- - map -+ method init(e1000::MMIO io, Builtin::number desc_count) - { +- { - size: ((${self}).size); - dma_base: ((${self}).dma_base); - } @@ -545,12 +372,10 @@ - ${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}); @@ -707,70 +532,56 @@ - - method init() - { -+ rtx_e1000_alloc_rx_ressources(${self}); - } - - map - { -+ descs: ((${self})->descs); // TODO: fix cast pour directement avoir les descs -+ desc_size: sizeof(/* XXX ${e1000::RxDescriptor} */int); - } - } - +- } +- +- map +- { +- } +- } +- - 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 */ @@ -835,183 +646,169 @@ - - ${Log::info("adapter_setup: general configuration done")}; - } -+ rtx_e1000_alloc_tx_ressources(${self}); +- } +- +- map +- { +- rx_ring: ((${self})->rx_ring); +- //tx_ring: ((${self})->tx_ring); XXX Circular dep with Context +- } +- } +- +- template type e1000::Register() +- { +- decl data_types() ++ decl data_types() + { + E1000_CTRL = 0x00000, /* Device Control - RW */ + E1000_CTRL_DUP = 0x00004, /* Device Control Duplicate (Shadow) - RW */ +@@ -593,19 +37,14 @@ + E1000_TDT = 0x03818, /* Transmit Descriptor Tail */ } +- method init(Builtin::number value) +- { +- ${self} = ${value}; +- } +- 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() +- template type e1000::Commands() ++ template type e1000::Command() { - 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; + E1000_CMD_FD = 0x00000001, /* Full duplex.0=half; 1=full */ + E1000_CMD_BEM = 0x00000002, /* Endian Mode.0=little,1=big */ +@@ -670,9 +109,9 @@ } - -- 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() -- { ++ template type e1000::TxDescriptorFlag() + { - 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 -- { -- } -- } -- ++ decl data_types() + { + E1000_TXD_DTYP_D = 0x00100000, /* Data Descriptor */ + E1000_TXD_DTYP_C = 0x00000000, /* Context Descriptor */ +@@ -701,326 +140,656 @@ + } + } + - /* TODO: make that a method of e1000::Context */ - template sequence e1000::print_status(Ethernet::Device rtx_ether_ctx) -- { ++ template type e1000::RxDescriptor() + { - chunk LKM::prototypes() ++ decl data_types() ++ { ++ __le64 buff_addr; ++ __le16 length; ++ __le16 csum; ++ unsigned char status; ++ unsigned char errors; ++ __le16 special; ++ } ++ ++ map ++ { ++ } ++ } ++ ++ // 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() ++ { ++ 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; ++ } ++ ++ map ++ { ++ } ++ } ++ ++ template type e1000::Buffer() ++ { ++ decl data_types() ++ { ++ ${Socket::SKBuff} sk_buff; ++ ${DMA::DMAHandle} dma; ++ } ++ ++ method init(Socket::SKBuff sk_buff, DMA::DMAHandle dma) ++ { ++ ${self.sk_buff} = ${sk_buff}; ++ ${self.dma} = ${dma}; ++ } ++ ++ map ++ { ++ sk_buff: ${self}->sk_buff; ++ dma: ${self}->dma; ++ } ++ } ++ ++ template type e1000::Context() ++ { ++ decl data_types() ++ { ++ unsigned char *io_addr; // XXX should be annoted with __iomem ++ // XXX Forced to hardcode the type because there is a circular ++ // dependency between the rings and the context. ++ // TODO: get the right generated types: ++ int tx_ring; ++ int rx_ring; ++ } ++ ++ chunk LKM::includes() ++ { ++ #include ++ } ++ + chunk LKM::prototypes() { static void rtx_e1000_print_status(${e1000::Context.ref}); ++ ++ // XXX Needed until we can call methods (issue #46): ++ static unsigned int rtx_e1000_reg_read32(${e1000::Context}, ${e1000::Register}); ++ static void rtx_e1000_reg_write32(${e1000::Context}, ${e1000::Register}, unsigned int); ++ static void rtx_e1000_reg_set32(${e1000::Context}, ${e1000::Register}, unsigned int); ++ static void rtx_e1000_reg_unset32(${e1000::Context}, ${e1000::Register}, unsigned int); } - 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) ++ static void rtx_e1000_print_status(${e1000::Context.ref} self) { - unsigned int status = rtx_e1000_register_read32(hw_ctx, E1000_STATUS); - ${Log::info("card status:")}; @@ -1019,24 +816,270 @@ - * 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); ++ unsigned int status = rtx_e1000_reg_read32(${local.self}, 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): ++ // XXX We can't use Log::info below because it just accepts a ++ // string (as opposed to a format string with its arguments): 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 @@ + pr_info("\tTransmission: %s\n", (status & 4) ? "Paused" : "Ok"); + pr_info("\tInterface: %s\n", (status & 3) == 3 ? "Up" : "Down"); } ++ ++ static unsigned int rtx_e1000_reg_read32(${e1000::Context} self, ${e1000::Register} reg) ++ { ++ return ioread32(${local.self.io_addr} + reg); ++ } ++ ++ static void rtx_e1000_reg_write32(${e1000::Context} self, ++ ${e1000::Register} reg, ++ unsigned int value) ++ { ++ return iowrite32(value, ${local.self.io_addr.io} + reg); ++ } ++ ++ static void rtx_e1000_reg_set32(${e1000::Context} self, ++ ${e1000::Register} reg, ++ unsigned int value) ++ { ++ return iowrite32( ++ rtx_e1000_reg_read32(${local.self}, reg) | value, ++ ${local.self.io_addr.io} + reg ++ ); ++ } ++ ++ static void rtx_e1000_reg_unset32(${e1000::Context} self, ++ ${e1000::Register} reg, ++ unsigned int value) ++ { ++ return iowrite32(rtx_e1000_reg_read32( ++ ${local.self}, reg) & ~value, ++ ${local.self.io_addr.io} + reg ++ ); ++ } } - chunk ::CALL() -+ chunk Ethernet::HardwareContext() ++ method init(Builtin::symbol io_addr) { - rtx_e1000_print_status(&${rtx_ether_ctx}->hw_ctx); -- } -- } -- ++ ${self.io_addr} = ${io_addr}; ++ } ++ ++ method reg_read32(e1000::Register reg) ++ { ++ ioread32(${self.io_addr} + ${local.reg}); ++ } ++ ++ method reg_write32(e1000::Register reg, Builtin::number value) ++ { ++ iowrite32(${value}, ${self.io_addr} + ${reg}); ++ } ++ ++ method reg_set32(e1000::Register reg, Builtin::number value) ++ { ++ iowrite32(ioread32(${self.io_addr} + ${reg}) | ${value}, ${self.io_addr} + ${reg}); ++ } ++ ++ method reg_unset32(e1000::Register reg, Builtin::number value) ++ { ++ iowrite32(ioread32(${self.io_addr} + ${reg}) & ~${value}, ${self.io_addr} + ${reg}); ++ } ++ ++ chunk Ethernet::HardwareContext() ++ { ++ ${e1000::Context} hw_ctx; ++ } ++ ++ chunk Ethernet::adapter_init_context(Ethernet::Device rtx_ether_ctx, Builtin::symbol io_addr) ++ { ++ { ++ ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx; ++ ${local.hw_ctx.init(local.io_addr)}; ++ ${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 Ethernet::adapter_reset(Ethernet::Device rtx_ether_ctx) ++ { ++ { ++ ${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 udelay too... ++ ${Log::info("adapter has been reset")}; ++ } ++ } ++ ++ chunk Ethernet::adapter_load_mac_address(Ethernet::Device rtx_ether_ctx) ++ { ++ { ++ ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx; ++ // Shamelessly borrowed from Minix ++ for (int i = 0; i < 3; ++i) { ++ rtx_e1000_reg_write32(hw_ctx, E1000_EEPROM_READ, (i << 8) | 1); ++ int value; ++ do { ++ value = rtx_e1000_reg_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: ++ ${local.rtx_ether_ctx.dev_addr}[i * 2] = value & 0xff; ++ ${local.rtx_ether_ctx.dev_addr}[i * 2 + 1] = (value >> 8) & 0xff; ++ } ++ ++ ${Log::info("mac address loaded from the EEPROM")}; ++ } ++ } ++ ++ // 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) ++ { ++ { ++ ${e1000::Context.ref} hw_ctx = &${local.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. ++ ++ // XXX #46: Use the read/write/set/unset methods on Context ++ rtx_e1000_reg_set32(hw_ctx, E1000_CTRL, E1000_CMD_ASDE|E1000_CMD_SLU); ++ rtx_e1000_reg_unset32( ++ hw_ctx, ++ E1000_CTRL, ++ E1000_CMD_LRST|E1000_CMD_FRCSPD|E1000_CMD_PHY_RST| ++ E1000_CMD_ILOS|E1000_CMD_VME ++ ); ++ rtx_e1000_reg_write32(hw_ctx, E1000_FCAH, 0); ++ rtx_e1000_reg_write32(hw_ctx, E1000_FCAL, 0); ++ rtx_e1000_reg_write32(hw_ctx, E1000_FCT, 0); ++ 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); ++ ++ ${Log::info("adapter_setup_rx_tx: general configuration done")}; ++ ++ int err; ++ ++ err = rtx_e1000_rx_ring_alloc_resources(&hw_ctx->rx_ring); ++ if (err) ++ goto err_alloc_rx_ring; ++ rtx_e1000_rx_ring_configure(&hw_ctx->rx_ring); ++ ++ err = rtx_e1000_tx_ring_alloc_resources(&hw_ctx->tx_ring); ++ if (err) ++ goto err_alloc_tx_ring; ++ rtx_e1000_tx_ring_configure(&hw_ctx->tx_ring); ++ ++ err_alloc_tx_ring: ++ rtx_e1000_rx_ring_free_resources(&hw_ctx->rx_ring); ++ err_alloc_rx_ring: ++ // XXX Can't return here since we don't know the context. ++ // TODO: hardcode a goto ++ (void)1; ++ } ++ } ++ ++ chunk Ethernet::adapter_enable_interrupts(Ethernet::Device) ++ { ++ { ++ ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx; ++ rtx_e1000_reg_write32( ++ hw_ctx, ++ E1000_IMS, ++ E1000_INTR_TXDW|E1000_INTR_TXQE|E1000_INTR_LSC| ++ E1000_INTR_RXO|E1000_INTR_RXT0 ++ ); ++ ++ // 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): ++ // XXX #46: ${local.hw_ctx.print_status()}; ++ rtx_e1000_print_status(hw_ctx); ++ } ++ } ++ ++ chunk Ethernet::disable_interrupts(Ethernet::Device rtx_ether_ctx) ++ { ++ { ${Log::info("adapter_disable_interrupts: TBD...")}; } ++ } ++ ++ chunk Ethernet::adapter_handle_interrupt(Ethernet::Device rtx_ether_ctx) ++ { ++ { ++ ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx; ++ unsigned int icr = rtx_e1000_reg_read32(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:")}; ++ // 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")}; ++ } ++ if (icr & E1000_INTR_RXT0) { ++ ${Log::info("handle_interrupt: RxRing: packet(s) received")}; ++ } ++ if (icr & E1000_INTR_RXO) { ++ ${Log::info("handle_interrupt: RxRing: overrun")}; ++ } ++ ++ // XXX: This sucks since we don't know the pointcut context: ++ return IRQ_HANDLED; ++ } ++ } ++ } ++ ++ chunk Ethernet::adapter_xmit(Ethernet::Device rtx_ether_ctx, Socket::SKBuff rtx_skb) ++ { ++ { ${Log::info("adapter_xmit: TBD...")}; } ++ } ++ ++ chunk Ethernet::adapter_disable_rx(Ethernet::Device rtx_ether_ctx) ++ { ++ { ${Log::info("adapter_disable_rx: TBD..")}; } ++ } ++ ++ chunk Ethernet::adpater_disable_tx(Ethernet::Device rtx_ether_ctx) ++ { ++ { ${Log::info("adapter_disable_tx: TBD..")}; } ++ } ++ ++ chunk Ethernet::adapter_free_rx_tx(Ethernet::Device rtx_ether_ctx) ++ { ++ { ${Log::info("adapter_free_rx_tx: TBD..")}; } ++ } ++ ++ method print_status() ++ { ++ rtx_e1000_print_status(${self}); ++ } ++ ++ map ++ { ++ io_addr: ${self}->io; ++ rx_ring: ${self}->rx_ring; ++ tx_ring: ${self}->tx_ring; + } + } + - /* - * We should have been able to do something along those lines, but - * it didn't work so we made the call manually. @@ -1056,174 +1099,332 @@ - * TODO: make them methods of e1000::Context - */ - template sequence e1000::register_read32(e1000::Context ctx, e1000::Register reg_offset) -- { ++ template type e1000::Ring() + { - chunk LKM::prototypes() -- { ++ decl data_types() + { - /* FIXME: See issue #54 */ - static unsigned int rtx_e1000_register_read32(/*const*/ ${e1000::Context.ref}, unsigned int); -+ ${e1000::Context} hw_ctx; ++ ${e1000::Context} hw_ctx; ++ ${DMA::DMAHandle} dma; ++ unsigned int size; ++ ${Builtin::symbol.ref} descs; ++ ${e1000::Buffer.ref} buffs; } - chunk LKM::code() -+ chunk Ethernet::adapter_init_context(Ethernet::Device rtx_ether_ctx, Builtin::symbol ioaddr) ++ chunk LKM::prototypes() { - /* FIXME: See issue #54 */ - static unsigned int rtx_e1000_register_read32(/*const*/ ${e1000::Context.ref} ctx, unsigned int reg_offset) ++ static void rtx_e1000_ring_init(${e1000::Ring.ref}, ${e1000::Context}, int, int); ++ } ++ ++ chunk LKM::code() ++ { ++ static void rtx_e1000_ring_init(${e1000::Ring.ref} self, ${e1000::Context} hw_ctx, ++ int desc_count, int desc_size) { - 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")}; ++ BUG_ON(desc_count <= 0 || desc_size <= 0); ++ memset(self, 0, sizeof(*self)); ++ self->size = ALIGN(desc_count * desc_size, 4096); ++ self->hw_ctx = hw_ctx; } } - chunk ::CALL() -+ chunk Ethernet::adapter_load_mac_address(Ethernet::Device rtx_ether_ctx) ++ method init(e1000::Context hw_ctx, Builtin::number desc_count, Builtin::number desc_size) + { +- rtx_e1000_register_read32(${ctx}, ${reg_offset}); ++ rtx_e1000_ring_init(&${self}, ${hw_ctx}, ${desc_count}, ${desc_size}); ++ } ++ ++ map ++ { ++ hw_ctx: ${self}->hw_ctx; ++ dma: ${self}->dma; ++ size: ${self}->size; ++ descs: ${self}->descs; ++ buffs: ${self}->buffs; + } + } + +- template sequence e1000::register_write32(e1000::Context ctx, e1000::Register reg_offset, ::number value) ++ template type e1000::RxRing() + { +- chunk LKM::prototypes() ++ decl data_types() + { +- /* FIXME: See issue #54 */ +- static void rtx_e1000_register_write32(/*const*/ ${e1000::Context.ref}, unsigned int, unsigned int); ++ ${e1000::Ring} ring; + } + +- chunk LKM::code() ++ chunk LKM::prototypes() { -- rtx_e1000_register_write32(${ctx}, ${reg_offset}, ${value}); -- } -- } +- /* FIXME: See issue #54 */ +- static void rtx_e1000_register_write32(/*const*/ ${e1000::Context.ref} ctx, unsigned int reg_offset, unsigned int value) ++ static int rtx_e1000_rx_ring_alloc_resources(${e1000::RxRing.ref}); ++ static void rtx_e1000_rx_ring_configure(${e1000::RxRing.ref}); ++ } ++ ++ chunk LKM::code() ++ { ++ static int rtx_e1000_rx_ring_alloc_resources(${e1000::RxRing.ref} self) + { +- iowrite32(value, ctx->ioaddr + reg_offset); ++ // XXX Reread & Fix everything down there (data structure changes and so on) ++ ++ // 4. Setup the receive descriptor ring ++ ++ int i; ++ ++ // Allocate the descriptors ++ hw_ctx->rx_ring.base = ${DMA::alloc_coherent( ++ local.self.hw_ctx.net_dev.device, local.self.size, ++ local.self.dma.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]; ++// // XXX #46: ${rtx_ether_ctx.alloc_rx_skbuff(local.skbuff, config.rx_buffer_len)}; ++// if (rtx_ethernet_alloc_rx_skbuff(ocal.skbuff, ${config.rx_buffer_len})) { ++// ${Log::info("adapter_init_rx: cannot allocate a skbuff for the rx ring")}; ++// goto err_skbuffs_alloc; ++// } ++// /* TODO: 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)); ++ ++ err_skbuffs_alloc: ++ while (i--) { ++ ${DMA::unmap( ++ local.self.hw_ctx.net_dev.device, ++ // XXX Leaking cast because of the array: (TODO: the data structure changed) ++ *((dma_addr_t *)&(self->buffs[i].dma_handle)), ++ ${config.rx_buffer_len}, ++ RTX_DMA_FROM_DEVICE ++ )}; ++ err_skbuffs_map: ++ // XXX leaking cast: (TODO: the data structure changed) ++ dev_kfree_skb((struct sk_buff *)hw_ctx->rx_ring.skbuffs[i].skbuff); ++ } ++ ++ ${DMA::free_coherent( ++ local.self.hw_ctx.net_dev.device, local.self.size, ++ local.self.descs, local.self.dma.dma_handle ++ )}; ++ err_rx_ring_alloc: ++ return -ENOMEM; ++ } ++ ++ static void rtx_e1000_rx_ring_configure(${e1000::RxRing.ref} self) + { -+ ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx; -+ // Shamelessly borrowed from Minix -+ for (int i = 0; i < 3; ++i) { -+ rtx_e1000_reg_write32(hw_ctx, E1000_EEPROM_READ, (i << 8) | 1); -+ int value; -+ do { -+ value = rtx_e1000_reg_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: -+ ${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")}; ++ // XXX Reread & Fix everything down there (data structure changes and so on) ++ ++ // 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_reg_write32( ++ ${local.self.hw_ctx}, E1000_RAL, ++ *(unsigned int *)(${local.self.hw_ctx.net_dev.dev_addr}) ++ ); ++ // The 16 upper bits of RAH also store the AS bits (which should be ++ // 0) and the AV bit (should be 1 to set the address as valid). ++ rtx_e1000_reg_write32( ++ ${local.self.hw_ctx}, E1000_RAH, ++ *(unsigned short *)(&${local.self.hw_ctx.net_dev.dev_addr}[4]) ++ ); ++ rtx_e1000_reg_set32(${local.self.hw_ctx}, E1000_RAH, E1000_RAH_AV); ++ ++ ${Log::info("rx_ring_configure: receive address programmed")}; ++ ++ // 2. Initialize the MTA ++ ++ for (i = 0; i != 128; ++i) // TODO Remove that hardcoded 128 ++ rtx_e1000_reg_write32(${local.self.hw_ctx}, E1000_MTA + i * 4, 0); ++ ++ ${Log::info("rx_ring_configure: MTA init done")}; ++ ++ // 5. Save the emplacement and the size of the ring in RDBA/RDLEN ++ rtx_e1000_reg_write32( ++ ${local.self.hw_ctx}, E1000_RDBAL, ++ ${local.self.hw_ctx}->rx_ring.dma_base & 0xffffffff ++ ); ++ rtx_e1000_reg_write32( ++ ${local.self.hw_ctx}, E1000_RDBAH, ++ ${local.self.hw_ctx}->rx_ring.dma_base >> 32 ++ ); ++ rtx_e1000_reg_write32( ++ ${local.self.hw_ctx}, E1000_RDLEN, ++ ${local.self.hw_ctx}->rx_ring.size ++ ); ++ ++ // 6. Setup RDH/RDT ++ rtx_e1000_reg_write32(${local.self.hw_ctx}, E1000_RDH, 0); ++ rtx_e1000_reg_write32( ++ ${local.self.hw_ctx}, E1000_RDT, ++ ${config.rx_ring_size} - 1 ++ ); ++ ++ // 7. Configure the buffer size ++ rtx_e1000_reg_set32( ++ ${local.self.hw_ctx}, E1000_RCTL, ++ E1000_RCTL_BSIZE_${config.rx_buffer_len} ++ ); ++ ++ // 8. Enable the receiver ++ rtx_e1000_reg_set32(${local.self.hw_ctx}, E1000_RCTL, E1000_RCTL_EN); ++ ++ ${Log::info("rx_ring_configure: receive registers configured and receiver enabled")}; ++ ++ return 0; } } - 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) ++ method init(e1000::Context hw_ctx, Builtin::number desc_count) + { +- rtx_e1000_register_write32(${ctx}, ${reg_offset}, ${value}); ++ ${self.ring.init(hw_ctx, desc_count, self.desc_size)}; ++ } ++ ++ method alloc() ++ { ++ rtx_e1000_rx_ring_alloc_resources(${self}); ++ } ++ ++ method configure() ++ { ++ rtx_e1000_rx_ring_configure(${self}); ++ } ++ ++ map ++ { ++ // TODO: fix cast to directly get the attributes from the Ring: ++ hw_ctx: ((int)(${self})->hw_ctx); ++ dma: ((int)(${self})->dma); ++ size: ((int)(${self})->size); ++ descs: ((int)(${self})->descs); ++ buffs: ((int)(${self})->buffs); ++ desc_size: sizeof(/* TODO: get the generated type... ${e1000::RxDescriptor} */int); + } + } + +- template sequence e1000::register_set32(e1000::Context ctx, e1000::Register reg_offset, ::number value) ++ template type e1000::TxRing() + { +- chunk LKM::prototypes() ++ decl data_types() + { +- /* FIXME: See issue #54 */ +- static void rtx_e1000_register_set32(/*const*/ ${e1000::Context.ref}, unsigned int, unsigned int); ++ ${e1000::Ring} ring; + } + +- chunk LKM::code() ++ chunk LKM::prototypes() + { +- /* FIXME: See issue #54 */ +- static void rtx_e1000_register_set32(/*const*/ ${e1000::Context.ref} ctx, unsigned int reg_offset, unsigned int value) ++ static int rtx_e1000_tx_ring_alloc_resources(${e1000::TxRing.ref}); ++ static void rtx_e1000_tx_ring_configure(${e1000::TxRing.ref}); ++ } ++ ++ chunk LKM::code() ++ { ++ static int rtx_e1000_tx_ring_alloc_resources(${e1000::TxRing.ref} self) + { +- iowrite32(rtx_e1000_register_read32(ctx, reg_offset) | value, ctx->ioaddr + reg_offset); ++ return 0; ++ } ++ ++ static void rtx_e1000_tx_ring_configure(${e1000::TxRing.ref} self) ++ { ++ // return ; XXX wtf fails with: ++ // function 'rtxPH_compile(local_node : node, compile : node, node_idx : value)' hasn't been implemented + } + } + +- chunk ::CALL() ++ method init(e1000::Context hw_ctx, Builtin::number desc_count) { - 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 & -+ // 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. -+ // -+ // XXX #46: Use the read/write/set/unset methods on Context -+ rtx_e1000_reg_set32(hw_ctx, E1000_CTRL, E1000_CMD_ASDE|E1000_CMD_SLU); -+ rtx_e1000_reg_unset32( -+ hw_ctx, -+ E1000_CTRL, -+ E1000_CMD_LRST|E1000_CMD_FRCSPD|E1000_CMD_PHY_RST| -+ E1000_CMD_ILOS|E1000_CMD_VME -+ ); -+ rtx_e1000_reg_write32(hw_ctx, E1000_FCAH, 0); -+ rtx_e1000_reg_write32(hw_ctx, E1000_FCAL, 0); -+ rtx_e1000_reg_write32(hw_ctx, E1000_FCT, 0); -+ 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); ++ ${self.ring.init(hw_ctx, desc_count, self.desc_size)}; + } - chunk LKM::code() -- { ++ method alloc() + { - /* 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")}; - } +- } ++ rtx_e1000_tx_ring_alloc_resources(${self}); } - chunk ::CALL() -+ chunk Ethernet::adapter_enable_interrupts(Ethernet::Device) ++ method configure() { - rtx_e1000_register_unset32(${ctx}, ${reg_offset}, ${value}); -- } ++ rtx_e1000_tx_ring_configure(${self}); + } - } -+ { -+ ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx; -+ rtx_e1000_reg_write32( -+ hw_ctx, -+ E1000_IMS, -+ 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() -- { ++ map + { - rtx_e1000_register_write32(&${rtx_ether_ctx}->hw_ctx, E1000_IMS, - E1000_INTR_TXDW | - E1000_INTR_TXQE | @@ -1316,63 +1517,29 @@ - } - - 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): -+ // 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...")}; } -+ } - +- - ${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; -+ unsigned int icr = rtx_e1000_reg_read32(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:")}; -+ // 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")}; -+ } -+ if (icr & E1000_INTR_RXT0) { -+ ${Log::info("handle_interrupt: RxRing: packet(s) received")}; -+ } -+ 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 @@ -1384,11 +1551,7 @@ - * ${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 @@ -1398,38 +1561,22 @@ - * 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)) - { @@ -1452,21 +1599,22 @@ - /* 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; ++ // TODO: fix cast to directly get the attributes from the Ring: ++ hw_ctx: ((int)(${self})->hw_ctx); ++ dma: ((int)(${self})->dma); ++ size: ((int)(${self})->size); ++ descs: ((int)(${self})->descs); ++ buffs: ((int)(${self})->buffs); ++ desc_size: sizeof(/* TODO: get the generated type ${e1000::TxDescriptor} */int); } } } 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 +@@ -1,157 +1,122 @@ +-interface e1000 : Socket, Ethernet, DMA, PCI, LKM, Builtin ++interface e1000 : Socket, Ethernet, Device, DMA, PCI, LKM, Builtin { - required variable Builtin::number rx_ring_size; - required variable Builtin::number tx_ring_size; @@ -1498,24 +1646,44 @@ } - 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 ++ provided type Context { decl data_types(); - method init(); + ++ chunk LKM::includes(); + chunk LKM::prototypes(); + chunk LKM::code(); ++ chunk Ethernet::HardwareContext(); ++ ++ // NOTE: Those callbacks/hooks should probably be in the front-end: ++ ++ chunk Ethernet::adapter_init_context(Ethernet::Device, Builtin::symbol); ++ chunk Ethernet::adapter_reset(Ethernet::Device); ++ chunk Ethernet::adapter_load_mac_address(Ethernet::Device); ++ chunk Ethernet::adapter_setup_rx_tx(Ethernet::Device); ++ chunk Ethernet::adapter_enable_interrupts(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 init(Builtin::symbol); -+ method read32(Register); -+ method write32(Register, Builtin::number); -+ method set32(Register, Builtin::number); -+ method unset32(Register, Builtin::number); ++ method print_status(); ++ method reg_read32(Register); ++ method reg_write32(Register, Builtin::number); ++ method reg_set32(Register, Builtin::number); ++ method reg_unset32(Register, Builtin::number); + -+ attribute Builtin::symbol.scalar io; ++ // XXX: Circular dependency with the rings, this will prevent us to ++ // call methods even when issue $46 is resolved, and it also forces ++ // us to hardcode generated types in the definition of the type: ++ attribute Builtin::symbol.scalar rx_ring; ++ attribute Builtin::symbol.scalar tx_ring; ++ ++ attribute Ethernet::Device.ref net_dev; + } + + provided type Ring @@ -1525,10 +1693,13 @@ + chunk LKM::prototypes(); + chunk LKM::code(); + -+ method init(MMIO, Builtin::number, Builtin::number); ++ method init(e1000::Context, Builtin::number); + -+ attribute MMIO.scalar io; -+ attribute DMA::DMAHandle.scalar dma; ++ // Keep a backref to The context since it's going to be needed for of ++ // operations involving the ethernet device, flags on the context, etc. ++ attribute Context.ref hw_ctx; ++ ++ attribute DMA::DMAHandle.scalar dma; + attribute Builtin::number.scalar size; // Total size in bytes + attribute Builtin::symbol.ref descs; + attribute Buffer.ref buffs; @@ -1545,31 +1716,22 @@ + chunk LKM::code(); - attribute DMA::DMAHandle.scalar dma_base; -- attribute Builtin::number.scalar size; -+ method init(MMIO, Builtin::number); ++ method init(e1000::Context, Builtin::number); + method alloc(); // Returns != 0 on failure -+ -+ attribute RxDescriptor.scalar descs; -+ } -+ -+ provided type TxRing -+ { -+ decl data_types(); ++ method free(); ++ method configure(); + -+ chunk LKM::prototypes(); -+ chunk LKM::code(); -+ -+ method init(MMIO, Builtin::number); -+ method alloc(); // Returns != 0 on failure -+ -+ attribute TxDescriptor.scalar descs; - } - - provided type Context - { ++ // Re-expose all the Ring attributes + the size of a single descriptor: ++ attribute Context.ref hw_ctx; ++ attribute DMA::DMAHandle.scalar dma; + attribute Builtin::number.scalar size; +- } +- +- provided type Context +- { - chunk Ethernet::HardwareContext(); - decl data_types(); - +- 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 @@ -1578,44 +1740,33 @@ - chunk Ethernet::adapter_init_context(Ethernet::Device, - Builtin::number, - Builtin::symbol); -+ chunk LKM::includes(); -+ chunk LKM::prototypes(); -+ chunk LKM::code(); -+ chunk Ethernet::HardwareContext(); -+ -+ // NOTE: Those callbacks/hooks should probably be in the front-end: -+ -+ chunk Ethernet::adapter_init_context(Ethernet::Device, Builtin::symbol); - chunk Ethernet::adapter_reset(Ethernet::Device); - chunk Ethernet::adapter_load_mac_address(Ethernet::Device); +- 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); -+ chunk Ethernet::adapter_enable_interrupts(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.scalar io; - attribute RxRing.scalar rx_ring; +- +- attribute RxRing.scalar rx_ring; - /* XXX: circular dependency with Contex: */ - //attribute TxRing.scalar tx_ring; -- } -- -- provided type TxRing -- { -- chunk LKM::prototypes(); -- chunk LKM::code(); ++ attribute RxDescriptor.scalar descs; ++ attribute Builtin::number.scalar desc_size; + } + + provided type TxRing + { ++ decl data_types(); ++ + 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); -- ++ method init(e1000::Context, Builtin::number); ++ method alloc(); // Returns != 0 on failure ++ method free(); ++ method configure(); + - /* Clean the ring (i.e: move the head closer to the tail): */ - method clean(); - /* Return the number of clean descriptors left in the ring: */ @@ -1707,12 +1858,15 @@ - provided chunk LKM::prototypes(); - provided chunk LKM::code(); - provided chunk ::CALL(); -+ attribute TxRing.scalar tx_ring; ++ // Re-expose all the Ring attributes + the size of a single descriptor: ++ attribute Context.ref hw_ctx; ++ attribute DMA::DMAHandle.scalar dma; ++ attribute Builtin::number.scalar size; ++ attribute TxDescriptor.scalar descs; ++ attribute Builtin::number.scalar desc_size; } } 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 @@ -1,4 +1,4 @@ @@ -1721,6 +1875,24 @@ { template type Ethernet::ProtocolId() { +@@ -9,7 +9,7 @@ + + chunk LKM::prototypes() + { +- static const char *rtx_ethernet_protocol_id_to_str(unsigned short); ++ static const char *rtx_ethernet_protocol_id_to_str(unsigned short); + } + + chunk LKM::data() +@@ -28,7 +28,7 @@ + + chunk LKM::code() + { +- static const char *rtx_ethernet_protocol_id_to_str(unsigned short proto_id) ++ static const char *rtx_ethernet_protocol_id_to_str(unsigned short proto_id) + { + for (int i = 0; + i != sizeof(rtx_ethernet_proto_table) / sizeof(rtx_ethernet_proto_table[0]); @@ -61,7 +61,7 @@ method init(Builtin::symbol dev) @@ -1755,9 +1927,18 @@ { chunk LKM::includes() { -@@ -164,60 +167,68 @@ +@@ -157,100 +160,114 @@ + + chunk LKM::prototypes() { - static int rtx_ethernet_open(struct net_device *dev) +- static int rtx_ethernet_open(struct net_device *); ++ static int rtx_ethernet_open(struct net_device *); + } + + chunk LKM::code() + { +- static int rtx_ethernet_open(struct net_device *dev) ++ static int rtx_ethernet_open(struct net_device *dev) { - /* - * XXX The casts are here because the compiler doesn't resolve @@ -1817,13 +1998,13 @@ 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); ++ 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) ++ 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; @@ -1849,12 +2030,14 @@ { chunk LKM::prototypes() { -@@ -226,31 +237,37 @@ +- static int rtx_ethernet_close(struct net_device *); ++ static int rtx_ethernet_close(struct net_device *); + } chunk LKM::code() { - static int rtx_ethernet_close(struct net_device *dev) -+ static int rtx_ethernet_close(struct net_device *net_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 */ @@ -1901,7 +2084,20 @@ { /* * We can't use the irqreturn_t type here because CNornm doesn't know -@@ -269,11 +286,16 @@ +@@ -258,29 +275,34 @@ + */ + chunk LKM::prototypes() + { +- static enum irqreturn rtx_ethernet_interrupt_handler(int, void *); ++ static enum irqreturn rtx_ethernet_interrupt_handler(int, void *); + } + + chunk LKM::code() + { +- static enum irqreturn rtx_ethernet_interrupt_handler(int irq, void *dev_id) ++ static enum irqreturn rtx_ethernet_interrupt_handler(int irq, void *dev_id) + { + ${Ethernet::AbstractDevice.ref} rtx_net_dev = dev_id; ${Ethernet::Device.ref} rtx_ether_ctx; rtx_ether_ctx = ${local.rtx_net_dev.rtx_ether_ctx}; @@ -1919,22 +2115,124 @@ } template sequence Ethernet::init() -@@ -342,12 +364,8 @@ - * XXX: the asssignments/casts are here to circumvent - * typing issues in the compiler (see previous XXX). - */ + { + chunk LKM::data() + { +- static const struct net_device_ops rtx_ether_ops = ++ static const struct net_device_ops rtx_ether_ops = + { + .ndo_open = rtx_ethernet_open, + .ndo_stop = rtx_ethernet_close, +@@ -298,64 +320,62 @@ + */ + chunk PCI::pci_probe_hook(PCI::Device rtx_pci_dev) + { +- ${Ethernet::AbstractDevice.ref} rtx_net_dev; +- ${Ethernet::Device.ref} rtx_ether_ctx; ++ { ++ ${Ethernet::AbstractDevice.ref} rtx_net_dev; ++ ${Ethernet::Device.ref} rtx_ether_ctx; + +- rtx_net_dev = (${Ethernet::AbstractDevice.ref})alloc_etherdev(sizeof(*rtx_ether_ctx)); +- if (!rtx_net_dev) +- { +- ${Log::info("cannot allocate the ethernet device context")}; +- error = -ENOMEM; +- goto fail; ++ rtx_net_dev = (${Ethernet::AbstractDevice.ref})alloc_etherdev(sizeof(*rtx_ether_ctx)); ++ if (!rtx_net_dev) ++ { ++ ${Log::info("cannot allocate the ethernet device context")}; ++ error = -ENOMEM; ++ goto fail; ++ } ++ SET_NETDEV_DEV(${local.rtx_net_dev.k_net_dev}, ${rtx_pci_dev.device}); ++ strlcpy(${local.rtx_net_dev.k_net_dev}->name, ++ ${config.ifname}, ++ sizeof(${local.rtx_net_dev.k_net_dev}->name)); ++ ${local.rtx_net_dev.k_net_dev}->irq = ${rtx_pci_dev.irq}; ++ ${local.rtx_net_dev.k_net_dev}->netdev_ops = &rtx_ether_ops; ++ ++ error = register_netdev(${local.rtx_net_dev.k_net_dev}); ++ if (error) ++ { ++ ${Log::info("cannot register the driver in the net subsystem")}; ++ goto fail; ++ } ++ ++ /* Initialize our context held by the net_device structure */ ++ /* ++ * XXX: the cast is here because the compiler resolve the ++ * type of rtx_pci_dev.pci_device to the type of ++ * rtx_pci_dev instead of the type of rtx_pci_dev.pci_device. ++ */ ++ ${PCI::AbstractDevice.ref} workaround = ${rtx_pci_dev.pci_device}; ++ ${cast local.workaround as PCI::AbstractDevice}; ++ { /* XXX: I end up with a placeholder if I don't open a scope */ ++ ${local.rtx_ether_ctx.init(local.rtx_net_dev, local.workaround)}; ++ } ++ ++ /* Register ourselves in the parent context: */ ++ /* ${rtx_pci_dev.set_context(local.rtx_ether_ctx)}; */ ++ ${rtx_pci_dev}->context = rtx_ether_ctx; ++ ++ /* ++ * XXX: the asssignments/casts are here to circumvent ++ * typing issues in the compiler (see previous XXX). ++ */ ++ unsigned char /* __iomem */ *io_addr = ${rtx_pci_dev.ioaddr}; ++ ${pointcut Ethernet::adapter_init_context(local.rtx_ether_ctx, local.io_addr)}; ++ ${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}, ++ ${local.rtx_ether_ctx.dev_addr}, ++ ${local.rtx_net_dev.k_net_dev}->addr_len); + } +- SET_NETDEV_DEV(${local.rtx_net_dev.k_net_dev}, ${rtx_pci_dev.device}); +- strlcpy(${local.rtx_net_dev.k_net_dev}->name, +- ${config.ifname}, +- sizeof(${local.rtx_net_dev.k_net_dev}->name)); +- ${local.rtx_net_dev.k_net_dev}->irq = ${rtx_pci_dev.irq}; +- ${local.rtx_net_dev.k_net_dev}->netdev_ops = &rtx_ether_ops; +- +- error = register_netdev(${local.rtx_net_dev.k_net_dev}); +- if (error) +- { +- ${Log::info("cannot register the driver in the net subsystem")}; +- goto fail; +- } +- +- /* Initialize our context held by the net_device structure */ +- /* +- * XXX: the cast is here because the compiler resolve the +- * type of rtx_pci_dev.pci_device to the type of +- * rtx_pci_dev instead of the type of rtx_pci_dev.pci_device. +- */ +- ${PCI::AbstractDevice.ref} workaround = ${rtx_pci_dev.pci_device}; +- ${cast local.workaround as PCI::AbstractDevice}; +- { /* XXX: I end up with a placeholder if I don't open a scope */ +- ${local.rtx_ether_ctx.init(local.rtx_net_dev, local.workaround)}; +- } +- +- /* Register ourselves in the parent context: */ +- /* ${rtx_pci_dev.set_context(local.rtx_ether_ctx)}; */ +- ${rtx_pci_dev}->context = rtx_ether_ctx; +- +- /* +- * XXX: the asssignments/casts are here to circumvent +- * typing issues in the compiler (see previous XXX). +- */ - int bars = ${rtx_pci_dev.bars}; - unsigned char /* __iomem */ *ioaddr = ${rtx_pci_dev.ioaddr}; +- unsigned char /* __iomem */ *ioaddr = ${rtx_pci_dev.ioaddr}; - ${cast local.bars as Builtin::number}; - ${pointcut Ethernet::adapter_init_context(local.rtx_ether_ctx, - local.bars, - local.ioaddr)}; -+ ${pointcut Ethernet::adapter_init_context(local.rtx_ether_ctx, local.ioaddr)}; - ${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); +- ${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}, +- ${local.rtx_ether_ctx.dev_addr}, +- ${local.rtx_net_dev.k_net_dev}->addr_len); } - /* This chunk should be removed (see #26) */ @@ -1942,8 +2240,23 @@ chunk ::CALL() { } -@@ -377,7 +395,7 @@ - free_netdev(${local.rtx_net_dev.k_net_dev}); +@@ -369,15 +389,17 @@ + */ + chunk PCI::pci_remove_hook(PCI::Device rtx_pci_dev) + { +- ${Ethernet::Device.ref} rtx_ether_ctx = ${rtx_pci_dev.rtx_drv_context}; +- BUG_ON(!rtx_ether_ctx); ++ { ++ ${Ethernet::Device.ref} rtx_ether_ctx = ${rtx_pci_dev.rtx_drv_context}; ++ BUG_ON(!rtx_ether_ctx); + +- ${Ethernet::AbstractDevice.ref} rtx_net_dev = ${local.rtx_ether_ctx.net_device}; +- unregister_netdev(${local.rtx_net_dev.k_net_dev}); +- free_netdev(${local.rtx_net_dev.k_net_dev}); ++ ${Ethernet::AbstractDevice.ref} rtx_net_dev = ${local.rtx_ether_ctx.net_device}; ++ unregister_netdev(${local.rtx_net_dev.k_net_dev}); ++ free_netdev(${local.rtx_net_dev.k_net_dev}); ++ } } - /* This chunk should be removed (see #26) */ @@ -1952,8 +2265,6 @@ { } 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 @@ -2,16 +2,16 @@ @@ -2058,7 +2369,7 @@ } - required sequence close(Ethernet::Device) -+ provided sequence close() ++ provided sequence close() { - provided chunk LKM::prototypes(); - provided chunk LKM::code(); @@ -2108,8 +2419,6 @@ } 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,40 +1,5 @@ @@ -2163,8 +2472,6 @@ /* 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 @@ -2190,13 +2497,9 @@ ${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 @@ @@ -2346,8 +2649,6 @@ } } 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 @@