# HG changeset patch # User Louis Opter # Date 1326459277 -3600 # Node ID 7b377e31fea359f64d4260380fea39854e9d7bc4 # Parent cf7d541b933154cea23c8229b313e741a491ffd5 Finish the patch the e1000 LKM diff -r cf7d541b9331 -r 7b377e31fea3 rathaxes_add_lkm_ethernet_sample.patch --- a/rathaxes_add_lkm_ethernet_sample.patch Fri Jan 13 11:59:42 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1268 +0,0 @@ -# HG changeset patch -# User Thomas Sanchez , Louis Opter -# Parent 3a7169517431da7a5a9a3c411ff95927c55f214f -rathaxes: add the beginning of a Linux Intel e1000 network card driver - -- With working LKM/PCI/Ethernet parts; -- Some interruption handling POC; -- Directly compiles to a .ko object. - -diff --git a/maintainers/CMakeScripts/Templates/MakefileLKM.in b/maintainers/CMakeScripts/Templates/MakefileLKM.in ---- a/maintainers/CMakeScripts/Templates/MakefileLKM.in -+++ b/maintainers/CMakeScripts/Templates/MakefileLKM.in -@@ -1,5 +1,9 @@ --KDIR = /lib/modules/$(shell uname -r)/build --obj-m := @LKM_OBJECTS@ -+# Disable this "coding-style" warning (seriously, you have to compile with -+# -pedantic to get it...) -+EXTRA_CFLAGS = -Wno-declaration-after-statement -+ -+KDIR = /lib/modules/$(shell uname -r)/build -+obj-m := @LKM_OBJECTS@ - - all: - $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) modules -diff --git a/maintainers/CMakeScripts/UseRathaxes.cmake b/maintainers/CMakeScripts/UseRathaxes.cmake ---- a/maintainers/CMakeScripts/UseRathaxes.cmake -+++ b/maintainers/CMakeScripts/UseRathaxes.cmake -@@ -193,6 +193,8 @@ - - SET(KERNEL_OBJECT_NAME "${RATHAXES_SOURCE}_${SYSTEM}.ko") - ADD_CUSTOM_COMMAND(OUTPUT "${KERNEL_OBJECT_NAME}" -+ # … -+ COMMAND "sed" "-i" "/TARTE/ d" "${RATHAXES_SOURCE}_${SYSTEM}.c" - # The linux Makefile to build kernel module is quite - # picky about file location and its own name. Let's - # copy our source side by side with the Makefile: -diff --git a/rathaxes/samples/CMakeLists.txt b/rathaxes/samples/CMakeLists.txt ---- a/rathaxes/samples/CMakeLists.txt -+++ b/rathaxes/samples/CMakeLists.txt -@@ -1,2 +1,3 @@ - ADD_SUBDIRECTORY(helloworld) - ADD_SUBDIRECTORY(syntax) -+ADD_SUBDIRECTORY(e1000) -diff --git a/rathaxes/samples/e1000/CMakeLists.txt b/rathaxes/samples/e1000/CMakeLists.txt -new file mode 100644 ---- /dev/null -+++ b/rathaxes/samples/e1000/CMakeLists.txt -@@ -0,0 +1,7 @@ -+ADD_RATHAXES_SOURCES(e1000_src lkm.rtx -+ 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) -+ -+# We can't name lkm since it's already used as the target name to generate the -+# source (with ADD_RATHAXES_SOURCES). -+ADD_RATHAXES_LKM(e1000 e1000_src) -diff --git a/rathaxes/samples/e1000/e1000.blt b/rathaxes/samples/e1000/e1000.blt -new file mode 100644 ---- /dev/null -+++ b/rathaxes/samples/e1000/e1000.blt -@@ -0,0 +1,435 @@ -+with e1000, Ethernet, Socket, PCI, LKM, Log -+{ -+ template type e1000::Context() -+ { -+ chunk LKM::includes() -+ { -+ /* -+ * 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). -+ */ -+ typedef int ${e1000::Context}; /* CNorm __std__ workaround */ -+ static const ${e1000::Context} force_struct_rtx_10000_ctx_decl; -+ } -+ -+ chunk ::decl() -+ { -+ struct rtx_e1000_ctx -+ { -+ int bars; -+ unsigned char /* __iomem */ *ioaddr; -+ int irq; -+ }; -+ } -+ -+ chunk ::init(bars, ioaddr) -+ { -+ ${self}.bars = ${bars}; -+ ${self}.ioaddr = ${ioaddr}; -+ } -+ -+ map -+ { -+ } -+ } -+ -+ template type e1000::Register() -+ { -+ chunk LKM::includes() -+ { -+ typedef int ${e1000::Register}; -+ static const ${e1000::Register} force_enum_rtx_e1000_registers_decl; -+ } -+ -+ chunk ::decl() -+ { -+ enum rtx_e1000_registers -+ { -+ 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 */ -+ }; -+ } -+ -+ chunk ::init(value) -+ { -+ ${self} = ${value}; -+ } -+ -+ map -+ { -+ } -+ } -+ -+ template type e1000::Commands() -+ { -+ chunk LKM::includes() -+ { -+ typedef int ${e1000::Commands}; -+ static const ${e1000::Commands} force_enum_rtx_e1000_commands_decls; -+ } -+ -+ chunk ::decl() -+ { -+ enum rtx_e1000_commands -+ { -+ 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 */ -+ }; -+ } -+ -+ map -+ { -+ } -+ } -+ -+ template sequence e1000::create_device() -+ { -+ chunk Ethernet::create_device() -+ { -+ rtx_ether_ctx->hw_ctx.irq = pdev->irq; -+ rtx_ether_ctx->hw_ctx.bars = pci_select_bars(pdev, IORESOURCE_MEM); -+ if (pci_enable_device_mem(pdev)) -+ { -+ ${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); -+ } -+ -+ /* 0 here is for BAR_0: */ -+ rtx_ether_ctx->hw_ctx.ioaddr = pci_ioremap_bar(pdev, 0); -+ if (!rtx_ether_ctx->hw_ctx.ioaddr) -+ { -+ ${Log::info("e1000::create: pci_ioremap_bar failed")}; -+ } -+ -+ /* Reset the card */ -+ rtx_e1000_register_write32(&rtx_ether_ctx->hw_ctx, E1000_CTRL, E1000_CMD_RST); -+ udelay(10); -+ -+ /* Now we can load its mac address */ -+ int i = 0; -+ for (i = 0 /* < this is not generated! */; i < 3; ++i) -+ { -+ rtx_e1000_register_write32(&rtx_ether_ctx->hw_ctx, E1000_EEPROM_READ, (i << 8) | 1); -+ -+ int value; -+ /* Should be a do { } while(); but the compiler doesn't do { } while(); yet. */ -+ value = rtx_e1000_register_read32(&rtx_ether_ctx->hw_ctx, E1000_EEPROM_READ); -+ while ((value & (1 << 4)) == 0) -+ value = rtx_e1000_register_read32(&rtx_ether_ctx->hw_ctx, E1000_EEPROM_READ); -+ value >>= 16; -+ -+ rtx_ether_ctx->net_dev->dev_addr[i * 2] = value & 0xff; -+ rtx_ether_ctx->net_dev->dev_addr[i * 2 + 1] = (value >> 8) & 0xff; -+ } -+ -+ memcpy(rtx_ether_ctx->net_dev->perm_addr, -+ rtx_ether_ctx->net_dev->dev_addr, -+ rtx_ether_ctx->net_dev->addr_len); -+ -+ { /* < mais lol. */ -+ ${Log::info("e1000::create: mac address loaded from the EEPROM")}; -+ } -+ } -+ -+ chunk ::CALL -+ { -+ } -+ } -+ -+ template sequence e1000::destroy_device() -+ { -+ chunk Ethernet::destroy_device -+ { -+ /* -+ * Here, we should have some checks to avoid to free resources that -+ * haven't been allocated. (e.g: in case of previous errors). -+ */ -+ struct rtx_ethernet_dev* rtx_ether_ctx = netdev_priv(net_dev); -+ iounmap(rtx_ether_ctx->hw_ctx.ioaddr); -+ pci_release_selected_regions(pdev, rtx_ether_ctx->hw_ctx.bars); -+ } -+ -+ chunk ::CALL -+ { -+ } -+ } -+ -+ template sequence e1000::print_status() -+ { -+ chunk LKM::prototypes() -+ { -+ static void rtx_e1000_print_status(struct rtx_e1000_ctx *); -+ } -+ -+ chunk LKM::code() -+ { -+ static void rtx_e1000_print_status(struct rtx_e1000_ctx *ctx) -+ { -+ unsigned int status = rtx_e1000_register_read32(ctx, E1000_STATUS); -+ pr_info("rtx_e1000 status: \n"); -+ pr_info("\tRegister value: 0x%x\n", status); -+ pr_info("\tMode: %s\n", (status & 1) ? "Full": "Half"); -+ pr_info("\tLink: %s\n", (status & 2) ? "Up" : "Down"); -+ pr_info("\tTransmission: %s\n", (status & 4) ? "Paused" : "Ok"); -+ pr_info("\tInterface: %s\n", (status & 3) == 3 ? "Up" : "Down"); -+ } -+ } -+ -+ chunk ::CALL -+ { -+ } -+ } -+ -+ /* -+ * 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": -+ * typedef int ${e1000::Register}; // cnorm __std__ workaround -+ * ${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)}; -+ */ -+ template sequence e1000::register_read32(e1000::Context ctx, e1000::Register reg_offset) -+ { -+ chunk LKM::prototypes() -+ { -+ static unsigned int rtx_e1000_register_read32(struct rtx_e1000_ctx *, unsigned int); -+ } -+ -+ chunk LKM::code() -+ { -+ static unsigned int rtx_e1000_register_read32(struct rtx_e1000_ctx *ctx, unsigned int reg_offset) -+ { -+ return ioread32(ctx->ioaddr + reg_offset); -+ } -+ } -+ -+ chunk ::CALL() -+ { -+ rtx_e1000_register_read32(&${ctx}, ${reg_offset}); -+ } -+ } -+ -+ template sequence e1000::register_write32(e1000::Context ctx, e1000::Register reg_offset, ::number value) -+ { -+ chunk LKM::prototypes() -+ { -+ static void rtx_e1000_register_write32(struct rtx_e1000_ctx *, unsigned int, unsigned int); -+ } -+ -+ chunk LKM::code() -+ { -+ static void rtx_e1000_register_write32(struct rtx_e1000_ctx *ctx, unsigned int reg_offset, unsigned int value) -+ { -+ iowrite32(value, ctx->ioaddr + reg_offset); -+ } -+ } -+ -+ chunk ::CALL() -+ { -+ rtx_e1000_register_write32(&${ctx}, ${reg_offset}); -+ } -+ } -+ -+ template sequence e1000::register_set32(e1000::Context ctx, e1000::Register reg_offset, ::number value) -+ { -+ chunk LKM::prototypes() -+ { -+ static void rtx_e1000_register_set32(struct rtx_e1000_ctx *, unsigned int, unsigned int); -+ } -+ -+ chunk LKM::code() -+ { -+ static void rtx_e1000_register_set32(struct rtx_e1000_ctx *ctx, unsigned int reg_offset, unsigned int value) -+ { -+ iowrite32(rtx_e1000_register_read32(ctx, reg_offset) | value, ctx->ioaddr + reg_offset); -+ } -+ } -+ -+ chunk ::CALL() -+ { -+ } -+ } -+ -+ template sequence e1000::setup_interrupt_handler() -+ { -+ chunk LKM::includes() -+ { -+ #include -+ } -+ chunk LKM::prototypes() -+ { -+ static int e1000_setup_interrupt_handler(struct rtx_ethernet_dev *); -+ } -+ -+ chunk LKM::code() -+ { -+ static int e1000_setup_interrupt_handler(struct rtx_ethernet_dev *ethernet_ctx) -+ { -+ int error; -+ -+ error = request_irq(ethernet_ctx->hw_ctx.irq, -+ rtx_ethernet_interrupt_handler, -+ IRQF_SHARED, -+ ${config.name}, -+ ethernet_ctx); -+ -+ if (error) -+ { -+ ${Log::info("Cannot register the interruption")}; -+ } -+ -+ return error; -+ } -+ } -+ -+ chunk ::CALL() -+ { -+ // this is an hack for the scope -+ (void)1; -+ { -+ int error; -+ error = e1000_setup_interrupt_handler(rtx_ether_dev); -+ if (error) -+ { -+ return error; -+ } -+ } -+ } -+ } -+ -+ template sequence e1000::free_interrupt_handler() -+ { -+ chunk LKM::prototypes() -+ { -+ static void e1000_free_interrupt_handler(struct rtx_ethernet_dev *ethernet_ctx); -+ } -+ -+ chunk LKM::code() -+ { -+ static void e1000_free_interrupt_handler(struct rtx_ethernet_dev *ethernet_ctx) -+ { -+ -+ free_irq(ethernet_ctx->hw_ctx.irq, ethernet_ctx); -+ } -+ } -+ -+ chunk ::CALL() -+ { -+ e1000_free_interrupt_handler(rtx_ether_dev); -+ } -+ } -+ -+ template sequence e1000::activate_device_interruption() -+ { -+ chunk ::CALL() -+ { -+ rtx_e1000_register_write32(ctx, E1000_IMS, -+ E1000_INTR_TXDW | -+ E1000_INTR_TXQE | -+ E1000_INTR_LSC | -+ E1000_INTR_RXO | -+ E1000_INTR_RXT0); -+ } -+ } -+ -+ template sequence e1000::set_up_device() -+ { -+ chunk ::CALL() -+ { -+ rtx_e1000_register_set32(ctx, E1000_CTRL, -+ E1000_CMD_ASDE | -+ E1000_CMD_SLU | -+ E1000_CMD_LRST | -+ E1000_CMD_PHY_RST); -+ } -+ } -+ -+ template sequence e1000::handle_intr() -+ { -+ chunk ::CALL() -+ { -+ int intr; -+ -+ intr = rtx_e1000_register_read32(ctx, E1000_ICR); -+ if (intr & E1000_INTR_LSC) -+ { -+ ${Log::info("Link status changed")}; -+ } -+ -+ if (intr) -+ { -+ return IRQ_HANDLED; -+ } -+ } -+ } -+} -diff --git a/rathaxes/samples/e1000/e1000.rti b/rathaxes/samples/e1000/e1000.rti -new file mode 100644 ---- /dev/null -+++ b/rathaxes/samples/e1000/e1000.rti -@@ -0,0 +1,89 @@ -+interface e1000 : Socket, Ethernet, PCI, LKM -+{ -+ provided type e1000::Context; -+ provided type e1000::Register; -+ provided type e1000::Commands; -+ -+ /* -+ * This sequence should receive an argument like Ethernet::Device, but it is -+ * unclear about how this argument should be bound to a variable/argument in -+ * the instrumented C code. -+ * -+ * Here again, we rely on the fact that *we* wrote the parent context and -+ * named the C variables we need/use with the same name everywhere. -+ */ -+ provided sequence e1000::create_device() -+ { -+ provided chunk Ethernet::create_device; -+ provided chunk ::CALL; -+ } -+ -+ provided sequence e1000::destroy_device() -+ { -+ provided chunk Ethernet::destroy_device; -+ provided chunk ::CALL; -+ } -+ -+ /* -+ * This should take an e1000::Context as the first argument but this was -+ * not working as wished. -+ */ -+ provided sequence e1000::print_status() -+ { -+ provided chunk LKM::prototypes; -+ provided chunk LKM::code; -+ provided chunk ::CALL; -+ } -+ -+ provided sequence e1000::setup_interrupt_handler() -+ { -+ provided chunk LKM::includes; // work without this one -+ provided chunk LKM::prototypes; -+ provided chunk LKM::code; -+ provided chunk ::CALL; -+ } -+ -+ provided sequence e1000::free_interrupt_handler() -+ { -+ provided chunk LKM::prototypes; -+ provided chunk LKM::code; -+ provided chunk ::CALL; -+ } -+ -+ provided sequence e1000::activate_device_interruption() -+ { -+ provided chunk ::CALL; -+ } -+ -+ provided sequence e1000::set_up_device() -+ { -+ provided chunk ::CALL; -+ } -+ -+ provided sequence e1000::handle_intr() -+ { -+ provided chunk ::CALL; -+ } -+ -+ -+ provided sequence e1000::register_read32(e1000::Context, e1000::Register) -+ { -+ provided chunk LKM::prototypes; -+ provided chunk LKM::code; -+ provided chunk ::CALL; -+ } -+ -+ provided sequence e1000::register_write32(e1000::Context, e1000::Register, ::number) -+ { -+ provided chunk LKM::prototypes; -+ provided chunk LKM::code; -+ provided chunk ::CALL; -+ } -+ -+ provided sequence e1000::register_set32(e1000::Context, e1000::Register, ::number) -+ { -+ provided chunk LKM::prototypes; -+ provided chunk LKM::code; -+ provided chunk ::CALL; -+ } -+} -diff --git a/rathaxes/samples/e1000/ethernet.blt b/rathaxes/samples/e1000/ethernet.blt -new file mode 100644 ---- /dev/null -+++ b/rathaxes/samples/e1000/ethernet.blt -@@ -0,0 +1,218 @@ -+with Ethernet, PCI, LKM, Log -+{ -+ template type Ethernet::Device() -+ { -+ chunk LKM::includes() -+ { -+ #include -+ #include -+ } -+ -+ chunk ::decl() -+ { -+ struct rtx_ethernet_dev -+ { -+ /* -+ * I think it's useless to use the ${PCI::Device} "abstraction" -+ * here, since we are already in a Linux specific context here. -+ */ -+ struct pci_dev *pci_dev; -+ struct net_device *net_dev; -+ -+ /* while waiting on issue #8 */ -+ struct rtx_e1000_ctx hw_ctx; -+ }; -+ } -+ -+ chunk ::init(net_dev) -+ { -+ ${self} = ${net_dev}; -+ } -+ -+ map -+ { -+ } -+ } -+ -+ template sequence Ethernet::open(Ethernet::Device dev) -+ { -+ chunk LKM::prototypes() -+ { -+ static int rtx_ethernet_open(struct net_device *); -+ } -+ -+ chunk LKM::code() -+ { -+ static int rtx_ethernet_open(struct net_device *dev) -+ { -+ struct rtx_ethernet_dev* rtx_ether_dev = netdev_priv(dev); -+ struct rtx_e1000_ctx* ctx = &rtx_ether_dev->hw_ctx; -+ -+ ${pointcut ::IMPLEMENTATION}; -+ -+ return 0; -+ } -+ } -+ } -+ -+ template sequence Ethernet::send(Ethernet::Device dev, Socket::SKBuff skb) -+ { -+ chunk LKM::prototypes() -+ { -+ static int rtx_ethernet_xmit(struct sk_buff* skb, struct net_device *dev); -+ } -+ -+ chunk LKM::code() -+ { -+ static int rtx_ethernet_xmit(struct sk_buff* skb, struct net_device *dev) -+ { -+ ${pointcut ::IMPLEMENTATION}; -+ -+ return 0; -+ } -+ } -+ } -+ -+ template sequence Ethernet::close(Ethernet::Device dev) -+ { -+ chunk LKM::prototypes() -+ { -+ static int rtx_ethernet_close(struct net_device *); -+ } -+ -+ chunk LKM::code() -+ { -+ static int rtx_ethernet_close(struct net_device *dev) -+ { -+ struct rtx_ethernet_dev* rtx_ether_dev = netdev_priv(dev); -+ struct rtx_e1000_ctx* ctx = &rtx_ether_dev->hw_ctx; -+ -+ ${pointcut ::IMPLEMENTATION}; -+ -+ return 0; -+ } -+ } -+ } -+ -+ template sequence Ethernet::interrupt_handler(Ethernet::Device dev) -+ { -+ /* -+ * We can't use the irqreturn_t type here because CNornm doesn't know -+ * it. -+ */ -+ chunk LKM::prototypes() -+ { -+ static enum irqreturn rtx_ethernet_interrupt_handler(int, void *); -+ } -+ -+ chunk LKM::code() -+ { -+ static enum irqreturn rtx_ethernet_interrupt_handler(int irq, void *dev_id) -+ { -+ struct rtx_ethernet_dev* rtx_ether_dev; -+ struct rtx_e1000_ctx* ctx; -+ -+ rtx_ether_dev = dev_id; -+ ctx = &rtx_ether_dev->hw_ctx; -+ ${pointcut ::IMPLEMENTATION}; -+ -+ return IRQ_NONE; -+ } -+ } -+ } -+ -+ template sequence Ethernet::init(PCI::Device pdev) -+ { -+ chunk LKM::data() -+ { -+ static const struct net_device_ops rtx_ether_ops = -+ { -+ .ndo_open = rtx_ethernet_open, -+ .ndo_stop = rtx_ethernet_close, -+ .ndo_start_xmit = rtx_ethernet_xmit, -+ }; -+ } -+ -+ chunk PCI::pci_probe_hook() -+ { -+ /* -+ * This typedef is needed to workaround a bug in CNorm __std__ -+ * dialect. -+ */ -+ typedef int ${Ethernet::Device}; -+ ${Ethernet::Device} *rtx_ether_ctx; -+ struct net_device *net_dev; -+ int error; -+ -+ error = 0; -+ net_dev = alloc_etherdev(sizeof(*rtx_ether_ctx)); -+ if (net_dev == 0) -+ { -+ ${Log::info("Cannot allocate memory")}; -+ /* -+ * Again, the error should be "raised" in the parent context. -+ * -+ * Here we know that we should return ENOMEM because *we* wrote -+ * the parent context. -+ */ -+ return -ENOMEM; -+ } -+ strlcpy(net_dev->name, ${config.ifname}, sizeof(net_dev->name)); -+ net_dev->irq = pdev->irq; -+ // Maybe we should try ${rtx_ether_ctx.init()} here: -+ rtx_ether_ctx = netdev_priv(net_dev); -+ //rtx_ether_ctx->pci_dev = ${pdev}; -+ rtx_ether_ctx->pci_dev = pdev; // In the meantime do it directly -+ rtx_ether_ctx->net_dev = net_dev; -+ -+ /* -+ * The substitution of ${pdev} fails here. I also tried to add a -+ * "substitute method" to the PCI::Device that was just doing -+ * "${self}" but it didn't work either (it was subsituted by a -+ * placeholder, e.g: _1). -+ * -+ * That's why we cheated a bit and named all the arguments pdev. -+ */ -+ //SET_NETDEV_DEV(net_dev, &${pdev}->dev); -+ SET_NETDEV_DEV(net_dev, &pdev->dev); -+ net_dev->netdev_ops = &rtx_ether_ops; -+ if ((error = register_netdev(net_dev))) -+ { -+ ${Log::info("Cannot register the driver")}; -+ return error; -+ } -+ -+ /* same problem as above with ${pdev} */ -+ //pci_set_drvdata(${pdev}, net_dev); -+ pci_set_drvdata(pdev, net_dev); -+ -+ ${pointcut Ethernet::create_device}; -+ } -+ -+ chunk ::CALL -+ { -+ } -+ } -+ -+ template sequence Ethernet::exit(PCI::Device pdev) -+ { -+ chunk PCI::pci_remove_hook() -+ { -+ struct net_device *net_dev = pci_get_drvdata(pdev); -+ -+ ${pointcut Ethernet::destroy_device}; -+ -+ unregister_netdev(net_dev); -+ /* -+ * If we had some cleanup todo with struct rtx_ether_ctx we would -+ * do a netdev_priv(net_dev) here and do it. -+ */ -+ free_netdev(net_dev); -+ } -+ -+ chunk ::CALL -+ { -+ } -+ } -+} -+ -diff --git a/rathaxes/samples/e1000/ethernet.rti b/rathaxes/samples/e1000/ethernet.rti -new file mode 100644 ---- /dev/null -+++ b/rathaxes/samples/e1000/ethernet.rti -@@ -0,0 +1,47 @@ -+interface Ethernet : Socket, PCI, LKM -+{ -+ provided type Ethernet::Device; -+ -+ required variable ::string Ethernet::ifname; -+ -+ required sequence Ethernet::open(Ethernet::Device) -+ { -+ provided chunk LKM::prototypes; -+ provided chunk LKM::code; -+ } -+ -+ required sequence Ethernet::send(Ethernet::Device dev, Socket::SKBuff skb) -+ { -+ provided chunk LKM::prototypes; -+ provided chunk LKM::code; -+ } -+ -+ required sequence Ethernet::close(Ethernet::Device) -+ { -+ provided chunk LKM::prototypes; -+ provided chunk LKM::code; -+ } -+ -+ required sequence Ethernet::interrupt_handler(Ethernet::Device) -+ { -+ provided chunk LKM::prototypes; -+ provided chunk LKM::code; -+ } -+ -+ provided sequence Ethernet::init(PCI::Device) -+ { -+ provided chunk LKM::data; -+ provided chunk PCI::pci_probe_hook; -+ provided chunk ::CALL; -+ -+ provided pointcut Ethernet::create_device; -+ } -+ -+ provided sequence Ethernet::exit(PCI::Device) -+ { -+ provided chunk ::CALL; -+ provided chunk PCI::pci_remove_hook; -+ -+ provided pointcut Ethernet::destroy_device; -+ } -+} -diff --git a/rathaxes/samples/e1000/lkm.blt b/rathaxes/samples/e1000/lkm.blt -new file mode 100644 ---- /dev/null -+++ b/rathaxes/samples/e1000/lkm.blt -@@ -0,0 +1,55 @@ -+with LKM -+{ -+ /* Skel of the generated C file: */ -+ ${pointcut LKM::includes}; -+ ${pointcut LKM::prototypes}; -+ ${pointcut LKM::data}; -+ ${pointcut LKM::code}; -+ -+ template sequence LKM::init() -+ { -+ chunk LKM::includes() -+ { -+ #include -+ #include -+ } -+ -+ chunk LKM::data() -+ { -+ MODULE_DESCRIPTION(${config.description}); -+ MODULE_AUTHOR(${config.author}); -+ MODULE_LICENSE(${config.license}); -+ } -+ -+ chunk LKM::code() -+ { -+ /* -+ * Rathaxes doesn't yet support arbitrary "decorators" like __init -+ * or __exit. -+ */ -+ static int __attribute__((__section__(".init.text"))) rtx_module_init(void) -+ { -+ ${pointcut ::IMPLEMENTATION}; -+ ${pointcut LKM::init_bus_hook}; -+ -+ return 0; -+ } -+ -+ module_init(rtx_module_init); -+ } -+ } -+ -+ template sequence LKM::exit() -+ { -+ chunk LKM::code() -+ { -+ static void __attribute__((__section__(".exit.text"))) rtx_module_exit(void) -+ { -+ ${pointcut ::IMPLEMENTATION}; -+ ${pointcut LKM::deinit_bus_hook}; -+ } -+ -+ module_exit(rtx_module_exit); -+ } -+ } -+} -diff --git a/rathaxes/samples/e1000/lkm.rti b/rathaxes/samples/e1000/lkm.rti -new file mode 100644 ---- /dev/null -+++ b/rathaxes/samples/e1000/lkm.rti -@@ -0,0 +1,25 @@ -+interface LKM -+{ -+ provided pointcut LKM::includes; -+ /* maybe it should be possible to use chunk ::decl in sequence templates? */ -+ provided pointcut LKM::prototypes; -+ provided pointcut LKM::data; -+ provided pointcut LKM::code; -+ -+ required variable ::string LKM::author; -+ required variable ::string LKM::description; -+ required variable ::string LKM::license; -+ -+ required sequence LKM::init() -+ { -+ provided chunk LKM::includes; -+ provided chunk LKM::code; -+ provided pointcut LKM::init_bus_hook; -+ } -+ -+ required sequence LKM::exit() -+ { -+ provided chunk LKM::code; -+ provided pointcut LKM::deinit_bus_hook; -+ } -+} -diff --git a/rathaxes/samples/e1000/lkm.rtx b/rathaxes/samples/e1000/lkm.rtx -new file mode 100644 ---- /dev/null -+++ b/rathaxes/samples/e1000/lkm.rtx -@@ -0,0 +1,52 @@ -+device LKM use LKM, PCI, Ethernet, Log -+{ -+ Ethernet::open(Ethernet::Device dev) -+ { -+ Log::info("Open the device"); -+ e1000::setup_interrupt_handler(); -+ Log::info("Interrupt handler installed"); -+ e1000::set_up_device(); -+ e1000::activate_device_interruption(); -+ } -+ -+ Ethernet::close(Ethernet::Device dev) -+ { -+ Log::info("Close the device"); -+ e1000::free_interrupt_handler(); -+ } -+ -+ Ethernet::interrupt_handler(Ethernet::Device dev) -+ { -+ Log::info("Got an interruption"); -+ e1000::handle_intr(); -+ } -+ -+ Ethernet::send(Ethernet::Device dev, Socket::SKBuff skb) -+ { -+ Log::info("We have one packet to transmit!"); -+ } -+ -+ LKM::init() -+ { -+ Log::info("Hello this is LKM"); -+ } -+ -+ LKM::exit() -+ { -+ Log::info("Good bye this was LKM"); -+ } -+} -+ -+configuration -+{ -+ LKM::name = "hello"; -+ LKM::author = "Rathaxes"; -+ LKM::description = "Hello World Loadable Kernel Module (LKM)"; -+ LKM::license = "GPL"; -+ -+ PCI::vendor_id = 0x8086; -+ PCI::product_id = 0x100f; -+ PCI::set_master = true; -+ -+ Ethernet::ifname = "rtx%d"; -+} -diff --git a/rathaxes/samples/e1000/log.blt b/rathaxes/samples/e1000/log.blt -new file mode 100644 ---- /dev/null -+++ b/rathaxes/samples/e1000/log.blt -@@ -0,0 +1,10 @@ -+with Log -+{ -+ template sequence Log::info(::string msg) -+ { -+ chunk ::CALL -+ { -+ pr_info("%s\n", ${msg}); -+ } -+ } -+} -diff --git a/rathaxes/samples/e1000/log.rti b/rathaxes/samples/e1000/log.rti -new file mode 100644 ---- /dev/null -+++ b/rathaxes/samples/e1000/log.rti -@@ -0,0 +1,7 @@ -+interface Log -+{ -+ provided sequence Log::info(::string) -+ { -+ provided chunk ::CALL; -+ } -+} -diff --git a/rathaxes/samples/e1000/pci.blt b/rathaxes/samples/e1000/pci.blt -new file mode 100644 ---- /dev/null -+++ b/rathaxes/samples/e1000/pci.blt -@@ -0,0 +1,143 @@ -+with PCI, LKM, Log -+{ -+ template type PCI::Device() -+ { -+ chunk LKM::includes() -+ { -+ #include -+ } -+ -+ chunk ::decl() -+ { -+ struct pci_dev; -+ } -+ -+ chunk ::init(pci_dev) -+ { -+ ${self} = ${pci_dev}; -+ } -+ -+ map -+ { -+ } -+ } -+ -+ template sequence PCI::probe(PCI::Device pdev) -+ { -+ chunk LKM::prototypes() -+ { -+ static int /* __devinit */ rtx_pci_probe(struct pci_dev *, -+ const struct pci_device_id *); -+ } -+ -+ chunk LKM::code() -+ { -+ static int /* __devinit */ rtx_pci_probe(struct pci_dev *pdev, -+ const struct pci_device_id *pdev_id) -+ { -+ int err; -+ -+ err = pci_enable_device(pdev); -+ if (err < 0) -+ goto fail; -+ -+ ${pointcut PCI::pci_probe_hook}; -+ -+ return 0; -+ -+ fail: -+ return err; -+ } -+ } -+ -+ chunk ::CALL -+ { -+ } -+ } -+ -+ template sequence PCI::remove(PCI::Device pdev) -+ { -+ chunk LKM::prototypes() -+ { -+ static void rtx_pci_remove(struct pci_dev *); -+ } -+ -+ chunk LKM::code() -+ { -+ static void rtx_pci_remove(struct pci_dev *pdev) -+ { -+ ${pointcut PCI::pci_remove_hook}; -+ -+ pci_disable_device(pdev); -+ } -+ } -+ -+ chunk ::CALL() -+ { -+ } -+ } -+ -+ template sequence PCI::register() -+ { -+ chunk LKM::data() -+ { -+ /* -+ * CNorm doesn't seem to like "dynamic" arrays (i.e: you always -+ * have to specify the exact size). -+ */ -+ static struct pci_device_id rtx_pci_device_table[2] = { -+ { ${config.vendor_id}, ${config.product_id}, PCI_ANY_ID, PCI_ANY_ID }, -+ { 0, } -+ }; -+ -+ static struct pci_driver rtx_pci_driver = { -+ .name = ${config.name}, -+ .id_table = rtx_pci_device_table, -+ .probe = rtx_pci_probe, -+ .remove = rtx_pci_remove -+ }; -+ } -+ -+ chunk LKM::init_bus_hook() -+ { -+ int error; -+ if ((error = pci_register_driver(&rtx_pci_driver))) -+ { -+ ${Log::info("Cannot register pci driver")}; -+ /* -+ * So we catched the error but how do we return it to the -+ * parent context? -+ * -+ * Here we know that we can just return error, but that's just -+ * a coincidence (and, in this case, *we* wrote the parent -+ * context). -+ */ -+ return error; -+ } -+ } -+ -+ chunk ::CALL() -+ { -+ /* -+ * The implementation of ::CALL is empty. This template sequence is -+ * actually not provided nor required. -+ * -+ * This sequence is just "intermediate" code that will just inject -+ * itself in the hook LKM::init_bus_hook for which this sequence -+ * has a chunk (see above chunk). -+ */ -+ } -+ } -+ -+ template sequence PCI::unregister() -+ { -+ chunk LKM::deinit_bus_hook() -+ { -+ pci_unregister_driver(&rtx_pci_driver); -+ } -+ -+ chunk ::CALL -+ { -+ } -+ } -+} -diff --git a/rathaxes/samples/e1000/pci.rti b/rathaxes/samples/e1000/pci.rti -new file mode 100644 ---- /dev/null -+++ b/rathaxes/samples/e1000/pci.rti -@@ -0,0 +1,36 @@ -+interface PCI : LKM -+{ -+ provided type PCI::Device; -+ -+ required variable ::number PCI::vendor_id; -+ required variable ::number PCI::product_id; -+ -+ provided sequence PCI::register() -+ { -+ provided chunk ::CALL; -+ provided chunk LKM::data; -+ provided chunk LKM::init_bus_hook; -+ } -+ -+ provided sequence PCI::unregister() -+ { -+ provided chunk ::CALL; -+ provided chunk LKM::deinit_bus_hook; -+ } -+ -+ provided sequence PCI::probe(PCI::Device) -+ { -+ provided chunk LKM::prototypes; -+ provided chunk LKM::code; -+ -+ provided pointcut PCI::pci_probe_hook; -+ } -+ -+ provided sequence PCI::remove(PCI::Device) -+ { -+ provided chunk LKM::prototypes; -+ provided chunk LKM::code; -+ -+ provided pointcut PCI::pci_remove_hook; -+ } -+} -diff --git a/rathaxes/samples/e1000/socket.blt b/rathaxes/samples/e1000/socket.blt -new file mode 100644 ---- /dev/null -+++ b/rathaxes/samples/e1000/socket.blt -@@ -0,0 +1,27 @@ -+with Socket, LKM -+{ -+ template type Socket::SKBuff() -+ { -+ chunk LKM::includes() -+ { -+ #include -+ } -+ -+ chunk ::decl() -+ { -+ struct sk_buff; -+ } -+ -+ chunk ::init() -+ { -+ } -+ -+ map -+ { -+ // some work may have to be done here in order -+ // to access to some field of the sk_buff. -+ // We should determine if all the sk_buff management -+ // can be abstracted from the user. -+ } -+ } -+} -diff --git a/rathaxes/samples/e1000/socket.rti b/rathaxes/samples/e1000/socket.rti -new file mode 100644 ---- /dev/null -+++ b/rathaxes/samples/e1000/socket.rti -@@ -0,0 +1,4 @@ -+interface Socket : LKM -+{ -+ provided type Socket::SKBuff; -+} diff -r cf7d541b9331 -r 7b377e31fea3 series --- a/series Fri Jan 13 11:59:42 2012 +0100 +++ b/series Fri Jan 13 13:54:37 2012 +0100 @@ -1,2 +1,1 @@ -rathaxes_add_lkm_ethernet_sample.patch maintainers_update_the_binaries_installed_with_make_install.patch