Subject: kern/36652: cbb0: Bad Vcc status once set will not clear -ThinkPad 570 / PCI1450
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <djb_netbsd@charter.net>
List: netbsd-bugs
Date: 07/15/2007 20:40:00
>Number:         36652
>Category:       kern
>Synopsis:       cbb0: Bad Vcc status once set will not clear -ThinkPad 570 / PCI1450
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Jul 15 20:40:00 +0000 2007
>Originator:     Dave Barnes
>Release:        4.99.19
>Organization:
>Environment:
ThinkPad 570
>Description:
Once bad Vcc bit gets set, removing and reinserting card doesn't clear bad Vcc.

during boot:
cbb0: bad Vcc request. sock_ctrl 0x0, sock_status 0x30000b20
cbb0: disabling socket
new status 0x30000b20

card removal and re-insert:
/netbsd: cbb0: bad Vcc request. sock_ctrl 0x0, sock_status 0x30000326
/netbsd: cbb0: disabling socket
/netbsd: new status 0x30000326
/netbsd: cbb0: bad Vcc request. sock_ctrl 0x30, sock_status 0x30000b68
/netbsd: cbb0: disabling socket
/netbsd: new status 0x30000b68
/netbsd: cbb0: bad Vcc request. sock_ctrl 0x0, sock_status 0x30000386
/netbsd: cbb0: disabling socket
/netbsd: new status 0x30000386
/netbsd: cbb0: bad Vcc request. sock_ctrl 0x30, sock_status 0x30000b68
/netbsd: cbb0: disabling socket
/netbsd: new status 0x30000b68
/netbsd: cbb0: bad Vcc request. sock_ctrl 0x0, sock_status 0x30000386
/netbsd: cbb0: disabling socket
/netbsd: new status 0x30000386

>How-To-Repeat:
For whatever reason, if you cold boot a ThinkPad 570 with a cardbus card in either slot you get bad Vcc set for the slot.

cbb0: bad Vcc request. sock_ctrl 0x0, sock_status 0x30000b20
cbb0: disabling socket
new status 0x30000b20

>Fix:
sys/dev/pci/pccbb.c starting with line 1363:

	if (status & CB_SOCKET_STAT_BADVCC) {	/* bad Vcc request */
		printf("%s: bad Vcc request. sock_ctrl 0x%x, sock_status 0x%x\n",
		    sc->sc_dev.dv_xname, sock_ctrl, status);
		printf("%s: disabling socket\n", sc->sc_dev.dv_xname);
		sock_ctrl &= ~CB_SOCKET_CTRL_VCCMASK;
		sock_ctrl &= ~CB_SOCKET_CTRL_VPPMASK;
		bus_space_write_4(memt, memh, CB_SOCKET_CTRL, sock_ctrl);
		status &= ~CB_SOCKET_STAT_BADVCC;
		bus_space_write_4(memt, memh, CB_SOCKET_STAT, status);
		printf("new status 0x%x\n", bus_space_read_4(memt, memh,
		    CB_SOCKET_STAT));
		return 0;
	}

"bus_space_write_4(memt, memh, CB_SOCKET_STAT, status);" does nothing since, at least on the PCI1450, CB_SOCKET_STAT is read only.
Correct register to use here is CB_SOCKET_FORCE.

A kernel with this one change shows:
 boot:
pccbb_power: CARDBUS_VCC_3V and CARDBUS_VPP_UC [0x1]
cbb0: power on failed?
cbb0: bad Vcc request. sock_ctrl 0x30, sock_status 0x30000b20
cbb0: disabling socket
new status 0x30000920
...

card removed and reinserted:
cbb0: 0x00000006 card removed, 0x30000926
pccbb_power: CARDBUS_VCC_0V and CARDBUS_VPP_0V [0x44]
cbb0: 0x00000000 card inserted, 0x30000920
pccbb_power: CARDBUS_VCC_3V and CARDBUS_VPP_UC [0x1]
Powercycling because of socket event
rtw0 at cardbus0 function 0: Realtek RTL8180 802.11 MAC/BBP
...

... card now works normally.

probably need to clear "data_lost" bit too: 
#define CB_SOCKET_STAT_DATALOST 0x0100 /* data lost */

May need to set bit 14 also to force re-interrogation of the card, update status registers and re-enable socket power control. See TI PCI1450 programming manual, page 111.  

I don't know whether this fix applies to cardbus chips other than the PCI1450.