[patch] ip autoconfig for PCMCIA NICs

Andrew Morton (akpm@zip.com.au)
Fri, 19 Oct 2001 13:52:54 -0700


It appears that ip autoconf doesn't work for cardbus NICs at present
because of an ordering problem. The call to init_pcmcia_ds() in
init/main.c comes after the ip-autoconf initcall has run. So of course,
autoconf complains that there are no network devices available.

This patch moves ds initialisation out of do_basic_setup() and into an
initcall. The pcmcia makefile is shuffled so that the ds.c initcall
comes at the end of pcmcia initialisation.

This all works fine. However it probably breaks something, but the rather
unilluminating comment

#ifdef CONFIG_PCMCIA
init_pcmcia_ds(); /* Do this last */
#endif

doesn't tell us what.

Also, yenta_open() currently defers device initialisation to keventd,
so there is a good chance that cardbus init hasn't completed by the
time we hit ip autoconf, so the yenta_open_bh functionality is made
synchronous.

yenta_open() is changed so that it has a single exit point. An error-path
leak in yenta_open() is fixed - missing an iounmap(). The module
refcount handling in yenta_open() is changed to make it less racy. The
registration of the polling timer in yenta_open_bh() is moved so that it
happens after the socket initialisation, to avoid running the poll timer
in the middle of initialisation.

Patch works fine for me, and is tested with modular PCMCIA
support as well. But what does it break?

Now, every time I try to understand the relationship between socket
services, card services, socket drivers and driver services my brain
bursts. Could some kind soul please what these things do, and how
they fit together? Thanks.

--- linux-2.4.12-ac3/init/main.c Mon Oct 15 16:04:25 2001
+++ ac/init/main.c Fri Oct 19 12:20:17 2001
@@ -839,9 +839,6 @@ static void __init do_basic_setup(void)
irda_proto_init();
irda_device_init(); /* Must be done after protocol initialization */
#endif
-#ifdef CONFIG_PCMCIA
- init_pcmcia_ds(); /* Do this last */
-#endif
}

extern void rd_load(void);
--- linux-2.4.12-ac3/drivers/pcmcia/Makefile Mon Oct 15 16:04:24 2001
+++ ac/drivers/pcmcia/Makefile Fri Oct 19 12:20:17 2001
@@ -22,7 +22,7 @@ ifeq ($(CONFIG_CARDBUS),y)
endif

ifeq ($(CONFIG_PCMCIA),y)
- obj-y := cistpl.o rsrc_mgr.o bulkmem.o ds.o cs.o
+ obj-y := cistpl.o rsrc_mgr.o bulkmem.o cs.o
ifeq ($(CONFIG_CARDBUS),y)
obj-y += cardbus.o cb_enabler.o yenta.o pci_socket.o
endif
@@ -35,6 +35,7 @@ ifeq ($(CONFIG_PCMCIA),y)
ifeq ($(CONFIG_HD64465_PCMCIA),y)
obj-y += hd64465_ss.o
endif
+ obj-y += ds.o
else
ifeq ($(CONFIG_PCMCIA),m)
obj-m := pcmcia_core.o ds.o
--- linux-2.4.12-ac3/drivers/pcmcia/ds.c Mon Oct 15 16:04:24 2001
+++ ac/drivers/pcmcia/ds.c Fri Oct 19 12:20:17 2001
@@ -964,14 +964,7 @@ int __init init_pcmcia_ds(void)
return 0;
}

-#ifdef MODULE
-
-int __init init_module(void)
-{
- return init_pcmcia_ds();
-}
-
-void __exit cleanup_module(void)
+void __exit cleanup_pcmcia_ds(void)
{
int i;
#ifdef CONFIG_PROC_FS
@@ -986,4 +979,6 @@ void __exit cleanup_module(void)
kfree(socket_table);
}

-#endif
+module_init(init_pcmcia_ds);
+module_exit(cleanup_pcmcia_ds);
+
--- linux-2.4.12-ac3/drivers/pcmcia/yenta.c Tue Oct 9 21:31:39 2001
+++ ac/drivers/pcmcia/yenta.c Fri Oct 19 13:00:51 2001
@@ -571,38 +571,6 @@ static void yenta_get_socket_capabilitie
printk("Yenta IRQ list %04x, PCI irq%d\n", socket->cap.irq_mask, socket->cb_irq);
}

