Mercurial > archived > louis > epitech > mq > rathaxes
view e1000_implement_the_frame_transmission_chunk.patch @ 87:e9736ab70995
Add a couple of patches to the build system and WIP on the e1000 code architecture to implement the tranmission
author | Louis Opter <louis@lse.epitech.net> |
---|---|
date | Mon, 24 Sep 2012 09:13:15 +0200 |
parents | c99e69966dd3 |
children | 8ffcdd6aa410 |
line wrap: on
line source
# HG changeset patch # Parent 87ba2a19a59fb7be346ad40a57439b6b752b152e rathaxes: start to queue up packets in the TX ring on the e1000 sample 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 @@ -1,6 +1,22 @@ -ADD_RATHAXES_SOURCES(e1000_src lkm.rtx - RTI builtin.rti log.rti lkm.rti pci.rti socket.rti ethernet.rti e1000.rti - BLT log.blt lkm.blt pci.blt socket.blt ethernet.blt e1000.blt) +ADD_RATHAXES_SOURCES(e1000_src + lkm.rtx + RTI + builtin.rti + log.rti + lkm.rti + device.rti + pci.rti + socket.rti + ethernet.rti + e1000.rti + BLT + log.blt + lkm.blt + pci.blt + device.blt + socket.blt + ethernet.blt + e1000.blt) IF (LINUX_KBUILD_DIR) ADD_RATHAXES_LKM(e1000 e1000_src) diff --git a/rathaxes/samples/e1000/device.blt b/rathaxes/samples/e1000/device.blt new file mode 100644 --- /dev/null +++ b/rathaxes/samples/e1000/device.blt @@ -0,0 +1,25 @@ +with Device, LKM +{ + template type Device::Device() + { + chunk LKM::includes() + { + #include <linux/device.h> + + static const ${Device::Device} force_rtx_device_decl; + } + + chunk decl() + { + typedef struct device *rtx_device_p; + } + + chunk init() + { + } + + map + { + } + } +} diff --git a/rathaxes/samples/e1000/device.rti b/rathaxes/samples/e1000/device.rti new file mode 100644 --- /dev/null +++ b/rathaxes/samples/e1000/device.rti @@ -0,0 +1,9 @@ +interface Device : LKM +{ + provided type Device + { + chunk LKM::includes(); + method decl(); + method init(); + } +} 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 @@ -110,9 +110,9 @@ { unsigned int size; struct rtx_e1000_rx_descriptor *base; - void* /* dma_addr_t */ dma_base; + dma_addr_t dma_base; struct sk_buff *skbuffs[256 /* ${config.rx_ring_size} */]; - void* /* dma_addr_t */ dma_skbuffs[256 /* ${config.rx_ring_size} */]; + dma_addr_t dma_skbuffs[256 /* ${config.rx_ring_size} */]; }; } @@ -148,11 +148,59 @@ struct rtx_e1000_tx_ring { unsigned int size; + /* We should probably use ${e1000::TxDescriptor} here: */ struct rtx_e1000_tx_descriptor *base; - void* /* dma_addr_t */ dma_base; + dma_addr_t dma_base; + /* indexes on base */ + unsigned int head; + unsigned int tail; }; } + chunk LKM::prototypes() + { + static unsigned int rtx_e1000_tx_ring_descriptors_remaining(struct rtx_e1000_tx_ring *); + static int rtx_e1000_tx_ring_tso_cksum_offload(struct rtx_e1000_tx_ring *, struct rtx_socket_skbuff *); + static int rtx_e1000_tx_ring_put(struct rtx_e1000_tx_ring *, struct rtx_socket_skbuff *); + } + + chunk LKM::code() + { + static unsigned int rtx_e1000_tx_ring_descriptors_remaining(struct rtx_e1000_tx_ring *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(struct rtx_e1000_tx_ring *self, struct rtx_socket_skbuff *skb) + { + return skb_is_gso(skb->skbuff) || skb->skbuff->ip_summed == CHECKSUM_PARTIAL; + } + + static int rtx_e1000_tx_ring_put(struct rtx_e1000_tx_ring *self, struct rtx_socket_skbuff *skb) + { + return NETDEV_TX_OK; + } + } + + chunk descriptors_remaining() + { + rtx_e1000_tx_ring_descriptors_remaining(${self}); + } + + chunk tso_cksum_offload(Socket::SKBuff skb) + { + } + + chunk put(Socket::SKBuff skb) + { + rtx_e1000_tx_ring_put(${self}, &${skb}); + } + chunk ::init() { } @@ -183,7 +231,7 @@ struct rtx_e1000_ctx { int bars; - unsigned char /* __iomem */ *ioaddr; + unsigned char __iomem *ioaddr; int irq; /* we can't use the Rathaxes type here (#8) */ @@ -334,6 +382,30 @@ } } + template type e1000::TxFlags() + { + chunk LKM::includes() + { + static const ${e1000::TxFlags} force_enum_rtx_e1000_tx_flags_decl; + } + + chunk ::decl() + { + enum rtx_e1000_tx_flags + { + E1000_TX_FLAGS_CSUM = 0x00000001, + E1000_TX_FLAGS_VLAN = 0x00000002, + E1000_TX_FLAGS_TSO = 0x00000004, + E1000_TX_FLAGS_IPV4 = 0x00000008, + E1000_TX_FLAGS_NO_FCS = 0x00000010, + }; + } + + map + { + } + } + template sequence e1000::create_device() { chunk Ethernet::create_device(PCI::Device pdev, Ethernet::Device rtx_ether_ctx) @@ -358,8 +430,8 @@ ${Log::info("e1000::create: pci_enable_device_mem failed")}; if (pci_request_selected_regions(${pdev}, ${rtx_ether_ctx}->hw_ctx.bars, ${config.name})) ${Log::info("e1000::create: pci_request_selected_regions failed")}; - if (${config.set_master}) - pci_set_master(${pdev}); +// XXX if (${config.set_master}) +// XXX pci_set_master(${pdev}); /* 0 here is for BAR_0: */ ${rtx_ether_ctx}->hw_ctx.ioaddr = pci_ioremap_bar(${pdev}, 0); @@ -630,8 +702,6 @@ { chunk ::CALL() { - typedef unsigned long int dma_addr_t; - /* * This part is documented in the Intel Gigabit Ethernet Controller * Software Developper manual. (You can find it in the doc/hardware @@ -733,7 +803,7 @@ hw_ctx->rx_ring.base = dma_alloc_coherent( &${ctx}->pci_dev->dev, hw_ctx->rx_ring.size, - (dma_addr_t *)&hw_ctx->rx_ring.dma_base, + &hw_ctx->rx_ring.dma_base, GFP_KERNEL); if (!hw_ctx->rx_ring.base) { @@ -758,7 +828,7 @@ ${Log::info("cannot allocate a skbuff for the rx ring")}; goto err_skbuffs_alloc; } - hw_ctx->rx_ring.dma_skbuffs[i] = (void *)dma_map_single( + hw_ctx->rx_ring.dma_skbuffs[i] = dma_map_single( &${ctx}->pci_dev->dev, hw_ctx->rx_ring.skbuffs[i]->data, ${config.rx_buffer_len}, @@ -820,7 +890,7 @@ hw_ctx->tx_ring.base = dma_alloc_coherent( &${ctx}->pci_dev->dev, hw_ctx->tx_ring.size, - (dma_addr_t *)&hw_ctx->tx_ring.dma_base, + &hw_ctx->tx_ring.dma_base, GFP_KERNEL); if (!hw_ctx->rx_ring.base) { @@ -838,6 +908,8 @@ /* 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_PSP); @@ -930,4 +1002,81 @@ } } } + + template sequence e1000::_xmit_tso_cksum_offload(Ethernet::Device ctx, Socket::SKBuff skb) + { + chunk ::CALL() + { + } + } + + template sequence e1000::xmit(Ethernet::Device ctx, Socket::KernelSKBuff kernel_skb) + { + chunk ::CALL() + { + /* + * Put packets on the TX ring, must return NETDEV_TX_OK or + * NETDEV_TX_BUSY. + */ + + /* + * XXX: This leaves a placeholder if I cast local.tx_ring as + * e1000::TxRing below. + */ + ${Socket::SKBuff} skb; + ${local.skb.init(kernel_skb)}; + + /* + * XXX: can't write ${e1000::TxRing} * (the placeholder isn't + * resolved). + */ + struct rtx_e1000_tx_ring *tx_ring = &${ctx}->hw_ctx.tx_ring; + //${cast local.tx_ring as e1000::TxRing}; + + ${Log::info("xmit: skbuff details:")}; + /* + * skb is 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); + + /* + * 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 contex + * 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. + */ + + /* XXX: same thing wanted to use: ${local.tx_ring.descriptors_remaining()} */ + if (!rtx_e1000_tx_ring_descriptors_remaining(tx_ring)) + return NETDEV_TX_BUSY; + + /* 1. Offloading */ + /* 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!")}; + return NETDEV_TX_OK; + } + + /* 2. Map the data */ + ${Device::Device} dev = &${ctx}->pci_dev->dev; + /* XXX: ${local.skb.dma_map(local.dev)}; */ + rtx_socket_dma_map(&skb, dev); + + /* 3. Update the TX Ring */ + /* XXX: ${local.tx_ring.put(skb)}; */ + rtx_e1000_tx_ring_put(tx_ring, &skb); + + return NETDEV_TX_OK; + } + } } diff --git a/rathaxes/samples/e1000/e1000.rti b/rathaxes/samples/e1000/e1000.rti --- a/rathaxes/samples/e1000/e1000.rti +++ b/rathaxes/samples/e1000/e1000.rti @@ -31,8 +31,14 @@ provided type TxRing { chunk LKM::includes(); + chunk LKM::prototypes(); + chunk LKM::code(); method decl(); method init(); + + method descriptors_remaining(); + method tso_cksum_offload(Socket::SKBuff); + method put(Socket::SKBuff); } /* @@ -51,6 +57,12 @@ method decl(); } + provided type TxFlags + { + chunk LKM::includes(); + chunk ::decl(); + } + provided sequence create_device() { provided chunk Ethernet::create_device(PCI::Device, Ethernet::Device); @@ -109,6 +121,16 @@ provided chunk ::CALL(); } + provided sequence _xmit_tso_cksum_offload(Ethernet::Device, Socket::SKBuff) + { + provided chunk ::CALL(); + } + + provided sequence xmit(Ethernet::Device, Socket::KernelSKBuff) + { + provided chunk ::CALL(); + } + provided sequence register_read32(e1000::Context, e1000::Register) { provided chunk LKM::prototypes(); 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 @@ -1,6 +1,56 @@ with Ethernet, PCI, LKM, Log { - template type Ethernet::Net() + template type Ethernet::ProtocolId() + { + chunk LKM::prototypes() + { + static const char *rtx_ethernet_protocol_id_to_str(unsigned short); + } + + chunk LKM::data() + { + static const struct + { + const unsigned short id; + const char *name; + } rtx_ethernet_proto_table[] = + { + { ETH_P_IP, "IPv4" }, + { ETH_P_IPV6, "IPv6" }, + { ETH_P_ARP, "ARP" }, + }; + } + + chunk LKM::code() + { + static const char *rtx_ethernet_protocol_id_to_str(unsigned short proto_id) + { + for (int i = 0; + i != sizeof(rtx_ethernet_proto_table[0]) / sizeof(rtx_ethernet_proto_table); + i++) + if (proto_id == rtx_ethernet_proto_table[i].id) + return rtx_ethernet_proto_table[i].name; + + return "Unknown"; + } + } + + chunk decl() + { + typedef unsigned short rtx_ether_protocol_id; + } + + chunk to_str() + { + rtx_ethernet_protocol_id_to_str(${self}); + } + + map + { + } + } + + template type Ethernet::AbstractDevice() { chunk LKM::includes() { @@ -17,11 +67,6 @@ } } - /* - * Unlike PCI::Device, Ethernet::Device doesn't match the struct net_device - * from Linux. Ethernet::Device is the type that we use in the private - * field of the struct net_device. - */ template type Ethernet::Device() { chunk LKM::includes() @@ -47,15 +92,15 @@ struct pci_dev *pci_dev; struct net_device *net_dev; - /* while waiting on issue #8 */ - //${e1000::Context} hw_ctx; - // In the long-term, this may disappear for a new concept allowing - // to embbed a descriptor defined and manipulated by the front-end + /* + * In the long-term, this may disappear for a new concept allowing + * to embbed a descriptor defined and manipulated by the front-end + */ ${pointcut Ethernet::SubContext()}; } *rtx_ethernet_dev_p; } - chunk ::init(Ethernet::Net net_dev, PCI::Device pci_dev) + chunk ::init(Ethernet::AbstractDevice net_dev, PCI::Device pci_dev) { ${self} = netdev_priv(${net_dev}); /* @@ -82,9 +127,8 @@ { static int rtx_ethernet_open(struct net_device *dev) { - struct rtx_ethernet_dev* rtx_ether_dev = netdev_priv(dev); + ${Ethernet::Device} rtx_ether_dev = netdev_priv(dev); - ${cast local.rtx_ether_dev as Ethernet::Device}; ${pointcut ::IMPLEMENTATION(local.rtx_ether_dev)}; return 0; @@ -92,7 +136,7 @@ } } - template sequence Ethernet::send(Ethernet::Device dev, Socket::SKBuff skb) + template sequence Ethernet::send(Ethernet::Device dev, Socket::KernelSKBuff skb) { chunk LKM::prototypes() { @@ -101,13 +145,11 @@ chunk LKM::code() { - static int rtx_ethernet_xmit(struct sk_buff* skb, struct net_device *dev) + static int rtx_ethernet_xmit(struct sk_buff* kernel_skb, struct net_device *net_dev) { - ${cast local.dev as Ethernet::Device}; - ${cast local.skb as Socket::SKBuff}; - ${pointcut ::IMPLEMENTATION(local.dev, local.skb)}; - - return 0; + ${Ethernet::Device} rtx_ethernet_dev = netdev_priv(net_dev); + ${cast local.kernel_skb as Socket::KernelSKBuff}; + ${pointcut ::IMPLEMENTATION(local.rtx_ethernet_dev, local.kernel_skb)}; } } } @@ -123,9 +165,8 @@ { static int rtx_ethernet_close(struct net_device *dev) { - struct rtx_ethernet_dev* rtx_ether_dev = netdev_priv(dev); + ${Ethernet::Device} rtx_ether_dev = netdev_priv(dev); - ${cast local.rtx_ether_dev as Ethernet::Device}; ${pointcut ::IMPLEMENTATION(local.rtx_ether_dev)}; return 0; @@ -148,11 +189,8 @@ { static enum irqreturn rtx_ethernet_interrupt_handler(int irq, void *dev_id) { - struct rtx_ethernet_dev* rtx_ether_dev; - struct rtx_e1000_ctx* ctx; + ${Ethernet::Device} rtx_ether_dev = dev_id; - rtx_ether_dev = dev_id; - ${cast local.rtx_ether_dev as Ethernet::Device}; ${pointcut ::IMPLEMENTATION(local.rtx_ether_dev)}; return IRQ_NONE; 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 @@ -1,16 +1,30 @@ interface Ethernet : Socket, PCI, LKM { - provided type Net + provided type ProtocolId + { + chunk LKM::prototypes(); + chunk LKM::data(); + chunk LKM::code(); + method decl(); + method to_str(); + } + + provided type AbstractDevice { chunk LKM::includes(); - method decl(); + method decl(); } + /* + * Unlike PCI::Device, Ethernet::Device doesn't match the struct net_device + * from Linux. Ethernet::Device is the type that we use in the private + * field of the struct net_device. + */ provided type Device { chunk LKM::includes(); method decl(); - method init(Ethernet::Net, PCI::Device); + method init(Ethernet::AbstractDevice, PCI::Device); pointcut Ethernet::SubContext(); } @@ -22,7 +36,7 @@ provided chunk LKM::code(); } - required sequence send(Ethernet::Device dev, Socket::SKBuff skb) + required sequence send(Ethernet::Device, Socket::KernelSKBuff) { provided chunk LKM::prototypes(); provided chunk LKM::code(); 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,4 +1,4 @@ -device LKM use LKM, PCI, Ethernet, Log +device LKM use LKM, PCI, Ethernet, Log, Socket { Ethernet::open(Ethernet::Device dev) { @@ -43,9 +43,10 @@ e1000::handle_interrupt(dev); } - Ethernet::send(Ethernet::Device dev, Socket::SKBuff skb) + Ethernet::send(Ethernet::Device dev, Socket::KernelSKBuff skb) { Log::info("we have one packet to transmit!"); + e1000::xmit(dev, skb); } LKM::init() @@ -79,4 +80,10 @@ * 4096, 8192 and 16384 bytes: */ e1000::rx_buffer_len = 2048; + /* + * 4096 bytes maximum per transmit descriptor is used on Linux and FreeBSD, + * 2048 on Minix and HelenOS, I can't find why. If I understand the Intel + * man correctly, the maximum should be 16288 (see section 3.3.3). + */ + e1000::tx_max_data_per_desc = 4096; } 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 @@ -1,20 +1,104 @@ -with Socket, LKM +with Socket, LKM, Device, Ethernet { + template type Socket::KernelSKBuff() + { + chunk LKM::includes() + { + #include <linux/skbuff.h> + + static const ${Socket::KernelSKBuff} force_rtx_socket_kernel_skbuff_decl; + } + + chunk ::decl() + { + typedef struct sk_buff *rtx_socket_kernel_skbuff_p; + } + + map + { + } + } + template type Socket::SKBuff() { chunk LKM::includes() { - #include <linux/skbuff.h> - static const ${Socket::SKBuff} force_rtx_lnux_skbuf_decl; + static const ${Socket::SKBuff} force_rtx_socket_skbuff_decl; } chunk ::decl() { - struct sk_buff; + struct rtx_socket_skbuff + { + struct sk_buff *skbuff; + dma_addr_t dma_handle; + }; } - chunk ::init() + chunk LKM::prototypes() { + static void rtx_socket_skbuff_dump_infos(struct rtx_socket_skbuff *); + static int rtx_socket_dma_map(struct rtx_socket_skbuff *, struct device *); + } + + chunk LKM::code() + { + static void rtx_socket_skbuff_dump_infos(struct rtx_socket_skbuff *self) + { + /* + * We should use a Rathaxes log abstraction instead of pr_info here, + * but Rathaxes doesn't support functions with a variable number of + * arguments yet. + */ + ${Ethernet::ProtocolId} ethernet_proto = be16_to_cpu(self->skbuff->protocol); + static const char * const ip_summed_values[] = { + "none", "unnecessary", "complete", "partial" + }; + struct skb_shared_info *shinfo = skb_shinfo(self->skbuff); + + pr_info( + "\t protocol = %#-5x (%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\n" + "\tip_summed = %d (%s)", + ethernet_proto, rtx_ethernet_protocol_id_to_str(ethernet_proto) /* XXX: ${local.ethernet_proto.to_str()} */, + self->skbuff->len, self->skbuff->data_len, skb_headlen(self->skbuff), + shinfo->nr_frags, shinfo->gso_size, shinfo->gso_segs, shinfo->gso_type, + self->skbuff->ip_summed, ip_summed_values[self->skbuff->ip_summed] + ); + } + + static int rtx_socket_dma_map(struct rtx_socket_skbuff *self, struct device *dev) + { + self->dma_handle = dma_map_single( + dev, + self->skbuff->data, + skb_headlen(self->skbuff), + DMA_TO_DEVICE); + return dma_mapping_error(dev, self->dma_handle); + } + } + + /* + * 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) + */ + chunk ::init(Socket::KernelSKBuff kernel_skb) + { + ${self}.skbuff = kernel_skb; + ${self}.dma_handle = 0; + } + + chunk dump_infos() + { + rtx_socket_skbuff_dump_infos(${self}); + } + + chunk dma_map(Device::Device dev) + { + rtx_socket_dma_map(${self}, ${dev}); } map 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 @@ -1,8 +1,19 @@ -interface Socket : LKM +interface Socket : LKM, Device { - provided type Socket::SKBuff { - chunk LKM::includes(); - method decl(); - method init(); + provided type KernelSKBuff + { + chunk LKM::includes(); + method decl(); + } + + provided type SKBuff + { + chunk LKM::includes(); + chunk LKM::prototypes(); + chunk LKM::code(); + method decl(); + method init(Socket::KernelSKBuff); + method dump_infos(); + method dma_map(Device::Device); } }