--- zzzz-none-000/linux-2.6.39.4/drivers/usb/core/hub.c 2011-08-03 19:43:28.000000000 +0000 +++ puma6-arm-6490-729/linux-2.6.39.4/drivers/usb/core/hub.c 2021-11-10 13:23:10.000000000 +0000 @@ -29,6 +29,10 @@ #include #include "usb.h" +#ifdef CONFIG_AVM_POWERMETER +#include +#include +#endif /*--- #ifdef CONFIG_AVM_POWERMETER ---*/ /* if we are in debug mode, always announce new devices */ #ifdef DEBUG @@ -37,6 +41,28 @@ #endif #endif +/* 20170405 AVM/VGJ USB KPI */ +#if defined (CONFIG_AVM_KERNEL) + +#define AVM_RECONNECT_ERROR_MS_THRESHOLD 2500 + +unsigned long disconnect_time[2]; +unsigned int disconnect_device_id[2]; + +int reconnect_count = 0; +module_param(reconnect_count, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(reconnect_count, "Count of reconnects"); + +int enum_error_count = 0; +module_param(enum_error_count, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(enum_error_count, "Count of enumeration errors"); + +int overcurrent_error_count = 0; +module_param(overcurrent_error_count, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(overcurrent_error_count, "Count of overcurrent errors"); + +#endif + struct usb_hub { struct device *intfdev; /* the "interface" device */ struct usb_device *hdev; @@ -1643,7 +1669,6 @@ { struct usb_device *udev = *pdev; int i; - struct usb_hcd *hcd = bus_to_hcd(udev->bus); if (!udev) { pr_debug ("%s nodev\n", __func__); @@ -1658,6 +1683,33 @@ dev_info(&udev->dev, "USB disconnect, device number %d\n", udev->devnum); +#if defined(CONFIG_AVM_POWERMETER) + { + unsigned nextmA = 0; + unsigned avm_powerdevice = 0; + + if (udev->level == 1) { + avm_powerdevice = (udev->bus->busnum == 1)? powerdevice_usb_host : powerdevice_usb_host2; + printk (KERN_INFO "Bus#%u disconnect: AVM Powermeter changed to %u mA\n", udev->bus->busnum, nextmA); + PowerManagmentRessourceInfo(avm_powerdevice, nextmA); + } + } +#endif // CONFIG_AVM_POWERMETER + +/* 20170405 AVM/VGJ store disconnect timestamp to check possible reconnects */ +#if defined (CONFIG_AVM_KERNEL) + // Only check reconnects of devices directly connected to root-hub + if (udev->level == 1) { + int port_index; + unsigned int device_id; + port_index = (udev->bus->busnum == 1)? 0 : 1; + disconnect_time[port_index] = jiffies; + device_id = (udev->descriptor.idVendor << 16) | udev->descriptor.idProduct; + disconnect_device_id[port_index] = device_id; + } +#endif + + usb_lock_device(udev); /* Free up all the children before we remove this device */ @@ -1671,9 +1723,12 @@ * so that the hardware is now fully quiesced. */ dev_dbg (&udev->dev, "unregistering device\n"); - mutex_lock(hcd->bandwidth_mutex); + + /* 20161116 AVM/WKR deadlock fix, acquire lock in usb_disable_device */ + // mutex_lock(hcd->bandwidth_mutex); usb_disable_device(udev, 0); - mutex_unlock(hcd->bandwidth_mutex); + // mutex_unlock(hcd->bandwidth_mutex); + usb_hcd_synchronize_unlinks(udev); usb_remove_ep_devs(&udev->ep0); @@ -1755,7 +1810,7 @@ /* descriptor may appear anywhere in config */ if (__usb_get_extra_descriptor (udev->rawdescriptors[0], le16_to_cpu(udev->config[0].desc.wTotalLength), - USB_DT_OTG, (void **) &desc) == 0) { + USB_DT_OTG, (void **) &desc, sizeof(*desc)) == 0) { if (desc->bmAttributes & USB_OTG_HNP) { unsigned port1 = udev->portnum; @@ -1905,6 +1960,39 @@ announce_device(udev); device_enable_async_suspend(&udev->dev); + +#if defined(CONFIG_AVM_POWERMETER) + { + unsigned nextmA = 100; + unsigned avm_powerdevice = 0; + if (udev->level == 1) { + avm_powerdevice = (udev->bus->busnum == 1)? powerdevice_usb_host : powerdevice_usb_host2; + printk (KERN_INFO "Bus#%u connect: AVM Powermeter changed to %u mA\n", udev->bus->busnum, nextmA); + PowerManagmentRessourceInfo(avm_powerdevice, nextmA); + } + } +#endif // CONFIG_AVM_POWERMETER + +/* 20170405 AVM/VGJ If connect comes too fast after disconnect -> reconnect error */ +#if defined (CONFIG_AVM_KERNEL) + // Only check reconnects of devices directly connected to root-hub + if (udev->level == 1) { + unsigned long jiffies_diff; + unsigned int device_id; + int port_index; + port_index = (udev->bus->busnum == 1)? 0 : 1; + // Check device_id to make sure that the stored time belongs to the same device + device_id = (udev->descriptor.idVendor << 16) | udev->descriptor.idProduct; + if ( device_id == disconnect_device_id[port_index] ) { + jiffies_diff = jiffies - disconnect_time[port_index]; + if ( jiffies_diff < msecs_to_jiffies(AVM_RECONNECT_ERROR_MS_THRESHOLD) ) { + printk(KERN_ERR "Spontaneous reconnect\n"); + reconnect_count++; + } + } + } +#endif + /* Register the device. The device driver is responsible * for configuring the device and invoking the add-device * notifier chain (used by usbfs and possibly others). @@ -3287,9 +3375,14 @@ } if (hub->hdev->parent || !hcd->driver->port_handed_over || - !(hcd->driver->port_handed_over)(hcd, port1)) + !(hcd->driver->port_handed_over)(hcd, port1)) { dev_err(hub_dev, "unable to enumerate USB device on port %d\n", port1); +/* 20170405 AVM/VGJ increment enumeration error */ +#if defined (CONFIG_AVM_KERNEL) + enum_error_count++; +#endif + } done: hub_port_disable(hub, port1, 1); @@ -3466,9 +3559,16 @@ msleep(100); /* Cool down */ hub_power_on(hub, true); hub_port_status(hub, i, &status, &unused); - if (status & USB_PORT_STAT_OVERCURRENT) + if (status & USB_PORT_STAT_OVERCURRENT) { dev_err(hub_dev, "over-current " "condition on port %d\n", i); +/* 20170405 AVM/VGJ increment overcurrent error */ +#if defined (CONFIG_AVM_KERNEL) + // Only count overcurrent events for root-hub + if(hdev->level == 0) + overcurrent_error_count++; +#endif + } } if (portchange & USB_PORT_STAT_C_RESET) { @@ -3527,9 +3627,16 @@ msleep(500); /* Cool down */ hub_power_on(hub, true); hub_hub_status(hub, &status, &unused); - if (status & HUB_STATUS_OVERCURRENT) + if (status & HUB_STATUS_OVERCURRENT) { dev_err(hub_dev, "over-current " "condition\n"); +/* 20170405 AVM/VGJ increment overcurrent error */ +#if defined (CONFIG_AVM_KERNEL) + // Only count overcurrent events for root-hub + if(hdev->level == 0) + overcurrent_error_count++; +#endif + } } }