-extern void cardbus_register(pci_socket_t *socket);
-
-/*
- * 'Bottom half' for the yenta_open routine. Allocate the interrupt line
- * and register the socket with the upper layers.
- */
-static void yenta_open_bh(void * data)
-{
- pci_socket_t * socket = (pci_socket_t *) data;
-
- /* It's OK to overwrite this now */
- socket->tq_task.routine = yenta_bh;
-
- if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, socket->dev->name, socket)) {
- /* No IRQ or request_irq failed. Poll */
- socket->cb_irq = 0; /* But zero is a valid IRQ number. */
- socket->poll_timer.function = yenta_interrupt_wrapper;
- socket->poll_timer.data = (unsigned long)socket;
- socket->poll_timer.expires = jiffies + HZ;
- add_timer(&socket->poll_timer);
- }
-
- /* Figure out what the dang thing can do for the PCMCIA layer... */
- yenta_get_socket_capabilities(socket, isa_interrupts);
- printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
-
- /* Register it with the pcmcia layer.. */
- cardbus_register(socket);
-
- MOD_DEC_USE_COUNT;
-}
-
static void yenta_clear_maps(pci_socket_t *socket)
{
int i;
@@ -813,6 +781,8 @@ static struct cardbus_override_struct {

#define NR_OVERRIDES (sizeof(cardbus_override)/sizeof(struct cardbus_override_struct))

+extern void cardbus_register(pci_socket_t *socket);
+
/*
* Initialize a cardbus controller. Make sure we have a usable
* interrupt, and that we can map the cardbus area. Fill in the
@@ -822,15 +792,19 @@ static int yenta_open(pci_socket_t *sock
{
int i;
struct pci_dev *dev = socket->dev;
+ int retval = -1;
+ int polling = 0;
+
+ MOD_INC_USE_COUNT;

/*
* Do some basic sanity checking..
*/
if (pci_enable_device(dev))
- return -1;
+ goto fail;
if (!pci_resource_start(dev, 0)) {
printk("No cardbus resource!\n");
- return -1;
+ goto fail;
}

/*
@@ -839,7 +813,7 @@ static int yenta_open(pci_socket_t *sock
*/
socket->base = ioremap(pci_resource_start(dev, 0), 0x1000);
if (!socket->base)
- return -1;
+ goto fail;

yenta_config_init(socket);

@@ -857,24 +831,43 @@ static int yenta_open(pci_socket_t *sock
if (dev->vendor == d->vendor && dev->device == d->device) {
socket->op = d->op;
if (d->op->open) {
- int retval = d->op->open(socket);
- if (retval < 0)
- return retval;
+ int ret = d->op->open(socket);
+ if (ret < 0) {
+ iounmap(socket->base);
+ retval = ret;
+ goto fail;
+ }
}
}
}

- /* Get the PCMCIA kernel thread to complete the
- initialisation later. We can't do this here,
- because, er, because Linus says so :)
- */
- socket->tq_task.routine = yenta_open_bh;
+ socket->tq_task.routine = yenta_bh;
socket->tq_task.data = socket;

- MOD_INC_USE_COUNT;
- schedule_task(&socket->tq_task);
+ if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt,
+ SA_SHIRQ, socket->dev->name, socket)) {
+ /* No IRQ or request_irq failed. Poll */
+ socket->cb_irq = 0; /* But zero is a valid IRQ number. */
+ socket->poll_timer.function = yenta_interrupt_wrapper;
+ socket->poll_timer.data = (unsigned long)socket;
+ socket->poll_timer.expires = jiffies + HZ;
+ polling = 1;
+ }

- return 0;
+ /* Figure out what the dang thing can do for the PCMCIA layer... */
+ yenta_get_socket_capabilities(socket, isa_interrupts);
+ printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
+
+ /* Register it with the pcmcia layer.. */
+ cardbus_register(socket);
+
+ if (polling)
+ add_timer(&socket->poll_timer);
+
+ retval = 0;
+fail:
+ MOD_DEC_USE_COUNT;
+ return retval;
}

/*
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/