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