* Re: sctp_close/sk_free: kernel BUG at arch/x86/mm/physaddr.c:18!
From: Fengguang Wu @ 2012-09-06 4:54 UTC (permalink / raw)
To: Eric Dumazet
Cc: Marc Kleine-Budde, H.K. Jerry Chu, Eric W. Biederman, networking,
linux-can
In-Reply-To: <1346864220.13121.157.camel@edumazet-glaptop>
On Wed, Sep 05, 2012 at 06:57:00PM +0200, Eric Dumazet wrote:
> Here is a more complete patch, as there are three potential problems,
> not only one :
It's fine, too.
Tested-by: Fengguang Wu <wfg@linux.intel.com>
Thanks!
^ permalink raw reply
* Re: changing usbnet's API to better deal with cdc-ncm
From: Ming Lei @ 2012-09-06 3:23 UTC (permalink / raw)
To: Oliver Neukum
Cc: alexey.orishko-0IS4wlFg1OjSUeElwK9/Pw, bjorn-yOkvZcmFvRU,
netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <2791550.LhGu6po6Xy-ugxBuEnWX9yG/4A2pS7c2Q@public.gmane.org>
On Thu, Sep 6, 2012 at 4:12 AM, Oliver Neukum <oneukum-l3A5Bk7waGM@public.gmane.org> wrote:
> Hi,
>
> looking at cdc-ncm it seeems to me that cdc-ncm is forced to play
> very dirty games because usbnet doesn't have a notion about aggregating
> packets for a single transfer.
The Ethernet API we are using does not support transmitting multiple Ethernet
frames in a single call, so the aggregation things should be done inside low
level driver, in fact it is just what some wlan(802.11n) drivers have
been doing.
IMO, the current .tx_fixup is intelligent enough to handle aggregation:
- return a skb_out for sending if low level drivers think it is
ready to send
the aggregated frames
- return NULL if the low level drivers think they need to wait
for more frames
Of course, the low level drivers need to start a timer to trigger sending
remainder frames in case of timeout and no further frames come from
upper protocol stack.
Looks the introduced .tx_bundle is not necessary since .tx_fixup is OK.
>
> It seems to me that this can be fixed introducing a method for bundling,
> which tells usbnet how packets have been aggregated. To have performance
> usbnet strives to always keep at least two transfers in flight.
IMO, usbnet only cares how to send out the aggregated frame, and
doesn't mind how the packets are aggregated. Also the way of
aggregation is per low level driver and should be handled by low
level driver.
>
> The code isn't complete and I need to get a device for testing, but to get
> your opinion, I ask you to comment on what I have now.
>
> Regards
> Oliver
>
> diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
> index 4cd582a..56ef743 100644
> --- a/drivers/net/usb/cdc_ncm.c
> +++ b/drivers/net/usb/cdc_ncm.c
> @@ -135,9 +135,6 @@ struct cdc_ncm_ctx {
> u16 connected;
> };
>
> -static void cdc_ncm_txpath_bh(unsigned long param);
> -static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx);
> -static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer);
> static struct usb_driver cdc_ncm_driver;
>
> static void
> @@ -464,10 +461,6 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
> if (ctx == NULL)
> return -ENODEV;
>
> - hrtimer_init(&ctx->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> - ctx->tx_timer.function = &cdc_ncm_tx_timer_cb;
> - ctx->bh.data = (unsigned long)ctx;
> - ctx->bh.func = cdc_ncm_txpath_bh;
The timeout timer is removed, so I am wondering how the low level driver or
usbnet handle the wait_for_more?
> atomic_set(&ctx->stop, 0);
> spin_lock_init(&ctx->mtx);
> ctx->netdev = dev->net;
> @@ -650,7 +643,7 @@ static void cdc_ncm_zero_fill(u8 *ptr, u32 first, u32 end, u32 max)
> memset(ptr + first, 0, end - first);
> }
>
> -static struct sk_buff *
> +static int
> cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
> {
> struct sk_buff *skb_out;
> @@ -659,12 +652,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
> u32 last_offset;
> u16 n = 0, index;
> u8 ready2send = 0;
> -
> - /* if there is a remaining skb, it gets priority */
> - if (skb != NULL)
> - swap(skb, ctx->tx_rem_skb);
> - else
> - ready2send = 1;
> + u8 error = 0;
>
> /*
> * +----------------+
> @@ -690,7 +678,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
> dev_kfree_skb_any(skb);
> ctx->netdev->stats.tx_dropped++;
> }
> - goto exit_no_skb;
> + return -EBUSY;
No send out skb, so you still want usbnet to transmit the NULL frame?
Also the current skb to send is not stored in ctx->tx_rem_skb, it will be lost.
> }
>
> /* make room for NTH and NDP */
> @@ -719,28 +707,15 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
> /* compute maximum buffer size */
> rem = ctx->tx_max - offset;
>
> - if (skb == NULL) {
> - skb = ctx->tx_rem_skb;
> - ctx->tx_rem_skb = NULL;
> -
> - /* check for end of skb */
> - if (skb == NULL)
> - break;
> - }
> -
> if (skb->len > rem) {
> if (n == 0) {
> /* won't fit, MTU problem? */
> dev_kfree_skb_any(skb);
> skb = NULL;
> ctx->netdev->stats.tx_dropped++;
> + error = 1;
> } else {
> - /* no room for skb - store for later */
> - if (ctx->tx_rem_skb != NULL) {
> - dev_kfree_skb_any(ctx->tx_rem_skb);
> - ctx->netdev->stats.tx_dropped++;
> - }
> - ctx->tx_rem_skb = skb;
> +
The 'skb' will be lost too, :-)
> skb = NULL;
> ready2send = 1;
> }
> @@ -768,13 +743,6 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
> skb = NULL;
> }
>
> - /* free up any dangling skb */
> - if (skb != NULL) {
> - dev_kfree_skb_any(skb);
> - skb = NULL;
> - ctx->netdev->stats.tx_dropped++;
> - }
> -
> ctx->tx_curr_frame_num = n;
>
> if (n == 0) {
> @@ -791,9 +759,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
> ctx->tx_curr_skb = skb_out;
> ctx->tx_curr_offset = offset;
> ctx->tx_curr_last_offset = last_offset;
> - /* set the pending count */
> - if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT)
> - ctx->tx_timer_pending = CDC_NCM_TIMER_PENDING_CNT;
> +
> goto exit_no_skb;
>
> } else {
> @@ -874,71 +840,37 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
> /* return skb */
> ctx->tx_curr_skb = NULL;
> ctx->netdev->stats.tx_packets += ctx->tx_curr_frame_num;
> - return skb_out;
>
> -exit_no_skb:
> - /* Start timer, if there is a remaining skb */
> - if (ctx->tx_curr_skb != NULL)
> - cdc_ncm_tx_timeout_start(ctx);
> - return NULL;
> -}
> -
> -static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx)
> -{
> - /* start timer, if not already started */
> - if (!(hrtimer_active(&ctx->tx_timer) || atomic_read(&ctx->stop)))
> - hrtimer_start(&ctx->tx_timer,
> - ktime_set(0, CDC_NCM_TIMER_INTERVAL),
> - HRTIMER_MODE_REL);
> -}
> + if (error)
> + return -EBUSY;
> + if (ready2send)
> + return -EBUSY;
> + else
> + return 0;
>
> -static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *timer)
> -{
> - struct cdc_ncm_ctx *ctx =
> - container_of(timer, struct cdc_ncm_ctx, tx_timer);
> +exit_no_skb:
>
> - if (!atomic_read(&ctx->stop))
> - tasklet_schedule(&ctx->bh);
> - return HRTIMER_NORESTART;
> + return -EAGAIN;
Return -EAGAIN will make the driver or usbnet lose the wait_for_more...
> }
>
> -static void cdc_ncm_txpath_bh(unsigned long param)
> +static int cdc_ncm_tx_bundle(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
> {
> - struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)param;
> -
> - spin_lock_bh(&ctx->mtx);
> - if (ctx->tx_timer_pending != 0) {
> - ctx->tx_timer_pending--;
> - cdc_ncm_tx_timeout_start(ctx);
> - spin_unlock_bh(&ctx->mtx);
> - } else if (ctx->netdev != NULL) {
> - spin_unlock_bh(&ctx->mtx);
> - netif_tx_lock_bh(ctx->netdev);
> - usbnet_start_xmit(NULL, ctx->netdev);
> - netif_tx_unlock_bh(ctx->netdev);
> - }
> + int err;
> + struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
> +
> + err = cdc_ncm_fill_tx_frame(ctx, skb);
> + return err;
> }
>
> static struct sk_buff *
> cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
> {
> - struct sk_buff *skb_out;
> struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
>
> - /*
> - * The Ethernet API we are using does not support transmitting
> - * multiple Ethernet frames in a single call. This driver will
> - * accumulate multiple Ethernet frames and send out a larger
> - * USB frame when the USB buffer is full or when a single jiffies
> - * timeout happens.
> - */
> if (ctx == NULL)
> goto error;
>
> - spin_lock_bh(&ctx->mtx);
> - skb_out = cdc_ncm_fill_tx_frame(ctx, skb);
> - spin_unlock_bh(&ctx->mtx);
> - return skb_out;
> + return ctx->tx_curr_skb;
So you basically replace .tx_fixup as .tx_bundle for ncm, don't you?
This also is what I commented above: .tx_fixup is enough for aggregation, :-)
>
> error:
> if (skb != NULL)
> @@ -1197,6 +1129,7 @@ static const struct driver_info cdc_ncm_info = {
> .manage_power = cdc_ncm_manage_power,
> .status = cdc_ncm_status,
> .rx_fixup = cdc_ncm_rx_fixup,
> + .tx_bundle = cdc_ncm_tx_bundle,
> .tx_fixup = cdc_ncm_tx_fixup,
> };
>
> @@ -1211,6 +1144,7 @@ static const struct driver_info wwan_info = {
> .manage_power = cdc_ncm_manage_power,
> .status = cdc_ncm_status,
> .rx_fixup = cdc_ncm_rx_fixup,
> + .tx_bundle = cdc_ncm_tx_bundle,
> .tx_fixup = cdc_ncm_tx_fixup,
> };
>
> diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
> index 8531c1c..d9a595e 100644
> --- a/drivers/net/usb/usbnet.c
> +++ b/drivers/net/usb/usbnet.c
> @@ -1024,6 +1024,7 @@ static void tx_complete (struct urb *urb)
> struct skb_data *entry = (struct skb_data *) skb->cb;
> struct usbnet *dev = entry->dev;
>
> + atomic_dec(&dev->tx_in_flight);
> if (urb->status == 0) {
> if (!(dev->driver_info->flags & FLAG_MULTI_PACKET))
> dev->net->stats.tx_packets++;
> @@ -1089,23 +1090,50 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
> struct urb *urb = NULL;
> struct skb_data *entry;
> struct driver_info *info = dev->driver_info;
> + struct sk_buff *skb_old = NULL;
> unsigned long flags;
> int retval;
> + int transmit_now = 1;
> + int bundle_again = 0;
>
> if (skb)
> skb_tx_timestamp(skb);
>
> + /*
> + * first we allow drivers to bundle packets together
> + * maintainance of the buffer is the responsibility
> + * of the lower layer
> + */
> +rebundle:
> + if (info->tx_bundle) {
> + bundle_again = 0;
> + retval = info->tx_bundle(dev, skb, GFP_ATOMIC);
> +
> + switch (retval) {
> + case 0: /* the package has been bundled */
> + if (atomic_read(&dev->tx_in_flight) < 2)
> + transmit_now = 1;
> + else
> + transmit_now = 0;
> + break;
> + case -EAGAIN:
> + transmit_now = 1;
> + bundle_again = 1;
I don't understand why you want to bundle the same SKB again...
> + skb_old = skb;
> + break;
> + case -EBUSY:
> + transmit_now = 1;
> + break;
> + }
> + }
> // some devices want funky USB-level framing, for
> // win32 driver (usually) and/or hardware quirks
> - if (info->tx_fixup) {
> + if (transmit_now && info->tx_fixup) {
> skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
> if (!skb) {
> if (netif_msg_tx_err(dev)) {
> netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n");
> goto drop;
> - } else {
> - /* cdc_ncm collected packet; waits for more */
> - goto not_drop;
This above may trigger oops since the null skb will be transmit later...
> }
> }
> }
> @@ -1164,14 +1192,17 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
> }
> #endif
>
> + atomic_inc(&dev->tx_in_flight);
> switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) {
> case -EPIPE:
> netif_stop_queue (net);
> usbnet_defer_kevent (dev, EVENT_TX_HALT);
> + atomic_dec(&dev->tx_in_flight);
> usb_autopm_put_interface_async(dev->intf);
> break;
> default:
> usb_autopm_put_interface_async(dev->intf);
> + atomic_dec(&dev->tx_in_flight);
> netif_dbg(dev, tx_err, dev->net,
> "tx: submit urb err %d\n", retval);
> break;
> @@ -1187,7 +1218,6 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
> netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", retval);
> drop:
> dev->net->stats.tx_dropped++;
> -not_drop:
> if (skb)
> dev_kfree_skb_any (skb);
> usb_free_urb (urb);
> @@ -1197,6 +1227,10 @@ not_drop:
> #ifdef CONFIG_PM
> deferred:
> #endif
> + if (bundle_again) {
> + skb = skb_old;
> + goto rebundle;
> + }
> return NETDEV_TX_OK;
> }
> EXPORT_SYMBOL_GPL(usbnet_start_xmit);
> @@ -1393,6 +1427,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
> dev->delay.data = (unsigned long) dev;
> init_timer (&dev->delay);
> mutex_init (&dev->phy_mutex);
> + atomic_set(&dev->tx_in_flight, 0);
>
> dev->net = net;
> strcpy (net->name, "usb%d");
> diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
> index f87cf62..bb2f622 100644
> --- a/include/linux/usb/usbnet.h
> +++ b/include/linux/usb/usbnet.h
> @@ -33,6 +33,7 @@ struct usbnet {
> wait_queue_head_t *wait;
> struct mutex phy_mutex;
> unsigned char suspend_count;
> + atomic_t tx_in_flight;
>
> /* i/o info: pipes etc */
> unsigned in, out;
> @@ -133,6 +134,12 @@ struct driver_info {
> /* fixup rx packet (strip framing) */
> int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb);
>
> + /* bundle individual package for transmission as
> + * larger package. This cannot sleep
> + */
> + int (*tx_bundle)(struct usbnet *dev,
> + struct sk_buff *skb, gfp_t flags);
> +
> /* fixup tx packet (add framing) */
> struct sk_buff *(*tx_fixup)(struct usbnet *dev,
> struct sk_buff *skb, gfp_t flags);
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Thanks,
--
Ming Lei
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Increased multicast packet drops in 3.4
From: Shawn Bohrer @ 2012-09-06 0:11 UTC (permalink / raw)
To: netdev; +Cc: eric.dumazet
I've been testing the 3.4 kernel compared to the 3.1 kernel and
noticed my application is experiencing a noticeable increase in packet
drops compared to 3.1. In this case I have 8 processes all listening
on the same multicast group and occasionally 1 or more of the
processes will report drops based on gaps in the sequence numbers on
the packets. One thing I find interesting is that some of the time 2
or 3 of the 8 processes will report that they missed the exact same
50+ packets. Since the other processes receive the packets I know
that they are making it to the machine and past the driver.
So far I have not been able to _see_ any OS counters increase when the
drops occur but perhaps there is a location that I have not yet
looked. I've been looking for drops in /proc/net/udp /proc/net/snmp
and /proc/net/dev.
I've tried using dropwatch/drop_monitor but it is awfully noisy even
after back porting many of the patches Eric Dumazet has contributed to
silence the false positives. Similarly I setup trace-cmd/ftrace to
record skb:kfree_skb calls with a stacktrace and had my application
stop the trace when a drop was reported. From these traces I see a
number of the following:
md_connector-12791 [014] 7952.982818: kfree_skb: skbaddr=0xffff880583bd7500 protocol=2048 location=0xffffffff813c930b
md_connector-12791 [014] 7952.982821: kernel_stack: <stack trace>
=> skb_release_data (ffffffff813c930b)
=> __kfree_skb (ffffffff813c934e)
=> skb_free_datagram_locked (ffffffff813ccca8)
=> udp_recvmsg (ffffffff8143335c)
=> inet_recvmsg (ffffffff8143cbfb)
=> sock_recvmsg_nosec (ffffffff813be80f)
=> __sys_recvmsg (ffffffff813bfe70)
=> __sys_recvmmsg (ffffffff813c2392)
=> sys_recvmmsg (ffffffff813c25b0)
=> system_call_fastpath (ffffffff8148cfd2)
Looking at the code it does look like these could be the drops, since
I do not see any counters incremented in this code path. However I'm
not very familiar with this code so it could also be a false positive.
It does look like the above stack only gets called if
skb_has_frag_list(skb) does this imply the packet was over one MTU
(1500)?
I'd appreciate any input on possible causes/solutions for these drops.
Or ways that I can further debug this issue to find the root cause of
the increase in drops on 3.4.
Thanks,
Shawn
--
---------------------------------------------------------------
This email, along with any attachments, is confidential. If you
believe you received this message in error, please contact the
sender immediately and delete all copies of the message.
Thank you.
^ permalink raw reply
* Re: [PATCH 09/10] net/macb: ethtool interface: add register dump feature
From: Ben Hutchings @ 2012-09-05 23:36 UTC (permalink / raw)
To: Nicolas Ferre
Cc: netdev, linux-arm-kernel, davem, havard, plagnioj, jamie,
linux-kernel, patrice.vilchez
In-Reply-To: <fcd1c2443a30f23ffcd8de28328c5a382e2a2459.1346775479.git.nicolas.ferre@atmel.com>
On Wed, 2012-09-05 at 11:00 +0200, Nicolas Ferre wrote:
> Add macb_get_regs() ethtool function and its helper function:
> macb_get_regs_len().
>
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
> ---
> drivers/net/ethernet/cadence/macb.c | 40 +++++++++++++++++++++++++++++++++++
> drivers/net/ethernet/cadence/macb.h | 3 +++
> 2 files changed, 43 insertions(+)
>
> diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
> index c7c39f1..f31c0a7 100644
> --- a/drivers/net/ethernet/cadence/macb.c
> +++ b/drivers/net/ethernet/cadence/macb.c
> @@ -1321,10 +1321,50 @@ static void macb_get_drvinfo(struct net_device *dev,
> strcpy(info->bus_info, dev_name(&bp->pdev->dev));
> }
>
> +static int macb_get_regs_len(struct net_device *netdev)
> +{
> + return MACB_GREGS_LEN * sizeof(u32);
> +}
> +
> +static void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs,
> + void *p)
> +{
> + struct macb *bp = netdev_priv(dev);
> + unsigned int tail, head;
> + u32 *regs_buff = p;
> +
> + memset(p, 0, MACB_GREGS_LEN * sizeof(u32));
The ethtool core does that for you. (Drivers can't be trusted to do
it!)
> + regs->version = MACB_BFEXT(IDNUM, macb_readl(bp, MID));
Note that the version field is supposed to be the version of the
register dump format. Is this value sufficient for userland to easily
decide whether macb_is_gem()? Are there spare bits that you can set if
you change the format later?
> + tail = macb_tx_ring_wrap(bp->tx_tail);
> + head = macb_tx_ring_wrap(bp->tx_head);
> +
> + regs_buff[0] = macb_readl(bp, NCR);
> + regs_buff[1] = macb_or_gem_readl(bp, NCFGR);
> + regs_buff[2] = macb_readl(bp, NSR);
> + regs_buff[3] = macb_readl(bp, TSR);
> + regs_buff[4] = macb_readl(bp, RBQP);
> + regs_buff[5] = macb_readl(bp, TBQP);
> + regs_buff[6] = macb_readl(bp, RSR);
> + regs_buff[7] = macb_readl(bp, IMR);
> +
> + regs_buff[8] = tail;
> + regs_buff[9] = head;
> + regs_buff[10] = macb_tx_dma(bp, tail);
> + regs_buff[11] = macb_tx_dma(bp, head);
> +
> + if (macb_is_gem(bp)) {
> + regs_buff[12] = gem_readl(bp, USRIO);
> + regs_buff[13] = gem_readl(bp, DMACFG);
> + }
> +}
> +
> static const struct ethtool_ops macb_ethtool_ops = {
> .get_settings = macb_get_settings,
> .set_settings = macb_set_settings,
> .get_drvinfo = macb_get_drvinfo,
> + .get_regs_len = macb_get_regs_len,
> + .get_regs = macb_get_regs,
> .get_link = ethtool_op_get_link,
> .get_ts_info = ethtool_op_get_ts_info,
> };
> diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
> index 8a4ee2f..d509e88 100644
> --- a/drivers/net/ethernet/cadence/macb.h
> +++ b/drivers/net/ethernet/cadence/macb.h
> @@ -10,6 +10,9 @@
> #ifndef _MACB_H
> #define _MACB_H
>
> +
> +#define MACB_GREGS_LEN 32
Why is this rather larger than the actual number of registers you
return? Also, the name is not a great idea as 'regs_len' is normally a
number of bytes.
Ben.
> /* MACB register offsets */
> #define MACB_NCR 0x0000
> #define MACB_NCFGR 0x0004
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* [net-next 6/6] igb: Add 1588 support to I210/I211.
From: Jeff Kirsher @ 2012-09-05 23:35 UTC (permalink / raw)
To: davem; +Cc: Matthew Vick, netdev, gospo, sassmann, Richard Cochran,
Jeff Kirsher
In-Reply-To: <1346888106-25638-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Matthew Vick <matthew.vick@intel.com>
Previously I210/I211 followed the same code flow as 82580/I350 for 1588.
However, since the register sets have changed, we must update the
implementation to accommodate the register changes.
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Matthew Vick <matthew.vick@intel.com>
Acked-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/e1000_defines.h | 3 +
drivers/net/ethernet/intel/igb/igb_ptp.c | 216 +++++++++++++++++++------
2 files changed, 174 insertions(+), 45 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h
index 0b27e8f..cae3070 100644
--- a/drivers/net/ethernet/intel/igb/e1000_defines.h
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h
@@ -322,6 +322,9 @@
#define E1000_FCRTC_RTH_COAL_SHIFT 4
#define E1000_PCIEMISC_LX_DECISION 0x00000080 /* Lx power decision */
+/* Timestamp in Rx buffer */
+#define E1000_RXPBS_CFG_TS_EN 0x80000000
+
/* SerDes Control */
#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index d57060c..e13ba1d 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -121,6 +121,41 @@ static cycle_t igb_ptp_read_82580(const struct cyclecounter *cc)
return val;
}
+/*
+ * SYSTIM read access for I210/I211
+ */
+
+static void igb_ptp_read_i210(struct igb_adapter *adapter, struct timespec *ts)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 sec, nsec, jk;
+
+ /*
+ * The timestamp latches on lowest register read. For I210/I211, the
+ * lowest register is SYSTIMR. Since we only need to provide nanosecond
+ * resolution, we can ignore it.
+ */
+ jk = rd32(E1000_SYSTIMR);
+ nsec = rd32(E1000_SYSTIML);
+ sec = rd32(E1000_SYSTIMH);
+
+ ts->tv_sec = sec;
+ ts->tv_nsec = nsec;
+}
+
+static void igb_ptp_write_i210(struct igb_adapter *adapter,
+ const struct timespec *ts)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ /*
+ * Writing the SYSTIMR register is not necessary as it only provides
+ * sub-nanosecond resolution.
+ */
+ wr32(E1000_SYSTIML, ts->tv_nsec);
+ wr32(E1000_SYSTIMH, ts->tv_sec);
+}
+
/**
* igb_ptp_systim_to_hwtstamp - convert system time value to hw timestamp
* @adapter: board private structure
@@ -146,24 +181,28 @@ static void igb_ptp_systim_to_hwtstamp(struct igb_adapter *adapter,
u64 ns;
switch (adapter->hw.mac.type) {
+ case e1000_82576:
+ case e1000_82580:
+ case e1000_i350:
+ spin_lock_irqsave(&adapter->tmreg_lock, flags);
+
+ ns = timecounter_cyc2time(&adapter->tc, systim);
+
+ spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
+
+ memset(hwtstamps, 0, sizeof(*hwtstamps));
+ hwtstamps->hwtstamp = ns_to_ktime(ns);
+ break;
case e1000_i210:
case e1000_i211:
- case e1000_i350:
- case e1000_82580:
- case e1000_82576:
+ memset(hwtstamps, 0, sizeof(*hwtstamps));
+ /* Upper 32 bits contain s, lower 32 bits contain ns. */
+ hwtstamps->hwtstamp = ktime_set(systim >> 32,
+ systim & 0xFFFFFFFF);
break;
default:
- return;
+ break;
}
-
- spin_lock_irqsave(&adapter->tmreg_lock, flags);
-
- ns = timecounter_cyc2time(&adapter->tc, systim);
-
- spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
-
- memset(hwtstamps, 0, sizeof(*hwtstamps));
- hwtstamps->hwtstamp = ns_to_ktime(ns);
}
/*
@@ -225,7 +264,7 @@ static int igb_ptp_adjfreq_82580(struct ptp_clock_info *ptp, s32 ppb)
return 0;
}
-static int igb_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+static int igb_ptp_adjtime_82576(struct ptp_clock_info *ptp, s64 delta)
{
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
ptp_caps);
@@ -243,7 +282,26 @@ static int igb_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
return 0;
}
-static int igb_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+static int igb_ptp_adjtime_i210(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
+ ptp_caps);
+ unsigned long flags;
+ struct timespec now, then = ns_to_timespec(delta);
+
+ spin_lock_irqsave(&igb->tmreg_lock, flags);
+
+ igb_ptp_read_i210(igb, &now);
+ now = timespec_add(now, then);
+ igb_ptp_write_i210(igb, (const struct timespec *)&now);
+
+ spin_unlock_irqrestore(&igb->tmreg_lock, flags);
+
+ return 0;
+}
+
+static int igb_ptp_gettime_82576(struct ptp_clock_info *ptp,
+ struct timespec *ts)
{
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
ptp_caps);
@@ -263,8 +321,24 @@ static int igb_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
return 0;
}
-static int igb_ptp_settime(struct ptp_clock_info *ptp,
- const struct timespec *ts)
+static int igb_ptp_gettime_i210(struct ptp_clock_info *ptp,
+ struct timespec *ts)
+{
+ struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
+ ptp_caps);
+ unsigned long flags;
+
+ spin_lock_irqsave(&igb->tmreg_lock, flags);
+
+ igb_ptp_read_i210(igb, ts);
+
+ spin_unlock_irqrestore(&igb->tmreg_lock, flags);
+
+ return 0;
+}
+
+static int igb_ptp_settime_82576(struct ptp_clock_info *ptp,
+ const struct timespec *ts)
{
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
ptp_caps);
@@ -283,6 +357,22 @@ static int igb_ptp_settime(struct ptp_clock_info *ptp,
return 0;
}
+static int igb_ptp_settime_i210(struct ptp_clock_info *ptp,
+ const struct timespec *ts)
+{
+ struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
+ ptp_caps);
+ unsigned long flags;
+
+ spin_lock_irqsave(&igb->tmreg_lock, flags);
+
+ igb_ptp_write_i210(igb, ts);
+
+ spin_unlock_irqrestore(&igb->tmreg_lock, flags);
+
+ return 0;
+}
+
static int igb_ptp_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on)
{
@@ -320,7 +410,7 @@ static void igb_ptp_overflow_check(struct work_struct *work)
container_of(work, struct igb_adapter, ptp_overflow_work.work);
struct timespec ts;
- igb_ptp_gettime(&igb->ptp_caps, &ts);
+ igb->ptp_caps.gettime(&igb->ptp_caps, &ts);
pr_debug("igb overflow check at %ld.%09lu\n", ts.tv_sec, ts.tv_nsec);
@@ -506,6 +596,13 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
if ((hw->mac.type >= e1000_82580) && tsync_rx_ctl) {
tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
+
+ if ((hw->mac.type == e1000_i210) ||
+ (hw->mac.type == e1000_i211)) {
+ regval = rd32(E1000_RXPBS);
+ regval |= E1000_RXPBS_CFG_TS_EN;
+ wr32(E1000_RXPBS, regval);
+ }
}
/* enable/disable TX */
@@ -556,7 +653,9 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
wrfl();
/* clear TX/RX time stamp registers, just to be sure */
+ regval = rd32(E1000_TXSTMPL);
regval = rd32(E1000_TXSTMPH);
+ regval = rd32(E1000_RXSTMPL);
regval = rd32(E1000_RXSTMPH);
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
@@ -569,19 +668,35 @@ void igb_ptp_init(struct igb_adapter *adapter)
struct net_device *netdev = adapter->netdev;
switch (hw->mac.type) {
- case e1000_i210:
- case e1000_i211:
- case e1000_i350:
+ case e1000_82576:
+ snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
+ adapter->ptp_caps.owner = THIS_MODULE;
+ adapter->ptp_caps.max_adj = 1000000000;
+ adapter->ptp_caps.n_ext_ts = 0;
+ adapter->ptp_caps.pps = 0;
+ adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576;
+ adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576;
+ adapter->ptp_caps.gettime = igb_ptp_gettime_82576;
+ adapter->ptp_caps.settime = igb_ptp_settime_82576;
+ adapter->ptp_caps.enable = igb_ptp_enable;
+ adapter->cc.read = igb_ptp_read_82576;
+ adapter->cc.mask = CLOCKSOURCE_MASK(64);
+ adapter->cc.mult = 1;
+ adapter->cc.shift = IGB_82576_TSYNC_SHIFT;
+ /* Dial the nominal frequency. */
+ wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576);
+ break;
case e1000_82580:
+ case e1000_i350:
snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
adapter->ptp_caps.owner = THIS_MODULE;
adapter->ptp_caps.max_adj = 62499999;
adapter->ptp_caps.n_ext_ts = 0;
adapter->ptp_caps.pps = 0;
adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580;
- adapter->ptp_caps.adjtime = igb_ptp_adjtime;
- adapter->ptp_caps.gettime = igb_ptp_gettime;
- adapter->ptp_caps.settime = igb_ptp_settime;
+ adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576;
+ adapter->ptp_caps.gettime = igb_ptp_gettime_82576;
+ adapter->ptp_caps.settime = igb_ptp_settime_82576;
adapter->ptp_caps.enable = igb_ptp_enable;
adapter->cc.read = igb_ptp_read_82580;
adapter->cc.mask = CLOCKSOURCE_MASK(IGB_NBITS_82580);
@@ -590,23 +705,20 @@ void igb_ptp_init(struct igb_adapter *adapter)
/* Enable the timer functions by clearing bit 31. */
wr32(E1000_TSAUXC, 0x0);
break;
- case e1000_82576:
+ case e1000_i210:
+ case e1000_i211:
snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
adapter->ptp_caps.owner = THIS_MODULE;
- adapter->ptp_caps.max_adj = 1000000000;
+ adapter->ptp_caps.max_adj = 62499999;
adapter->ptp_caps.n_ext_ts = 0;
adapter->ptp_caps.pps = 0;
- adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576;
- adapter->ptp_caps.adjtime = igb_ptp_adjtime;
- adapter->ptp_caps.gettime = igb_ptp_gettime;
- adapter->ptp_caps.settime = igb_ptp_settime;
+ adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580;
+ adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210;
+ adapter->ptp_caps.gettime = igb_ptp_gettime_i210;
+ adapter->ptp_caps.settime = igb_ptp_settime_i210;
adapter->ptp_caps.enable = igb_ptp_enable;
- adapter->cc.read = igb_ptp_read_82576;
- adapter->cc.mask = CLOCKSOURCE_MASK(64);
- adapter->cc.mult = 1;
- adapter->cc.shift = IGB_82576_TSYNC_SHIFT;
- /* Dial the nominal frequency. */
- wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576);
+ /* Enable the timer functions by clearing bit 31. */
+ wr32(E1000_TSAUXC, 0x0);
break;
default:
adapter->ptp_clock = NULL;
@@ -615,17 +727,24 @@ void igb_ptp_init(struct igb_adapter *adapter)
wrfl();
- timecounter_init(&adapter->tc, &adapter->cc,
- ktime_to_ns(ktime_get_real()));
+ spin_lock_init(&adapter->tmreg_lock);
+ INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work);
- INIT_DELAYED_WORK(&adapter->ptp_overflow_work, igb_ptp_overflow_check);
+ /* Initialize the clock and overflow work for devices that need it. */
+ if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) {
+ struct timespec ts = ktime_to_timespec(ktime_get_real());
- spin_lock_init(&adapter->tmreg_lock);
+ igb_ptp_settime_i210(&adapter->ptp_caps, &ts);
+ } else {
+ timecounter_init(&adapter->tc, &adapter->cc,
+ ktime_to_ns(ktime_get_real()));
- INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work);
+ INIT_DELAYED_WORK(&adapter->ptp_overflow_work,
+ igb_ptp_overflow_check);
- schedule_delayed_work(&adapter->ptp_overflow_work,
- IGB_SYSTIM_OVERFLOW_PERIOD);
+ schedule_delayed_work(&adapter->ptp_overflow_work,
+ IGB_SYSTIM_OVERFLOW_PERIOD);
+ }
/* Initialize the time sync interrupts for devices that support it. */
if (hw->mac.type >= e1000_82580) {
@@ -708,6 +827,13 @@ void igb_ptp_reset(struct igb_adapter *adapter)
return;
}
- timecounter_init(&adapter->tc, &adapter->cc,
- ktime_to_ns(ktime_get_real()));
+ /* Re-initialize the timer. */
+ if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) {
+ struct timespec ts = ktime_to_timespec(ktime_get_real());
+
+ igb_ptp_settime_i210(&adapter->ptp_caps, &ts);
+ } else {
+ timecounter_init(&adapter->tc, &adapter->cc,
+ ktime_to_ns(ktime_get_real()));
+ }
}
--
1.7.11.4
^ permalink raw reply related
* [net-next 5/6] igb: Prevent dropped Tx timestamps via work items and interrupts.
From: Jeff Kirsher @ 2012-09-05 23:35 UTC (permalink / raw)
To: davem; +Cc: Matthew Vick, netdev, gospo, sassmann, Richard Cochran,
Jeff Kirsher
In-Reply-To: <1346888106-25638-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Matthew Vick <matthew.vick@intel.com>
In rare circumstances, it's possible a descriptor writeback will occur
before a timestamped Tx packet will go out on the wire, leading to the
driver believing the hardware failed to timestamp the packet. Schedule a
work item for 82576 and use the available time sync interrupt registers
on 82580 and above to account for this.
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Matthew Vick <matthew.vick@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/e1000_defines.h | 5 ++
drivers/net/ethernet/intel/igb/e1000_regs.h | 2 +
drivers/net/ethernet/intel/igb/igb.h | 8 +-
drivers/net/ethernet/intel/igb/igb_main.c | 61 +++++++++++++--
drivers/net/ethernet/intel/igb/igb_ptp.c | 102 +++++++++++++++++++++----
5 files changed, 153 insertions(+), 25 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h
index ec7e4fe..0b27e8f 100644
--- a/drivers/net/ethernet/intel/igb/e1000_defines.h
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h
@@ -360,6 +360,7 @@
#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */
#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */
#define E1000_ICR_VMMB 0x00000100 /* VM MB event */
+#define E1000_ICR_TS 0x00080000 /* Time Sync Interrupt */
#define E1000_ICR_DRSTA 0x40000000 /* Device Reset Asserted */
/* If this bit asserted, the driver should claim the interrupt */
#define E1000_ICR_INT_ASSERTED 0x80000000
@@ -399,6 +400,7 @@
#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */
#define E1000_IMS_VMMB E1000_ICR_VMMB /* Mail box activity */
+#define E1000_IMS_TS E1000_ICR_TS /* Time Sync Interrupt */
#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
@@ -510,6 +512,9 @@
#define E1000_TIMINCA_16NS_SHIFT 24
+#define E1000_TSICR_TXTS 0x00000002
+#define E1000_TSIM_TXTS 0x00000002
+
#define E1000_MDICNFG_EXT_MDIO 0x80000000 /* MDI ext/int destination */
#define E1000_MDICNFG_COM_MDIO 0x40000000 /* MDI shared w/ lan 0 */
#define E1000_MDICNFG_PHY_MASK 0x03E00000
diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h
index 28394be..faec840 100644
--- a/drivers/net/ethernet/intel/igb/e1000_regs.h
+++ b/drivers/net/ethernet/intel/igb/e1000_regs.h
@@ -91,6 +91,8 @@
#define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */
#define E1000_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */
#define E1000_SYSTIMR 0x0B6F8 /* System time register Residue */
+#define E1000_TSICR 0x0B66C /* Interrupt Cause Register */
+#define E1000_TSIM 0x0B674 /* Interrupt Mask Register */
/* Filtering Registers */
#define E1000_SAQF(_n) (0x5980 + 4 * (_n))
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 7973469..43c8e29 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -381,6 +381,8 @@ struct igb_adapter {
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_caps;
struct delayed_work ptp_overflow_work;
+ struct work_struct ptp_tx_work;
+ struct sk_buff *ptp_tx_skb;
spinlock_t tmreg_lock;
struct cyclecounter cc;
struct timecounter tc;
@@ -394,6 +396,7 @@ struct igb_adapter {
#define IGB_FLAG_QUAD_PORT_A (1 << 2)
#define IGB_FLAG_QUEUE_PAIRS (1 << 3)
#define IGB_FLAG_DMAC (1 << 4)
+#define IGB_FLAG_PTP (1 << 5)
/* DMA Coalescing defines */
#define IGB_MIN_TXPBSIZE 20408
@@ -440,8 +443,9 @@ extern void igb_set_fw_version(struct igb_adapter *);
#ifdef CONFIG_IGB_PTP
extern void igb_ptp_init(struct igb_adapter *adapter);
extern void igb_ptp_stop(struct igb_adapter *adapter);
-extern void igb_ptp_tx_hwtstamp(struct igb_q_vector *q_vector,
- struct igb_tx_buffer *buffer_info);
+extern void igb_ptp_reset(struct igb_adapter *adapter);
+extern void igb_ptp_tx_work(struct work_struct *work);
+extern void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter);
extern void igb_ptp_rx_hwtstamp(struct igb_q_vector *q_vector,
union e1000_adv_rx_desc *rx_desc,
struct sk_buff *skb);
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 6e39f0c..19d7666 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -1751,6 +1751,11 @@ void igb_reset(struct igb_adapter *adapter)
/* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE);
+#ifdef CONFIG_IGB_PTP
+ /* Re-enable PTP, where applicable. */
+ igb_ptp_reset(adapter);
+#endif /* CONFIG_IGB_PTP */
+
igb_get_phy_info(hw);
}
@@ -4234,7 +4239,7 @@ static __le32 igb_tx_cmd_type(u32 tx_flags)
#ifdef CONFIG_IGB_PTP
/* set timestamp bit if present */
- if (tx_flags & IGB_TX_FLAGS_TSTAMP)
+ if (unlikely(tx_flags & IGB_TX_FLAGS_TSTAMP))
cmd_type |= cpu_to_le32(E1000_ADVTXD_MAC_TSTAMP);
#endif /* CONFIG_IGB_PTP */
@@ -4445,6 +4450,9 @@ static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
struct igb_ring *tx_ring)
{
+#ifdef CONFIG_IGB_PTP
+ struct igb_adapter *adapter = netdev_priv(tx_ring->netdev);
+#endif /* CONFIG_IGB_PTP */
struct igb_tx_buffer *first;
int tso;
u32 tx_flags = 0;
@@ -4468,9 +4476,14 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
first->gso_segs = 1;
#ifdef CONFIG_IGB_PTP
- if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+ if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+ !(adapter->ptp_tx_skb))) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IGB_TX_FLAGS_TSTAMP;
+
+ adapter->ptp_tx_skb = skb_get(skb);
+ if (adapter->hw.mac.type == e1000_82576)
+ schedule_work(&adapter->ptp_tx_work);
}
#endif /* CONFIG_IGB_PTP */
@@ -4859,6 +4872,19 @@ static irqreturn_t igb_msix_other(int irq, void *data)
mod_timer(&adapter->watchdog_timer, jiffies + 1);
}
+#ifdef CONFIG_IGB_PTP
+ if (icr & E1000_ICR_TS) {
+ u32 tsicr = rd32(E1000_TSICR);
+
+ if (tsicr & E1000_TSICR_TXTS) {
+ /* acknowledge the interrupt */
+ wr32(E1000_TSICR, E1000_TSICR_TXTS);
+ /* retrieve hardware timestamp */
+ schedule_work(&adapter->ptp_tx_work);
+ }
+ }
+#endif /* CONFIG_IGB_PTP */
+
wr32(E1000_EIMS, adapter->eims_other);
return IRQ_HANDLED;
@@ -5650,6 +5676,19 @@ static irqreturn_t igb_intr_msi(int irq, void *data)
mod_timer(&adapter->watchdog_timer, jiffies + 1);
}
+#ifdef CONFIG_IGB_PTP
+ if (icr & E1000_ICR_TS) {
+ u32 tsicr = rd32(E1000_TSICR);
+
+ if (tsicr & E1000_TSICR_TXTS) {
+ /* acknowledge the interrupt */
+ wr32(E1000_TSICR, E1000_TSICR_TXTS);
+ /* retrieve hardware timestamp */
+ schedule_work(&adapter->ptp_tx_work);
+ }
+ }
+#endif /* CONFIG_IGB_PTP */
+
napi_schedule(&q_vector->napi);
return IRQ_HANDLED;
@@ -5691,6 +5730,19 @@ static irqreturn_t igb_intr(int irq, void *data)
mod_timer(&adapter->watchdog_timer, jiffies + 1);
}
+#ifdef CONFIG_IGB_PTP
+ if (icr & E1000_ICR_TS) {
+ u32 tsicr = rd32(E1000_TSICR);
+
+ if (tsicr & E1000_TSICR_TXTS) {
+ /* acknowledge the interrupt */
+ wr32(E1000_TSICR, E1000_TSICR_TXTS);
+ /* retrieve hardware timestamp */
+ schedule_work(&adapter->ptp_tx_work);
+ }
+ }
+#endif /* CONFIG_IGB_PTP */
+
napi_schedule(&q_vector->napi);
return IRQ_HANDLED;
@@ -5794,11 +5846,6 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
total_bytes += tx_buffer->bytecount;
total_packets += tx_buffer->gso_segs;
-#ifdef CONFIG_IGB_PTP
- /* retrieve hardware timestamp */
- igb_ptp_tx_hwtstamp(q_vector, tx_buffer);
-#endif /* CONFIG_IGB_PTP */
-
/* free the skb */
dev_kfree_skb_any(tx_buffer->skb);
tx_buffer->skb = NULL;
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index e69555f..d57060c 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -289,6 +289,31 @@ static int igb_ptp_enable(struct ptp_clock_info *ptp,
return -EOPNOTSUPP;
}
+/**
+ * igb_ptp_tx_work
+ * @work: pointer to work struct
+ *
+ * This work function polls the TSYNCTXCTL valid bit to determine when a
+ * timestamp has been taken for the current stored skb.
+ */
+void igb_ptp_tx_work(struct work_struct *work)
+{
+ struct igb_adapter *adapter = container_of(work, struct igb_adapter,
+ ptp_tx_work);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 tsynctxctl;
+
+ if (!adapter->ptp_tx_skb)
+ return;
+
+ tsynctxctl = rd32(E1000_TSYNCTXCTL);
+ if (tsynctxctl & E1000_TSYNCTXCTL_VALID)
+ igb_ptp_tx_hwtstamp(adapter);
+ else
+ /* reschedule to check later */
+ schedule_work(&adapter->ptp_tx_work);
+}
+
static void igb_ptp_overflow_check(struct work_struct *work)
{
struct igb_adapter *igb =
@@ -305,31 +330,25 @@ static void igb_ptp_overflow_check(struct work_struct *work)
/**
* igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp
- * @q_vector: pointer to q_vector containing needed info
- * @buffer: pointer to igb_tx_buffer structure
+ * @adapter: Board private structure.
*
* If we were asked to do hardware stamping and such a time stamp is
* available, then it must have been for this skb here because we only
* allow only one such packet into the queue.
*/
-void igb_ptp_tx_hwtstamp(struct igb_q_vector *q_vector,
- struct igb_tx_buffer *buffer_info)
+void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
{
- struct igb_adapter *adapter = q_vector->adapter;
struct e1000_hw *hw = &adapter->hw;
struct skb_shared_hwtstamps shhwtstamps;
u64 regval;
- /* if skb does not support hw timestamp or TX stamp not valid exit */
- if (likely(!(buffer_info->tx_flags & IGB_TX_FLAGS_TSTAMP)) ||
- !(rd32(E1000_TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID))
- return;
-
regval = rd32(E1000_TXSTMPL);
regval |= (u64)rd32(E1000_TXSTMPH) << 32;
igb_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval);
- skb_tstamp_tx(buffer_info->skb, &shhwtstamps);
+ skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
+ dev_kfree_skb_any(adapter->ptp_tx_skb);
+ adapter->ptp_tx_skb = NULL;
}
void igb_ptp_rx_hwtstamp(struct igb_q_vector *q_vector,
@@ -603,16 +622,26 @@ void igb_ptp_init(struct igb_adapter *adapter)
spin_lock_init(&adapter->tmreg_lock);
+ INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work);
+
schedule_delayed_work(&adapter->ptp_overflow_work,
IGB_SYSTIM_OVERFLOW_PERIOD);
+ /* Initialize the time sync interrupts for devices that support it. */
+ if (hw->mac.type >= e1000_82580) {
+ wr32(E1000_TSIM, E1000_TSIM_TXTS);
+ wr32(E1000_IMS, E1000_IMS_TS);
+ }
+
adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps);
if (IS_ERR(adapter->ptp_clock)) {
adapter->ptp_clock = NULL;
dev_err(&adapter->pdev->dev, "ptp_clock_register failed\n");
- } else
+ } else {
dev_info(&adapter->pdev->dev, "added PHC on %s\n",
adapter->netdev->name);
+ adapter->flags |= IGB_FLAG_PTP;
+ }
}
/**
@@ -624,20 +653,61 @@ void igb_ptp_init(struct igb_adapter *adapter)
void igb_ptp_stop(struct igb_adapter *adapter)
{
switch (adapter->hw.mac.type) {
- case e1000_i211:
- case e1000_i210:
- case e1000_i350:
- case e1000_82580:
case e1000_82576:
+ case e1000_82580:
+ case e1000_i350:
cancel_delayed_work_sync(&adapter->ptp_overflow_work);
break;
+ case e1000_i210:
+ case e1000_i211:
+ /* No delayed work to cancel. */
+ break;
default:
return;
}
+ cancel_work_sync(&adapter->ptp_tx_work);
+
if (adapter->ptp_clock) {
ptp_clock_unregister(adapter->ptp_clock);
dev_info(&adapter->pdev->dev, "removed PHC on %s\n",
adapter->netdev->name);
+ adapter->flags &= ~IGB_FLAG_PTP;
}
}
+
+/**
+ * igb_ptp_reset - Re-enable the adapter for PTP following a reset.
+ * @adapter: Board private structure.
+ *
+ * This function handles the reset work required to re-enable the PTP device.
+ **/
+void igb_ptp_reset(struct igb_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (!(adapter->flags & IGB_FLAG_PTP))
+ return;
+
+ switch (adapter->hw.mac.type) {
+ case e1000_82576:
+ /* Dial the nominal frequency. */
+ wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576);
+ break;
+ case e1000_82580:
+ case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
+ /* Enable the timer functions and interrupts. */
+ wr32(E1000_TSAUXC, 0x0);
+ wr32(E1000_TSIM, E1000_TSIM_TXTS);
+ wr32(E1000_IMS, E1000_IMS_TS);
+ break;
+ default:
+ /* No work to do. */
+ return;
+ }
+
+ timecounter_init(&adapter->tc, &adapter->cc,
+ ktime_to_ns(ktime_get_real()));
+}
--
1.7.11.4
^ permalink raw reply related
* [net-next 4/6] igb: Store the MAC address in the name in the PTP struct.
From: Jeff Kirsher @ 2012-09-05 23:35 UTC (permalink / raw)
To: davem; +Cc: Matthew Vick, netdev, gospo, sassmann, Richard Cochran,
Jeff Kirsher
In-Reply-To: <1346888106-25638-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Matthew Vick <matthew.vick@intel.com>
Change the name of the adapter in the PTP struct to enable easier
correlation between interface and PTP device.
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Matthew Vick <matthew.vick@intel.com>
Acked-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb_ptp.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index 34e0d69..e69555f 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -547,14 +547,15 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
void igb_ptp_init(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
switch (hw->mac.type) {
case e1000_i210:
case e1000_i211:
case e1000_i350:
case e1000_82580:
+ snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
adapter->ptp_caps.owner = THIS_MODULE;
- strcpy(adapter->ptp_caps.name, "igb-82580");
adapter->ptp_caps.max_adj = 62499999;
adapter->ptp_caps.n_ext_ts = 0;
adapter->ptp_caps.pps = 0;
@@ -570,10 +571,9 @@ void igb_ptp_init(struct igb_adapter *adapter)
/* Enable the timer functions by clearing bit 31. */
wr32(E1000_TSAUXC, 0x0);
break;
-
case e1000_82576:
+ snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
adapter->ptp_caps.owner = THIS_MODULE;
- strcpy(adapter->ptp_caps.name, "igb-82576");
adapter->ptp_caps.max_adj = 1000000000;
adapter->ptp_caps.n_ext_ts = 0;
adapter->ptp_caps.pps = 0;
@@ -589,7 +589,6 @@ void igb_ptp_init(struct igb_adapter *adapter)
/* Dial the nominal frequency. */
wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576);
break;
-
default:
adapter->ptp_clock = NULL;
return;
--
1.7.11.4
^ permalink raw reply related
* [net-next 2/6] igb: Update PTP function names/variables and locations.
From: Jeff Kirsher @ 2012-09-05 23:35 UTC (permalink / raw)
To: davem; +Cc: Matthew Vick, netdev, gospo, sassmann, Richard Cochran,
Jeff Kirsher
In-Reply-To: <1346888106-25638-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Matthew Vick <matthew.vick@intel.com>
Where possible, move PTP-related functions into igb_ptp.c and update the
names of functions and variables to match the established coding style
in the files and specify that they are PTP-specific.
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Matthew Vick <matthew.vick@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb.h | 17 +-
drivers/net/ethernet/intel/igb/igb_ethtool.c | 34 +-
drivers/net/ethernet/intel/igb/igb_main.c | 257 +-------------
drivers/net/ethernet/intel/igb/igb_ptp.c | 485 ++++++++++++++++++++-------
4 files changed, 398 insertions(+), 395 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index a3b5b90..7973469 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -344,7 +344,6 @@ struct igb_adapter {
/* OS defined structs */
struct pci_dev *pdev;
- struct hwtstamp_config hwtstamp_config;
spinlock_t stats64_lock;
struct rtnl_link_stats64 stats64;
@@ -380,8 +379,8 @@ struct igb_adapter {
#ifdef CONFIG_IGB_PTP
struct ptp_clock *ptp_clock;
- struct ptp_clock_info caps;
- struct delayed_work overflow_work;
+ struct ptp_clock_info ptp_caps;
+ struct delayed_work ptp_overflow_work;
spinlock_t tmreg_lock;
struct cyclecounter cc;
struct timecounter tc;
@@ -440,10 +439,14 @@ extern void igb_power_up_link(struct igb_adapter *);
extern void igb_set_fw_version(struct igb_adapter *);
#ifdef CONFIG_IGB_PTP
extern void igb_ptp_init(struct igb_adapter *adapter);
-extern void igb_ptp_remove(struct igb_adapter *adapter);
-extern void igb_systim_to_hwtstamp(struct igb_adapter *adapter,
- struct skb_shared_hwtstamps *hwtstamps,
- u64 systim);
+extern void igb_ptp_stop(struct igb_adapter *adapter);
+extern void igb_ptp_tx_hwtstamp(struct igb_q_vector *q_vector,
+ struct igb_tx_buffer *buffer_info);
+extern void igb_ptp_rx_hwtstamp(struct igb_q_vector *q_vector,
+ union e1000_adv_rx_desc *rx_desc,
+ struct sk_buff *skb);
+extern int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
+ struct ifreq *ifr, int cmd);
#endif /* CONFIG_IGB_PTP */
static inline s32 igb_reset_phy(struct e1000_hw *hw)
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 0c4e29a..ffed4d0 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -2295,21 +2295,8 @@ static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
}
}
-static int igb_ethtool_begin(struct net_device *netdev)
-{
- struct igb_adapter *adapter = netdev_priv(netdev);
- pm_runtime_get_sync(&adapter->pdev->dev);
- return 0;
-}
-
-static void igb_ethtool_complete(struct net_device *netdev)
-{
- struct igb_adapter *adapter = netdev_priv(netdev);
- pm_runtime_put(&adapter->pdev->dev);
-}
-
#ifdef CONFIG_IGB_PTP
-static int igb_ethtool_get_ts_info(struct net_device *dev,
+static int igb_get_ts_info(struct net_device *dev,
struct ethtool_ts_info *info)
{
struct igb_adapter *adapter = netdev_priv(dev);
@@ -2340,6 +2327,19 @@ static int igb_ethtool_get_ts_info(struct net_device *dev,
}
#endif /* CONFIG_IGB_PTP */
+static int igb_ethtool_begin(struct net_device *netdev)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ pm_runtime_get_sync(&adapter->pdev->dev);
+ return 0;
+}
+
+static void igb_ethtool_complete(struct net_device *netdev)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ pm_runtime_put(&adapter->pdev->dev);
+}
+
static const struct ethtool_ops igb_ethtool_ops = {
.get_settings = igb_get_settings,
.set_settings = igb_set_settings,
@@ -2366,11 +2366,11 @@ static const struct ethtool_ops igb_ethtool_ops = {
.get_ethtool_stats = igb_get_ethtool_stats,
.get_coalesce = igb_get_coalesce,
.set_coalesce = igb_set_coalesce,
- .begin = igb_ethtool_begin,
- .complete = igb_ethtool_complete,
#ifdef CONFIG_IGB_PTP
- .get_ts_info = igb_ethtool_get_ts_info,
+ .get_ts_info = igb_get_ts_info,
#endif /* CONFIG_IGB_PTP */
+ .begin = igb_ethtool_begin,
+ .complete = igb_ethtool_complete,
};
void igb_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 03477d7..6e39f0c 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2260,7 +2260,7 @@ static void __devexit igb_remove(struct pci_dev *pdev)
pm_runtime_get_noresume(&pdev->dev);
#ifdef CONFIG_IGB_PTP
- igb_ptp_remove(adapter);
+ igb_ptp_stop(adapter);
#endif /* CONFIG_IGB_PTP */
/*
@@ -5750,37 +5750,6 @@ static int igb_poll(struct napi_struct *napi, int budget)
return 0;
}
-#ifdef CONFIG_IGB_PTP
-/**
- * igb_tx_hwtstamp - utility function which checks for TX time stamp
- * @q_vector: pointer to q_vector containing needed info
- * @buffer: pointer to igb_tx_buffer structure
- *
- * If we were asked to do hardware stamping and such a time stamp is
- * available, then it must have been for this skb here because we only
- * allow only one such packet into the queue.
- */
-static void igb_tx_hwtstamp(struct igb_q_vector *q_vector,
- struct igb_tx_buffer *buffer_info)
-{
- struct igb_adapter *adapter = q_vector->adapter;
- struct e1000_hw *hw = &adapter->hw;
- struct skb_shared_hwtstamps shhwtstamps;
- u64 regval;
-
- /* if skb does not support hw timestamp or TX stamp not valid exit */
- if (likely(!(buffer_info->tx_flags & IGB_TX_FLAGS_TSTAMP)) ||
- !(rd32(E1000_TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID))
- return;
-
- regval = rd32(E1000_TXSTMPL);
- regval |= (u64)rd32(E1000_TXSTMPH) << 32;
-
- igb_systim_to_hwtstamp(adapter, &shhwtstamps, regval);
- skb_tstamp_tx(buffer_info->skb, &shhwtstamps);
-}
-#endif /* CONFIG_IGB_PTP */
-
/**
* igb_clean_tx_irq - Reclaim resources after transmit completes
* @q_vector: pointer to q_vector containing needed info
@@ -5827,7 +5796,7 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
#ifdef CONFIG_IGB_PTP
/* retrieve hardware timestamp */
- igb_tx_hwtstamp(q_vector, tx_buffer);
+ igb_ptp_tx_hwtstamp(q_vector, tx_buffer);
#endif /* CONFIG_IGB_PTP */
/* free the skb */
@@ -6001,47 +5970,6 @@ static inline void igb_rx_hash(struct igb_ring *ring,
skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
}
-#ifdef CONFIG_IGB_PTP
-static void igb_rx_hwtstamp(struct igb_q_vector *q_vector,
- union e1000_adv_rx_desc *rx_desc,
- struct sk_buff *skb)
-{
- struct igb_adapter *adapter = q_vector->adapter;
- struct e1000_hw *hw = &adapter->hw;
- u64 regval;
-
- if (!igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP |
- E1000_RXDADV_STAT_TS))
- return;
-
- /*
- * If this bit is set, then the RX registers contain the time stamp. No
- * other packet will be time stamped until we read these registers, so
- * read the registers to make them available again. Because only one
- * packet can be time stamped at a time, we know that the register
- * values must belong to this one here and therefore we don't need to
- * compare any of the additional attributes stored for it.
- *
- * If nothing went wrong, then it should have a shared tx_flags that we
- * can turn into a skb_shared_hwtstamps.
- */
- if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) {
- u32 *stamp = (u32 *)skb->data;
- regval = le32_to_cpu(*(stamp + 2));
- regval |= (u64)le32_to_cpu(*(stamp + 3)) << 32;
- skb_pull(skb, IGB_TS_HDR_LEN);
- } else {
- if(!(rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID))
- return;
-
- regval = rd32(E1000_RXSTMPL);
- regval |= (u64)rd32(E1000_RXSTMPH) << 32;
- }
-
- igb_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval);
-}
-#endif /* CONFIG_IGB_PTP */
-
static void igb_rx_vlan(struct igb_ring *ring,
union e1000_adv_rx_desc *rx_desc,
struct sk_buff *skb)
@@ -6153,7 +6081,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
}
#ifdef CONFIG_IGB_PTP
- igb_rx_hwtstamp(q_vector, rx_desc, skb);
+ igb_ptp_rx_hwtstamp(q_vector, rx_desc, skb);
#endif /* CONFIG_IGB_PTP */
igb_rx_hash(rx_ring, rx_desc, skb);
igb_rx_checksum(rx_ring, rx_desc, skb);
@@ -6347,183 +6275,6 @@ static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
return 0;
}
-#ifdef CONFIG_IGB_PTP
-/**
- * igb_hwtstamp_ioctl - control hardware time stamping
- * @netdev:
- * @ifreq:
- * @cmd:
- *
- * Outgoing time stamping can be enabled and disabled. Play nice and
- * disable it when requested, although it shouldn't case any overhead
- * when no packet needs it. At most one packet in the queue may be
- * marked for time stamping, otherwise it would be impossible to tell
- * for sure to which packet the hardware time stamp belongs.
- *
- * Incoming time stamping has to be configured via the hardware
- * filters. Not all combinations are supported, in particular event
- * type has to be specified. Matching the kind of event packet is
- * not supported, with the exception of "all V2 events regardless of
- * level 2 or 4".
- *
- **/
-static int igb_hwtstamp_ioctl(struct net_device *netdev,
- struct ifreq *ifr, int cmd)
-{
- struct igb_adapter *adapter = netdev_priv(netdev);
- struct e1000_hw *hw = &adapter->hw;
- struct hwtstamp_config config;
- u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED;
- u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
- u32 tsync_rx_cfg = 0;
- bool is_l4 = false;
- bool is_l2 = false;
- u32 regval;
-
- if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
- return -EFAULT;
-
- /* reserved for future extensions */
- if (config.flags)
- return -EINVAL;
-
- switch (config.tx_type) {
- case HWTSTAMP_TX_OFF:
- tsync_tx_ctl = 0;
- case HWTSTAMP_TX_ON:
- break;
- default:
- return -ERANGE;
- }
-
- switch (config.rx_filter) {
- case HWTSTAMP_FILTER_NONE:
- tsync_rx_ctl = 0;
- break;
- case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
- case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
- case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
- case HWTSTAMP_FILTER_ALL:
- /*
- * register TSYNCRXCFG must be set, therefore it is not
- * possible to time stamp both Sync and Delay_Req messages
- * => fall back to time stamping all packets
- */
- tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
- config.rx_filter = HWTSTAMP_FILTER_ALL;
- break;
- case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
- tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
- tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE;
- is_l4 = true;
- break;
- case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
- tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
- tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE;
- is_l4 = true;
- break;
- case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
- case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
- tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
- tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE;
- is_l2 = true;
- is_l4 = true;
- config.rx_filter = HWTSTAMP_FILTER_SOME;
- break;
- case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
- case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
- tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
- tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE;
- is_l2 = true;
- is_l4 = true;
- config.rx_filter = HWTSTAMP_FILTER_SOME;
- break;
- case HWTSTAMP_FILTER_PTP_V2_EVENT:
- case HWTSTAMP_FILTER_PTP_V2_SYNC:
- case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
- tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2;
- config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
- is_l2 = true;
- is_l4 = true;
- break;
- default:
- return -ERANGE;
- }
-
- if (hw->mac.type == e1000_82575) {
- if (tsync_rx_ctl | tsync_tx_ctl)
- return -EINVAL;
- return 0;
- }
-
- /*
- * Per-packet timestamping only works if all packets are
- * timestamped, so enable timestamping in all packets as
- * long as one rx filter was configured.
- */
- if ((hw->mac.type >= e1000_82580) && tsync_rx_ctl) {
- tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
- tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
- }
-
- /* enable/disable TX */
- regval = rd32(E1000_TSYNCTXCTL);
- regval &= ~E1000_TSYNCTXCTL_ENABLED;
- regval |= tsync_tx_ctl;
- wr32(E1000_TSYNCTXCTL, regval);
-
- /* enable/disable RX */
- regval = rd32(E1000_TSYNCRXCTL);
- regval &= ~(E1000_TSYNCRXCTL_ENABLED | E1000_TSYNCRXCTL_TYPE_MASK);
- regval |= tsync_rx_ctl;
- wr32(E1000_TSYNCRXCTL, regval);
-
- /* define which PTP packets are time stamped */
- wr32(E1000_TSYNCRXCFG, tsync_rx_cfg);
-
- /* define ethertype filter for timestamped packets */
- if (is_l2)
- wr32(E1000_ETQF(3),
- (E1000_ETQF_FILTER_ENABLE | /* enable filter */
- E1000_ETQF_1588 | /* enable timestamping */
- ETH_P_1588)); /* 1588 eth protocol type */
- else
- wr32(E1000_ETQF(3), 0);
-
-#define PTP_PORT 319
- /* L4 Queue Filter[3]: filter by destination port and protocol */
- if (is_l4) {
- u32 ftqf = (IPPROTO_UDP /* UDP */
- | E1000_FTQF_VF_BP /* VF not compared */
- | E1000_FTQF_1588_TIME_STAMP /* Enable Timestamping */
- | E1000_FTQF_MASK); /* mask all inputs */
- ftqf &= ~E1000_FTQF_MASK_PROTO_BP; /* enable protocol check */
-
- wr32(E1000_IMIR(3), htons(PTP_PORT));
- wr32(E1000_IMIREXT(3),
- (E1000_IMIREXT_SIZE_BP | E1000_IMIREXT_CTRL_BP));
- if (hw->mac.type == e1000_82576) {
- /* enable source port check */
- wr32(E1000_SPQF(3), htons(PTP_PORT));
- ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP;
- }
- wr32(E1000_FTQF(3), ftqf);
- } else {
- wr32(E1000_FTQF(3), E1000_FTQF_MASK);
- }
- wrfl();
-
- adapter->hwtstamp_config = config;
-
- /* clear TX/RX time stamp registers, just to be sure */
- regval = rd32(E1000_TXSTMPH);
- regval = rd32(E1000_RXSTMPH);
-
- return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
- -EFAULT : 0;
-}
-#endif /* CONFIG_IGB_PTP */
-
/**
* igb_ioctl -
* @netdev:
@@ -6539,7 +6290,7 @@ static int igb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
return igb_mii_ioctl(netdev, ifr, cmd);
#ifdef CONFIG_IGB_PTP
case SIOCSHWTSTAMP:
- return igb_hwtstamp_ioctl(netdev, ifr, cmd);
+ return igb_ptp_hwtstamp_ioctl(netdev, ifr, cmd);
#endif /* CONFIG_IGB_PTP */
default:
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index c846ea9..34e0d69 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -69,22 +69,22 @@
* 2^40 * 10^-9 / 60 = 18.3 minutes.
*/
-#define IGB_OVERFLOW_PERIOD (HZ * 60 * 9)
-#define INCPERIOD_82576 (1 << E1000_TIMINCA_16NS_SHIFT)
-#define INCVALUE_82576_MASK ((1 << E1000_TIMINCA_16NS_SHIFT) - 1)
-#define INCVALUE_82576 (16 << IGB_82576_TSYNC_SHIFT)
-#define IGB_NBITS_82580 40
+#define IGB_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 9)
+#define INCPERIOD_82576 (1 << E1000_TIMINCA_16NS_SHIFT)
+#define INCVALUE_82576_MASK ((1 << E1000_TIMINCA_16NS_SHIFT) - 1)
+#define INCVALUE_82576 (16 << IGB_82576_TSYNC_SHIFT)
+#define IGB_NBITS_82580 40
/*
* SYSTIM read access for the 82576
*/
-static cycle_t igb_82576_systim_read(const struct cyclecounter *cc)
+static cycle_t igb_ptp_read_82576(const struct cyclecounter *cc)
{
- u64 val;
- u32 lo, hi;
struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc);
struct e1000_hw *hw = &igb->hw;
+ u64 val;
+ u32 lo, hi;
lo = rd32(E1000_SYSTIML);
hi = rd32(E1000_SYSTIMH);
@@ -99,12 +99,12 @@ static cycle_t igb_82576_systim_read(const struct cyclecounter *cc)
* SYSTIM read access for the 82580
*/
-static cycle_t igb_82580_systim_read(const struct cyclecounter *cc)
+static cycle_t igb_ptp_read_82580(const struct cyclecounter *cc)
{
- u64 val;
- u32 lo, hi, jk;
struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc);
struct e1000_hw *hw = &igb->hw;
+ u64 val;
+ u32 lo, hi, jk;
/*
* The timestamp latches on lowest register read. For the 82580
@@ -121,17 +121,63 @@ static cycle_t igb_82580_systim_read(const struct cyclecounter *cc)
return val;
}
+/**
+ * igb_ptp_systim_to_hwtstamp - convert system time value to hw timestamp
+ * @adapter: board private structure
+ * @hwtstamps: timestamp structure to update
+ * @systim: unsigned 64bit system time value.
+ *
+ * We need to convert the system time value stored in the RX/TXSTMP registers
+ * into a hwtstamp which can be used by the upper level timestamping functions.
+ *
+ * The 'tmreg_lock' spinlock is used to protect the consistency of the
+ * system time value. This is needed because reading the 64 bit time
+ * value involves reading two (or three) 32 bit registers. The first
+ * read latches the value. Ditto for writing.
+ *
+ * In addition, here have extended the system time with an overflow
+ * counter in software.
+ **/
+static void igb_ptp_systim_to_hwtstamp(struct igb_adapter *adapter,
+ struct skb_shared_hwtstamps *hwtstamps,
+ u64 systim)
+{
+ unsigned long flags;
+ u64 ns;
+
+ switch (adapter->hw.mac.type) {
+ case e1000_i210:
+ case e1000_i211:
+ case e1000_i350:
+ case e1000_82580:
+ case e1000_82576:
+ break;
+ default:
+ return;
+ }
+
+ spin_lock_irqsave(&adapter->tmreg_lock, flags);
+
+ ns = timecounter_cyc2time(&adapter->tc, systim);
+
+ spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
+
+ memset(hwtstamps, 0, sizeof(*hwtstamps));
+ hwtstamps->hwtstamp = ns_to_ktime(ns);
+}
+
/*
* PTP clock operations
*/
-static int ptp_82576_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+static int igb_ptp_adjfreq_82576(struct ptp_clock_info *ptp, s32 ppb)
{
+ struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
+ ptp_caps);
+ struct e1000_hw *hw = &igb->hw;
+ int neg_adj = 0;
u64 rate;
u32 incvalue;
- int neg_adj = 0;
- struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps);
- struct e1000_hw *hw = &igb->hw;
if (ppb < 0) {
neg_adj = 1;
@@ -153,13 +199,14 @@ static int ptp_82576_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
return 0;
}
-static int ptp_82580_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+static int igb_ptp_adjfreq_82580(struct ptp_clock_info *ptp, s32 ppb)
{
+ struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
+ ptp_caps);
+ struct e1000_hw *hw = &igb->hw;
+ int neg_adj = 0;
u64 rate;
u32 inca;
- int neg_adj = 0;
- struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps);
- struct e1000_hw *hw = &igb->hw;
if (ppb < 0) {
neg_adj = 1;
@@ -178,11 +225,12 @@ static int ptp_82580_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
return 0;
}
-static int igb_adjtime(struct ptp_clock_info *ptp, s64 delta)
+static int igb_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
- s64 now;
+ struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
+ ptp_caps);
unsigned long flags;
- struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps);
+ s64 now;
spin_lock_irqsave(&igb->tmreg_lock, flags);
@@ -195,12 +243,13 @@ static int igb_adjtime(struct ptp_clock_info *ptp, s64 delta)
return 0;
}
-static int igb_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+static int igb_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
{
+ struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
+ ptp_caps);
+ unsigned long flags;
u64 ns;
u32 remainder;
- unsigned long flags;
- struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps);
spin_lock_irqsave(&igb->tmreg_lock, flags);
@@ -214,11 +263,13 @@ static int igb_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
return 0;
}
-static int igb_settime(struct ptp_clock_info *ptp, const struct timespec *ts)
+static int igb_ptp_settime(struct ptp_clock_info *ptp,
+ const struct timespec *ts)
{
- u64 ns;
+ struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
+ ptp_caps);
unsigned long flags;
- struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps);
+ u64 ns;
ns = ts->tv_sec * 1000000000ULL;
ns += ts->tv_nsec;
@@ -232,29 +283,265 @@ static int igb_settime(struct ptp_clock_info *ptp, const struct timespec *ts)
return 0;
}
-static int ptp_82576_enable(struct ptp_clock_info *ptp,
- struct ptp_clock_request *rq, int on)
+static int igb_ptp_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
{
return -EOPNOTSUPP;
}
-static int ptp_82580_enable(struct ptp_clock_info *ptp,
- struct ptp_clock_request *rq, int on)
+static void igb_ptp_overflow_check(struct work_struct *work)
{
- return -EOPNOTSUPP;
+ struct igb_adapter *igb =
+ container_of(work, struct igb_adapter, ptp_overflow_work.work);
+ struct timespec ts;
+
+ igb_ptp_gettime(&igb->ptp_caps, &ts);
+
+ pr_debug("igb overflow check at %ld.%09lu\n", ts.tv_sec, ts.tv_nsec);
+
+ schedule_delayed_work(&igb->ptp_overflow_work,
+ IGB_SYSTIM_OVERFLOW_PERIOD);
}
-static void igb_overflow_check(struct work_struct *work)
+/**
+ * igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp
+ * @q_vector: pointer to q_vector containing needed info
+ * @buffer: pointer to igb_tx_buffer structure
+ *
+ * If we were asked to do hardware stamping and such a time stamp is
+ * available, then it must have been for this skb here because we only
+ * allow only one such packet into the queue.
+ */
+void igb_ptp_tx_hwtstamp(struct igb_q_vector *q_vector,
+ struct igb_tx_buffer *buffer_info)
{
- struct timespec ts;
- struct igb_adapter *igb =
- container_of(work, struct igb_adapter, overflow_work.work);
+ struct igb_adapter *adapter = q_vector->adapter;
+ struct e1000_hw *hw = &adapter->hw;
+ struct skb_shared_hwtstamps shhwtstamps;
+ u64 regval;
- igb_gettime(&igb->caps, &ts);
+ /* if skb does not support hw timestamp or TX stamp not valid exit */
+ if (likely(!(buffer_info->tx_flags & IGB_TX_FLAGS_TSTAMP)) ||
+ !(rd32(E1000_TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID))
+ return;
- pr_debug("igb overflow check at %ld.%09lu\n", ts.tv_sec, ts.tv_nsec);
+ regval = rd32(E1000_TXSTMPL);
+ regval |= (u64)rd32(E1000_TXSTMPH) << 32;
- schedule_delayed_work(&igb->overflow_work, IGB_OVERFLOW_PERIOD);
+ igb_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval);
+ skb_tstamp_tx(buffer_info->skb, &shhwtstamps);
+}
+
+void igb_ptp_rx_hwtstamp(struct igb_q_vector *q_vector,
+ union e1000_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
+{
+ struct igb_adapter *adapter = q_vector->adapter;
+ struct e1000_hw *hw = &adapter->hw;
+ u64 regval;
+
+ if (!igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP |
+ E1000_RXDADV_STAT_TS))
+ return;
+
+ /*
+ * If this bit is set, then the RX registers contain the time stamp. No
+ * other packet will be time stamped until we read these registers, so
+ * read the registers to make them available again. Because only one
+ * packet can be time stamped at a time, we know that the register
+ * values must belong to this one here and therefore we don't need to
+ * compare any of the additional attributes stored for it.
+ *
+ * If nothing went wrong, then it should have a shared tx_flags that we
+ * can turn into a skb_shared_hwtstamps.
+ */
+ if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) {
+ u32 *stamp = (u32 *)skb->data;
+ regval = le32_to_cpu(*(stamp + 2));
+ regval |= (u64)le32_to_cpu(*(stamp + 3)) << 32;
+ skb_pull(skb, IGB_TS_HDR_LEN);
+ } else {
+ if (!(rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID))
+ return;
+
+ regval = rd32(E1000_RXSTMPL);
+ regval |= (u64)rd32(E1000_RXSTMPH) << 32;
+ }
+
+ igb_ptp_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval);
+}
+
+/**
+ * igb_ptp_hwtstamp_ioctl - control hardware time stamping
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ *
+ * Outgoing time stamping can be enabled and disabled. Play nice and
+ * disable it when requested, although it shouldn't case any overhead
+ * when no packet needs it. At most one packet in the queue may be
+ * marked for time stamping, otherwise it would be impossible to tell
+ * for sure to which packet the hardware time stamp belongs.
+ *
+ * Incoming time stamping has to be configured via the hardware
+ * filters. Not all combinations are supported, in particular event
+ * type has to be specified. Matching the kind of event packet is
+ * not supported, with the exception of "all V2 events regardless of
+ * level 2 or 4".
+ *
+ **/
+int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
+ struct ifreq *ifr, int cmd)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ struct hwtstamp_config config;
+ u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED;
+ u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
+ u32 tsync_rx_cfg = 0;
+ bool is_l4 = false;
+ bool is_l2 = false;
+ u32 regval;
+
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+ return -EFAULT;
+
+ /* reserved for future extensions */
+ if (config.flags)
+ return -EINVAL;
+
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ tsync_tx_ctl = 0;
+ case HWTSTAMP_TX_ON:
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ tsync_rx_ctl = 0;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_ALL:
+ /*
+ * register TSYNCRXCFG must be set, therefore it is not
+ * possible to time stamp both Sync and Delay_Req messages
+ * => fall back to time stamping all packets
+ */
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
+ tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE;
+ is_l4 = true;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
+ tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE;
+ is_l4 = true;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
+ tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE;
+ is_l2 = true;
+ is_l4 = true;
+ config.rx_filter = HWTSTAMP_FILTER_SOME;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
+ tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE;
+ is_l2 = true;
+ is_l4 = true;
+ config.rx_filter = HWTSTAMP_FILTER_SOME;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2;
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+ is_l2 = true;
+ is_l4 = true;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ if (hw->mac.type == e1000_82575) {
+ if (tsync_rx_ctl | tsync_tx_ctl)
+ return -EINVAL;
+ return 0;
+ }
+
+ /*
+ * Per-packet timestamping only works if all packets are
+ * timestamped, so enable timestamping in all packets as
+ * long as one rx filter was configured.
+ */
+ if ((hw->mac.type >= e1000_82580) && tsync_rx_ctl) {
+ tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
+ }
+
+ /* enable/disable TX */
+ regval = rd32(E1000_TSYNCTXCTL);
+ regval &= ~E1000_TSYNCTXCTL_ENABLED;
+ regval |= tsync_tx_ctl;
+ wr32(E1000_TSYNCTXCTL, regval);
+
+ /* enable/disable RX */
+ regval = rd32(E1000_TSYNCRXCTL);
+ regval &= ~(E1000_TSYNCRXCTL_ENABLED | E1000_TSYNCRXCTL_TYPE_MASK);
+ regval |= tsync_rx_ctl;
+ wr32(E1000_TSYNCRXCTL, regval);
+
+ /* define which PTP packets are time stamped */
+ wr32(E1000_TSYNCRXCFG, tsync_rx_cfg);
+
+ /* define ethertype filter for timestamped packets */
+ if (is_l2)
+ wr32(E1000_ETQF(3),
+ (E1000_ETQF_FILTER_ENABLE | /* enable filter */
+ E1000_ETQF_1588 | /* enable timestamping */
+ ETH_P_1588)); /* 1588 eth protocol type */
+ else
+ wr32(E1000_ETQF(3), 0);
+
+#define PTP_PORT 319
+ /* L4 Queue Filter[3]: filter by destination port and protocol */
+ if (is_l4) {
+ u32 ftqf = (IPPROTO_UDP /* UDP */
+ | E1000_FTQF_VF_BP /* VF not compared */
+ | E1000_FTQF_1588_TIME_STAMP /* Enable Timestamping */
+ | E1000_FTQF_MASK); /* mask all inputs */
+ ftqf &= ~E1000_FTQF_MASK_PROTO_BP; /* enable protocol check */
+
+ wr32(E1000_IMIR(3), htons(PTP_PORT));
+ wr32(E1000_IMIREXT(3),
+ (E1000_IMIREXT_SIZE_BP | E1000_IMIREXT_CTRL_BP));
+ if (hw->mac.type == e1000_82576) {
+ /* enable source port check */
+ wr32(E1000_SPQF(3), htons(PTP_PORT));
+ ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP;
+ }
+ wr32(E1000_FTQF(3), ftqf);
+ } else {
+ wr32(E1000_FTQF(3), E1000_FTQF_MASK);
+ }
+ wrfl();
+
+ /* clear TX/RX time stamp registers, just to be sure */
+ regval = rd32(E1000_TXSTMPH);
+ regval = rd32(E1000_RXSTMPH);
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
}
void igb_ptp_init(struct igb_adapter *adapter)
@@ -266,39 +553,39 @@ void igb_ptp_init(struct igb_adapter *adapter)
case e1000_i211:
case e1000_i350:
case e1000_82580:
- adapter->caps.owner = THIS_MODULE;
- strcpy(adapter->caps.name, "igb-82580");
- adapter->caps.max_adj = 62499999;
- adapter->caps.n_ext_ts = 0;
- adapter->caps.pps = 0;
- adapter->caps.adjfreq = ptp_82580_adjfreq;
- adapter->caps.adjtime = igb_adjtime;
- adapter->caps.gettime = igb_gettime;
- adapter->caps.settime = igb_settime;
- adapter->caps.enable = ptp_82580_enable;
- adapter->cc.read = igb_82580_systim_read;
- adapter->cc.mask = CLOCKSOURCE_MASK(IGB_NBITS_82580);
- adapter->cc.mult = 1;
- adapter->cc.shift = 0;
+ adapter->ptp_caps.owner = THIS_MODULE;
+ strcpy(adapter->ptp_caps.name, "igb-82580");
+ adapter->ptp_caps.max_adj = 62499999;
+ adapter->ptp_caps.n_ext_ts = 0;
+ adapter->ptp_caps.pps = 0;
+ adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580;
+ adapter->ptp_caps.adjtime = igb_ptp_adjtime;
+ adapter->ptp_caps.gettime = igb_ptp_gettime;
+ adapter->ptp_caps.settime = igb_ptp_settime;
+ adapter->ptp_caps.enable = igb_ptp_enable;
+ adapter->cc.read = igb_ptp_read_82580;
+ adapter->cc.mask = CLOCKSOURCE_MASK(IGB_NBITS_82580);
+ adapter->cc.mult = 1;
+ adapter->cc.shift = 0;
/* Enable the timer functions by clearing bit 31. */
wr32(E1000_TSAUXC, 0x0);
break;
case e1000_82576:
- adapter->caps.owner = THIS_MODULE;
- strcpy(adapter->caps.name, "igb-82576");
- adapter->caps.max_adj = 1000000000;
- adapter->caps.n_ext_ts = 0;
- adapter->caps.pps = 0;
- adapter->caps.adjfreq = ptp_82576_adjfreq;
- adapter->caps.adjtime = igb_adjtime;
- adapter->caps.gettime = igb_gettime;
- adapter->caps.settime = igb_settime;
- adapter->caps.enable = ptp_82576_enable;
- adapter->cc.read = igb_82576_systim_read;
- adapter->cc.mask = CLOCKSOURCE_MASK(64);
- adapter->cc.mult = 1;
- adapter->cc.shift = IGB_82576_TSYNC_SHIFT;
+ adapter->ptp_caps.owner = THIS_MODULE;
+ strcpy(adapter->ptp_caps.name, "igb-82576");
+ adapter->ptp_caps.max_adj = 1000000000;
+ adapter->ptp_caps.n_ext_ts = 0;
+ adapter->ptp_caps.pps = 0;
+ adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576;
+ adapter->ptp_caps.adjtime = igb_ptp_adjtime;
+ adapter->ptp_caps.gettime = igb_ptp_gettime;
+ adapter->ptp_caps.settime = igb_ptp_settime;
+ adapter->ptp_caps.enable = igb_ptp_enable;
+ adapter->cc.read = igb_ptp_read_82576;
+ adapter->cc.mask = CLOCKSOURCE_MASK(64);
+ adapter->cc.mult = 1;
+ adapter->cc.shift = IGB_82576_TSYNC_SHIFT;
/* Dial the nominal frequency. */
wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576);
break;
@@ -313,13 +600,14 @@ void igb_ptp_init(struct igb_adapter *adapter)
timecounter_init(&adapter->tc, &adapter->cc,
ktime_to_ns(ktime_get_real()));
- INIT_DELAYED_WORK(&adapter->overflow_work, igb_overflow_check);
+ INIT_DELAYED_WORK(&adapter->ptp_overflow_work, igb_ptp_overflow_check);
spin_lock_init(&adapter->tmreg_lock);
- schedule_delayed_work(&adapter->overflow_work, IGB_OVERFLOW_PERIOD);
+ schedule_delayed_work(&adapter->ptp_overflow_work,
+ IGB_SYSTIM_OVERFLOW_PERIOD);
- adapter->ptp_clock = ptp_clock_register(&adapter->caps);
+ adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps);
if (IS_ERR(adapter->ptp_clock)) {
adapter->ptp_clock = NULL;
dev_err(&adapter->pdev->dev, "ptp_clock_register failed\n");
@@ -328,7 +616,13 @@ void igb_ptp_init(struct igb_adapter *adapter)
adapter->netdev->name);
}
-void igb_ptp_remove(struct igb_adapter *adapter)
+/**
+ * igb_ptp_stop - Disable PTP device and stop the overflow check.
+ * @adapter: Board private structure.
+ *
+ * This function stops the PTP support and cancels the delayed work.
+ **/
+void igb_ptp_stop(struct igb_adapter *adapter)
{
switch (adapter->hw.mac.type) {
case e1000_i211:
@@ -336,7 +630,7 @@ void igb_ptp_remove(struct igb_adapter *adapter)
case e1000_i350:
case e1000_82580:
case e1000_82576:
- cancel_delayed_work_sync(&adapter->overflow_work);
+ cancel_delayed_work_sync(&adapter->ptp_overflow_work);
break;
default:
return;
@@ -348,48 +642,3 @@ void igb_ptp_remove(struct igb_adapter *adapter)
adapter->netdev->name);
}
}
-
-/**
- * igb_systim_to_hwtstamp - convert system time value to hw timestamp
- * @adapter: board private structure
- * @hwtstamps: timestamp structure to update
- * @systim: unsigned 64bit system time value.
- *
- * We need to convert the system time value stored in the RX/TXSTMP registers
- * into a hwtstamp which can be used by the upper level timestamping functions.
- *
- * The 'tmreg_lock' spinlock is used to protect the consistency of the
- * system time value. This is needed because reading the 64 bit time
- * value involves reading two (or three) 32 bit registers. The first
- * read latches the value. Ditto for writing.
- *
- * In addition, here have extended the system time with an overflow
- * counter in software.
- **/
-void igb_systim_to_hwtstamp(struct igb_adapter *adapter,
- struct skb_shared_hwtstamps *hwtstamps,
- u64 systim)
-{
- u64 ns;
- unsigned long flags;
-
- switch (adapter->hw.mac.type) {
- case e1000_i210:
- case e1000_i211:
- case e1000_i350:
- case e1000_82580:
- case e1000_82576:
- break;
- default:
- return;
- }
-
- spin_lock_irqsave(&adapter->tmreg_lock, flags);
-
- ns = timecounter_cyc2time(&adapter->tc, systim);
-
- spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
-
- memset(hwtstamps, 0, sizeof(*hwtstamps));
- hwtstamps->hwtstamp = ns_to_ktime(ns);
-}
--
1.7.11.4
^ permalink raw reply related
* [net-next 3/6] igb: Correct PTP support query from ethtool.
From: Jeff Kirsher @ 2012-09-05 23:35 UTC (permalink / raw)
To: davem; +Cc: Matthew Vick, netdev, gospo, sassmann, Richard Cochran,
Jeff Kirsher
In-Reply-To: <1346888106-25638-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Matthew Vick <matthew.vick@intel.com>
Update ethtool_get_ts_info to not report any supported functionality on
82575 and add support for V2 Sync and V2 Delay packets. In the case
where CONFIG_IGB_PTP is not defined, we should be reporting default
values.
v2: Correct the function to return EOPNOTSUPP when there is no PTP support
or the device does not support PTP. Also fix minor whitespace issue.
Signed-off-by: Matthew Vick <matthew.vick@intel.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb_ethtool.c | 62 +++++++++++++++++-----------
1 file changed, 38 insertions(+), 24 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index ffed4d0..2ea0128 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -2295,37 +2295,53 @@ static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
}
}
-#ifdef CONFIG_IGB_PTP
static int igb_get_ts_info(struct net_device *dev,
- struct ethtool_ts_info *info)
+ struct ethtool_ts_info *info)
{
struct igb_adapter *adapter = netdev_priv(dev);
- info->so_timestamping =
- SOF_TIMESTAMPING_TX_HARDWARE |
- SOF_TIMESTAMPING_RX_HARDWARE |
- SOF_TIMESTAMPING_RAW_HARDWARE;
+ switch (adapter->hw.mac.type) {
+#ifdef CONFIG_IGB_PTP
+ case e1000_82576:
+ case e1000_82580:
+ case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
+ info->so_timestamping =
+ SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
- if (adapter->ptp_clock)
- info->phc_index = ptp_clock_index(adapter->ptp_clock);
- else
- info->phc_index = -1;
+ if (adapter->ptp_clock)
+ info->phc_index = ptp_clock_index(adapter->ptp_clock);
+ else
+ info->phc_index = -1;
- info->tx_types =
- (1 << HWTSTAMP_TX_OFF) |
- (1 << HWTSTAMP_TX_ON);
+ info->tx_types =
+ (1 << HWTSTAMP_TX_OFF) |
+ (1 << HWTSTAMP_TX_ON);
- info->rx_filters =
- (1 << HWTSTAMP_FILTER_NONE) |
- (1 << HWTSTAMP_FILTER_ALL) |
- (1 << HWTSTAMP_FILTER_SOME) |
- (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
- (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
- (1 << HWTSTAMP_FILTER_PTP_V2_EVENT);
+ info->rx_filters = 1 << HWTSTAMP_FILTER_NONE;
- return 0;
-}
+ /* 82576 does not support timestamping all packets. */
+ if (adapter->hw.mac.type >= e1000_82580)
+ info->rx_filters |= 1 << HWTSTAMP_FILTER_ALL;
+ else
+ info->rx_filters |=
+ (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_EVENT);
+
+ return 0;
#endif /* CONFIG_IGB_PTP */
+ default:
+ return -EOPNOTSUPP;
+ }
+}
static int igb_ethtool_begin(struct net_device *netdev)
{
@@ -2366,9 +2382,7 @@ static const struct ethtool_ops igb_ethtool_ops = {
.get_ethtool_stats = igb_get_ethtool_stats,
.get_coalesce = igb_get_coalesce,
.set_coalesce = igb_set_coalesce,
-#ifdef CONFIG_IGB_PTP
.get_ts_info = igb_get_ts_info,
-#endif /* CONFIG_IGB_PTP */
.begin = igb_ethtool_begin,
.complete = igb_ethtool_complete,
};
--
1.7.11.4
^ permalink raw reply related
* [net-next 1/6] igb: Tidy up wrapping for CONFIG_IGB_PTP.
From: Jeff Kirsher @ 2012-09-05 23:35 UTC (permalink / raw)
To: davem; +Cc: Matthew Vick, netdev, gospo, sassmann, Richard Cochran,
Jeff Kirsher
In-Reply-To: <1346888106-25638-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Matthew Vick <matthew.vick@intel.com>
For users without CONFIG_IGB_PTP=y, we should not be compiling any PTP
code into the driver. Tidy up the wrapping in igb to support this.
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Matthew Vick <matthew.vick@intel.com>
Acked-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb.h | 8 ++++++--
drivers/net/ethernet/intel/igb/igb_ethtool.c | 4 ++--
drivers/net/ethernet/intel/igb/igb_main.c | 23 +++++++++++++++++------
3 files changed, 25 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 0c9f62c..a3b5b90 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -34,9 +34,11 @@
#include "e1000_mac.h"
#include "e1000_82575.h"
+#ifdef CONFIG_IGB_PTP
#include <linux/clocksource.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
+#endif /* CONFIG_IGB_PTP */
#include <linux/bitops.h>
#include <linux/if_vlan.h>
@@ -376,12 +378,15 @@ struct igb_adapter {
int node;
u32 *shadow_vfta;
+#ifdef CONFIG_IGB_PTP
struct ptp_clock *ptp_clock;
struct ptp_clock_info caps;
struct delayed_work overflow_work;
spinlock_t tmreg_lock;
struct cyclecounter cc;
struct timecounter tc;
+#endif /* CONFIG_IGB_PTP */
+
char fw_version[32];
};
@@ -436,12 +441,11 @@ extern void igb_set_fw_version(struct igb_adapter *);
#ifdef CONFIG_IGB_PTP
extern void igb_ptp_init(struct igb_adapter *adapter);
extern void igb_ptp_remove(struct igb_adapter *adapter);
-
extern void igb_systim_to_hwtstamp(struct igb_adapter *adapter,
struct skb_shared_hwtstamps *hwtstamps,
u64 systim);
+#endif /* CONFIG_IGB_PTP */
-#endif
static inline s32 igb_reset_phy(struct e1000_hw *hw)
{
if (hw->phy.ops.reset)
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index a294441..0c4e29a 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -2338,8 +2338,8 @@ static int igb_ethtool_get_ts_info(struct net_device *dev,
return 0;
}
+#endif /* CONFIG_IGB_PTP */
-#endif
static const struct ethtool_ops igb_ethtool_ops = {
.get_settings = igb_get_settings,
.set_settings = igb_set_settings,
@@ -2370,7 +2370,7 @@ static const struct ethtool_ops igb_ethtool_ops = {
.complete = igb_ethtool_complete,
#ifdef CONFIG_IGB_PTP
.get_ts_info = igb_ethtool_get_ts_info,
-#endif
+#endif /* CONFIG_IGB_PTP */
};
void igb_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 73cc273..03477d7 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2180,11 +2180,12 @@ static int __devinit igb_probe(struct pci_dev *pdev,
}
#endif
+
#ifdef CONFIG_IGB_PTP
/* do hw tstamp init after resetting */
igb_ptp_init(adapter);
+#endif /* CONFIG_IGB_PTP */
-#endif
dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n");
/* print bus type/speed/width info */
dev_info(&pdev->dev, "%s: (PCIe:%s:%s) %pM\n",
@@ -2260,8 +2261,8 @@ static void __devexit igb_remove(struct pci_dev *pdev)
pm_runtime_get_noresume(&pdev->dev);
#ifdef CONFIG_IGB_PTP
igb_ptp_remove(adapter);
+#endif /* CONFIG_IGB_PTP */
-#endif
/*
* The watchdog timer may be rescheduled, so explicitly
* disable watchdog from being rescheduled.
@@ -3184,8 +3185,10 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
srrctl |= (PAGE_SIZE / 2) >> E1000_SRRCTL_BSIZEPKT_SHIFT;
#endif
srrctl |= E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
+#ifdef CONFIG_IGB_PTP
if (hw->mac.type >= e1000_82580)
srrctl |= E1000_SRRCTL_TIMESTAMP;
+#endif /* CONFIG_IGB_PTP */
/* Only set Drop Enable if we are supporting multiple queues */
if (adapter->vfs_allocated_count || adapter->num_rx_queues > 1)
srrctl |= E1000_SRRCTL_DROP_EN;
@@ -4229,9 +4232,11 @@ static __le32 igb_tx_cmd_type(u32 tx_flags)
if (tx_flags & IGB_TX_FLAGS_VLAN)
cmd_type |= cpu_to_le32(E1000_ADVTXD_DCMD_VLE);
+#ifdef CONFIG_IGB_PTP
/* set timestamp bit if present */
if (tx_flags & IGB_TX_FLAGS_TSTAMP)
cmd_type |= cpu_to_le32(E1000_ADVTXD_MAC_TSTAMP);
+#endif /* CONFIG_IGB_PTP */
/* set segmentation bits for TSO */
if (tx_flags & IGB_TX_FLAGS_TSO)
@@ -4462,10 +4467,12 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
first->bytecount = skb->len;
first->gso_segs = 1;
+#ifdef CONFIG_IGB_PTP
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IGB_TX_FLAGS_TSTAMP;
}
+#endif /* CONFIG_IGB_PTP */
if (vlan_tx_tag_present(skb)) {
tx_flags |= IGB_TX_FLAGS_VLAN;
@@ -5772,8 +5779,8 @@ static void igb_tx_hwtstamp(struct igb_q_vector *q_vector,
igb_systim_to_hwtstamp(adapter, &shhwtstamps, regval);
skb_tstamp_tx(buffer_info->skb, &shhwtstamps);
}
+#endif /* CONFIG_IGB_PTP */
-#endif
/**
* igb_clean_tx_irq - Reclaim resources after transmit completes
* @q_vector: pointer to q_vector containing needed info
@@ -5821,8 +5828,8 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
#ifdef CONFIG_IGB_PTP
/* retrieve hardware timestamp */
igb_tx_hwtstamp(q_vector, tx_buffer);
+#endif /* CONFIG_IGB_PTP */
-#endif
/* free the skb */
dev_kfree_skb_any(tx_buffer->skb);
tx_buffer->skb = NULL;
@@ -6033,8 +6040,8 @@ static void igb_rx_hwtstamp(struct igb_q_vector *q_vector,
igb_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval);
}
+#endif /* CONFIG_IGB_PTP */
-#endif
static void igb_rx_vlan(struct igb_ring *ring,
union e1000_adv_rx_desc *rx_desc,
struct sk_buff *skb)
@@ -6147,7 +6154,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
#ifdef CONFIG_IGB_PTP
igb_rx_hwtstamp(q_vector, rx_desc, skb);
-#endif
+#endif /* CONFIG_IGB_PTP */
igb_rx_hash(rx_ring, rx_desc, skb);
igb_rx_checksum(rx_ring, rx_desc, skb);
igb_rx_vlan(rx_ring, rx_desc, skb);
@@ -6340,6 +6347,7 @@ static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
return 0;
}
+#ifdef CONFIG_IGB_PTP
/**
* igb_hwtstamp_ioctl - control hardware time stamping
* @netdev:
@@ -6514,6 +6522,7 @@ static int igb_hwtstamp_ioctl(struct net_device *netdev,
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
-EFAULT : 0;
}
+#endif /* CONFIG_IGB_PTP */
/**
* igb_ioctl -
@@ -6528,8 +6537,10 @@ static int igb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
case SIOCGMIIREG:
case SIOCSMIIREG:
return igb_mii_ioctl(netdev, ifr, cmd);
+#ifdef CONFIG_IGB_PTP
case SIOCSHWTSTAMP:
return igb_hwtstamp_ioctl(netdev, ifr, cmd);
+#endif /* CONFIG_IGB_PTP */
default:
return -EOPNOTSUPP;
}
--
1.7.11.4
^ permalink raw reply related
* [net-next 0/6][pull request] Intel Wired LAN Driver Updates
From: Jeff Kirsher @ 2012-09-05 23:35 UTC (permalink / raw)
To: davem; +Cc: Jeff Kirsher, netdev, gospo, sassmann
This series contains updates to igb (specifically PTP code).
The following are changes since commit f6fe569fe056388166575af1cfaed0bcbc688305:
Revert "usbnet: drop unneeded check for NULL"
and are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next master
Matthew Vick (6):
igb: Tidy up wrapping for CONFIG_IGB_PTP.
igb: Update PTP function names/variables and locations.
igb: Correct PTP support query from ethtool.
igb: Store the MAC address in the name in the PTP struct.
igb: Prevent dropped Tx timestamps via work items and interrupts.
igb: Add 1588 support to I210/I211.
drivers/net/ethernet/intel/igb/e1000_defines.h | 8 +
drivers/net/ethernet/intel/igb/e1000_regs.h | 2 +
drivers/net/ethernet/intel/igb/igb.h | 29 +-
drivers/net/ethernet/intel/igb/igb_ethtool.c | 84 +--
drivers/net/ethernet/intel/igb/igb_main.c | 329 +++---------
drivers/net/ethernet/intel/igb/igb_ptp.c | 676 ++++++++++++++++++++-----
6 files changed, 708 insertions(+), 420 deletions(-)
--
1.7.11.4
^ permalink raw reply
* Re: [PATCH 08/10] net/macb: macb_get_drvinfo: add GEM/MACB suffix to differentiate revision
From: Ben Hutchings @ 2012-09-05 23:27 UTC (permalink / raw)
To: Nicolas Ferre
Cc: netdev, linux-arm-kernel, davem, havard, plagnioj, jamie,
linux-kernel, patrice.vilchez
In-Reply-To: <fc701a2ed18198b7a671c55f1e65725f1709509c.1346775479.git.nicolas.ferre@atmel.com>
On Wed, 2012-09-05 at 11:00 +0200, Nicolas Ferre wrote:
> Add an indication about which revision of the hardware we are running in
> info->driver string.
>
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
> ---
> drivers/net/ethernet/cadence/macb.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
> index bd331fd..c7c39f1 100644
> --- a/drivers/net/ethernet/cadence/macb.c
> +++ b/drivers/net/ethernet/cadence/macb.c
> @@ -1313,6 +1313,10 @@ static void macb_get_drvinfo(struct net_device *dev,
> struct macb *bp = netdev_priv(dev);
>
> strcpy(info->driver, bp->pdev->dev.driver->name);
> + if (macb_is_gem(bp))
> + strcat(info->driver, " GEM");
> + else
> + strcat(info->driver, " MACB");
> strcpy(info->version, "$Revision: 1.14 $");
Related to hardware revisions (which don't belong here, as David said),
I rather doubt this CVS ID is very useful as a driver version.
If the driver doesn't have a meaningful version (aside from the kernel
version) then you can remove this function and let the ethtool core fill
in the other two fields automatically.
Ben.
> strcpy(info->bus_info, dev_name(&bp->pdev->dev));
> }
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [V2 PATCH 6/9] csiostor: Chelsio FCoE offload driver submission (headers part 1).
From: Ben Hutchings @ 2012-09-05 23:07 UTC (permalink / raw)
To: Naresh Kumar Inna
Cc: Stephen Hemminger, JBottomley@parallels.com,
linux-scsi@vger.kernel.org, Dimitrios Michailidis, Casey Leedom,
netdev@vger.kernel.org, Chethan Seshadri
In-Reply-To: <50478B36.6000103@chelsio.com>
On Wed, 2012-09-05 at 22:56 +0530, Naresh Kumar Inna wrote:
> On 9/5/2012 10:01 PM, Stephen Hemminger wrote:
> > On Wed, 5 Sep 2012 18:03:59 +0530
> > Naresh Kumar Inna <naresh@chelsio.com> wrote:
> >
> >> +#define CSIO_ROUNDUP(__v, __r) (((__v) + (__r) - 1) / (__r))
> >
> > This is similar to existing round_up() in kernel.h could you use that?
> >
> I will replace it with round_up() if it serves the same purpose. Thanks.
Stephen is probably thinking of DIV_ROUND_UP(). round_up() does
something different.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: sctp_close/sk_free: kernel BUG at arch/x86/mm/physaddr.c:18!
From: Jerry Chu @ 2012-09-05 23:07 UTC (permalink / raw)
To: Fengguang Wu
Cc: Eric Dumazet, Marc Kleine-Budde, Eric W. Biederman, networking,
linux-can
In-Reply-To: <20120905222850.GA11230@localhost>
On Wed, Sep 5, 2012 at 3:28 PM, Fengguang Wu <fengguang.wu@intel.com> wrote:
> On Wed, Sep 05, 2012 at 06:57:00PM +0200, Eric Dumazet wrote:
>> On Wed, 2012-09-05 at 17:40 +0200, Eric Dumazet wrote:
>>
>> > Could you test the following patch please ?
>
> It works - no single error for 1000 boots!
Sorry for introducing the bug, one of the casualties dealing with code
that is shared
outside of TCP. I did spend some effort adding special checks but I was wrong in
assuming inet_create() will zero all the field including fastopenq
inside icsk_accept_queue
inside struct inet_connection_sock - although this is true for TCP and
DCCP, SCTP doesn't
have inet_connection_sock hence inet_csk(sk) is bogus.
Kudo to Eric for fixing it quickly before I got to it.
Jerry
>
> btw, the first bad commit has been bisected to
>
> commit 8336886f786fdacbc19b719c1f7ea91eb70706d4
> Author: Jerry Chu <hkchu@google.com>
> Date: Fri Aug 31 12:29:12 2012 +0000
>
> tcp: TCP Fast Open Server - support TFO listeners
>
>> > (Not sure why sctp doesnt memset/bzero its whole socket by the way...)
>> >
>> > Thanks
>>
>> Here is a more complete patch, as there are three potential problems,
>> not only one :
>
> Great! I'll start tests for it.
>
> Thanks,
> Fengguang
>
>> diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
>> index 4f70ef0..845372b 100644
>> --- a/net/ipv4/af_inet.c
>> +++ b/net/ipv4/af_inet.c
>> @@ -149,11 +149,8 @@ void inet_sock_destruct(struct sock *sk)
>> pr_err("Attempt to release alive inet socket %p\n", sk);
>> return;
>> }
>> - if (sk->sk_type == SOCK_STREAM) {
>> - struct fastopen_queue *fastopenq =
>> - inet_csk(sk)->icsk_accept_queue.fastopenq;
>> - kfree(fastopenq);
>> - }
>> + if (sk->sk_protocol == IPPROTO_TCP)
>> + kfree(inet_csk(sk)->icsk_accept_queue.fastopenq);
>>
>> WARN_ON(atomic_read(&sk->sk_rmem_alloc));
>> WARN_ON(atomic_read(&sk->sk_wmem_alloc));
>> diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
>> index 8464b79..f0c5b9c 100644
>> --- a/net/ipv4/inet_connection_sock.c
>> +++ b/net/ipv4/inet_connection_sock.c
>> @@ -314,7 +314,7 @@ struct sock *inet_csk_accept(struct sock *sk, int flags, int *err)
>> newsk = req->sk;
>>
>> sk_acceptq_removed(sk);
>> - if (sk->sk_type == SOCK_STREAM && queue->fastopenq != NULL) {
>> + if (sk->sk_protocol == IPPROTO_TCP && queue->fastopenq != NULL) {
>> spin_lock_bh(&queue->fastopenq->lock);
>> if (tcp_rsk(req)->listener) {
>> /* We are still waiting for the final ACK from 3WHS
>> @@ -775,7 +775,7 @@ void inet_csk_listen_stop(struct sock *sk)
>>
>> percpu_counter_inc(sk->sk_prot->orphan_count);
>>
>> - if (sk->sk_type == SOCK_STREAM && tcp_rsk(req)->listener) {
>> + if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(req)->listener) {
>> BUG_ON(tcp_sk(child)->fastopen_rsk != req);
>> BUG_ON(sk != tcp_rsk(req)->listener);
>>
>>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [V2 PATCH 2/9] csiostor: Chelsio FCoE offload driver submission (sources part 2).
From: Stephen Hemminger @ 2012-09-05 22:59 UTC (permalink / raw)
To: Naresh Kumar Inna
Cc: JBottomley@parallels.com, linux-scsi@vger.kernel.org,
Dimitrios Michailidis, Casey Leedom, netdev@vger.kernel.org,
Chethan Seshadri
In-Reply-To: <50478F52.208@chelsio.com>
On Wed, 5 Sep 2012 23:13:46 +0530
Naresh Kumar Inna <naresh@chelsio.com> wrote:
> On 9/5/2012 9:59 PM, Stephen Hemminger wrote:
> > On Wed, 5 Sep 2012 18:03:55 +0530
> > Naresh Kumar Inna <naresh@chelsio.com> wrote:
> >
> >> This patch contains code for driver initialization, driver resource
> >> allocation and the Work Request module functionality. Driver initialization
> >> includes module entry/exit points, registration with PCI, FC transport and
> >> SCSI mid layer subsystems. The Work Request module provides services for
> >> allocation of DMA queues, posting Work Requests on them and processing
> >> completions.
> >>
> >> Signed-off-by: Naresh Kumar Inna <naresh@chelsio.com>
> >
> > Although the comments say you are using proc fs, there is no
> > code here related to that.
>
> I will remove that comment.
>
> >
> > Any use of debugfs must be conditional the DEBUG_FS kernel configuration
> > parameter. Your code probably will break if DEBUG_FS is not
> > enabled. For a possible alternative see how a sub-config parameter
> > was added in sky2 driver.
> >
>
> It appears that debugfs_create_dir() returns an error if DEBUG_FS is not
> enabled. Considering the driver handles this error and continues
> initialization, do you still think I should guard this code within DEBUG_FS?
>
> Thanks.
That works, just make sure and test it.
^ permalink raw reply
* Re: [PATCH] usbnet: drop unneeded check for NULL
From: Ben Hutchings @ 2012-09-05 22:53 UTC (permalink / raw)
To: Oliver Neukum; +Cc: David Miller, richardcochran, netdev, Alexander Duyck
In-Reply-To: <2059099.RnKXUv0tR1@linux-lqwf.site>
On Thu, 2012-09-06 at 00:34 +0200, Oliver Neukum wrote:
> On Wednesday 05 September 2012 23:14:35 Ben Hutchings wrote:
> > cdc-ncm is aggregating skbs into jumbo USB packets and then, because the
> > netdev is not signalled when the qdisc stops transmitting, flushing them
> > after one scheduler tick. Flushing is done by calling
> > usbnet_start_xmit() with a null skb pointer and then substituting a real
> > skb in the tx_fixup callback.
> >
> > Perhaps the skb_tx_timestamp() call should be moved below the
> > 'if (info->tx_fixup)' block, at which point skb is definitely non-null.
> > It doesn't look like cdc-ncm will provide useful timestamps either way.
> >
> > cdc-ncm's aggregation could be improved by either (1) implementing some
> > type of GSO with appropriate gso_max_size and gso_max_segs limits (2)
> > adding an explicit transmit flushing operation, similar to that
> > Alexander Duyck proposed.
>
> Actually, I thought about changing it. This is the current version. What do you think?
> It lacks a bit of logic in the completion handler still.
[...]
I'm not familiar with the USB net framework (or USB in general), so I
don't know whether this would work. But it looks like you're trying to
use the TX completions to trigger flushing of the aggregated USB packet,
and flushing immediately if there are no packets currently outstanding.
That seems like a reasonable approach.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [PATCH] usbnet: drop unneeded check for NULL
From: Oliver Neukum @ 2012-09-05 22:34 UTC (permalink / raw)
To: Ben Hutchings; +Cc: David Miller, richardcochran, netdev, Alexander Duyck
In-Reply-To: <1346883275.5325.28.camel@bwh-desktop.uk.solarflarecom.com>
On Wednesday 05 September 2012 23:14:35 Ben Hutchings wrote:
> cdc-ncm is aggregating skbs into jumbo USB packets and then, because the
> netdev is not signalled when the qdisc stops transmitting, flushing them
> after one scheduler tick. Flushing is done by calling
> usbnet_start_xmit() with a null skb pointer and then substituting a real
> skb in the tx_fixup callback.
>
> Perhaps the skb_tx_timestamp() call should be moved below the
> 'if (info->tx_fixup)' block, at which point skb is definitely non-null.
> It doesn't look like cdc-ncm will provide useful timestamps either way.
>
> cdc-ncm's aggregation could be improved by either (1) implementing some
> type of GSO with appropriate gso_max_size and gso_max_segs limits (2)
> adding an explicit transmit flushing operation, similar to that
> Alexander Duyck proposed.
Actually, I thought about changing it. This is the current version. What do you think?
It lacks a bit of logic in the completion handler still.
Regards
Oliver
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 4cd582a..56ef743 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -135,9 +135,6 @@ struct cdc_ncm_ctx {
u16 connected;
};
-static void cdc_ncm_txpath_bh(unsigned long param);
-static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx);
-static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer);
static struct usb_driver cdc_ncm_driver;
static void
@@ -464,10 +461,6 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
if (ctx == NULL)
return -ENODEV;
- hrtimer_init(&ctx->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- ctx->tx_timer.function = &cdc_ncm_tx_timer_cb;
- ctx->bh.data = (unsigned long)ctx;
- ctx->bh.func = cdc_ncm_txpath_bh;
atomic_set(&ctx->stop, 0);
spin_lock_init(&ctx->mtx);
ctx->netdev = dev->net;
@@ -650,7 +643,7 @@ static void cdc_ncm_zero_fill(u8 *ptr, u32 first, u32 end, u32 max)
memset(ptr + first, 0, end - first);
}
-static struct sk_buff *
+static int
cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
{
struct sk_buff *skb_out;
@@ -659,12 +652,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
u32 last_offset;
u16 n = 0, index;
u8 ready2send = 0;
-
- /* if there is a remaining skb, it gets priority */
- if (skb != NULL)
- swap(skb, ctx->tx_rem_skb);
- else
- ready2send = 1;
+ u8 error = 0;
/*
* +----------------+
@@ -690,7 +678,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
dev_kfree_skb_any(skb);
ctx->netdev->stats.tx_dropped++;
}
- goto exit_no_skb;
+ return -EBUSY;
}
/* make room for NTH and NDP */
@@ -719,28 +707,15 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
/* compute maximum buffer size */
rem = ctx->tx_max - offset;
- if (skb == NULL) {
- skb = ctx->tx_rem_skb;
- ctx->tx_rem_skb = NULL;
-
- /* check for end of skb */
- if (skb == NULL)
- break;
- }
-
if (skb->len > rem) {
if (n == 0) {
/* won't fit, MTU problem? */
dev_kfree_skb_any(skb);
skb = NULL;
ctx->netdev->stats.tx_dropped++;
+ error = 1;
} else {
- /* no room for skb - store for later */
- if (ctx->tx_rem_skb != NULL) {
- dev_kfree_skb_any(ctx->tx_rem_skb);
- ctx->netdev->stats.tx_dropped++;
- }
- ctx->tx_rem_skb = skb;
+
skb = NULL;
ready2send = 1;
}
@@ -768,13 +743,6 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
skb = NULL;
}
- /* free up any dangling skb */
- if (skb != NULL) {
- dev_kfree_skb_any(skb);
- skb = NULL;
- ctx->netdev->stats.tx_dropped++;
- }
-
ctx->tx_curr_frame_num = n;
if (n == 0) {
@@ -791,9 +759,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
ctx->tx_curr_skb = skb_out;
ctx->tx_curr_offset = offset;
ctx->tx_curr_last_offset = last_offset;
- /* set the pending count */
- if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT)
- ctx->tx_timer_pending = CDC_NCM_TIMER_PENDING_CNT;
+
goto exit_no_skb;
} else {
@@ -874,71 +840,37 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
/* return skb */
ctx->tx_curr_skb = NULL;
ctx->netdev->stats.tx_packets += ctx->tx_curr_frame_num;
- return skb_out;
-exit_no_skb:
- /* Start timer, if there is a remaining skb */
- if (ctx->tx_curr_skb != NULL)
- cdc_ncm_tx_timeout_start(ctx);
- return NULL;
-}
-
-static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx)
-{
- /* start timer, if not already started */
- if (!(hrtimer_active(&ctx->tx_timer) || atomic_read(&ctx->stop)))
- hrtimer_start(&ctx->tx_timer,
- ktime_set(0, CDC_NCM_TIMER_INTERVAL),
- HRTIMER_MODE_REL);
-}
+ if (error)
+ return -EBUSY;
+ if (ready2send)
+ return -EBUSY;
+ else
+ return 0;
-static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *timer)
-{
- struct cdc_ncm_ctx *ctx =
- container_of(timer, struct cdc_ncm_ctx, tx_timer);
+exit_no_skb:
- if (!atomic_read(&ctx->stop))
- tasklet_schedule(&ctx->bh);
- return HRTIMER_NORESTART;
+ return -EAGAIN;
}
-static void cdc_ncm_txpath_bh(unsigned long param)
+static int cdc_ncm_tx_bundle(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
- struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)param;
-
- spin_lock_bh(&ctx->mtx);
- if (ctx->tx_timer_pending != 0) {
- ctx->tx_timer_pending--;
- cdc_ncm_tx_timeout_start(ctx);
- spin_unlock_bh(&ctx->mtx);
- } else if (ctx->netdev != NULL) {
- spin_unlock_bh(&ctx->mtx);
- netif_tx_lock_bh(ctx->netdev);
- usbnet_start_xmit(NULL, ctx->netdev);
- netif_tx_unlock_bh(ctx->netdev);
- }
+ int err;
+ struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+
+ err = cdc_ncm_fill_tx_frame(ctx, skb);
+ return err;
}
static struct sk_buff *
cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
- struct sk_buff *skb_out;
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
- /*
- * The Ethernet API we are using does not support transmitting
- * multiple Ethernet frames in a single call. This driver will
- * accumulate multiple Ethernet frames and send out a larger
- * USB frame when the USB buffer is full or when a single jiffies
- * timeout happens.
- */
if (ctx == NULL)
goto error;
- spin_lock_bh(&ctx->mtx);
- skb_out = cdc_ncm_fill_tx_frame(ctx, skb);
- spin_unlock_bh(&ctx->mtx);
- return skb_out;
+ return ctx->tx_curr_skb;
error:
if (skb != NULL)
@@ -1197,6 +1129,7 @@ static const struct driver_info cdc_ncm_info = {
.manage_power = cdc_ncm_manage_power,
.status = cdc_ncm_status,
.rx_fixup = cdc_ncm_rx_fixup,
+ .tx_bundle = cdc_ncm_tx_bundle,
.tx_fixup = cdc_ncm_tx_fixup,
};
@@ -1211,6 +1144,7 @@ static const struct driver_info wwan_info = {
.manage_power = cdc_ncm_manage_power,
.status = cdc_ncm_status,
.rx_fixup = cdc_ncm_rx_fixup,
+ .tx_bundle = cdc_ncm_tx_bundle,
.tx_fixup = cdc_ncm_tx_fixup,
};
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 8531c1c..d9a595e 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1024,6 +1024,7 @@ static void tx_complete (struct urb *urb)
struct skb_data *entry = (struct skb_data *) skb->cb;
struct usbnet *dev = entry->dev;
+ atomic_dec(&dev->tx_in_flight);
if (urb->status == 0) {
if (!(dev->driver_info->flags & FLAG_MULTI_PACKET))
dev->net->stats.tx_packets++;
@@ -1089,23 +1090,50 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
struct urb *urb = NULL;
struct skb_data *entry;
struct driver_info *info = dev->driver_info;
+ struct sk_buff *skb_old = NULL;
unsigned long flags;
int retval;
+ int transmit_now = 1;
+ int bundle_again = 0;
if (skb)
skb_tx_timestamp(skb);
+ /*
+ * first we allow drivers to bundle packets together
+ * maintainance of the buffer is the responsibility
+ * of the lower layer
+ */
+rebundle:
+ if (info->tx_bundle) {
+ bundle_again = 0;
+ retval = info->tx_bundle(dev, skb, GFP_ATOMIC);
+
+ switch (retval) {
+ case 0: /* the package has been bundled */
+ if (atomic_read(&dev->tx_in_flight) < 2)
+ transmit_now = 1;
+ else
+ transmit_now = 0;
+ break;
+ case -EAGAIN:
+ transmit_now = 1;
+ bundle_again = 1;
+ skb_old = skb;
+ break;
+ case -EBUSY:
+ transmit_now = 1;
+ break;
+ }
+ }
// some devices want funky USB-level framing, for
// win32 driver (usually) and/or hardware quirks
- if (info->tx_fixup) {
+ if (transmit_now && info->tx_fixup) {
skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
if (!skb) {
if (netif_msg_tx_err(dev)) {
netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n");
goto drop;
- } else {
- /* cdc_ncm collected packet; waits for more */
- goto not_drop;
}
}
}
@@ -1164,14 +1192,17 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
}
#endif
+ atomic_inc(&dev->tx_in_flight);
switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) {
case -EPIPE:
netif_stop_queue (net);
usbnet_defer_kevent (dev, EVENT_TX_HALT);
+ atomic_dec(&dev->tx_in_flight);
usb_autopm_put_interface_async(dev->intf);
break;
default:
usb_autopm_put_interface_async(dev->intf);
+ atomic_dec(&dev->tx_in_flight);
netif_dbg(dev, tx_err, dev->net,
"tx: submit urb err %d\n", retval);
break;
@@ -1187,7 +1218,6 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", retval);
drop:
dev->net->stats.tx_dropped++;
-not_drop:
if (skb)
dev_kfree_skb_any (skb);
usb_free_urb (urb);
@@ -1197,6 +1227,10 @@ not_drop:
#ifdef CONFIG_PM
deferred:
#endif
+ if (bundle_again) {
+ skb = skb_old;
+ goto rebundle;
+ }
return NETDEV_TX_OK;
}
EXPORT_SYMBOL_GPL(usbnet_start_xmit);
@@ -1393,6 +1427,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev->delay.data = (unsigned long) dev;
init_timer (&dev->delay);
mutex_init (&dev->phy_mutex);
+ atomic_set(&dev->tx_in_flight, 0);
dev->net = net;
strcpy (net->name, "usb%d");
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index f87cf62..bb2f622 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -33,6 +33,7 @@ struct usbnet {
wait_queue_head_t *wait;
struct mutex phy_mutex;
unsigned char suspend_count;
+ atomic_t tx_in_flight;
/* i/o info: pipes etc */
unsigned in, out;
@@ -133,6 +134,12 @@ struct driver_info {
/* fixup rx packet (strip framing) */
int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb);
+ /* bundle individual package for transmission as
+ * larger package. This cannot sleep
+ */
+ int (*tx_bundle)(struct usbnet *dev,
+ struct sk_buff *skb, gfp_t flags);
+
/* fixup tx packet (add framing) */
struct sk_buff *(*tx_fixup)(struct usbnet *dev,
struct sk_buff *skb, gfp_t flags);
^ permalink raw reply related
* Re: sctp_close/sk_free: kernel BUG at arch/x86/mm/physaddr.c:18!
From: Fengguang Wu @ 2012-09-05 22:28 UTC (permalink / raw)
To: Eric Dumazet
Cc: Marc Kleine-Budde, H.K. Jerry Chu, Eric W. Biederman, networking,
linux-can
In-Reply-To: <1346864220.13121.157.camel@edumazet-glaptop>
On Wed, Sep 05, 2012 at 06:57:00PM +0200, Eric Dumazet wrote:
> On Wed, 2012-09-05 at 17:40 +0200, Eric Dumazet wrote:
>
> > Could you test the following patch please ?
It works - no single error for 1000 boots!
btw, the first bad commit has been bisected to
commit 8336886f786fdacbc19b719c1f7ea91eb70706d4
Author: Jerry Chu <hkchu@google.com>
Date: Fri Aug 31 12:29:12 2012 +0000
tcp: TCP Fast Open Server - support TFO listeners
> > (Not sure why sctp doesnt memset/bzero its whole socket by the way...)
> >
> > Thanks
>
> Here is a more complete patch, as there are three potential problems,
> not only one :
Great! I'll start tests for it.
Thanks,
Fengguang
> diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
> index 4f70ef0..845372b 100644
> --- a/net/ipv4/af_inet.c
> +++ b/net/ipv4/af_inet.c
> @@ -149,11 +149,8 @@ void inet_sock_destruct(struct sock *sk)
> pr_err("Attempt to release alive inet socket %p\n", sk);
> return;
> }
> - if (sk->sk_type == SOCK_STREAM) {
> - struct fastopen_queue *fastopenq =
> - inet_csk(sk)->icsk_accept_queue.fastopenq;
> - kfree(fastopenq);
> - }
> + if (sk->sk_protocol == IPPROTO_TCP)
> + kfree(inet_csk(sk)->icsk_accept_queue.fastopenq);
>
> WARN_ON(atomic_read(&sk->sk_rmem_alloc));
> WARN_ON(atomic_read(&sk->sk_wmem_alloc));
> diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
> index 8464b79..f0c5b9c 100644
> --- a/net/ipv4/inet_connection_sock.c
> +++ b/net/ipv4/inet_connection_sock.c
> @@ -314,7 +314,7 @@ struct sock *inet_csk_accept(struct sock *sk, int flags, int *err)
> newsk = req->sk;
>
> sk_acceptq_removed(sk);
> - if (sk->sk_type == SOCK_STREAM && queue->fastopenq != NULL) {
> + if (sk->sk_protocol == IPPROTO_TCP && queue->fastopenq != NULL) {
> spin_lock_bh(&queue->fastopenq->lock);
> if (tcp_rsk(req)->listener) {
> /* We are still waiting for the final ACK from 3WHS
> @@ -775,7 +775,7 @@ void inet_csk_listen_stop(struct sock *sk)
>
> percpu_counter_inc(sk->sk_prot->orphan_count);
>
> - if (sk->sk_type == SOCK_STREAM && tcp_rsk(req)->listener) {
> + if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(req)->listener) {
> BUG_ON(tcp_sk(child)->fastopen_rsk != req);
> BUG_ON(sk != tcp_rsk(req)->listener);
>
>
^ permalink raw reply
* Re: [PATCH] usbnet: drop unneeded check for NULL
From: Ben Hutchings @ 2012-09-05 22:14 UTC (permalink / raw)
To: David Miller; +Cc: oneukum, richardcochran, netdev, Alexander Duyck
In-Reply-To: <20120905.125016.2259674613767082102.davem@davemloft.net>
On Wed, 2012-09-05 at 12:50 -0400, David Miller wrote:
> From: Oliver Neukum <oneukum@suse.de>
> Date: Wed, 05 Sep 2012 08:24:25 +0200
>
> > On Wednesday 05 September 2012 06:47:12 Richard Cochran wrote:
> >> and so I think the problem that the test addresses is still present,
> >> or am I missing something?
> >
> > No,
> >
> > you are right. Thank you.
> >
> > Dave, for now, please don't apply this patch. In the long run, this crap
> > in cdc-ncm needs to go. I am starting rewriting this driver right now.
>
> I already applied it several days ago, someone send me a revert with a
> verbose commit message explaining the situation.
cdc-ncm is aggregating skbs into jumbo USB packets and then, because the
netdev is not signalled when the qdisc stops transmitting, flushing them
after one scheduler tick. Flushing is done by calling
usbnet_start_xmit() with a null skb pointer and then substituting a real
skb in the tx_fixup callback.
Perhaps the skb_tx_timestamp() call should be moved below the
'if (info->tx_fixup)' block, at which point skb is definitely non-null.
It doesn't look like cdc-ncm will provide useful timestamps either way.
cdc-ncm's aggregation could be improved by either (1) implementing some
type of GSO with appropriate gso_max_size and gso_max_segs limits (2)
adding an explicit transmit flushing operation, similar to that
Alexander Duyck proposed.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [net-next PATCH] be2net: use PCIe AER capability
From: David Miller @ 2012-09-05 21:51 UTC (permalink / raw)
To: sathya.perla; +Cc: netdev
In-Reply-To: <2fad6337-6291-43f5-af76-e8ba8a9a5296@exht1.ad.emulex.com>
From: Sathya Perla <sathya.perla@emulex.com>
Date: Wed, 5 Sep 2012 17:26:48 +0530
> This patch allows code to handle the PCIe AER capability.
> The PCI callbacks for error handling/reset/recovery already exist in be2net
> and have been tested with EEH/ppc.
> This patch has been tested using the aer-inject tool.
>
> Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next] net: qdisc busylock needs lockdep annotations
From: David Miller @ 2012-09-05 21:51 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev
In-Reply-To: <1346842976.13121.143.camel@edumazet-glaptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Wed, 05 Sep 2012 13:02:56 +0200
> From: Eric Dumazet <edumazet@google.com>
>
> It seems we need to provide ability for stacked devices
> to use specific lock_class_key for sch->busylock
>
> We could instead default l2tpeth tx_queue_len to 0 (no qdisc), but
> a user might use a qdisc anyway.
>
> (So same fixes are probably needed on non LLTX stacked drivers)
>
> Noticed while stressing L2TPV3 setup :
...
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Applied, thanks Eric.
^ permalink raw reply
* Re: [RFC PATCH v3] ipv6: fix handling of blackhole and prohibit routes
From: David Miller @ 2012-09-05 21:50 UTC (permalink / raw)
To: nicolas.dichtel; +Cc: netdev
In-Reply-To: <1346847162-3558-1-git-send-email-nicolas.dichtel@6wind.com>
From: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Date: Wed, 5 Sep 2012 08:12:42 -0400
> When adding a blackhole or a prohibit route, they were handling like classic
> routes. Moreover, it was only possible to add this kind of routes by specifying
> an interface.
>
> Bug already reported here:
> http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=498498
>
> Before the patch:
> $ ip route add blackhole 2001::1/128
> RTNETLINK answers: No such device
> $ ip route add blackhole 2001::1/128 dev eth0
> $ ip -6 route | grep 2001
> 2001::1 dev eth0 metric 1024
>
> After:
> $ ip route add blackhole 2001::1/128
> $ ip -6 route | grep 2001
> blackhole 2001::1 dev lo metric 1024 error -22
>
> v2: wrong patch
> v3: add a field fc_type in struct fib6_config to store RTN_* type
>
> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
I like this a lot more than your original patch, applied to net-next,
thanks.
^ permalink raw reply
* Re: [PATCH] bnx2x: use list_move_tail instead of list_del/list_add_tail
From: David Miller @ 2012-09-05 21:50 UTC (permalink / raw)
To: weiyj.lk; +Cc: eilong, yongjun_wei, netdev
In-Reply-To: <CAPgLHd-P-x3ZqrUMirMBbx74vz1XXNLb-nb3UWa43nVmmwNMCg@mail.gmail.com>
From: Wei Yongjun <weiyj.lk@gmail.com>
Date: Wed, 5 Sep 2012 15:06:55 +0800
> From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
>
> Using list_move_tail() instead of list_del() + list_add_tail().
>
> spatch with a semantic match is used to found this problem.
> (http://coccinelle.lip6.fr/)
>
> Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
Applied.
^ permalink raw reply
* Re: linux-next: build failure after merge of the final tree (net-next tree related)
From: David Miller @ 2012-09-05 21:46 UTC (permalink / raw)
To: sfr; +Cc: netdev, linux-next, linux-kernel, kaber
In-Reply-To: <20120905153932.eebf343364800678aecc98f2@canb.auug.org.au>
From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Wed, 5 Sep 2012 15:39:32 +1000
> (I always thought IPv6 NAT was a bad idea ;-))
ROFL :)
> From: Stephen Rothwell <sfr@canb.auug.org.au>
> Date: Wed, 5 Sep 2012 15:34:58 +1000
> Subject: [PATCH] netfilter: ipv6: using csum_ipv6_magic requires
> net/ip6_checksum.h
>
> Fixes this build error:
>
> net/ipv6/netfilter/nf_nat_l3proto_ipv6.c: In function 'nf_nat_ipv6_csum_recalc':
> net/ipv6/netfilter/nf_nat_l3proto_ipv6.c:144:4: error: implicit declaration of function 'csum_ipv6_magic' [-Werror=implicit-function-declaration]
>
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Applied, thanks Stephen.
^ permalink raw reply
* Re: [PATCH] ibmveth: Fix alignment of rx queue bug
From: David Miller @ 2012-09-05 21:45 UTC (permalink / raw)
To: santil; +Cc: netdev
In-Reply-To: <50469FC1.2000202@linux.vnet.ibm.com>
From: Santiago Leon <santil@linux.vnet.ibm.com>
Date: Tue, 04 Sep 2012 19:41:37 -0500
> This patch fixes a bug found by Nish Aravamudan
> (https://lkml.org/lkml/2012/5/15/220) where the driver is not following
> the spec (it is not aligning the rx buffer on a 16-byte boundary) and the
> hypervisor aborts the registration, making the device unusable.
>
> The fix follows BenH's recommendation (https://lkml.org/lkml/2012/7/20/461)
> to replace the kmalloc+map for a single call to dma_alloc_coherent()
> because that function always aligns to a 16-byte boundary.
>
> The stable trees will run into this bug whenever the rx buffer kmalloc call
> returns something not aligned on a 16-byte boundary.
>
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Santiago Leon <santil@linux.vnet.ibm.com>
Applied, thanks.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox