Commit b76dc054 authored by Dominik Brodowski's avatar Dominik Brodowski

pcmcia pcnet_cs: try setting io_lines to 16 if card setup fails

Some pcnet_cs compatible cards require an exact 16-lines match
of the ioport areas specified in CIS, but set the "iolines"
value in the CIS incorrectly. We can easily work around this
issue -- same as we do in serial_cs -- by first trying setting
iolines to the CIS-specified value, and then trying a 16-line
match.
Reported-and-tested-by: default avatarWolfram Sang <w.sang@pengutronix.de>
Hardware-supplied-by: default avatarJochen Frieling <j.frieling@pengutronix.de>
CC: netdev@vger.kernel.org
Signed-off-by: default avatarDominik Brodowski <linux@dominikbrodowski.net>
parent eb838fe1
...@@ -508,7 +508,8 @@ static int pcnet_confcheck(struct pcmcia_device *p_dev, ...@@ -508,7 +508,8 @@ static int pcnet_confcheck(struct pcmcia_device *p_dev,
unsigned int vcc, unsigned int vcc,
void *priv_data) void *priv_data)
{ {
int *has_shmem = priv_data; int *priv = priv_data;
int try = (*priv & 0x1);
int i; int i;
cistpl_io_t *io = &cfg->io; cistpl_io_t *io = &cfg->io;
...@@ -525,33 +526,39 @@ static int pcnet_confcheck(struct pcmcia_device *p_dev, ...@@ -525,33 +526,39 @@ static int pcnet_confcheck(struct pcmcia_device *p_dev,
i = p_dev->resource[1]->end = 0; i = p_dev->resource[1]->end = 0;
} }
*has_shmem = ((cfg->mem.nwin == 1) && *priv &= ((cfg->mem.nwin == 1) &&
(cfg->mem.win[0].len >= 0x4000)); (cfg->mem.win[0].len >= 0x4000)) ? 0x10 : ~0x10;
p_dev->resource[0]->start = io->win[i].base; p_dev->resource[0]->start = io->win[i].base;
p_dev->resource[0]->end = io->win[i].len; p_dev->resource[0]->end = io->win[i].len;
if (!try)
p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
else
p_dev->io_lines = 16;
if (p_dev->resource[0]->end + p_dev->resource[1]->end >= 32) if (p_dev->resource[0]->end + p_dev->resource[1]->end >= 32)
return try_io_port(p_dev); return try_io_port(p_dev);
return 0; return -EINVAL;
} }
static int pcnet_config(struct pcmcia_device *link) static hw_info_t *pcnet_try_config(struct pcmcia_device *link,
int *has_shmem, int try)
{ {
struct net_device *dev = link->priv; struct net_device *dev = link->priv;
pcnet_dev_t *info = PRIV(dev);
int ret, start_pg, stop_pg, cm_offset;
int has_shmem = 0;
hw_info_t *local_hw_info; hw_info_t *local_hw_info;
pcnet_dev_t *info = PRIV(dev);
int priv = try;
int ret;
dev_dbg(&link->dev, "pcnet_config\n"); ret = pcmcia_loop_config(link, pcnet_confcheck, &priv);
if (ret) {
ret = pcmcia_loop_config(link, pcnet_confcheck, &has_shmem); dev_warn(&link->dev, "no useable port range found\n");
if (ret) return NULL;
goto failed; }
*has_shmem = (priv & 0x10);
if (!link->irq) if (!link->irq)
goto failed; return NULL;
if (resource_size(link->resource[1]) == 8) { if (resource_size(link->resource[1]) == 8) {
link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Attributes |= CONF_ENABLE_SPKR;
...@@ -563,40 +570,60 @@ static int pcnet_config(struct pcmcia_device *link) ...@@ -563,40 +570,60 @@ static int pcnet_config(struct pcmcia_device *link)
ret = pcmcia_request_configuration(link, &link->conf); ret = pcmcia_request_configuration(link, &link->conf);
if (ret) if (ret)
goto failed; return NULL;
dev->irq = link->irq; dev->irq = link->irq;
dev->base_addr = link->resource[0]->start; dev->base_addr = link->resource[0]->start;
if (info->flags & HAS_MISC_REG) { if (info->flags & HAS_MISC_REG) {
if ((if_port == 1) || (if_port == 2)) if ((if_port == 1) || (if_port == 2))
dev->if_port = if_port; dev->if_port = if_port;
else else
printk(KERN_NOTICE "pcnet_cs: invalid if_port requested\n"); dev_notice(&link->dev, "invalid if_port requested\n");
} else { } else
dev->if_port = 0; dev->if_port = 0;
}
if ((link->conf.ConfigBase == 0x03c0) && if ((link->conf.ConfigBase == 0x03c0) &&
(link->manf_id == 0x149) && (link->card_id == 0xc1ab)) { (link->manf_id == 0x149) && (link->card_id == 0xc1ab)) {
printk(KERN_INFO "pcnet_cs: this is an AX88190 card!\n"); dev_info(&link->dev,
printk(KERN_INFO "pcnet_cs: use axnet_cs instead.\n"); "this is an AX88190 card - use axnet_cs instead.\n");
goto failed; return NULL;
} }
local_hw_info = get_hwinfo(link); local_hw_info = get_hwinfo(link);
if (local_hw_info == NULL) if (!local_hw_info)
local_hw_info = get_prom(link); local_hw_info = get_prom(link);
if (local_hw_info == NULL) if (!local_hw_info)
local_hw_info = get_dl10019(link); local_hw_info = get_dl10019(link);
if (local_hw_info == NULL) if (!local_hw_info)
local_hw_info = get_ax88190(link); local_hw_info = get_ax88190(link);
if (local_hw_info == NULL) if (!local_hw_info)
local_hw_info = get_hwired(link); local_hw_info = get_hwired(link);
return local_hw_info;
}
static int pcnet_config(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
pcnet_dev_t *info = PRIV(dev);
int start_pg, stop_pg, cm_offset;
int has_shmem = 0;
hw_info_t *local_hw_info;
dev_dbg(&link->dev, "pcnet_config\n");
local_hw_info = pcnet_try_config(link, &has_shmem, 0);
if (!local_hw_info) {
/* check whether forcing io_lines to 16 helps... */
pcmcia_disable_device(link);
local_hw_info = pcnet_try_config(link, &has_shmem, 1);
if (local_hw_info == NULL) { if (local_hw_info == NULL) {
printk(KERN_NOTICE "pcnet_cs: unable to read hardware net" dev_notice(&link->dev, "unable to read hardware net"
" address for io base %#3lx\n", dev->base_addr); " address for io base %#3lx\n", dev->base_addr);
goto failed; goto failed;
} }
}
info->flags = local_hw_info->flags; info->flags = local_hw_info->flags;
/* Check for user overrides */ /* Check for user overrides */
......
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