--- zzzz-none-000/linux-4.19.183/drivers/net/usb/usbnet.c 2021-03-24 10:07:39.000000000 +0000 +++ bcm63-7530ax-756/linux-4.19.183/drivers/net/usb/usbnet.c 2023-06-28 08:54:19.000000000 +0000 @@ -46,6 +46,17 @@ #include #include +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BLOG)) +#include +#endif +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) +#include +#include +#include +#endif + +#include + #define DRIVER_VERSION "22-Aug-2005" @@ -77,6 +88,11 @@ // between wakeups #define UNLINK_TIMEOUT_MS 3 +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) +#define USBNET_RX_BUDGET 64 +#define USBNET_PENDING_RX_SKB_THRESH_DEFAULT 64 +#endif + /*-------------------------------------------------------------------------*/ // randomly generated ethernet address @@ -328,6 +344,49 @@ return; } +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_ACCELERATION) && defined(CONFIG_BLOG)) + { + int blog_action; + unsigned int len; + + if(skb->bcm_ext.clone_fc_head == NULL) + { + /* Make sure fcache does not expand the skb->data if clone_fc_head + * is not set by the dongle driver's(ex:rndis_host.c, asix.c etc..) + * we expect dongle/class drivers using fcache to set minumun headroom + * available for all packets in an aggregated skb by calling + * skb_clone_headers_set() before calling usbnet_skb_return. + * + * Ex:rndis based drivers have 8 bytes spacig between 2 packets in an + * aggreated skb. we can call skb_clone_ headers_set(skb, 8) in + * rndis_rx_fixup(); + * By setting this we are telling fcache or enet driver can expand + * skb->data for upto 8 bytes. This is helpful to avoid packet + * copy incase of LAN VLAN's, External Switch tag's etc.. + * + */ + skb_clone_headers_set(skb, 0); + } + + len = skb->len - ETH_HLEN; + blog_action = blog_sinit(skb, skb->dev, TYPE_ETH, 0, BLOG_USBPHY); + + if (likely(PKT_DONE == blog_action)){ + dev->net->stats.rx_packets++; + dev->net->stats.rx_bytes += len; + return; + } + + if (PKT_DROP == blog_action){ + dev->net->stats.rx_packets++; + dev->net->stats.rx_bytes += len; + dev->net->stats.rx_dropped++; + dev_kfree_skb_any(skb); + return; + } + + } +#endif /* only update if unset to allow minidriver rx_fixup override */ if (skb->protocol == 0) skb->protocol = eth_type_trans (skb, dev->net); @@ -344,7 +403,19 @@ if (skb_defer_rx_timestamp(skb)) return; +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_ACCELERATION) && defined(CONFIG_BLOG)) + +#if defined(CONFIG_BCM_USBNET_THREAD) + local_bh_disable(); + status = netif_receive_skb(skb); + local_bh_enable(); +#else + status = netif_receive_skb(skb); +#endif + +#else status = netif_rx (skb); +#endif if (status != NET_RX_SUCCESS) netif_dbg(dev, rx_err, dev->net, "netif_rx status %d\n", status); @@ -377,6 +448,13 @@ insanity: dev->rx_qlen = dev->tx_qlen = 4; } + +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + if(dev->rx_qlen < USBNET_RX_BUDGET) + dev->rx_qlen = USBNET_RX_BUDGET; + + dev->pending_rx_skb_thresh = 2 * dev->rx_qlen; +#endif } EXPORT_SYMBOL_GPL(usbnet_update_max_qlen); @@ -426,6 +504,106 @@ entry->state = state; } +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + +static inline int bcm_skb_queue_len(struct sk_buff_head *list) +{ + unsigned long flags; + __u32 qlen; + + spin_lock_irqsave(&list->lock, flags); + qlen = list->qlen; + spin_unlock_irqrestore(&list->lock, flags); + return qlen; +} + +static inline struct sk_buff *bcm_skb_done_dequeue(struct usbnet *dev) +{ + unsigned long flags; + struct sk_buff *result; + + spin_lock_irqsave(&dev->done.lock, flags); + result = __skb_dequeue(&dev->done); + + if(result && (((struct skb_data *) result->cb)->state != tx_done)) + dev->pending_rx_skb_count--; + + spin_unlock_irqrestore(&dev->done.lock, flags); + return result; +} + +static void usbnet_bh (struct timer_list *t); + + +static int usbnet_thread_func(void *thread_data) +{ + struct usbnet *dev =(struct usbnet *)thread_data; + + while (1) { + + wait_event_interruptible(dev->thread_wq, + (bcm_skb_queue_len(&dev->done) | dev->usbnet_thread_resched + | kthread_should_stop())); + + if(unlikely(kthread_should_stop())) + { + return 0; + } + + /*clear all conditions */ + dev->usbnet_thread_resched=0; + + usbnet_bh(&dev->delay); + + if (dev->usbnet_thread_resched || (bcm_skb_queue_len(&dev->done) >= 1)) { + //cond_resched(); + yield(); + } + } + return 0; +} + +static inline void usbnet_thread_wakeup(struct usbnet *dev) +{ + wake_up_interruptible(&dev->thread_wq); +} + +static inline void usbnet_thread_schedule(struct usbnet *dev) +{ + dev->usbnet_thread_resched = 1; + usbnet_thread_wakeup(dev); +} + +static void usbnet_bh_timer(struct timer_list *t) +{ + struct usbnet *dev = from_timer(dev, t, delay); + usbnet_thread_schedule(dev); +} + +struct task_struct *create_usbnet_thread(void *thread_data) +{ + struct task_struct *tsk; + struct sched_param param; + + /*TODO fix thread name when multiple devices are present + * this is just a cosmetic issue + */ + + tsk = kthread_create(usbnet_thread_func, thread_data, "usbnet_thread"); + + if (IS_ERR(tsk)) { + printk("usbnet_thread_free_task creation failed\n"); + return NULL; + } + + param.sched_priority = BCM_RTPRIO_DATA; + sched_setscheduler(tsk, SCHED_RR, ¶m); + wake_up_process(tsk); + + printk("usbnet_thread created successfully \n"); + return tsk; +} +#endif /*-------------------------------------------------------------------------*/ /* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from @@ -451,8 +629,21 @@ spin_lock_nested(&dev->done.lock, SINGLE_DEPTH_NESTING); __skb_queue_tail(&dev->done, skb); +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + /* restrict number of pending urbs/skb's to avoid irq flooding */ + if((state != tx_done)) + { + ++dev->pending_rx_skb_count; + old_state = unlink_start; + } + + if (dev->done.qlen == 1) + usbnet_thread_wakeup(dev); + +#else if (dev->done.qlen == 1) tasklet_schedule(&dev->bh); +#endif spin_unlock(&dev->done.lock); spin_unlock_irqrestore(&list->lock, flags); return old_state; @@ -534,7 +725,11 @@ default: netif_dbg(dev, rx_err, dev->net, "rx submit, %d\n", retval); +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + usbnet_thread_schedule(dev); +#else tasklet_schedule (&dev->bh); +#endif break; case 0: __usbnet_queue_skb(&dev->rxq, skb, rx_start); @@ -579,7 +774,16 @@ } done: +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + /* there is no need to queue the skb back to done queue just for freeing, + * we can just call free here as we are in thread context + */ + + usb_free_urb (((struct skb_data *)skb->cb)->urb); + dev_kfree_skb (skb); +#else skb_queue_tail(&dev->done, skb); +#endif } /*-------------------------------------------------------------------------*/ @@ -696,7 +900,11 @@ num++; } +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + usbnet_thread_schedule(dev); +#else tasklet_schedule(&dev->bh); +#endif netif_dbg(dev, rx_status, dev->net, "paused rx queue disabled, %d skbs requeued\n", num); @@ -765,7 +973,12 @@ { if (netif_running(dev->net)) { (void) unlink_urbs (dev, &dev->rxq); + +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + usbnet_thread_schedule(dev); +#else tasklet_schedule(&dev->bh); +#endif } } EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs); @@ -851,7 +1064,11 @@ */ dev->flags = 0; del_timer_sync (&dev->delay); +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + /* no need to do anything here for now*/ +#else tasklet_kill (&dev->bh); +#endif if (!pm) usb_autopm_put_interface(dev->intf); @@ -935,7 +1152,11 @@ clear_bit(EVENT_RX_KILL, &dev->flags); // delay posting reads until we're fully open +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + usbnet_thread_schedule(dev); +#else tasklet_schedule (&dev->bh); +#endif if (info->manage_power) { retval = info->manage_power(dev, 1); if (retval < 0) { @@ -1111,7 +1332,11 @@ */ } else { /* submitting URBs for reading packets */ +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + usbnet_thread_schedule(dev); +#else tasklet_schedule(&dev->bh); +#endif } /* hard_mtu or rx_urb_size may change during link change */ @@ -1184,7 +1409,11 @@ status); } else { clear_bit (EVENT_RX_HALT, &dev->flags); +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + usbnet_thread_schedule(dev); +#else tasklet_schedule (&dev->bh); +#endif } } @@ -1209,7 +1438,11 @@ usb_autopm_put_interface(dev->intf); fail_lowmem: if (resched) +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + usbnet_thread_schedule(dev); +#else tasklet_schedule (&dev->bh); +#endif } } @@ -1310,7 +1543,11 @@ struct usbnet *dev = netdev_priv(net); unlink_urbs (dev, &dev->txq); +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + usbnet_thread_schedule(dev); +#else tasklet_schedule (&dev->bh); +#endif /* this needs to be handled individually because the generic layer * doesn't know what is sufficient and could not restore private * information if a remedy of an unconditional reset were used. @@ -1366,6 +1603,26 @@ unsigned long flags; int retval; +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_ACCELERATION) && defined(CONFIG_BLOG)) + if(skb) + { + struct sk_buff *orig_skb = skb; + + if(unlikely(netif_queue_stopped(net))) + skb = NULL; + else + skb = nbuff_xlate((pNBuff_t )skb); + + if (skb == NULL) + { + dev->net->stats.tx_dropped++; + nbuff_free((pNBuff_t) orig_skb); + return NETDEV_TX_OK; + } + blog_emit( skb, net, TYPE_ETH, 0, BLOG_USBPHY ); + } +#endif + if (skb) skb_tx_timestamp(skb); @@ -1532,8 +1789,19 @@ struct sk_buff *skb; struct skb_data *entry; +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + int rx_budget = USBNET_RX_BUDGET; + + while ((skb = bcm_skb_done_dequeue (dev))) { + entry = (struct skb_data *) skb->cb; + + /*TODO: try to add seperate tx_done queue*/ + if(entry->state != tx_done) + rx_budget--; +#else while ((skb = skb_dequeue (&dev->done))) { entry = (struct skb_data *) skb->cb; +#endif switch (entry->state) { case rx_done: entry->state = rx_cleanup; @@ -1548,6 +1816,11 @@ default: netdev_dbg(dev->net, "bogus skb state %d\n", entry->state); } + +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + if(rx_budget == 0) + break; +#endif } /* restart RX again after disabling due to high error rate */ @@ -1569,15 +1842,25 @@ !test_bit(EVENT_RX_HALT, &dev->flags)) { int temp = dev->rxq.qlen; +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + if ( (dev->pending_rx_skb_count < dev->pending_rx_skb_thresh) && + (temp < RX_QLEN(dev)) ) { + if (rx_alloc_submit(dev, GFP_KERNEL) == -ENOLINK) +#else if (temp < RX_QLEN(dev)) { if (rx_alloc_submit(dev, GFP_ATOMIC) == -ENOLINK) +#endif return; if (temp != dev->rxq.qlen) netif_dbg(dev, link, dev->net, "rxqlen %d --> %d\n", temp, dev->rxq.qlen); if (dev->rxq.qlen < RX_QLEN(dev)) +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + usbnet_thread_schedule(dev); +#else tasklet_schedule (&dev->bh); +#endif } if (dev->txq.qlen < TX_QLEN (dev)) netif_wake_queue (dev->net); @@ -1625,6 +1908,9 @@ usb_free_urb(dev->interrupt); kfree(dev->padding_pkt); +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + kthread_stop(dev->usbnet_thread ); +#endif free_percpu(dev->stats64); free_netdev(net); } @@ -1711,11 +1997,25 @@ skb_queue_head_init (&dev->txq); skb_queue_head_init (&dev->done); skb_queue_head_init(&dev->rxq_pause); +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + init_waitqueue_head(&dev->thread_wq); + dev->usbnet_thread = create_usbnet_thread(dev); + if(dev->usbnet_thread == NULL) + goto out1; + dev->usbnet_thread_resched=0; + dev->pending_rx_skb_thresh=USBNET_PENDING_RX_SKB_THRESH_DEFAULT; + dev->pending_rx_skb_count=0; +#else dev->bh.func = (void (*)(unsigned long))usbnet_bh; dev->bh.data = (unsigned long)&dev->delay; +#endif INIT_WORK (&dev->kevent, usbnet_deferred_kevent); init_usb_anchor(&dev->deferred); +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + timer_setup(&dev->delay, usbnet_bh_timer, 0); +#else timer_setup(&dev->delay, usbnet_bh, 0); +#endif mutex_init (&dev->phy_mutex); mutex_init(&dev->interrupt_mutex); dev->interrupt_count = 0; @@ -1824,6 +2124,8 @@ if (dev->driver_info->flags & FLAG_LINK_INTR) usbnet_link_change(dev, 0, 0); + avm_pa_dev_register(dev->net); + return 0; out5: @@ -1842,6 +2144,10 @@ cancel_work_sync(&dev->kevent); del_timer_sync(&dev->delay); free_percpu(dev->stats64); +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + if(dev->usbnet_thread) + kthread_stop(dev->usbnet_thread ); +#endif out0: free_netdev(net); out: @@ -1931,7 +2237,12 @@ if (!(dev->txq.qlen >= TX_QLEN(dev))) netif_tx_wake_all_queues(dev->net); + +#if (defined(CONFIG_BCM_KF_USBNET) && defined(CONFIG_BCM_USBNET_THREAD)) + usbnet_thread_schedule(dev); +#else tasklet_schedule (&dev->bh); +#endif } }