Mercurial > archived > louis > epitech > mq > rathaxes
view rathaxes_rewrite_create_and_destroy_device_in_the_e1000_sample.patch @ 97:ffdb018893e2
Finish the patch on the create/destroy_device rewrite in the e1000 sample and fix Builtin::symbol
author | Louis Opter <louis@lse.epita.fr> |
---|---|
date | Thu, 22 Nov 2012 15:37:46 -0800 |
parents | 3e715b3e0ecd |
children | e2c237d6c37b |
line wrap: on
line source
# HG changeset patch # Parent d65cd0228e5c25692e6f37d0524e61ae26102a33 rathaxes: rehaul the device initialization/destruction in the e1000 sample - Add several chunks on the e1000::Context; these chunks perform low-level, device-dependant operations and should be move in the front-end at some point. They weave into pointcuts defined by the Ethernet subsystem; - The e1000::{create,destroy}_device sequence templates are entirely gone; they are replaced by the aforementioned chunks and more generic code in the PCI and Ethernet subsystems; - The PCI::{probe,remove} chunks/pointcuts have been rehauled and are centered on the new PCI::Device type template. 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 @@ -1,4 +1,4 @@ -with e1000, Ethernet, Socket, PCI, LKM, Log +with e1000, Ethernet, Socket, PCI, LKM, Log, Builtin { template type e1000::RxDescriptor() { @@ -268,6 +268,22 @@ template type e1000::Context() { + chunk ::decl() + { + struct rtx_e1000_ctx + { + int bars; + unsigned char /* __iomem */ *ioaddr; + unsigned int irq; + + /* we can't use the Rathaxes type here (#8) */ + //${e1000::RxRing} rx_ring; + //${e1000::TxRing} tx_ring; + struct rtx_e1000_rx_ring rx_ring; + struct rtx_e1000_tx_ring tx_ring; + }; + } + chunk Ethernet::SubContext() { /* @@ -278,28 +294,58 @@ ${e1000::Context} hw_ctx; } - chunk ::decl() + chunk Ethernet::adapter_init_context(Ethernet::Device rtx_ether_ctx, + Builtin::number bars, + Builtin::symbol ioaddr, + Builtin::number irq) { - /* - * Yes, this typedef looks ugly but read the remark about - * Ethernet::Device in ethernet.blt. - */ - struct rtx_e1000_ctx { - int bars; - unsigned char /* __iomem */ *ioaddr; - int irq; - - /* we can't use the Rathaxes type here (#8) */ - //${e1000::RxRing} rx_ring; - //${e1000::TxRing} tx_ring; - struct rtx_e1000_rx_ring rx_ring; - struct rtx_e1000_tx_ring tx_ring; - }; + struct rtx_e1000_ctx *hw_ctx = &${rtx_ether_ctx}->hw_ctx; + hw_ctx->bars = ${bars}; + hw_ctx->ioaddr = ${ioaddr}; + hw_ctx->irq = ${irq}; + } } - chunk ::init() + chunk Ethernet::adapter_reset(Ethernet::Device rtx_ether_ctx) { + { + struct rtx_e1000_ctx *hw_ctx = &${rtx_ether_ctx}->hw_ctx; + rtx_e1000_register_write32(hw_ctx, E1000_CTRL, E1000_CMD_RST); + udelay(10); + } + } + + chunk Ethernet::adapter_load_mac_address(Ethernet::Device rtx_ether_ctx) + { + { + struct rtx_e1000_ctx *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; + /* + * XXX: The net_dev manipulations here should take place in the + * ethernet templates: + * TODO: recevoir un Builtin::symbol avec le tableau ici pour + * pouvoir les remonter directement. + */ + ${rtx_ether_ctx}->net_dev->dev_addr[i * 2] = value & 0xff; + ${rtx_ether_ctx}->net_dev->dev_addr[i * 2 + 1] = (value >> 8) & 0xff; + } + + /* TODO: deplacer ça dans Ethernet (see above point): */ + memcpy(${rtx_ether_ctx}->net_dev->perm_addr, + ${rtx_ether_ctx}->net_dev->dev_addr, + ${rtx_ether_ctx}->net_dev->addr_len); + + ${Log::info("e1000::create: mac address loaded from the EEPROM")}; + } } map @@ -477,91 +523,6 @@ } } - template sequence e1000::create_device() - { - chunk Ethernet::create_device(PCI::AbstractDevice pdev, Ethernet::Device rtx_ether_ctx) - { - /* - * PCI init stuff: - * - * Some of that code should certainly be moved in the PCI/Ethernet - * blts, also at some point maybe we could do that completely - * automatically in the PCI/Ethernet blts. - */ - - /* - * We could have used an init function here but since we can't init - * all the fields at once (see, ioaddr) and cannot call a C - * function within a placeholder (${}), it wasn't really worth it. - */ - ${rtx_ether_ctx}->hw_ctx.bars = pci_select_bars(${pdev}, IORESOURCE_MEM); - ${rtx_ether_ctx}->hw_ctx.irq = ${pdev}->irq; - - 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")}; - - /* - * The really device specific algorithm starts here (so it should - * certainly be written in the frontend): - */ - - /* 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 (thanks minix code) */ - for (int i = 0; i < 3; ++i) - { - rtx_e1000_register_write32(&${rtx_ether_ctx}->hw_ctx, E1000_EEPROM_READ, (i << 8) | 1); - - int value; - do - value = rtx_e1000_register_read32(&${rtx_ether_ctx}->hw_ctx, E1000_EEPROM_READ); - while ((value & (1 << 4)) == 0); - 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); - - ${Log::info("e1000::create: mac address loaded from the EEPROM")}; - } - - chunk ::CALL() - { - } - } - - template sequence e1000::destroy_device() - { - chunk Ethernet::destroy_device(PCI::AbstractDevice pdev, Ethernet::Device rtx_ether_ctx) - { - /* - * Here, we should have some checks to avoid to free resources that - * haven't been allocated. (e.g: in case of previous errors). - */ - iounmap(${rtx_ether_ctx}->hw_ctx.ioaddr); - pci_release_selected_regions(${pdev}, ${rtx_ether_ctx}->hw_ctx.bars); - } - - chunk ::CALL() - { - } - } - /* TODO: make that a method of e1000::Context */ template sequence e1000::print_status(Ethernet::Device ctx) { 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 @@ -1,8 +1,5 @@ interface e1000 : Socket, Ethernet, PCI, LKM, Builtin { - /* XXX: This should be in pci.rti, also maybe we need a bool type */ - required variable Builtin::symbol set_master; - required variable Builtin::number rx_ring_size; required variable Builtin::number tx_ring_size; required variable Builtin::number rx_buffer_len; @@ -10,9 +7,18 @@ provided type Context { + method decl(); + chunk Ethernet::SubContext(); - method decl(); - method init(); + + /* Callbacks/Hooks which should probably be in the front-end: */ + chunk Ethernet::adapter_init_context(Ethernet::Device, + Builtin::number, + Builtin::symbol, + Builtin::number); +// chunk Ethernet::adapter_init_context(Ethernet::Device); + chunk Ethernet::adapter_reset(Ethernet::Device); + chunk Ethernet::adapter_load_mac_address(Ethernet::Device); } provided type RxDescriptor @@ -76,18 +82,6 @@ chunk ::decl(); } - provided sequence create_device() - { - provided chunk Ethernet::create_device(PCI::AbstractDevice, Ethernet::Device); - provided chunk ::CALL(); - } - - provided sequence destroy_device() - { - provided chunk Ethernet::destroy_device(PCI::AbstractDevice, Ethernet::Device); - provided chunk ::CALL(); - } - /* * This should take an e1000::Context as the first argument but this was * not working as wished. 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 @@ -113,6 +113,8 @@ map { + pci_device: ${self}->pci_dev; + net_device: ${self}->net_dev; } } @@ -210,48 +212,72 @@ }; } - /* For now the type is not handled, so we just omit it (see #17) */ - chunk PCI::pci_probe_hook(PCI::AbstractDevice pdev) + /* + * NOTE: for now, the error handling is leaking from PCI::probe(), but + * it's better than doing it at all. + * + * XXX: the chunk argument isn't correctly expanded by the + * compiler I have to use the same name as the actual C + * variable: + */ + chunk PCI::pci_probe_hook(PCI::Device rtx_pci_dev) { - /* - * This typedef is needed to workaround a bug in CNorm __std__ - * dialect. - */ ${Ethernet::Device} rtx_ether_ctx; - struct net_device *net_dev; - int error; + ${Ethernet::AbstractDevice} net_dev; - /* Initialize the net_device structure */ net_dev = alloc_etherdev(sizeof(*rtx_ether_ctx)); - if (net_dev == 0) + if (!net_dev) { - ${Log::info("cannot allocate memory")}; - /* - * Again, the error should be "raised" in the parent context. - * - * Here we know that we can return ENOMEM because *we* wrote - * the parent context. - */ - return -ENOMEM; + ${Log::info("cannot allocate the ethernet device context")}; + error = -ENOMEM; + goto fail; } - SET_NETDEV_DEV(net_dev, &${pdev}->dev); + SET_NETDEV_DEV(net_dev, ${rtx_pci_dev.device}); strlcpy(net_dev->name, ${config.ifname}, sizeof(net_dev->name)); - net_dev->irq = ${pdev}->irq; + net_dev->irq = ${rtx_pci_dev.irq}; net_dev->netdev_ops = &rtx_ether_ops; error = register_netdev(net_dev); if (error) { ${Log::info("cannot register the driver in the net subsystem")}; - return error; + goto fail; } /* Initialize our context held by the net_device structure */ - ${rtx_ether_ctx.init(local.net_dev, pdev)}; + /* + * XXX: the cast is here because the compiler resolve the + * type of rtx_pci_dev.pci_device to the type of + * rtx_pci_dev instead of the type of rtx_pci_dev.pci_device. + * + * Also, I'm getting placeholder in the generated code if + * I don't open a scope here. + */ + { + struct pci_dev *pci_device = ${rtx_pci_dev.pci_device}; + ${cast local.pci_device as PCI::AbstractDevice}; + ${local.rtx_ether_ctx.init(local.net_dev, local.pci_device)}; + } - pci_set_drvdata(${pdev}, net_dev); + /* Register ourselves in the parent context: */ + /* ${rtx_pci_dev.set_context(local.rtx_ether_ctx)}; */ + ${rtx_pci_dev}->context = rtx_ether_ctx; - ${pointcut Ethernet::create_device(pdev, local.rtx_ether_ctx)}; + /* + * XXX: the asssignments/casts are here to circumvent + * typing issues in the compiler (see previous XXX). + */ + int bars = ${rtx_pci_dev.bars}; + unsigned char /* __iomem */ *ioaddr = ${rtx_pci_dev.ioaddr}; + int irq = ${rtx_pci_dev.irq}; + ${cast local.bars as Builtin::number}; + ${cast local.irq as Builtin::number}; + ${pointcut Ethernet::adapter_init_context(local.rtx_ether_ctx, + local.bars, + local.ioaddr, + local.irq)}; + ${pointcut Ethernet::adapter_reset(local.rtx_ether_ctx)}; + ${pointcut Ethernet::adapter_load_mac_address(local.rtx_ether_ctx)}; } /* This chunk should be removed (see #26) */ @@ -262,16 +288,18 @@ template sequence Ethernet::exit() { - chunk PCI::pci_remove_hook(PCI::AbstractDevice pdev) + /* + * XXX: We have to use the same name as the C variable for + * the chunk argument... + */ + chunk PCI::pci_remove_hook(PCI::Device rtx_pci_dev) { - /* workaround for cnorm unstrict */ - struct net_device *net_dev = pci_get_drvdata(${pdev}); - ${Ethernet::Device} rtx_ether_ctx = netdev_priv(net_dev); + ${Ethernet::Device} rtx_ether_ctx = ${rtx_pci_dev.context}; - ${pointcut Ethernet::destroy_device(pdev, local.rtx_ether_ctx)}; + BUG_ON(!rtx_ether_ctx); - unregister_netdev(net_dev); - free_netdev(net_dev); + unregister_netdev(${local.rtx_ether_ctx.net_device}); + free_netdev(${local.rtx_ether_ctx.net_device}); } /* This chunk should be removed (see #26) */ 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,4 +1,4 @@ -interface Ethernet : Socket, PCI, LKM +interface Ethernet : Socket, PCI, LKM, Builtin { required variable Builtin::string ifname; @@ -23,6 +23,9 @@ method decl(); method init(Ethernet::AbstractDevice, PCI::AbstractDevice); pointcut Ethernet::SubContext(); + + attribute PCI::AbstractDevice pci_device; + attribute Ethernet::AbstractDevice net_device; } required sequence open(Ethernet::Device) @@ -52,15 +55,18 @@ provided sequence init() { provided chunk LKM::data(); - provided chunk PCI::pci_probe_hook(PCI::AbstractDevice); + provided chunk PCI::pci_probe_hook(PCI::Device); - provided pointcut Ethernet::create_device(PCI::AbstractDevice, Ethernet::Device); + provided pointcut Ethernet::adapter_init_context(Ethernet::Device, + Builtin::number, + Builtin::symbol, + Builtin::number); + provided pointcut Ethernet::adapter_reset(Ethernet::Device); + provided pointcut Ethernet::adapter_load_mac_address(Ethernet::Device); } provided sequence exit() { - provided chunk PCI::pci_remove_hook(PCI::AbstractDevice); - - provided pointcut Ethernet::destroy_device(PCI::AbstractDevice, Ethernet::Device); + provided chunk PCI::pci_remove_hook(PCI::Device); } } diff --git a/rathaxes/samples/e1000/lkm.rtx b/rathaxes/samples/e1000/lkm.rtx --- a/rathaxes/samples/e1000/lkm.rtx +++ b/rathaxes/samples/e1000/lkm.rtx @@ -74,7 +74,6 @@ */ PCI::vendor_id = 0x8086; PCI::product_id = 0x100e; - PCI::set_master = true; Ethernet::ifname = "rtx%d"; diff --git a/rathaxes/samples/e1000/pci.blt b/rathaxes/samples/e1000/pci.blt --- a/rathaxes/samples/e1000/pci.blt +++ b/rathaxes/samples/e1000/pci.blt @@ -12,12 +12,102 @@ struct pci_dev; } - chunk ::init(PCI::AbstractDevice) + chunk ::init(PCI::AbstractDevice) { } + chunk set_context(Builtin::symbol ctx) + { + pci_set_drvdata(${self}, ${ctx}); + } + map { + context: pci_get_drvdata(${self}); + } + } + + template type PCI::Device() + { + chunk ::decl() + { + struct rtx_pci_dev + { + struct pci_dev *pdev; + int bars; + /* It could be an array at some point: */ + unsigned char /* __iomem */ *ioaddr; + void *context; + }; + } + + chunk ::init(PCI::AbstractDevice pdev) + { + ${self}->pdev = ${pdev}; + ${self}->bars = pci_select_bars(${pdev}, IORESOURCE_MEM); + ${self}->ioaddr = NULL; + ${self}->context = NULL; + } + + chunk LKM::prototypes() + { + static int rtx_pci_device_enable(struct rtx_pci_dev *); + static void rtx_pci_device_disable(struct rtx_pci_dev *); + } + + chunk LKM::code() + { + static int rtx_pci_device_enable(struct rtx_pci_dev *self) + { + int error; + error = pci_enable_device(self->pdev); + if (error) + return error; + error = pci_request_selected_regions(self->pdev, self->bars, ${config.name}); + if (error) + return error; + pci_set_master(self->pdev); + return 0; + } + + static void rtx_pci_device_disable(struct rtx_pci_dev *self) + { + if (self->ioaddr) + iounmap(self->ioaddr); + pci_release_selected_regions(self->pdev, self->bars); + pci_disable_device(self->pdev); + } + } + + chunk enable() + { + rtx_pci_device_enable(${self}); + } + + chunk disable() + { + rtx_pci_device_disable(${self}); + } + + chunk select_ioaddr(Builtin::number bar) + { + ${self}->ioaddr = pci_ioremap_bar(${self}->pdev, ${bar}); + } + + chunk set_context(Builtin::symbol ctx) + { + ${self}->context = ctx; + } + + map + { + context: ${self}->context; + device: &${self}->pdev->dev; + pci_device: ${self}->pdev; + irq: ${self}->pdev->irq; + bars: ${self}->bars; + ioaddr: ${self}->ioaddr; + BAR_0: 0; } } @@ -34,24 +124,67 @@ static int /* __devinit */ rtx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) { - int err; + ${cast local.pdev as PCI::AbstractDevice}; + int error; + ${PCI::Device} *rtx_pci_dev; - err = pci_enable_device(pdev); - if (err < 0) + rtx_pci_dev = kmalloc(sizeof(*rtx_pci_dev), GFP_KERNEL); + if (!rtx_pci_dev) + { + ${Log::info("cannot allocate the pci device context")}; + error = -ENOMEM; goto fail; + } - /* Use local. to reference a local C variable: */ - ${cast local.pdev as PCI::AbstractDevice}; - ${pointcut PCI::pci_probe_hook(local.pdev)}; + /* + * XXX: I'm getting placeholder in the generated code if I don't + * open a scope here: + */ + { + ${local.rtx_pci_dev.init(local.pdev)}; + } + + /* ${local.pdev.set_context(local.rtx_pci_dev)}; */ + pci_set_drvdata(pdev, rtx_pci_dev); + + /* ${local.rtx_pci_dev.enable()}; */ + error = rtx_pci_device_enable(rtx_pci_dev); + if (error) + { + ${Log::info("rtx_pci_device_enable failed")}; + goto fail; + } + + /* ${local.rtx_pci_dev.select_ioaddr(local.rtx_pci_dev.BAR_0)}; */ + rtx_pci_dev->ioaddr = pci_ioremap_bar( + rtx_pci_dev->pdev, ${local.rtx_pci_dev.BAR_0} + ); + if (!${local.rtx_pci_dev.ioaddr}) + { + ${Log::info("can't map the device address space")}; + error = 1; /* XXX anything more approriate? */ + goto fail; + } + + /* + * XXX: We have to cast here because the compiler is + * confused by the fact that rtx_pci_dev is a + * pointer. + */ + ${cast local.rtx_pci_dev as PCI::Device}; + ${pointcut PCI::pci_probe_hook(local.rtx_pci_dev)}; return 0; - fail: - return err; + fail: + /* ${local.pdev.set_context(NULL)}; */ + pci_set_drvdata(pdev, NULL); + kfree(rtx_pci_dev); + return error; } } - /* This chunk should be remove (see #26) */ + /* This chunk should be removed (see #26) */ chunk ::CALL() { } @@ -69,9 +202,16 @@ static void rtx_pci_remove(struct pci_dev *pdev) { ${cast local.pdev as PCI::AbstractDevice}; - ${pointcut PCI::pci_remove_hook(local.pdev)}; + ${PCI::Device} *rtx_pci_dev = ${local.pdev.context}; - pci_disable_device(pdev); + BUG_ON(!rtx_pci_dev); + + /* XXX: compiler confused by the pointer type. */ + ${cast local.rtx_pci_dev as PCI::Device}; + ${pointcut PCI::pci_remove_hook(local.rtx_pci_dev)}; + + /* ${local.rtx_pci_dev.disable()}; */ + rtx_pci_device_disable(rtx_pci_dev); } } diff --git a/rathaxes/samples/e1000/pci.rti b/rathaxes/samples/e1000/pci.rti --- a/rathaxes/samples/e1000/pci.rti +++ b/rathaxes/samples/e1000/pci.rti @@ -1,14 +1,40 @@ -interface PCI : LKM +interface PCI : LKM, Builtin, Device { + required variable Builtin::string LKM::name; + required variable Builtin::number PCI::vendor_id; + required variable Builtin::number PCI::product_id; + provided type PCI::AbstractDevice { chunk LKM::includes(); + method decl(); method init(PCI::AbstractDevice); + method set_context(Builtin::symbol); + + attribute Builtin::symbol context; } - required variable Builtin::number PCI::vendor_id; - required variable Builtin::number PCI::product_id; + provided type PCI::Device + { + chunk LKM::prototypes(); + chunk LKM::code(); + + method decl(); + method init(PCI::AbstractDevice); + method enable(); + method disable(); + method select_ioaddr(Builtin::number); + method set_context(Builtin::symbol); + + attribute Builtin::symbol context; + attribute Device::AbstractDevice device; + attribute PCI::AbstractDevice pci_device; + attribute Builtin::symbol ioaddr; + attribute Builtin::number BAR_0; + attribute Builtin::number irq; + attribute Builtin::number bars; + } provided sequence register() { @@ -28,7 +54,7 @@ provided chunk LKM::prototypes(); provided chunk LKM::code(); - provided pointcut PCI::pci_probe_hook(PCI::AbstractDevice); + provided pointcut PCI::pci_probe_hook(PCI::Device); } provided sequence remove() @@ -36,6 +62,6 @@ provided chunk LKM::prototypes(); provided chunk LKM::code(); - provided pointcut PCI::pci_remove_hook(PCI::AbstractDevice); + provided pointcut PCI::pci_remove_hook(PCI::Device); } }