sfc: Add channel specific receive_skb handler and post_remove callback
authorStuart Hodgson <smhodgson@solarflare.com>
Wed, 18 Jul 2012 08:52:11 +0000 (09:52 +0100)
committerBen Hutchings <bhutchings@solarflare.com>
Fri, 7 Sep 2012 20:13:39 +0000 (21:13 +0100)
Allows an extra channel to override the standard receive_skb handler
and also for extra non generic operations to be performed on remove.

Also set default rx strategy so only skbs can be delivered to the
PTP receive function.

Signed-off-by: Stuart Hodgson <smhodgson@solarflare.com>
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/efx.h
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/sfc/rx.c

index 342a1f31e5b85cd93b31e6ff9a5031279329a8a8..8b79a6413fe4568b37693ff0c2b8a8b4296f6594 100644 (file)
@@ -734,6 +734,7 @@ static void efx_remove_channel(struct efx_channel *channel)
        efx_for_each_possible_channel_tx_queue(tx_queue, channel)
                efx_remove_tx_queue(tx_queue);
        efx_remove_eventq(channel);
+       channel->type->post_remove(channel);
 }
 
 static void efx_remove_channels(struct efx_nic *efx)
@@ -852,6 +853,7 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue)
 
 static const struct efx_channel_type efx_default_channel_type = {
        .pre_probe              = efx_channel_dummy_op_int,
+       .post_remove            = efx_channel_dummy_op_void,
        .get_name               = efx_get_channel_name,
        .copy                   = efx_copy_channel,
        .keep_eventq            = false,
@@ -862,6 +864,10 @@ int efx_channel_dummy_op_int(struct efx_channel *channel)
        return 0;
 }
 
+void efx_channel_dummy_op_void(struct efx_channel *channel)
+{
+}
+
 /**************************************************************************
  *
  * Port handling
index 70755c97251aaab4e9cafe969b0a8b95821a1cbb..f11170bc48bf4f292d38c4ac5c31a55db10499ee 100644 (file)
@@ -102,6 +102,7 @@ static inline void efx_filter_rfs_expire(struct efx_channel *channel) {}
 
 /* Channels */
 extern int efx_channel_dummy_op_int(struct efx_channel *channel);
+extern void efx_channel_dummy_op_void(struct efx_channel *channel);
 extern void efx_process_channel_now(struct efx_channel *channel);
 extern int
 efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries);
index 24a78a35bddbaa4cf71d72667de97d0e0215e5c9..0f0926e6896357de71c2dc9d350ca7c3a28b1461 100644 (file)
@@ -393,14 +393,17 @@ struct efx_channel {
  * @get_name: Generate the channel's name (used for its IRQ handler)
  * @copy: Copy the channel state prior to reallocation.  May be %NULL if
  *     reallocation is not supported.
+ * @receive_skb: Handle an skb ready to be passed to netif_receive_skb()
  * @keep_eventq: Flag for whether event queue should be kept initialised
  *     while the device is stopped
  */
 struct efx_channel_type {
        void (*handle_no_channel)(struct efx_nic *);
        int (*pre_probe)(struct efx_channel *);
+       void (*post_remove)(struct efx_channel *);
        void (*get_name)(struct efx_channel *, char *buf, size_t len);
        struct efx_channel *(*copy)(const struct efx_channel *);
+       void (*receive_skb)(struct efx_channel *, struct sk_buff *);
        bool keep_eventq;
 };
 
index e997f83f14f555501592a2369a5636365185eeb0..9e0ad1b75c335c0bf014fd1b47962c6719705767 100644 (file)
@@ -575,7 +575,10 @@ static void efx_rx_deliver(struct efx_channel *channel,
        skb_record_rx_queue(skb, channel->rx_queue.core_index);
 
        /* Pass the packet up */
-       netif_receive_skb(skb);
+       if (channel->type->receive_skb)
+               channel->type->receive_skb(channel, skb);
+       else
+               netif_receive_skb(skb);
 
        /* Update allocation strategy method */
        channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
@@ -617,7 +620,8 @@ void __efx_rx_packet(struct efx_channel *channel, struct efx_rx_buffer *rx_buf)
        if (unlikely(!(efx->net_dev->features & NETIF_F_RXCSUM)))
                rx_buf->flags &= ~EFX_RX_PKT_CSUMMED;
 
-       if (likely(rx_buf->flags & (EFX_RX_BUF_PAGE | EFX_RX_PKT_CSUMMED)))
+       if (likely(rx_buf->flags & (EFX_RX_BUF_PAGE | EFX_RX_PKT_CSUMMED)) &&
+           !channel->type->receive_skb)
                efx_rx_packet_gro(channel, rx_buf, eh);
        else
                efx_rx_deliver(channel, rx_buf);
@@ -627,6 +631,11 @@ void efx_rx_strategy(struct efx_channel *channel)
 {
        enum efx_rx_alloc_method method = rx_alloc_method;
 
+       if (channel->type->receive_skb) {
+               channel->rx_alloc_push_pages = false;
+               return;
+       }
+
        /* Only makes sense to use page based allocation if GRO is enabled */
        if (!(channel->efx->net_dev->features & NETIF_F_GRO)) {
                method = RX_ALLOC_METHOD_SKB;