Commit 16f31113 authored by Yum Rayan's avatar Yum Rayan Committed by Linus Torvalds

[PATCH] serial_cs: Reduce stack usage in serial_event()

This patch reduces the stack usage of the function serial_event() in
serial_cs from 2212 to 228.  I used a patched version of gcc 3.4.3 on i386
with -fno-unit-at-a-time disabled.

This patch is only compile tested.
Acked-by: default avatarRandy Dunlap <rddunlap@osdl.org>
Signed-off-by: default avatarYum Rayan <yum.rayan@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent dbcf31ba
...@@ -107,6 +107,13 @@ struct serial_info { ...@@ -107,6 +107,13 @@ struct serial_info {
int line[4]; int line[4];
}; };
struct serial_cfg_mem {
tuple_t tuple;
cisparse_t parse;
u_char buf[256];
};
static void serial_config(dev_link_t * link); static void serial_config(dev_link_t * link);
static int serial_event(event_t event, int priority, static int serial_event(event_t event, int priority,
event_callback_args_t * args); event_callback_args_t * args);
...@@ -357,14 +364,24 @@ static int simple_config(dev_link_t *link) ...@@ -357,14 +364,24 @@ static int simple_config(dev_link_t *link)
static int size_table[2] = { 8, 16 }; static int size_table[2] = { 8, 16 };
client_handle_t handle = link->handle; client_handle_t handle = link->handle;
struct serial_info *info = link->priv; struct serial_info *info = link->priv;
tuple_t tuple; struct serial_cfg_mem *cfg_mem;
u_char buf[256]; tuple_t *tuple;
cisparse_t parse; u_char *buf;
cistpl_cftable_entry_t *cf = &parse.cftable_entry; cisparse_t *parse;
cistpl_cftable_entry_t *cf;
config_info_t config; config_info_t config;
int i, j, try; int i, j, try;
int s; int s;
cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
if (!cfg_mem)
return -1;
tuple = &cfg_mem->tuple;
parse = &cfg_mem->parse;
cf = &parse->cftable_entry;
buf = cfg_mem->buf;
/* If the card is already configured, look up the port and irq */ /* If the card is already configured, look up the port and irq */
i = pcmcia_get_configuration_info(handle, &config); i = pcmcia_get_configuration_info(handle, &config);
if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) { if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) {
...@@ -377,21 +394,23 @@ static int simple_config(dev_link_t *link) ...@@ -377,21 +394,23 @@ static int simple_config(dev_link_t *link)
port = config.BasePort1 + 0x28; port = config.BasePort1 + 0x28;
info->slave = 1; info->slave = 1;
} }
if (info->slave) if (info->slave) {
kfree(cfg_mem);
return setup_serial(handle, info, port, config.AssignedIRQ); return setup_serial(handle, info, port, config.AssignedIRQ);
}
} }
link->conf.Vcc = config.Vcc; link->conf.Vcc = config.Vcc;
/* First pass: look for a config entry that looks normal. */ /* First pass: look for a config entry that looks normal. */
tuple.TupleData = (cisdata_t *) buf; tuple->TupleData = (cisdata_t *) buf;
tuple.TupleOffset = 0; tuple->TupleOffset = 0;
tuple.TupleDataMax = 255; tuple->TupleDataMax = 255;
tuple.Attributes = 0; tuple->Attributes = 0;
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
/* Two tries: without IO aliases, then with aliases */ /* Two tries: without IO aliases, then with aliases */
for (s = 0; s < 2; s++) { for (s = 0; s < 2; s++) {
for (try = 0; try < 2; try++) { for (try = 0; try < 2; try++) {
i = first_tuple(handle, &tuple, &parse); i = first_tuple(handle, tuple, parse);
while (i != CS_NO_MORE_ITEMS) { while (i != CS_NO_MORE_ITEMS) {
if (i != CS_SUCCESS) if (i != CS_SUCCESS)
goto next_entry; goto next_entry;
...@@ -409,14 +428,14 @@ static int simple_config(dev_link_t *link) ...@@ -409,14 +428,14 @@ static int simple_config(dev_link_t *link)
goto found_port; goto found_port;
} }
next_entry: next_entry:
i = next_tuple(handle, &tuple, &parse); i = next_tuple(handle, tuple, parse);
} }
} }
} }
/* Second pass: try to find an entry that isn't picky about /* Second pass: try to find an entry that isn't picky about
its base address, then try to grab any standard serial port its base address, then try to grab any standard serial port
address, and finally try to get any free port. */ address, and finally try to get any free port. */
i = first_tuple(handle, &tuple, &parse); i = first_tuple(handle, tuple, parse);
while (i != CS_NO_MORE_ITEMS) { while (i != CS_NO_MORE_ITEMS) {
if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && if ((i == CS_SUCCESS) && (cf->io.nwin > 0) &&
((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
...@@ -429,7 +448,7 @@ static int simple_config(dev_link_t *link) ...@@ -429,7 +448,7 @@ static int simple_config(dev_link_t *link)
goto found_port; goto found_port;
} }
} }
i = next_tuple(handle, &tuple, &parse); i = next_tuple(handle, tuple, parse);
} }
found_port: found_port:
...@@ -437,6 +456,7 @@ static int simple_config(dev_link_t *link) ...@@ -437,6 +456,7 @@ static int simple_config(dev_link_t *link)
printk(KERN_NOTICE printk(KERN_NOTICE
"serial_cs: no usable port range found, giving up\n"); "serial_cs: no usable port range found, giving up\n");
cs_error(link->handle, RequestIO, i); cs_error(link->handle, RequestIO, i);
kfree(cfg_mem);
return -1; return -1;
} }
...@@ -450,9 +470,10 @@ static int simple_config(dev_link_t *link) ...@@ -450,9 +470,10 @@ static int simple_config(dev_link_t *link)
i = pcmcia_request_configuration(link->handle, &link->conf); i = pcmcia_request_configuration(link->handle, &link->conf);
if (i != CS_SUCCESS) { if (i != CS_SUCCESS) {
cs_error(link->handle, RequestConfiguration, i); cs_error(link->handle, RequestConfiguration, i);
kfree(cfg_mem);
return -1; return -1;
} }
kfree(cfg_mem);
return setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); return setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
} }
...@@ -460,29 +481,39 @@ static int multi_config(dev_link_t * link) ...@@ -460,29 +481,39 @@ static int multi_config(dev_link_t * link)
{ {
client_handle_t handle = link->handle; client_handle_t handle = link->handle;
struct serial_info *info = link->priv; struct serial_info *info = link->priv;
tuple_t tuple; struct serial_cfg_mem *cfg_mem;
u_char buf[256]; tuple_t *tuple;
cisparse_t parse; u_char *buf;
cistpl_cftable_entry_t *cf = &parse.cftable_entry; cisparse_t *parse;
cistpl_cftable_entry_t *cf;
config_info_t config; config_info_t config;
int i, base2 = 0; int i, rc, base2 = 0;
cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
if (!cfg_mem)
return -1;
tuple = &cfg_mem->tuple;
parse = &cfg_mem->parse;
cf = &parse->cftable_entry;
buf = cfg_mem->buf;
i = pcmcia_get_configuration_info(handle, &config); i = pcmcia_get_configuration_info(handle, &config);
if (i != CS_SUCCESS) { if (i != CS_SUCCESS) {
cs_error(handle, GetConfigurationInfo, i); cs_error(handle, GetConfigurationInfo, i);
return -1; rc = -1;
goto free_cfg_mem;
} }
link->conf.Vcc = config.Vcc; link->conf.Vcc = config.Vcc;
tuple.TupleData = (cisdata_t *) buf; tuple->TupleData = (cisdata_t *) buf;
tuple.TupleOffset = 0; tuple->TupleOffset = 0;
tuple.TupleDataMax = 255; tuple->TupleDataMax = 255;
tuple.Attributes = 0; tuple->Attributes = 0;
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
/* First, look for a generic full-sized window */ /* First, look for a generic full-sized window */
link->io.NumPorts1 = info->multi * 8; link->io.NumPorts1 = info->multi * 8;
i = first_tuple(handle, &tuple, &parse); i = first_tuple(handle, tuple, parse);
while (i != CS_NO_MORE_ITEMS) { while (i != CS_NO_MORE_ITEMS) {
/* The quad port cards have bad CIS's, so just look for a /* The quad port cards have bad CIS's, so just look for a
window larger than 8 ports and assume it will be right */ window larger than 8 ports and assume it will be right */
...@@ -497,14 +528,14 @@ static int multi_config(dev_link_t * link) ...@@ -497,14 +528,14 @@ static int multi_config(dev_link_t * link)
if (i == CS_SUCCESS) if (i == CS_SUCCESS)
break; break;
} }
i = next_tuple(handle, &tuple, &parse); i = next_tuple(handle, tuple, parse);
} }
/* If that didn't work, look for two windows */ /* If that didn't work, look for two windows */
if (i != CS_SUCCESS) { if (i != CS_SUCCESS) {
link->io.NumPorts1 = link->io.NumPorts2 = 8; link->io.NumPorts1 = link->io.NumPorts2 = 8;
info->multi = 2; info->multi = 2;
i = first_tuple(handle, &tuple, &parse); i = first_tuple(handle, tuple, parse);
while (i != CS_NO_MORE_ITEMS) { while (i != CS_NO_MORE_ITEMS) {
if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) { if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) {
link->conf.ConfigIndex = cf->index; link->conf.ConfigIndex = cf->index;
...@@ -517,13 +548,14 @@ static int multi_config(dev_link_t * link) ...@@ -517,13 +548,14 @@ static int multi_config(dev_link_t * link)
if (i == CS_SUCCESS) if (i == CS_SUCCESS)
break; break;
} }
i = next_tuple(handle, &tuple, &parse); i = next_tuple(handle, tuple, parse);
} }
} }
if (i != CS_SUCCESS) { if (i != CS_SUCCESS) {
cs_error(link->handle, RequestIO, i); cs_error(link->handle, RequestIO, i);
return -1; rc = -1;
goto free_cfg_mem;
} }
i = pcmcia_request_irq(link->handle, &link->irq); i = pcmcia_request_irq(link->handle, &link->irq);
...@@ -541,7 +573,8 @@ static int multi_config(dev_link_t * link) ...@@ -541,7 +573,8 @@ static int multi_config(dev_link_t * link)
i = pcmcia_request_configuration(link->handle, &link->conf); i = pcmcia_request_configuration(link->handle, &link->conf);
if (i != CS_SUCCESS) { if (i != CS_SUCCESS) {
cs_error(link->handle, RequestConfiguration, i); cs_error(link->handle, RequestConfiguration, i);
return -1; rc = -1;
goto free_cfg_mem;
} }
/* The Oxford Semiconductor OXCF950 cards are in fact single-port: /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
...@@ -554,17 +587,23 @@ static int multi_config(dev_link_t * link) ...@@ -554,17 +587,23 @@ static int multi_config(dev_link_t * link)
setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
outb(12, base2 + 1); outb(12, base2 + 1);
} }
return 0; rc = 0;
goto free_cfg_mem;
} }
setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
/* The Nokia cards are not really multiport cards */ /* The Nokia cards are not really multiport cards */
if (info->manfid == MANFID_NOKIA) if (info->manfid == MANFID_NOKIA) {
return 0; rc = 0;
goto free_cfg_mem;
}
for (i = 0; i < info->multi - 1; i++) for (i = 0; i < info->multi - 1; i++)
setup_serial(handle, info, base2 + (8 * i), link->irq.AssignedIRQ); setup_serial(handle, info, base2 + (8 * i),
link->irq.AssignedIRQ);
return 0; rc = 0;
free_cfg_mem:
kfree(cfg_mem);
return rc;
} }
/*====================================================================== /*======================================================================
...@@ -579,39 +618,49 @@ void serial_config(dev_link_t * link) ...@@ -579,39 +618,49 @@ void serial_config(dev_link_t * link)
{ {
client_handle_t handle = link->handle; client_handle_t handle = link->handle;
struct serial_info *info = link->priv; struct serial_info *info = link->priv;
tuple_t tuple; struct serial_cfg_mem *cfg_mem;
u_short buf[128]; tuple_t *tuple;
cisparse_t parse; u_char *buf;
cistpl_cftable_entry_t *cf = &parse.cftable_entry; cisparse_t *parse;
cistpl_cftable_entry_t *cf;
int i, last_ret, last_fn; int i, last_ret, last_fn;
DEBUG(0, "serial_config(0x%p)\n", link); DEBUG(0, "serial_config(0x%p)\n", link);
tuple.TupleData = (cisdata_t *) buf; cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
tuple.TupleOffset = 0; if (!cfg_mem)
tuple.TupleDataMax = 255; goto failed;
tuple.Attributes = 0;
tuple = &cfg_mem->tuple;
parse = &cfg_mem->parse;
cf = &parse->cftable_entry;
buf = cfg_mem->buf;
tuple->TupleData = (cisdata_t *) buf;
tuple->TupleOffset = 0;
tuple->TupleDataMax = 255;
tuple->Attributes = 0;
/* Get configuration register information */ /* Get configuration register information */
tuple.DesiredTuple = CISTPL_CONFIG; tuple->DesiredTuple = CISTPL_CONFIG;
last_ret = first_tuple(handle, &tuple, &parse); last_ret = first_tuple(handle, tuple, parse);
if (last_ret != CS_SUCCESS) { if (last_ret != CS_SUCCESS) {
last_fn = ParseTuple; last_fn = ParseTuple;
goto cs_failed; goto cs_failed;
} }
link->conf.ConfigBase = parse.config.base; link->conf.ConfigBase = parse->config.base;
link->conf.Present = parse.config.rmask[0]; link->conf.Present = parse->config.rmask[0];
/* Configure card */ /* Configure card */
link->state |= DEV_CONFIG; link->state |= DEV_CONFIG;
/* Is this a compliant multifunction card? */ /* Is this a compliant multifunction card? */
tuple.DesiredTuple = CISTPL_LONGLINK_MFC; tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS); info->multi = (first_tuple(handle, tuple, parse) == CS_SUCCESS);
/* Is this a multiport card? */ /* Is this a multiport card? */
tuple.DesiredTuple = CISTPL_MANFID; tuple->DesiredTuple = CISTPL_MANFID;
if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
info->manfid = le16_to_cpu(buf[0]); info->manfid = le16_to_cpu(buf[0]);
for (i = 0; i < MULTI_COUNT; i++) for (i = 0; i < MULTI_COUNT; i++)
if ((info->manfid == multi_id[i].manfid) && if ((info->manfid == multi_id[i].manfid) &&
...@@ -623,13 +672,13 @@ void serial_config(dev_link_t * link) ...@@ -623,13 +672,13 @@ void serial_config(dev_link_t * link)
/* Another check for dual-serial cards: look for either serial or /* Another check for dual-serial cards: look for either serial or
multifunction cards that ask for appropriate IO port ranges */ multifunction cards that ask for appropriate IO port ranges */
tuple.DesiredTuple = CISTPL_FUNCID; tuple->DesiredTuple = CISTPL_FUNCID;
if ((info->multi == 0) && if ((info->multi == 0) &&
((first_tuple(handle, &tuple, &parse) != CS_SUCCESS) || ((first_tuple(handle, tuple, parse) != CS_SUCCESS) ||
(parse.funcid.func == CISTPL_FUNCID_MULTI) || (parse->funcid.func == CISTPL_FUNCID_MULTI) ||
(parse.funcid.func == CISTPL_FUNCID_SERIAL))) { (parse->funcid.func == CISTPL_FUNCID_SERIAL))) {
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
info->multi = cf->io.win[0].len >> 3; info->multi = cf->io.win[0].len >> 3;
if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
...@@ -664,6 +713,7 @@ void serial_config(dev_link_t * link) ...@@ -664,6 +713,7 @@ void serial_config(dev_link_t * link)
link->dev = &info->node[0]; link->dev = &info->node[0];
link->state &= ~DEV_CONFIG_PENDING; link->state &= ~DEV_CONFIG_PENDING;
kfree(cfg_mem);
return; return;
cs_failed: cs_failed:
...@@ -671,6 +721,7 @@ void serial_config(dev_link_t * link) ...@@ -671,6 +721,7 @@ void serial_config(dev_link_t * link)
failed: failed:
serial_remove(link); serial_remove(link);
link->state &= ~DEV_CONFIG_PENDING; link->state &= ~DEV_CONFIG_PENDING;
kfree(cfg_mem);
} }
/*====================================================================== /*======================================================================
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment