You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
[PATCH] yenta TI: turn off interrupts during card power-on #2
- make boot-up card recognition more reliable (ie. redo interrogation always if there is no valid 'card inserted' state) (and yes, i saw it happening on an o2micro controller that both CB_CBARD and CB_16BITCARD bits were set at the same time) - also redo interrogation before probing the ISA interrupts. it's safer to do the probing with the socket in a clean state. - make card insert detect more reliable. yenta_get_status() now returns SS_PENDING as long as the card is not completley inserted and one of the voltage bits is set. also !CB_CBARD doesn't mean CB_16BITCARD. there is CB_NOTACARD as well, so make an explicit check for CB_16BITCARD. - for TI bridges: disable IRQs during power-on. in all-serial and tied interrupt mode the interrupts are always disabled for single-slot controllers. for two-slot contollers the disabling is only done when the other slot is empty. to force disabling there is a new module parameter now: pwr_irqs_off=Y (which is a regression for working setups. that's why it's an option, only use when required) - modparm to disable ISA interrupt probing (isa_probe, defaults to on) - remove unneeded code/cleanups (ie. merge yenta_events() into yenta_interrupts()) Signed-off-by: Daniel Ritz <daniel.ritz@gmx.ch> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
committed by
Linus Torvalds
parent
7007cab531
commit
fa912bcb06
@@ -611,6 +611,170 @@ out:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Returns true value if the second slot of a two-slot controller is empty */
|
||||
static int ti12xx_2nd_slot_empty(struct yenta_socket *socket)
|
||||
{
|
||||
struct pci_dev *func;
|
||||
struct yenta_socket *slot2;
|
||||
int devfn;
|
||||
unsigned int state;
|
||||
int ret = 1;
|
||||
|
||||
/* catch the two-slot controllers */
|
||||
switch (socket->dev->device) {
|
||||
case PCI_DEVICE_ID_TI_1220:
|
||||
case PCI_DEVICE_ID_TI_1221:
|
||||
case PCI_DEVICE_ID_TI_1225:
|
||||
case PCI_DEVICE_ID_TI_1251A:
|
||||
case PCI_DEVICE_ID_TI_1251B:
|
||||
case PCI_DEVICE_ID_TI_1420:
|
||||
case PCI_DEVICE_ID_TI_1450:
|
||||
case PCI_DEVICE_ID_TI_1451A:
|
||||
case PCI_DEVICE_ID_TI_1520:
|
||||
case PCI_DEVICE_ID_TI_1620:
|
||||
case PCI_DEVICE_ID_TI_4520:
|
||||
case PCI_DEVICE_ID_TI_4450:
|
||||
case PCI_DEVICE_ID_TI_4451:
|
||||
/*
|
||||
* there are way more, but they need to be added in yenta_socket.c
|
||||
* and pci_ids.h first anyway.
|
||||
*/
|
||||
break;
|
||||
|
||||
/* single-slot controllers have the 2nd slot empty always :) */
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* get other slot */
|
||||
devfn = socket->dev->devfn & ~0x07;
|
||||
func = pci_get_slot(socket->dev->bus,
|
||||
(socket->dev->devfn & 0x07) ? devfn : devfn | 0x01);
|
||||
if (!func)
|
||||
return 1;
|
||||
|
||||
slot2 = pci_get_drvdata(func);
|
||||
if (!slot2)
|
||||
goto out;
|
||||
|
||||
/* check state */
|
||||
yenta_get_status(&socket->socket, &state);
|
||||
if (state & SS_DETECT) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
pci_dev_put(func);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* TI specifiy parts for the power hook.
|
||||
*
|
||||
* some TI's with some CB's produces interrupt storm on power on. it has been
|
||||
* seen with atheros wlan cards on TI1225 and TI1410. solution is simply to
|
||||
* disable any CB interrupts during this time.
|
||||
*/
|
||||
static int ti12xx_power_hook(struct pcmcia_socket *sock, int operation)
|
||||
{
|
||||
struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
|
||||
u32 mfunc, devctl, sysctl;
|
||||
u8 gpio3;
|
||||
|
||||
/* only POWER_PRE and POWER_POST are interesting */
|
||||
if ((operation != HOOK_POWER_PRE) && (operation != HOOK_POWER_POST))
|
||||
return 0;
|
||||
|
||||
devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
|
||||
sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
|
||||
mfunc = config_readl(socket, TI122X_MFUNC);
|
||||
|
||||
/*
|
||||
* all serial/tied: only disable when modparm set. always doing it
|
||||
* would mean a regression for working setups 'cos it disables the
|
||||
* interrupts for both both slots on 2-slot controllers
|
||||
* (and users of single slot controllers where it's save have to
|
||||
* live with setting the modparm, most don't have to anyway)
|
||||
*/
|
||||
if (((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) &&
|
||||
(pwr_irqs_off || ti12xx_2nd_slot_empty(socket))) {
|
||||
switch (socket->dev->device) {
|
||||
case PCI_DEVICE_ID_TI_1250:
|
||||
case PCI_DEVICE_ID_TI_1251A:
|
||||
case PCI_DEVICE_ID_TI_1251B:
|
||||
case PCI_DEVICE_ID_TI_1450:
|
||||
case PCI_DEVICE_ID_TI_1451A:
|
||||
case PCI_DEVICE_ID_TI_4450:
|
||||
case PCI_DEVICE_ID_TI_4451:
|
||||
/* these chips have no IRQSER setting in MFUNC3 */
|
||||
break;
|
||||
|
||||
default:
|
||||
if (operation == HOOK_POWER_PRE)
|
||||
mfunc = (mfunc & ~TI122X_MFUNC3_MASK);
|
||||
else
|
||||
mfunc = (mfunc & ~TI122X_MFUNC3_MASK) | TI122X_MFUNC3_IRQSER;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do the job differently for func0/1 */
|
||||
if ((PCI_FUNC(socket->dev->devfn) == 0) ||
|
||||
((sysctl & TI122X_SCR_INTRTIE) &&
|
||||
(pwr_irqs_off || ti12xx_2nd_slot_empty(socket)))) {
|
||||
/* some bridges are different */
|
||||
switch (socket->dev->device) {
|
||||
case PCI_DEVICE_ID_TI_1250:
|
||||
case PCI_DEVICE_ID_TI_1251A:
|
||||
case PCI_DEVICE_ID_TI_1251B:
|
||||
case PCI_DEVICE_ID_TI_1450:
|
||||
/* those oldies use gpio3 for INTA */
|
||||
gpio3 = config_readb(socket, TI1250_GPIO3_CONTROL);
|
||||
if (operation == HOOK_POWER_PRE)
|
||||
gpio3 = (gpio3 & ~TI1250_GPIO_MODE_MASK) | 0x40;
|
||||
else
|
||||
gpio3 &= ~TI1250_GPIO_MODE_MASK;
|
||||
config_writeb(socket, TI1250_GPIO3_CONTROL, gpio3);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* all new bridges are the same */
|
||||
if (operation == HOOK_POWER_PRE)
|
||||
mfunc &= ~TI122X_MFUNC0_MASK;
|
||||
else
|
||||
mfunc |= TI122X_MFUNC0_INTA;
|
||||
config_writel(socket, TI122X_MFUNC, mfunc);
|
||||
}
|
||||
} else {
|
||||
switch (socket->dev->device) {
|
||||
case PCI_DEVICE_ID_TI_1251A:
|
||||
case PCI_DEVICE_ID_TI_1251B:
|
||||
case PCI_DEVICE_ID_TI_1450:
|
||||
/* those have INTA elsewhere and INTB in MFUNC0 */
|
||||
if (operation == HOOK_POWER_PRE)
|
||||
mfunc &= ~TI122X_MFUNC0_MASK;
|
||||
else
|
||||
mfunc |= TI125X_MFUNC0_INTB;
|
||||
config_writel(socket, TI122X_MFUNC, mfunc);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
/* all new bridges are the same */
|
||||
if (operation == HOOK_POWER_PRE)
|
||||
mfunc &= ~TI122X_MFUNC1_MASK;
|
||||
else
|
||||
mfunc |= TI122X_MFUNC1_INTB;
|
||||
config_writel(socket, TI122X_MFUNC, mfunc);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti12xx_override(struct yenta_socket *socket)
|
||||
{
|
||||
u32 val, val_orig;
|
||||
@@ -654,6 +818,9 @@ static int ti12xx_override(struct yenta_socket *socket)
|
||||
else
|
||||
ti12xx_irqroute_func1(socket);
|
||||
|
||||
/* install power hook */
|
||||
socket->socket.power_hook = ti12xx_power_hook;
|
||||
|
||||
return ti_override(socket);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user