Module Name: src Committed By: martin Date: Fri Sep 13 06:51:59 UTC 2019
Modified Files: src/sys/dev/usb [netbsd-9]: if_upl.c if_url.c if_urndis.c usb_mem.c usbnet.c usbnet.h Log Message: Pull up following revision(s) (requested by mrg in ticket #197): sys/dev/usb/if_url.c: revision 1.71 sys/dev/usb/usbnet.h: revision 1.15 sys/dev/usb/usb_mem.c: revision 1.72 sys/dev/usb/if_urndis.c: revision 1.24 sys/dev/usb/if_upl.c: revision 1.67 sys/dev/usb/usbnet.c: revision 1.25 sys/dev/usb/usbnet.c: revision 1.26 sys/dev/usb/usbnet.c: revision 1.27 sys/dev/usb/usbnet.c: revision 1.28 Teach urndis to handle some REMOTE_NDIS_INDICATE_STATUS_MSG. If the status is reasonable, don't tell userland we got an error. Stops spurious EIO. >From openbsd. Fix bug, remove {0,0} because we switched to usb_lookup(). s/no free/no freelist entry/ in a debug message. fix a lock hang reported by sc.dying in PR#54495. remove locking in usbnet_tick(). assume that all locking needs are handled inside usbnet_tick_task(), which runs in the usbtask thread. ensure that usbnet private is valid before using it. also check NULL private pointer in usbnet_isdying(). all the other cases should never happen. don't try to set dying when we haven't usbnet_attach()d yet. reported by maxv. - use CALLARGS vs CALLED for better usbhist - turn off usbnetdebug default - log for all entry/exit points of usbnet_pipe_intr() - in usbnet_start_locked() track whether any packet has been transmitted for setting the timer. avoids spurious "watchdog timeouts" - in usbnet_stop() use callout_halt() vs callout_halt, and also stop the usb task. fixes crash of usbtask after the phy has detached. - add a little more defensive checking in the tick task, and add some high-log-level logs. - in usbnet_detach() move the call to usbnet_stop_ifp() above the calls to callout/usbtask stopping. - set ec_mii and unp_pri to NULL when freeing their data normalise an error message. document usbnet_private locking. minor knf. To generate a diff of this commit: cvs rdiff -u -r1.64.2.1 -r1.64.2.2 src/sys/dev/usb/if_upl.c cvs rdiff -u -r1.66.2.1 -r1.66.2.2 src/sys/dev/usb/if_url.c cvs rdiff -u -r1.21.4.1 -r1.21.4.2 src/sys/dev/usb/if_urndis.c cvs rdiff -u -r1.70.10.1 -r1.70.10.2 src/sys/dev/usb/usb_mem.c cvs rdiff -u -r1.25.2.2 -r1.25.2.3 src/sys/dev/usb/usbnet.c cvs rdiff -u -r1.14.2.2 -r1.14.2.3 src/sys/dev/usb/usbnet.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/usb/if_upl.c diff -u src/sys/dev/usb/if_upl.c:1.64.2.1 src/sys/dev/usb/if_upl.c:1.64.2.2 --- src/sys/dev/usb/if_upl.c:1.64.2.1 Sun Sep 1 13:00:36 2019 +++ src/sys/dev/usb/if_upl.c Fri Sep 13 06:51:58 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if_upl.c,v 1.64.2.1 2019/09/01 13:00:36 martin Exp $ */ +/* $NetBSD: if_upl.c,v 1.64.2.2 2019/09/13 06:51:58 martin Exp $ */ /* * Copyright (c) 2000 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_upl.c,v 1.64.2.1 2019/09/01 13:00:36 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_upl.c,v 1.64.2.2 2019/09/13 06:51:58 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -95,8 +95,7 @@ static struct usb_devno sc_devs[] = { { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2302 }, { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL25A1 }, { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U258 }, - { USB_VENDOR_NI, USB_PRODUCT_NI_HTOH_7825 }, - { 0, 0 } + { USB_VENDOR_NI, USB_PRODUCT_NI_HTOH_7825 } }; int upl_match(device_t, cfdata_t, void *); Index: src/sys/dev/usb/if_url.c diff -u src/sys/dev/usb/if_url.c:1.66.2.1 src/sys/dev/usb/if_url.c:1.66.2.2 --- src/sys/dev/usb/if_url.c:1.66.2.1 Sun Sep 1 13:00:36 2019 +++ src/sys/dev/usb/if_url.c Fri Sep 13 06:51:58 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if_url.c,v 1.66.2.1 2019/09/01 13:00:36 martin Exp $ */ +/* $NetBSD: if_url.c,v 1.66.2.2 2019/09/13 06:51:58 martin Exp $ */ /* * Copyright (c) 2001, 2002 @@ -44,7 +44,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_url.c,v 1.66.2.1 2019/09/01 13:00:36 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_url.c,v 1.66.2.2 2019/09/13 06:51:58 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -190,7 +190,7 @@ url_attach(device_t parent, device_t sel if (err) { aprint_error_dev(self, "failed to set configuration" ", err=%s\n", usbd_errstr(err)); - goto bad; + return; } /* get control interface */ @@ -198,7 +198,7 @@ url_attach(device_t parent, device_t sel if (err) { aprint_error_dev(self, "failed to get interface, err=%s\n", usbd_errstr(err)); - goto bad; + return; } un->un_iface = iface; @@ -221,7 +221,7 @@ url_attach(device_t parent, device_t sel if (ed == NULL) { aprint_error_dev(self, "couldn't get endpoint %d\n", i); - goto bad; + return; } if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) @@ -238,7 +238,7 @@ url_attach(device_t parent, device_t sel un->un_ed[USBNET_ENDPT_TX] == 0 || un->un_ed[USBNET_ENDPT_INTR] == 0) { aprint_error_dev(self, "missing endpoint\n"); - goto bad; + return; } /* Set these up now for url_mem(). */ Index: src/sys/dev/usb/if_urndis.c diff -u src/sys/dev/usb/if_urndis.c:1.21.4.1 src/sys/dev/usb/if_urndis.c:1.21.4.2 --- src/sys/dev/usb/if_urndis.c:1.21.4.1 Sun Sep 1 13:00:36 2019 +++ src/sys/dev/usb/if_urndis.c Fri Sep 13 06:51:58 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if_urndis.c,v 1.21.4.1 2019/09/01 13:00:36 martin Exp $ */ +/* $NetBSD: if_urndis.c,v 1.21.4.2 2019/09/13 06:51:58 martin Exp $ */ /* $OpenBSD: if_urndis.c,v 1.31 2011/07/03 15:47:17 matthew Exp $ */ /* @@ -21,7 +21,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_urndis.c,v 1.21.4.1 2019/09/01 13:00:36 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_urndis.c,v 1.21.4.2 2019/09/13 06:51:58 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_usb.h" @@ -79,6 +79,8 @@ static uint32_t urndis_ctrl_handle_query const struct rndis_comp_hdr *, void **, size_t *); static uint32_t urndis_ctrl_handle_reset(struct usbnet *, const struct rndis_comp_hdr *); +static uint32_t urndis_ctrl_handle_status(struct usbnet *, + const struct rndis_comp_hdr *); static uint32_t urndis_ctrl_set(struct usbnet *, uint32_t, void *, size_t); @@ -207,6 +209,10 @@ urndis_ctrl_handle(struct usbnet *un, st rval = le32toh(hdr->rm_status); break; + case REMOTE_NDIS_INDICATE_STATUS_MSG: + rval = urndis_ctrl_handle_status(un, hdr); + break; + default: printf("%s: ctrl message error: unknown event 0x%x\n", DEVNAME(un), le32toh(hdr->rm_type)); @@ -380,6 +386,38 @@ urndis_ctrl_handle_reset(struct usbnet * } static uint32_t +urndis_ctrl_handle_status(struct usbnet *un, + const struct rndis_comp_hdr *hdr) +{ + const struct rndis_status_msg *msg; + uint32_t rval; + + msg = (const struct rndis_status_msg *)hdr; + + rval = le32toh(msg->rm_status); + + DPRINTF(("%s: urndis_ctrl_handle_status: len %u status 0x%x " + "stbuflen %u\n", + DEVNAME(un), + le32toh(msg->rm_len), + rval, + le32toh(msg->rm_stbuflen))); + + switch (rval) { + case RNDIS_STATUS_MEDIA_CONNECT: + case RNDIS_STATUS_MEDIA_DISCONNECT: + case RNDIS_STATUS_OFFLOAD_CURRENT_CONFIG: + rval = RNDIS_STATUS_SUCCESS; + break; + + default: + printf("%s: status 0x%x\n", DEVNAME(un), rval); + } + + return rval; +} + +static uint32_t urndis_ctrl_init(struct usbnet *un) { struct rndis_init_req *msg; Index: src/sys/dev/usb/usb_mem.c diff -u src/sys/dev/usb/usb_mem.c:1.70.10.1 src/sys/dev/usb/usb_mem.c:1.70.10.2 --- src/sys/dev/usb/usb_mem.c:1.70.10.1 Sun Sep 1 13:00:36 2019 +++ src/sys/dev/usb/usb_mem.c Fri Sep 13 06:51:58 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: usb_mem.c,v 1.70.10.1 2019/09/01 13:00:36 martin Exp $ */ +/* $NetBSD: usb_mem.c,v 1.70.10.2 2019/09/13 06:51:58 martin Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -38,7 +38,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: usb_mem.c,v 1.70.10.1 2019/09/01 13:00:36 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: usb_mem.c,v 1.70.10.2 2019/09/13 06:51:58 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_usb.h" @@ -136,7 +136,7 @@ usb_block_allocmem(bus_dma_tag_t tag, si } } - DPRINTFN(6, "no free", 0, 0, 0, 0); + DPRINTFN(6, "no freelist entry", 0, 0, 0, 0); mutex_exit(&usb_blk_lock); b = kmem_zalloc(sizeof(*b), KM_SLEEP); Index: src/sys/dev/usb/usbnet.c diff -u src/sys/dev/usb/usbnet.c:1.25.2.2 src/sys/dev/usb/usbnet.c:1.25.2.3 --- src/sys/dev/usb/usbnet.c:1.25.2.2 Sun Sep 1 13:00:36 2019 +++ src/sys/dev/usb/usbnet.c Fri Sep 13 06:51:58 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: usbnet.c,v 1.25.2.2 2019/09/01 13:00:36 martin Exp $ */ +/* $NetBSD: usbnet.c,v 1.25.2.3 2019/09/13 06:51:58 martin Exp $ */ /* * Copyright (c) 2019 Matthew R. Green @@ -33,7 +33,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.25.2.2 2019/09/01 13:00:36 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.25.2.3 2019/09/13 06:51:58 martin Exp $"); #include <sys/param.h> #include <sys/kernel.h> @@ -59,6 +59,11 @@ struct usbnet_private { * - unp_rxlock protects the rx path and its data * - unp_txlock protects the tx path and its data * - unp_detachcv handles detach vs open references + * + * the lock ordering is: + * ifnet lock -> unp_lock -> unp_rxlock -> unp_txlock + * unp_lock -> unp_miilock + * and unp_lock may be dropped after taking unp_miilock. */ kmutex_t unp_lock; kmutex_t unp_miilock; @@ -101,7 +106,7 @@ static int usbnet_modcmd(modcmd_t, void #ifndef USBNET_DEBUG #define usbnetdebug 0 #else -static int usbnetdebug = 1; +static int usbnetdebug = 0; SYSCTL_SETUP(sysctl_hw_usbnet_setup, "sysctl hw.usbnet setup") { @@ -418,6 +423,7 @@ usbnet_txeof(struct usbd_xfer *xfer, voi static void usbnet_pipe_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) { + USBNETHIST_FUNC(); struct usbnet * const un = priv; struct usbnet_private * const unp = un->un_pri; struct usbnet_intr * const uni = un->un_intr; @@ -425,8 +431,12 @@ usbnet_pipe_intr(struct usbd_xfer *xfer, if (uni == NULL || unp->unp_dying || unp->unp_stopping || status == USBD_INVAL || status == USBD_NOT_STARTED || - status == USBD_CANCELLED || !(ifp->if_flags & IFF_RUNNING)) + status == USBD_CANCELLED || !(ifp->if_flags & IFF_RUNNING)) { + USBNETHIST_CALLARGS("%d: uni %jx d/s %x status %x", + unp->unp_number, (uintptr_t)uni, + (unp->unp_dying << 8) | unp->unp_stopping, status); return; + } if (status != USBD_NORMAL_COMPLETION) { if (usbd_ratecheck(&unp->unp_intr_notice)) { @@ -435,6 +445,8 @@ usbnet_pipe_intr(struct usbd_xfer *xfer, } if (status == USBD_STALLED) usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_INTR]); + USBNETHIST_CALLARGS("%d: not normal status %x", + unp->unp_number, status, 0, 0); return; } @@ -444,14 +456,19 @@ usbnet_pipe_intr(struct usbd_xfer *xfer, static void usbnet_start_locked(struct ifnet *ifp) { - USBNETHIST_FUNC(); USBNETHIST_CALLED(); + USBNETHIST_FUNC(); struct usbnet * const un = ifp->if_softc; struct usbnet_cdata * const cd = un_cdata(un); struct usbnet_private * const unp = un->un_pri; struct mbuf *m; unsigned length; + bool done_transmit = false; int idx; + USBNETHIST_CALLARGS("%d: tx_cnt %d list_cnt %d link %d", + unp->unp_number, cd->uncd_tx_cnt, un->un_tx_list_cnt, + unp->unp_link); + usbnet_isowned_tx(un); KASSERT(cd->uncd_tx_cnt <= un->un_tx_list_cnt); @@ -502,6 +519,7 @@ usbnet_start_locked(struct ifnet *ifp) ifp->if_oerrors++; break; } + done_transmit = true; IFQ_DEQUEUE(&ifp->if_snd, m); @@ -517,10 +535,14 @@ usbnet_start_locked(struct ifnet *ifp) } cd->uncd_tx_prod = idx; + DPRINTF("finished with start; tx_cnt %d list_cnt %d link %d", + cd->uncd_tx_cnt, un->un_tx_list_cnt, unp->unp_link, 0); + /* * Set a timeout in case the chip goes out to lunch. */ - unp->unp_timer = 5; + if (done_transmit) + unp->unp_timer = 5; } static void @@ -529,6 +551,10 @@ usbnet_start(struct ifnet *ifp) struct usbnet * const un = ifp->if_softc; struct usbnet_private * const unp = un->un_pri; + USBNETHIST_FUNC(); + USBNETHIST_CALLARGS("%d, stopping %d", + unp->unp_number, unp->unp_stopping, 0, 0); + mutex_enter(&unp->unp_txlock); if (!unp->unp_stopping) usbnet_start_locked(ifp); @@ -1065,7 +1091,9 @@ usbnet_stop(struct usbnet *un, struct if ifp->if_flags &= ~IFF_RUNNING; unp->unp_timer = 0; - callout_stop(&unp->unp_stat_ch); + callout_halt(&unp->unp_stat_ch, &unp->unp_lock); + usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER, + &unp->unp_lock); /* Stop transfers. */ usbnet_ep_stop_pipes(un); @@ -1098,15 +1126,16 @@ usbnet_stop_ifp(struct ifnet *ifp, int d static void usbnet_tick(void *arg) { + USBNETHIST_FUNC(); struct usbnet * const un = arg; struct usbnet_private * const unp = un->un_pri; - mutex_enter(&unp->unp_lock); - if (!unp->unp_stopping && !unp->unp_dying) { + USBNETHIST_CALLARGSN(10, "%d: enter", unp->unp_number, 0, 0, 0); + + if (unp != NULL && !unp->unp_stopping && !unp->unp_dying) { /* Perform periodic stuff in process context */ usb_add_task(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER); } - mutex_exit(&unp->unp_lock); } static void @@ -1138,9 +1167,15 @@ usbnet_watchdog(struct ifnet *ifp) static void usbnet_tick_task(void *arg) { + USBNETHIST_FUNC(); struct usbnet * const un = arg; struct usbnet_private * const unp = un->un_pri; + if (unp == NULL) + return; + + USBNETHIST_CALLARGSN(8, "%d: enter", unp->unp_number, 0, 0, 0); + mutex_enter(&unp->unp_lock); if (unp->unp_stopping || unp->unp_dying) { mutex_exit(&unp->unp_lock); @@ -1157,6 +1192,7 @@ usbnet_tick_task(void *arg) usbnet_watchdog(ifp); if (mii && ifp) { + DPRINTFN(8, "mii %jx ifp %jx", (uintptr_t)mii, (uintptr_t)ifp, 0, 0); mii_tick(mii); if (!unp->unp_link) @@ -1225,7 +1261,6 @@ usbnet_rndsrc(struct usbnet *un) void * usbnet_softc(struct usbnet *un) { - //return un->un_pri->unp_sc; return un->un_sc; } @@ -1238,7 +1273,7 @@ usbnet_havelink(struct usbnet *un) bool usbnet_isdying(struct usbnet *un) { - return un->un_pri->unp_dying; + return un->un_pri == NULL || un->un_pri->unp_dying; } @@ -1421,7 +1456,7 @@ usbnet_attach_ifp(struct usbnet *un, /* Attach the interface. */ int rv = if_initialize(ifp); if (rv != 0) { - aprint_error_dev(un->un_dev, "if_initialize failed(%d)\n", rv); + aprint_error_dev(un->un_dev, "if_initialize failed: %d\n", rv); return; } if (ifp->_if_input == NULL) @@ -1470,15 +1505,16 @@ usbnet_detach(device_t self, int flags) unp->unp_dying = true; mutex_exit(&unp->unp_lock); - callout_halt(&unp->unp_stat_ch, NULL); - usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER, NULL); - if (ifp->if_flags & IFF_RUNNING) { IFNET_LOCK(ifp); usbnet_stop_ifp(ifp, 1); IFNET_UNLOCK(ifp); } + callout_halt(&unp->unp_stat_ch, NULL); + usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER, + NULL); + mutex_enter(&unp->unp_lock); unp->unp_refcnt--; while (unp->unp_refcnt > 0) { @@ -1496,6 +1532,7 @@ usbnet_detach(device_t self, int flags) if (mii) { mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY); ifmedia_delete_instance(&mii->mii_media, IFM_INST_ANY); + usbnet_ec(un)->ec_mii = NULL; } if (ifp->if_softc) { if (!usbnet_empty_eaddr(un)) @@ -1516,6 +1553,7 @@ usbnet_detach(device_t self, int flags) usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, un->un_udev, un->un_dev); kmem_free(unp, sizeof(*unp)); + un->un_pri = NULL; return 0; } Index: src/sys/dev/usb/usbnet.h diff -u src/sys/dev/usb/usbnet.h:1.14.2.2 src/sys/dev/usb/usbnet.h:1.14.2.3 --- src/sys/dev/usb/usbnet.h:1.14.2.2 Sun Sep 1 13:00:36 2019 +++ src/sys/dev/usb/usbnet.h Fri Sep 13 06:51:58 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: usbnet.h,v 1.14.2.2 2019/09/01 13:00:36 martin Exp $ */ +/* $NetBSD: usbnet.h,v 1.14.2.3 2019/09/13 06:51:58 martin Exp $ */ /* * Copyright (c) 2019 Matthew R. Green @@ -352,7 +352,8 @@ void usbnet_input(struct usbnet * const, /* autoconf */ void usbnet_attach(struct usbnet *un, const char *); -void usbnet_attach_ifp(struct usbnet *, unsigned, unsigned, const struct usbnet_mii *); +void usbnet_attach_ifp(struct usbnet *, unsigned, unsigned, + const struct usbnet_mii *); int usbnet_detach(device_t, int); int usbnet_activate(device_t, devact_t);