[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: Randy Dunlap <rddunlap@osdl.org> Signed-off-by: Yum Rayan <yum.rayan@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
dbcf31ba68
commit
16f31113a6
@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 @@ next_entry:
|
|||||||
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 @@ next_entry:
|
|||||||
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 @@ next_entry:
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
|
|
||||||
/* 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)
|
|||||||
|
|
||||||
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)
|
|||||||
failed:
|
failed:
|
||||||
serial_remove(link);
|
serial_remove(link);
|
||||||
link->state &= ~DEV_CONFIG_PENDING;
|
link->state &= ~DEV_CONFIG_PENDING;
|
||||||
|
kfree(cfg_mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*======================================================================
|
/*======================================================================
|
||||||
|
Loading…
Reference in New Issue
Block a user