diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index bdbd7da99286..65f1398723a4 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -958,6 +958,14 @@ void ecard_release_resources(struct expansion_card *ec) } EXPORT_SYMBOL(ecard_release_resources); +void ecard_setirq(struct expansion_card *ec, const struct expansion_card_ops *ops, void *irq_data) +{ + ec->irq_data = irq_data; + barrier(); + ec->ops = ops; +} +EXPORT_SYMBOL(ecard_setirq); + /* * Probe for an expansion card. * @@ -1133,6 +1141,14 @@ static int ecard_drv_remove(struct device *dev) drv->remove(ec); ecard_release(ec); + /* + * Restore the default operations. We ensure that the + * ops are set before we change the data. + */ + ec->ops = &ecard_default_ops; + barrier(); + ec->irq_data = NULL; + return 0; } diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index dbc8ee2adcf0..d7621a39ed09 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -434,8 +434,8 @@ pata_icside_register_v5(struct ata_probe_ent *ae, struct expansion_card *ec) ec->irqaddr = base + ICS_ARCIN_V5_INTRSTAT; ec->irqmask = 1; - ec->irq_data = state; - ec->ops = &pata_icside_ops_arcin_v5; + + ecard_setirq(ec, &pata_icside_ops_arcin_v5, state); /* * Be on the safe side - disable interrupts @@ -480,8 +480,7 @@ pata_icside_register_v6(struct ata_probe_ent *ae, struct expansion_card *ec) writeb(sel, ioc_base); - ec->irq_data = state; - ec->ops = &pata_icside_ops_arcin_v6; + ecard_setirq(ec, &pata_icside_ops_arcin_v6, state); state->irq_port = easi_base; state->ioc_base = ioc_base; @@ -609,8 +608,7 @@ static void pata_icside_shutdown(struct expansion_card *ec) * this register via that region. */ local_irq_save(flags); - if (ec->ops) - ec->ops->irqdisable(ec, ec->irq); + ec->ops->irqdisable(ec, ec->irq); local_irq_restore(flags); /* @@ -638,9 +636,6 @@ static void __devexit pata_icside_remove(struct expansion_card *ec) * don't NULL out the drvdata - devres/libata wants it * to free the ata_host structure. */ - ec->ops = NULL; - ec->irq_data = NULL; - if (state->dma != NO_DMA) free_dma(state->dma); if (state->ioc_base) diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index 1fe0457243db..69c949ea93e3 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -574,8 +574,8 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec) ec->irqaddr = base + ICS_ARCIN_V5_INTRSTAT; ec->irqmask = 1; - ec->irq_data = state; - ec->ops = &icside_ops_arcin_v5; + + ecard_setirq(ec, &icside_ops_arcin_v5, state); /* * Be on the safe side - disable interrupts @@ -630,8 +630,7 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec) writeb(sel, ioc_base); - ec->irq_data = state; - ec->ops = &icside_ops_arcin_v6; + ecard_setirq(ec, &icside_ops_arcin_v6, state); state->irq_port = easi_base; state->ioc_base = ioc_base; @@ -793,8 +792,6 @@ static void __devexit icside_remove(struct expansion_card *ec) } ecard_set_drvdata(ec, NULL); - ec->ops = NULL; - ec->irq_data = NULL; if (state->ioc_base) iounmap(state->ioc_base); diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 61f574aa3a99..387f1e3a4e84 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -710,8 +710,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) * IRQ and control port handling - only for non-NIC slot cards. */ if (ec->slot_no != 8) { - ec->ops = ðerh_ops; - ec->irq_data = eh; + ecard_setirq(ec, ðerh_ops, eh); } else { /* * If we're in the NIC slot, make sure the IRQ is enabled @@ -778,7 +777,6 @@ static void __devexit etherh_remove(struct expansion_card *ec) ecard_set_drvdata(ec, NULL); unregister_netdev(dev); - ec->ops = NULL; if (eh->ioc_fast) iounmap(eh->ioc_fast); diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c index 82add77ad131..f51aa3446bc7 100644 --- a/drivers/scsi/arm/cumana_2.c +++ b/drivers/scsi/arm/cumana_2.c @@ -450,8 +450,8 @@ cumanascsi2_probe(struct expansion_card *ec, const struct ecard_id *id) ec->irqaddr = info->base + CUMANASCSI2_STATUS; ec->irqmask = STATUS_INT; - ec->irq_data = info; - ec->ops = &cumanascsi_2_ops; + + ecard_setirq(ec, &cumanascsi_2_ops, info); ret = fas216_init(host); if (ret) diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c index ed06a8c19ad6..cc5d513aa99a 100644 --- a/drivers/scsi/arm/eesox.c +++ b/drivers/scsi/arm/eesox.c @@ -569,8 +569,8 @@ eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id) ec->irqaddr = base + EESOX_DMASTAT; ec->irqmask = EESOX_STAT_INTR; - ec->irq_data = info; - ec->ops = &eesoxscsi_ops; + + ecard_setirq(ec, &eesoxscsi_ops, info); device_create_file(&ec->dev, &dev_attr_bus_term); diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c index 159047a34997..3cbd525b58c5 100644 --- a/drivers/scsi/arm/powertec.c +++ b/drivers/scsi/arm/powertec.c @@ -361,8 +361,8 @@ powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id) ec->irqaddr = base + POWERTEC_INTR_STATUS; ec->irqmask = POWERTEC_INTR_BIT; - ec->irq_data = info; - ec->ops = &powertecscsi_ops; + + ecard_setirq(ec, &powertecscsi_ops, info); device_create_file(&ec->dev, &dev_attr_bus_term); diff --git a/include/asm-arm/ecard.h b/include/asm-arm/ecard.h index 3a6d3eb27622..8f1000eac91f 100644 --- a/include/asm-arm/ecard.h +++ b/include/asm-arm/ecard.h @@ -121,7 +121,7 @@ struct in_ecid { /* Packed card ID information */ typedef struct expansion_card ecard_t; typedef unsigned long *loader_t; -typedef struct { /* Card handler routines */ +typedef struct expansion_card_ops { /* Card handler routines */ void (*irqenable)(ecard_t *ec, int irqnr); void (*irqdisable)(ecard_t *ec, int irqnr); int (*irqpending)(ecard_t *ec); @@ -179,6 +179,8 @@ struct expansion_card { u64 dma_mask; }; +void ecard_setirq(struct expansion_card *ec, const struct expansion_card_ops *ops, void *irq_data); + struct in_chunk_dir { unsigned int start_offset; union {