Date: Sat, 21 Apr 2007 19:44:22 GMT From: Karsten Brandt<spam_schlucker@web.de> To: freebsd-gnats-submit@FreeBSD.org Subject: i386/111990: system freeze in initialization process of an UMTS card "Merlin U630" Message-ID: <200704211944.l3LJiMIg063608@www.freebsd.org> Resent-Message-ID: <200704211950.l3LJo2qo074305@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 111990 >Category: i386 >Synopsis: system freeze in initialization process of an UMTS card "Merlin U630" >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-i386 >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Sat Apr 21 19:50:02 GMT 2007 >Closed-Date: >Last-Modified: >Originator: Karsten Brandt >Release: 6.2 >Organization: >Environment: FreeBSD pegasus.local 6.2-STABLE FreeBSD 6.2-STABLE #49: Mon Apr 16 18:31:59 UTC 2007 root@pegasus.local:/usr/obj/usr/src/sys/PEGASUS_KERNEL i386 >Description: I use a Merlin U630 UMTS card as device for my internet access. This card caused in most cases on cold start an error during the initialization process for the second Modem channel (second card function). The system was freezed until I have rejected the card. Therefore I have analyzed the startup procedure of the card and found the point of trouble in the cbb_power function in pccbb.c. See the following code snippet from pccbb.c. The point of trouble is marked with [KB]. cbb_power(device_t brdev, int volts) { uint32_t status, sock_ctrl; struct cbb_softc *sc = device_get_softc(brdev); int timeout; int retval = 0; uint32_t sockevent; uint8_t reg = 0; status = cbb_get(sc, CBB_SOCKET_STATE); sock_ctrl = cbb_get(sc, CBB_SOCKET_CONTROL); sock_ctrl &= ~CBB_SOCKET_CTRL_VCCMASK; switch (volts & CARD_VCCMASK) { case 5: sock_ctrl |= CBB_SOCKET_CTRL_VCC_5V; break; case 3: sock_ctrl |= CBB_SOCKET_CTRL_VCC_3V; break; case XV: sock_ctrl |= CBB_SOCKET_CTRL_VCC_XV; break; case YV: sock_ctrl |= CBB_SOCKET_CTRL_VCC_YV; break; case 0: break; default: return (0); /* power NEVER changed */ } /* VPP == VCC */ sock_ctrl &= ~CBB_SOCKET_CTRL_VPPMASK; sock_ctrl |= ((sock_ctrl >> 4) & 0x07); if (cbb_get(sc, CBB_SOCKET_CONTROL) == sock_ctrl) return (1); /* no change necessary */ DEVPRINTF((sc->dev, "cbb_power: %dV\n", volts)); if (volts != 0 && sc->chipset == CB_O2MICRO) reg = cbb_o2micro_power_hack(sc); cbb_set(sc, CBB_SOCKET_CONTROL, sock_ctrl); // [KB] status = cbb_get(sc, CBB_SOCKET_STATE); // <- function call of cbb_get() lead to a frozen system // until the card will be rejected >How-To-Repeat: see description above >Fix: After I have identified the problem, I searched a solution. The result of my effort is the following patch: --- ctm/org_src/sys/dev/pccbb/pccbb.c Mon Mar 26 05:35:45 2007 +++ sys/dev/pccbb/pccbb.c Mon Mar 26 05:45:03 2007 @@ -738,21 +738,22 @@ int cbb_power(device_t brdev, int volts) { uint32_t status, sock_ctrl; struct cbb_softc *sc = device_get_softc(brdev); int timeout; int retval = 0; uint32_t sockevent; uint8_t reg = 0; - status = cbb_get(sc, CBB_SOCKET_STATE); +//[KB 0] moved to place of first use of variable status +// status = cbb_get(sc, CBB_SOCKET_STATE); sock_ctrl = cbb_get(sc, CBB_SOCKET_CONTROL); sock_ctrl &= ~CBB_SOCKET_CTRL_VCCMASK; switch (volts & CARD_VCCMASK) { case 5: sock_ctrl |= CBB_SOCKET_CTRL_VCC_5V; break; case 3: sock_ctrl |= CBB_SOCKET_CTRL_VCC_3V; break; @@ -771,22 +772,26 @@ /* VPP == VCC */ sock_ctrl &= ~CBB_SOCKET_CTRL_VPPMASK; sock_ctrl |= ((sock_ctrl >> 4) & 0x07); if (cbb_get(sc, CBB_SOCKET_CONTROL) == sock_ctrl) return (1); /* no change necessary */ DEVPRINTF((sc->dev, "cbb_power: %dV\n", volts)); if (volts != 0 && sc->chipset == CB_O2MICRO) reg = cbb_o2micro_power_hack(sc); +// [KB 1] I don't know, but we couldt try it. And yes, it works! + sc->chipinit(sc); + cbb_set(sc, CBB_SOCKET_CONTROL, sock_ctrl); - status = cbb_get(sc, CBB_SOCKET_STATE); +// [KB 2] moved to the place of first use of status variable +// status = cbb_get(sc, CBB_SOCKET_STATE); /* * XXX This busy wait is bogus. We should wait for a power * interrupt and then whine if the status is bad. If we're * worried about the card not coming up, then we should also * schedule a timeout which we can cancel in the power interrupt. */ timeout = 20; do { DELAY(20*1000); @@ -800,20 +805,23 @@ goto done; } /* XXX * delay 400 ms: thgough the standard defines that the Vcc set-up time * is 20 ms, some PC-Card bridge requires longer duration. * XXX Note: We should check the stutus AFTER the delay to give time * for things to stabilize. */ DELAY(400*1000); + +// [KB 3] moved from [KB 0 and KB 2] above + status = cbb_get(sc, CBB_SOCKET_STATE); if (status & CBB_STATE_BAD_VCC_REQ) { device_printf(sc->dev, "bad Vcc request. ctrl=0x%x, status=0x%x\n", sock_ctrl ,status); printf("cbb_power: %dV\n", volts); goto done; } retval = 1; done:; The important part in this patch is marked with [KB 1]. This part initialize the card before we try to set the voltage value. This prevent the described problem. The initialization process for the Merlin U630 looks to be faster and stable now. The changes marked with [KB 0], [KB 2] and [KB 3] were only inserted for a better code structure and makes the code cleaner. On mark [KB 0] the variable 'status' will filled with the sock state but this will not used up to the next call of cbb_get to get the sock state. On [KB 2] is the second call of cbb_get but the variable 'status' is also here not used direct after this call. The 'status' variable will used only on the end of the ccb_power function on mark [KB 3]. Therefore I have moved the call of cbb_get to this point and removed them from the points, which where marked with [KB 0] and [KB 2]. I hope this was helpfully. Please, verify this patch with other systems and configurations. I don't have the possibility to do this. For further information you can contact me. Best regards Karsten Brandt >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200704211944.l3LJiMIg063608>