Mercurial > archived > louis > epitech > mq > rathaxes
diff rathaxes_sample_e1000_rewrite_device_dependent_code.patch @ 131:c209851a82de
Wip, start a rewrite of the e1000 device dependent code
author | Louis Opter <kalessin@kalessin.fr> |
---|---|
date | Fri, 03 Jan 2014 15:01:47 +0100 |
parents | |
children | f2e4dd91dc6f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rathaxes_sample_e1000_rewrite_device_dependent_code.patch Fri Jan 03 15:01:47 2014 +0100 @@ -0,0 +1,1252 @@ +# HG changeset patch +# Parent 7d00455945ec97c5851ac0d735da7c3cfbd8e39c +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,9 @@ ++- 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); ++- I'm using a pointcut inside the ethernet context "decl data_types" to inject ++ my hardware context; it's impossible to get it back without hardcoding stuff, ++ 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. +diff --git a/rathaxes/samples/e1000/CMakeLists.txt b/rathaxes/samples/e1000/CMakeLists.txt +--- 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 @@ + dma.blt + pci.blt + socket.blt +- e1000.blt + ethernet.blt) + +-IF (LINUX_KBUILD_DIR) +- ADD_RATHAXES_LKM(e1000 e1000_src) +-ENDIF (LINUX_KBUILD_DIR) ++#IF (LINUX_KBUILD_DIR) ++# ADD_RATHAXES_LKM(e1000 e1000_src) ++#ENDIF (LINUX_KBUILD_DIR) +diff --git a/rathaxes/samples/e1000/e1000.blt b/rathaxes/samples/e1000/e1000.blt +--- a/rathaxes/samples/e1000/e1000.blt ++++ b/rathaxes/samples/e1000/e1000.blt +@@ -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 ++{ ++ template type e1000::Register() ++ { ++ 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; ++ __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::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}); ++ } ++ } ++ ++ template type e1000::RxRing() ++ { ++ decl data_types() ++ { ++ ${e1000::Ring} ring; ++ } ++ ++ chunk LKM::prototypes() ++ { ++ static int rtx_e1000_alloc_rx_ressources(${e1000::RxRing.ref}); ++ } ++ ++ 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; ++ ++ /* ++ * 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]; ++ // 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: 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: ++ 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. */ ++ } ++ } ++ ++ method init(e1000::MMIO io, Builtin::number desc_count) ++ { ++ ${self.ring.init(local.io, local.desc_count, self.desc_size)}; ++ } ++ ++ method alloc() ++ { ++ 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); ++ } ++ } ++ ++ template type e1000::TxRing() ++ { ++ decl data_types() ++ { ++ ${e1000::Ring} ring; ++ } ++ ++ chunk LKM::prototypes() ++ { ++ static int rtx_e1000_alloc_tx_ressources(${e1000::TxRing.ref}); ++ } ++ ++ chunk LKM::code() ++ { ++ static int rtx_e1000_alloc_tx_ressources(${e1000::TxRing.ref} self) ++ { ++ return 0; ++ } ++ } ++ ++ method init(e1000::MMIO io, Builtin::number desc_count) ++ { ++ ${self.ring.init(local.io, local.desc_count, self.desc_size)}; ++ } ++ ++ method alloc() ++ { ++ rtx_e1000_alloc_tx_ressources(${self}); ++ } ++ ++ map ++ { ++ descs: ((${self})->descs); // TODO: fix cast pour directement avoir les descs ++ desc_size: sizeof(/* XXX ${e1000::TxDescriptor} */int); ++ } ++ } ++ ++ template type e1000::Context() ++ { ++ decl data_types() ++ { ++ ${e1000::MMIO} io; ++ ${e1000::TxRing} tx_ring; ++ ${e1000::RxRing} rx_ring; ++ } ++ ++ chunk LKM::includes() ++ { ++ #include <linux/types.h> ++ } ++ ++ chunk LKM::prototypes() ++ { ++ static void rtx_e1000_print_status(${e1000::Context.ref}); ++ } ++ ++ chunk LKM::code() ++ { ++ static void rtx_e1000_print_status(${e1000::Context.ref} hw_ctx) ++ { ++ 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"); ++ } ++ } ++ ++ chunk Ethernet::HardwareContext() ++ { ++ ${e1000::Context} hw_ctx; ++ } ++ ++ chunk Ethernet::adapter_init_context(Ethernet::Device rtx_ether_ctx, Builtin::symbol ioaddr) ++ { ++ { ++ ${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 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 this 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")}; ++ } ++ } ++ ++ 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: general configuration done")}; ++ } ++ } ++ ++ 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): ++ ${local.hw_ctx.print_status()}; ++ } ++ } ++ ++ chunk Ethernet::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:")}; ++ ${local.hw_ctx.print_status()}; ++ } ++ 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; ++ } ++ } ++ } ++ ++ method print_status() ++ { ++ rtx_e1000_print_status(${self}); ++ } ++ ++ 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 ++{ ++ 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; ++ ++ // Hardware values/data structures, should probably be in the front-end: ++ provided type Register { decl data_types(); } ++ provided type Command { decl data_types(); } ++ provided type TxDescriptorFlag { decl data_types(); } ++ provided type RxDescriptor { decl data_types(); } ++ provided type TxDescriptor { decl data_types(); } ++ ++ provided type Buffer ++ { ++ decl data_types(); ++ ++ method init(Socket::SKBuff, DMA::DMAHandle); ++ ++ attribute Socket::SKBuff.ref sk_buff; ++ attribute DMA::DMAHandle.ref dma; ++ } ++ ++ // 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(); ++ ++ chunk LKM::prototypes(); ++ chunk LKM::code(); ++ ++ method init(Builtin::symbol); ++ method read32(Register); ++ method write32(Register, Builtin::number); ++ method set32(Register, Builtin::number); ++ method unset32(Register, Builtin::number); ++ ++ attribute Builtin::symbol io; ++ } ++ ++ provided type Ring ++ { ++ decl data_types(); ++ ++ chunk LKM::prototypes(); ++ chunk LKM::code(); ++ ++ 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(); ++ ++ chunk LKM::prototypes(); ++ chunk LKM::code(); ++ ++ method init(MMIO, Builtin::number); ++ method alloc(); // Returns != 0 on failure ++ ++ attribute RxDescriptor descs; ++ } ++ ++ provided type TxRing ++ { ++ decl data_types(); ++ ++ chunk LKM::prototypes(); ++ chunk LKM::code(); ++ ++ method init(MMIO, Builtin::number); ++ method alloc(); // Returns != 0 on failure ++ ++ attribute TxDescriptor descs; ++ } ++ ++ provided type Context ++ { ++ decl data_types(); ++ ++ chunk LKM::includes(); ++ chunk LKM::prototypes(); ++ chunk LKM::code(); ++ chunk Ethernet::HardwareContext(); ++ ++ // 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_setup_rx_tx(Ethernet::Device); ++ ++ // Enable interrupts. ++ chunk Ethernet::adapter_enable_interrupts(Ethernet::Device); ++ ++ // Interrupt handler. ++ chunk Ethernet::handle_interrupt(Ethernet::Device); ++ ++ method print_status(); ++ ++ attribute MMIO io; ++ attribute RxRing.scalar rx_ring; ++ attribute TxRing.scalar tx_ring; ++ } ++} +diff --git a/rathaxes/samples/e1000/ethernet.blt b/rathaxes/samples/e1000/ethernet.blt +--- a/rathaxes/samples/e1000/ethernet.blt ++++ b/rathaxes/samples/e1000/ethernet.blt +@@ -106,7 +106,7 @@ + { + ${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)}; + return 0; + } + return 1; +@@ -164,34 +164,30 @@ + { + static int rtx_ethernet_open(struct net_device *dev) + { +- /* +- * XXX The casts are here because the compiler doesn't resolve +- * "enclosed" type (e.g: local.var.enclosed) correctly. +- */ + ${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)}; + } + ${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, +- ${config.name}, +- dev); +- if (error) +- { ++ int error = request_irq( ++ ${local.rtx_ether_ctx.irq}, ++ rtx_ethernet_interrupt_handler, ++ IRQF_SHARED, ++ ${config.name}, ++ dev ++ ); ++ if (error) { + ${Log::info("Cannot register the interrupt handler")}; + return error; + } +- ${pointcut Ethernet::adapter_setup(local.rtx_ether_ctx)}; +- ${pointcut Ethernet::adapter_init_rx(local.rtx_ether_ctx)}; +- ${pointcut Ethernet::adapter_init_tx(local.rtx_ether_ctx)}; +- ${pointcut ::IMPLEMENTATION(local.rtx_ether_ctx)}; ++ ++ ${pointcut Ethernet::adapter_enable_interrupts(local.rtx_ether_ctx)}; + + return 0; + } +@@ -269,7 +265,7 @@ + ${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)}; + + return IRQ_NONE; + } +@@ -342,12 +338,8 @@ + * 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}; +- ${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}, +diff --git a/rathaxes/samples/e1000/ethernet.rti b/rathaxes/samples/e1000/ethernet.rti +--- a/rathaxes/samples/e1000/ethernet.rti ++++ b/rathaxes/samples/e1000/ethernet.rti +@@ -28,8 +28,12 @@ + + provided type Device + { ++ decl data_types(); ++ + chunk LKM::includes(); +- decl data_types(); ++ chunk LKM::prototypes(); ++ chunk LKM::code(); ++ + pointcut Ethernet::HardwareContext(); + + method init(Ethernet::AbstractDevice, PCI::AbstractDevice); +@@ -51,7 +55,7 @@ + attribute Builtin::symbol.scalar irq; + } + +- required sequence open(Ethernet::Device) ++ provided sequence open(Ethernet::Device) + { + 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 pointcut Ethernet::adapter_setup(Ethernet::Device); +- provided pointcut Ethernet::adapter_init_rx(Ethernet::Device); +- provided pointcut Ethernet::adapter_init_tx(Ethernet::Device); ++ provided pointcut Ethernet::adapter_setup_rx_tx(Ethernet::Device); ++ 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 interrupt_handler(Ethernet::Device) ++ provided sequence interrupt_handler(Ethernet::Device) + { + provided chunk LKM::prototypes(); + provided chunk LKM::code(); ++ ++ provided pointcut Ethernet::handle_interrupt(Ethernet::Device); + } + + provided sequence init() +@@ -90,9 +95,7 @@ + provided chunk LKM::data(); + provided chunk PCI::pci_probe_hook(PCI::Device); + +- provided pointcut Ethernet::adapter_init_context(Ethernet::Device, +- Builtin::number, +- Builtin::symbol); ++ provided pointcut Ethernet::adapter_init_context(Ethernet::Device, Builtin::symbol); + provided pointcut Ethernet::adapter_reset(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 +--- a/rathaxes/samples/e1000/lkm.rtx ++++ b/rathaxes/samples/e1000/lkm.rtx +@@ -1,34 +1,5 @@ + device LKM use LKM, PCI, Ethernet, Log, Socket + { +- Ethernet::open(Ethernet::Device dev) +- { +- Log::info("opening the device"); +- +- e1000::activate_device_interruption(dev); +- Log::info("interruption enabled"); +- +- e1000::print_status(dev); +- } +- +- Ethernet::close(Ethernet::Device dev) +- { +- Log::info("closing the device"); +- +- /* +- * Note: some calls to release resources must be done when IRQs are +- * enabled (dma_free_coherent() for example). So we have to cleanup our +- * stuff before free_interrupt_handler(). +- */ +- e1000::free_rx_tx(dev); +- Log::info("free'ed up rx/tx resources"); +- } +- +- Ethernet::interrupt_handler(Ethernet::Device dev) +- { +- Log::info("got an interruption"); +- e1000::handle_interrupt(dev); +- } +- + Ethernet::send(Ethernet::Device dev, Socket::AbstractSKBuff skb) + { + Log::info("we have one packet to transmit!"); +diff --git a/rathaxes/samples/e1000/socket.blt b/rathaxes/samples/e1000/socket.blt +--- a/rathaxes/samples/e1000/socket.blt ++++ b/rathaxes/samples/e1000/socket.blt +@@ -22,16 +22,12 @@ + { + decl data_types() + { +- ${Socket::AbstractSKBuff.ref} skbuff; +- ${DMA::AbstractDMAHandle.scalar} dma_handle; +- unsigned int size; ++ ${Socket::AbstractSKBuff.ref} skbuff; + } + + chunk LKM::prototypes() + { + static void rtx_socket_skbuff_dump_infos(${Socket::SKBuff.ref}); +- static int rtx_socket_skbuff_map(${Socket::SKBuff.ref}, ${Device::AbstractDevice.ref}, ${DMA::DMADirection.scalar}); +- static void rtx_socket_skbuff_unmap_and_free(${Socket::SKBuff.ref}, ${Device::AbstractDevice.ref}, ${DMA::DMADirection.scalar}); + } + + chunk LKM::code() +@@ -63,85 +59,6 @@ + shinfo->nr_frags, shinfo->gso_size, shinfo->gso_segs, shinfo->gso_type + ); + } +- +- static int rtx_socket_skbuff_map(${Socket::SKBuff.ref} self, +- ${Device::AbstractDevice.ref} dev, +- ${DMA::DMADirection.scalar} direction) +- { +- WARN_ON(!${local.self.sk_buff}); +- WARN_ON(${local.self.dma_handle}); +- /* +- * TODO: we don't support skbuffs with paged data yet (see also +- * http://vger.kernel.org/~davem/skb_data.html). +- */ +- WARN_ON(skb_is_nonlinear(${local.self.sk_buff.k_sk_buff})); +- +- unsigned int len = ${local.self.size}; +- ${cast local.len as Builtin::number}; +- ${local.self.dma_handle} = ${DMA::map(local.dev, local.self.sk_buff.k_sk_buff, local.len, local.direction)}; +- int err = ${DMA::mapping_error(local.dev, local.self.dma_handle)}; +- if (err) +- { +- ${local.self.dma_handle} = 0; +- return err; +- } +- return 0; +- } +- +- static void rtx_socket_skbuff_unmap_and_free(${Socket::SKBuff.ref} self, +- ${Device::AbstractDevice.ref} dev, +- ${DMA::DMADirection} direction) +- { +- WARN_ON(!${local.self.sk_buff}); +- WARN_ON(skb_is_nonlinear(${local.self.sk_buff.k_sk_buff}); +- +- if (${local.self.dma_handle}) +- { +- unsigned int len = ${local.self.size}; +- ${cast local.len as Builtin::number}; +- ${DMA::unmap(local.dev, local.self.dma_handle, local.len, local.direction)}; +- ${local.self.dma_handle} = 0; +- } +- 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) +- { +- ${self.sk_buff} = ${kernel_skb}; +- ${self.size} = ${size}; +- ${self.dma_handle} = 0; +- } +- +- 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); +- } +- +- method map_from(Device::AbstractDevice dev) +- { +- rtx_socket_skbuff_map(${self}, ${dev}, RTX_DMA_FROM_DEVICE); +- } +- +- method unmap_to_and_free(Device::AbstractDevice dev) +- { +- rtx_socket_skbuff_unmap_and_free(${self}, ${dev}, RTX_DMA_TO_DEVICE); +- } +- +- 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 @@ + // management can be abstracted from the user. But this is at least + // useful for internal use: + sk_buff: (${self})->skbuff; +- // XXX: We need to cast here so we can do things like +- // var.dma_handle = 0; but the type shouldn't be hardcoded (at the +- // same time ${DMA:AbstractDMAHandle} couldn't be used because that +- // would yield to a struct type which you can't assign directly; +- // but maybe doing the ->data in that case would be acceptable). +- dma_handle: (*((dma_addr_t *)&(${self})->dma_handle)); +- size: (${self})->size; ++ ++ data: ((struct sk_buff *)((${self})->sk_buff))->data; ++ len: ((struct sk_buff *)((${self})->sk_buff))->len; + } + } + } +diff --git a/rathaxes/samples/e1000/socket.rti b/rathaxes/samples/e1000/socket.rti +--- a/rathaxes/samples/e1000/socket.rti ++++ b/rathaxes/samples/e1000/socket.rti +@@ -12,20 +12,14 @@ + { + chunk LKM::prototypes(); + chunk LKM::code(); ++ + decl data_types(); +- method init(Socket::AbstractSKBuff, Builtin::number); ++ ++ method init(Socket::AbstractSKBuff); + method dump_infos(); +- /* +- * map_to and map_from return a non-zero value on failure (which +- * doesn't correspond to an errno value): +- */ +- method map_to(Device::AbstractDevice); +- method map_from(Device::AbstractDevice); +- method unmap_to_and_free(Device::AbstractDevice); +- method unmap_from_and_free(Device::AbstractDevice); + +- attribute Socket::AbstractSKBuff.ref sk_buff; +- attribute DMA::AbstractDMAHandle.scalar dma_handle; +- attribute Builtin::number.scalar size; ++ attribute Socket::AbstractSKBuff.ref sk_buff; ++ attribute Builtin::symbol.ref data; ++ attribute Builtin::number.scalar len; + } + }