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: Wolfram Sang <w.sang@pengutronix.de> Hardware-supplied-by: Jochen Frieling <j.frieling@pengutronix.de> CC: netdev@vger.kernel.org Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
This commit is contained in:
Родитель
eb838fe109
Коммит
b76dc05467
|
@ -508,7 +508,8 @@ static int pcnet_confcheck(struct pcmcia_device *p_dev,
|
|||
unsigned int vcc,
|
||||
void *priv_data)
|
||||
{
|
||||
int *has_shmem = priv_data;
|
||||
int *priv = priv_data;
|
||||
int try = (*priv & 0x1);
|
||||
int i;
|
||||
cistpl_io_t *io = &cfg->io;
|
||||
|
||||
|
@ -525,77 +526,103 @@ static int pcnet_confcheck(struct pcmcia_device *p_dev,
|
|||
i = p_dev->resource[1]->end = 0;
|
||||
}
|
||||
|
||||
*has_shmem = ((cfg->mem.nwin == 1) &&
|
||||
(cfg->mem.win[0].len >= 0x4000));
|
||||
*priv &= ((cfg->mem.nwin == 1) &&
|
||||
(cfg->mem.win[0].len >= 0x4000)) ? 0x10 : ~0x10;
|
||||
|
||||
p_dev->resource[0]->start = io->win[i].base;
|
||||
p_dev->resource[0]->end = io->win[i].len;
|
||||
p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
|
||||
if (!try)
|
||||
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)
|
||||
return try_io_port(p_dev);
|
||||
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static hw_info_t *pcnet_try_config(struct pcmcia_device *link,
|
||||
int *has_shmem, int try)
|
||||
{
|
||||
struct net_device *dev = link->priv;
|
||||
hw_info_t *local_hw_info;
|
||||
pcnet_dev_t *info = PRIV(dev);
|
||||
int priv = try;
|
||||
int ret;
|
||||
|
||||
ret = pcmcia_loop_config(link, pcnet_confcheck, &priv);
|
||||
if (ret) {
|
||||
dev_warn(&link->dev, "no useable port range found\n");
|
||||
return NULL;
|
||||
}
|
||||
*has_shmem = (priv & 0x10);
|
||||
|
||||
if (!link->irq)
|
||||
return NULL;
|
||||
|
||||
if (resource_size(link->resource[1]) == 8) {
|
||||
link->conf.Attributes |= CONF_ENABLE_SPKR;
|
||||
link->conf.Status = CCSR_AUDIO_ENA;
|
||||
}
|
||||
if ((link->manf_id == MANFID_IBM) &&
|
||||
(link->card_id == PRODID_IBM_HOME_AND_AWAY))
|
||||
link->conf.ConfigIndex |= 0x10;
|
||||
|
||||
ret = pcmcia_request_configuration(link, &link->conf);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
dev->irq = link->irq;
|
||||
dev->base_addr = link->resource[0]->start;
|
||||
|
||||
if (info->flags & HAS_MISC_REG) {
|
||||
if ((if_port == 1) || (if_port == 2))
|
||||
dev->if_port = if_port;
|
||||
else
|
||||
dev_notice(&link->dev, "invalid if_port requested\n");
|
||||
} else
|
||||
dev->if_port = 0;
|
||||
|
||||
if ((link->conf.ConfigBase == 0x03c0) &&
|
||||
(link->manf_id == 0x149) && (link->card_id == 0xc1ab)) {
|
||||
dev_info(&link->dev,
|
||||
"this is an AX88190 card - use axnet_cs instead.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
local_hw_info = get_hwinfo(link);
|
||||
if (!local_hw_info)
|
||||
local_hw_info = get_prom(link);
|
||||
if (!local_hw_info)
|
||||
local_hw_info = get_dl10019(link);
|
||||
if (!local_hw_info)
|
||||
local_hw_info = get_ax88190(link);
|
||||
if (!local_hw_info)
|
||||
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 ret, start_pg, stop_pg, cm_offset;
|
||||
int start_pg, stop_pg, cm_offset;
|
||||
int has_shmem = 0;
|
||||
hw_info_t *local_hw_info;
|
||||
|
||||
dev_dbg(&link->dev, "pcnet_config\n");
|
||||
|
||||
ret = pcmcia_loop_config(link, pcnet_confcheck, &has_shmem);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
if (!link->irq)
|
||||
goto failed;
|
||||
|
||||
if (resource_size(link->resource[1]) == 8) {
|
||||
link->conf.Attributes |= CONF_ENABLE_SPKR;
|
||||
link->conf.Status = CCSR_AUDIO_ENA;
|
||||
}
|
||||
if ((link->manf_id == MANFID_IBM) &&
|
||||
(link->card_id == PRODID_IBM_HOME_AND_AWAY))
|
||||
link->conf.ConfigIndex |= 0x10;
|
||||
|
||||
ret = pcmcia_request_configuration(link, &link->conf);
|
||||
if (ret)
|
||||
goto failed;
|
||||
dev->irq = link->irq;
|
||||
dev->base_addr = link->resource[0]->start;
|
||||
if (info->flags & HAS_MISC_REG) {
|
||||
if ((if_port == 1) || (if_port == 2))
|
||||
dev->if_port = if_port;
|
||||
else
|
||||
printk(KERN_NOTICE "pcnet_cs: invalid if_port requested\n");
|
||||
} else {
|
||||
dev->if_port = 0;
|
||||
}
|
||||
|
||||
if ((link->conf.ConfigBase == 0x03c0) &&
|
||||
(link->manf_id == 0x149) && (link->card_id == 0xc1ab)) {
|
||||
printk(KERN_INFO "pcnet_cs: this is an AX88190 card!\n");
|
||||
printk(KERN_INFO "pcnet_cs: use axnet_cs instead.\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
local_hw_info = get_hwinfo(link);
|
||||
if (local_hw_info == NULL)
|
||||
local_hw_info = get_prom(link);
|
||||
if (local_hw_info == NULL)
|
||||
local_hw_info = get_dl10019(link);
|
||||
if (local_hw_info == NULL)
|
||||
local_hw_info = get_ax88190(link);
|
||||
if (local_hw_info == NULL)
|
||||
local_hw_info = get_hwired(link);
|
||||
|
||||
if (local_hw_info == NULL) {
|
||||
printk(KERN_NOTICE "pcnet_cs: unable to read hardware net"
|
||||
" address for io base %#3lx\n", dev->base_addr);
|
||||
goto failed;
|
||||
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) {
|
||||
dev_notice(&link->dev, "unable to read hardware net"
|
||||
" address for io base %#3lx\n", dev->base_addr);
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
info->flags = local_hw_info->flags;
|
||||
|
|
Загрузка…
Ссылка в новой задаче