Sample driver using raw Ethernet packet interface
cover Sample driver using raw Ethernet packet interface
*** Applies to ipipe-2.6.36-powerpc-2.12-03
This patch provides an example driver for the raw packet interface. Much of the code is copy/paste from the main gainfar driver. The patch uses the hardware priority queues of the P2020 to make a fast path for real time traffic. Note this might not work on other eTSEC devices due to slight implementation differences in the hardware!
If you really want to run this code, you might also apply the following patch.
cd0ea241 gianfar: Fix crashes on RX path
Richard Cochran (4):
gianfar: reserve the first transmit queue
gianfar: reserve the first receive queue
Add a real time module for the gianfar driver. Add a real time packet reception to the gianfar driver.
drivers/net/Makefile | 5 + drivers/net/gianfar.c | 120 ++++---------- drivers/net/gianfar.h | 90 ++++++++++- drivers/net/gianfar_ethtool.c | 163 +------------------ drivers/net/gianfar_rt.c | 366 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 487 insertions(+), 257 deletions(-) create mode 100644 drivers/net/gianfar_rt.c
Signature · 1 line
1.7.2.5
RFC 1/4 gianfar: reserve the first transmit queue
This commit adjusts the code to use the second hardware transmit queue. The idea is to keep the first queue open for later use as a fast path for real time Ethernet packets.
--- drivers/net/gianfar.c | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-)
drivers/net/gianfar.c +7 -4
@@ -99,6 +99,9 @@#include "gianfar.h" #include "fsl_pq_mdio.h" +/* Reserve the first transmit queue. */ +#define QADJ (x) (x+1) +#define TX_TIMEOUT (1*HZ)#undef BRIEF_GFAR_ERRORS#undef VERBOSE_GFAR_ERRORS
@@ -331,7 +334,7 @@ static void gfar_init_tx_rx_base(struct gfar_private *priv)u32 __iomem *baddr;int i; - baddr = ®s->tbase0; + baddr = ®s->tbase1;for (i =0 ; i < priv->num_tx_queues; i++) {gfar_write (baddr, priv->tx_queue[i]->tx_bd_dma_base); baddr +=2 ;
@@ -1121,8 +1124,8 @@ static int gfar_probe(struct platform_device *ofdev, priv->num_tx_queues) { priv->gfargrp[grp_idx].num_tx_queues++; priv->tx_queue[i]->grp = &priv->gfargrp[grp_idx]; - tstat = tstat | (TSTAT_CLEAR_THALT >> i); - tqueue = tqueue | (TQUEUE_EN0 >> i); + tstat = tstat | (TSTAT_CLEAR_THALT >>QADJ (i)); + tqueue = tqueue | (TQUEUE_EN0 >>QADJ (i)); } priv->gfargrp[grp_idx].rstat = rstat; priv->gfargrp[grp_idx].tstat = tstat;
@@ -2247,7 +2250,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) }/* Tell the DMA to go go go */ -gfar_write (®s->tstat,TSTAT_CLEAR_THALT >> tx_queue->qindex); +gfar_write (®s->tstat,TSTAT_CLEAR_THALT >>QADJ (tx_queue->qindex));/* Unlock priv */ spin_unlock_irqrestore (&tx_queue->txlock, flags);
Signature · 1 line
1.7.2.5
RFC 2/4 gianfar: reserve the first receive queue
In reply to Richard CochranThis commit adjusts the code to use the second hardware receive queue. The idea is to keep the first queue open for later use as a fast path for real time Ethernet packets.
Note that this patch relies on the specific filer capabilities of eTSEC version 1.2 (like in the p2020) and probably will not work on later versions (like in the p1020), since Freescale keeps changing their hardware interfaces.
--- drivers/net/gianfar.c | 85 +++------------------ drivers/net/gianfar.h | 14 ++- drivers/net/gianfar_ethtool.c | 163 +---------------------------------------- 3 files changed, 23 insertions(+), 239 deletions(-)
drivers/net/gianfar.c +12 -73
@@ -340,7 +340,7 @@ static void gfar_init_tx_rx_base(struct gfar_private *priv) baddr +=2 ; } - baddr = ®s->rbase0; + baddr = ®s->rbase1;for (i =0 ; i < priv->num_rx_queues; i++) {gfar_write (baddr, priv->rx_queue[i]->rx_bd_dma_base); baddr +=2 ;
@@ -361,11 +361,8 @@ static void gfar_init_mac(struct net_device *ndev)/* Configure the coalescing support */ gfar_configure_coalescing (priv,0xFF ,0xFF ); -if (priv->rx_filer_enable) { - rctrl |=RCTRL_FILREN ; -/* Program the RIR0 reg with the required distribution */ -gfar_write (®s->rir0,DEFAULT_RIR0 ); - } +/* Enable the filer to allow packets into the second Rx queue. */ + rctrl |=RCTRL_FILREN |RCTRL_PRSDEP_L2 ;if (priv->rx_csum_enable) rctrl |=RCTRL_CHECKSUMMING ;
@@ -479,9 +476,6 @@ static const struct net_device_ops gfar_netdev_ops = {#endif }; -unsigned int ftp_rqfpr[MAX_FILER_IDX +1 ]; -unsigned int ftp_rqfcr[MAX_FILER_IDX +1 ]; -void lock_rx_qs (struct gfar_private *priv) {int i =0x0 ;
@@ -865,71 +859,16 @@ static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs)return new_bit_map; } -static u32 cluster_entry_per_class (struct gfar_private *priv,u32 rqfar, -u32 class) -{ -u32 rqfpr =FPR_FILER_MASK ; -u32 rqfcr =0x0 ; - - rqfar--; - rqfcr =RQFCR_CLE |RQFCR_PID_MASK |RQFCR_CMP_EXACT ; - ftp_rqfpr[rqfar] = rqfpr; - ftp_rqfcr[rqfar] = rqfcr; -gfar_write_filer (priv, rqfar, rqfcr, rqfpr); - - rqfar--; - rqfcr =RQFCR_CMP_NOMATCH ; - ftp_rqfpr[rqfar] = rqfpr; - ftp_rqfcr[rqfar] = rqfcr; -gfar_write_filer (priv, rqfar, rqfcr, rqfpr); - - rqfar--; - rqfcr =RQFCR_CMP_EXACT |RQFCR_PID_PARSE |RQFCR_CLE |RQFCR_AND ; - rqfpr = class; - ftp_rqfcr[rqfar] = rqfcr; - ftp_rqfpr[rqfar] = rqfpr; -gfar_write_filer (priv, rqfar, rqfcr, rqfpr); - - rqfar--; - rqfcr =RQFCR_CMP_EXACT |RQFCR_PID_MASK |RQFCR_AND ; - rqfpr = class; - ftp_rqfcr[rqfar] = rqfcr; - ftp_rqfpr[rqfar] = rqfpr; -gfar_write_filer (priv, rqfar, rqfcr, rqfpr); - -return rqfar; -} -static void gfar_init_filer_table (struct gfar_private *priv) { -int i =0x0 ; -u32 rqfar =MAX_FILER_IDX ; -u32 rqfcr =0x0 ; -u32 rqfpr =FPR_FILER_MASK ; - -/* Default rule */ - rqfcr =RQFCR_CMP_MATCH ; - ftp_rqfcr[rqfar] = rqfcr; - ftp_rqfpr[rqfar] = rqfpr; -gfar_write_filer (priv, rqfar, rqfcr, rqfpr); - - rqfar =cluster_entry_per_class (priv, rqfar,RQFPR_IPV6 ); - rqfar =cluster_entry_per_class (priv, rqfar,RQFPR_IPV6 |RQFPR_UDP ); - rqfar =cluster_entry_per_class (priv, rqfar,RQFPR_IPV6 |RQFPR_TCP ); - rqfar =cluster_entry_per_class (priv, rqfar,RQFPR_IPV4 ); - rqfar =cluster_entry_per_class (priv, rqfar,RQFPR_IPV4 |RQFPR_UDP ); - rqfar =cluster_entry_per_class (priv, rqfar,RQFPR_IPV4 |RQFPR_TCP ); - -/* cur_filer_idx indicated the first non-masked rule */ - priv->cur_filer_idx = rqfar; - -/* Rest are masked rules */ - rqfcr =RQFCR_CMP_NOMATCH ; -for (i =0 ; i < rqfar; i++) { - ftp_rqfcr[i] = rqfcr; - ftp_rqfpr[i] = rqfpr; +int i; +u32 rqfcr =RQFCR_QUEUE_1 |RQFCR_CMP_MATCH ; +u32 rqfpr =0 ; +/* +* By default, deliver all packets to the second queue. +*/ +for (i =0 ; i <MAX_FILER_IDX ; i++)gfar_write_filer (priv, i, rqfcr, rqfpr); - } }static void gfar_detect_errata (struct gfar_private *priv)
@@ -1116,8 +1055,8 @@ static int gfar_probe(struct platform_device *ofdev, priv->num_rx_queues) { priv->gfargrp[grp_idx].num_rx_queues++; priv->rx_queue[i]->grp = &priv->gfargrp[grp_idx]; - rstat = rstat | (RSTAT_CLEAR_RHALT >> i); - rqueue = rqueue | ((RQUEUE_EN0 |RQUEUE_EX0 ) >> i); + rstat = rstat | (RSTAT_CLEAR_RHALT >>QADJ (i)); + rqueue = rqueue | ((RQUEUE_EN0 |RQUEUE_EX0 ) >>QADJ (i)); } priv->gfargrp[grp_idx].num_tx_queues =0x0 ; for_each_set_bit(i, &priv->gfargrp[grp_idx].tx_bit_map,
drivers/net/gianfar.h +9 -5
@@ -271,6 +271,7 @@ extern const char gfar_driver_version[];#define RCTRL_TUCSEN 0x00000100#define RCTRL_PRSDEP_MASK 0x000000c0#define RCTRL_PRSDEP_INIT 0x000000c0 +#define RCTRL_PRSDEP_L2 0x00000040#define RCTRL_PROM 0x00000008#define RCTRL_EMEN 0x00000002#define RCTRL_REQ_PARSER (RCTRL_VLEX | RCTRL_IPCSEN | \
@@ -414,6 +415,14 @@ extern const char gfar_driver_version[];#define RQFCR_HASHTBL_2 0x00060000#define RQFCR_HASHTBL_3 0x00080000#define RQFCR_HASH 0x00010000 +#define RQFCR_QUEUE_7 0x00004000 +#define RQFCR_QUEUE_6 0x00003000 +#define RQFCR_QUEUE_5 0x00002000 +#define RQFCR_QUEUE_4 0x00001000 +#define RQFCR_QUEUE_3 0x00000C00 +#define RQFCR_QUEUE_2 0x00000800 +#define RQFCR_QUEUE_1 0x00000400 +#define RQFCR_QUEUE_0 0x00000000#define RQFCR_CLE 0x00000200#define RQFCR_RJE 0x00000100#define RQFCR_AND 0x00000080
@@ -1066,8 +1075,6 @@ struct gfar_private {unsigned int rx_stash_size;unsigned int rx_stash_index; -u32 cur_filer_idx; -struct sk_buff_head rx_recycle;struct vlan_group *vlgrp;
@@ -1115,9 +1122,6 @@ struct gfar_private {int hwts_tx_en; }; -extern unsigned int ftp_rqfpr[MAX_FILER_IDX +1 ]; -extern unsigned int ftp_rqfcr[MAX_FILER_IDX +1 ]; -static inline int gfar_has_errata (struct gfar_private *priv,enum gfar_errata err) {
drivers/net/gianfar_ethtool.c +2 -161
171 lines not on this page · raw message
Signature · 1 line
1.7.2.5
RFC 3/4 Add a real time module for the gianfar driver.
In reply to Richard CochranThis commit adds support for the xenomai packet interface to the gianfar driver. Only the transmit path is implemented.
--- drivers/net/Makefile | 5 + drivers/net/gianfar.c | 20 +-- drivers/net/gianfar.h | 74 +++++++++++ drivers/net/gianfar_rt.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 399 insertions(+), 14 deletions(-) create mode 100644 drivers/net/gianfar_rt.c
drivers/net/Makefile +5 -0
@@ -40,6 +40,11 @@ gianfar_driver-objs := gianfar.o \ gianfar_ethtool.o \ gianfar_sysfs.o +ifeq ($(CONFIG_XENOMAI),y) +EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai +gianfar_driver-objs += gianfar_rt.o +endif + obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o
drivers/net/gianfar.c +6 -14
@@ -1071,6 +1071,8 @@ static int gfar_probe(struct platform_device *ofdev, rstat = tstat =0 ; } + tqueue |=TQUEUE_EN0 ;/* Enable real time Tx queue. */ +gfar_write (®s->rqueue, rqueue);gfar_write (®s->tqueue, tqueue);
@@ -1166,6 +1168,8 @@ static int gfar_probe(struct platform_device *ofdev,printk (KERN_INFO "%s: TX BD ring size for Q[%d]: %d\n" , dev->name, i, priv->tx_queue[i]->tx_ring_size); +gfar_rt_init (priv); +return 0 ; register_fail:
@@ -1195,6 +1199,8 @@ static int gfar_remove(struct platform_device *ofdev)unmap_group_regs (priv);free_netdev (priv->ndev); +gfar_rt_cleanup (priv); +return 0 ; }
@@ -1961,20 +1967,6 @@ void inline gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb) fcb->vlctl =vlan_tx_tag_get (skb); } -static inline struct txbd8 *skip_txbd (struct txbd8 *bdp,int stride, -struct txbd8 *base,int ring_size) -{ -struct txbd8 *new_bd = bdp + stride; - -return (new_bd >= (base + ring_size)) ? (new_bd - ring_size) : new_bd; -} - -static inline struct txbd8 *next_txbd (struct txbd8 *bdp,struct txbd8 *base, -int ring_size) -{ -return skip_txbd (bdp,1 , base, ring_size); -} -/* This is called by the kernel when a frame is ready for transmission. */ /* It is pointed to by the dev->hard_start_xmit function pointer */ static int gfar_start_xmit (struct sk_buff *skb,struct net_device *dev)
drivers/net/gianfar.h +74 -0
102 lines not on this page · raw message
drivers/net/gianfar_rt.c new file +314 -0
314 lines not on this page · raw message
Signature · 1 line
1.7.2.5
RFC 4/4 Add a real time packet reception to the gianfar driver.
In reply to Richard CochranThis commit completes the support for the xenomai packet interface in the gianfar driver.
--- drivers/net/gianfar.c | 4 +++ drivers/net/gianfar.h | 2 + drivers/net/gianfar_rt.c | 60 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 62 insertions(+), 4 deletions(-)
drivers/net/gianfar.c +4 -0
@@ -1072,6 +1072,7 @@ static int gfar_probe(struct platform_device *ofdev, } tqueue |=TQUEUE_EN0 ;/* Enable real time Tx queue. */ + rqueue |= (RQUEUE_EN0 |RQUEUE_EX0 );gfar_write (®s->rqueue, rqueue);gfar_write (®s->tqueue, tqueue);
@@ -2749,6 +2750,9 @@ static int gfar_poll(struct napi_struct *napi, int budget)* because of the packets that have already arrived */ gfar_write (®s->ievent,IEVENT_RTX_MASK ); +gfar_rt_clean_tx_ring (priv); +gfar_rt_clean_rx_ring (priv); +while (num_queues && left_over_budget) { budget_per_queue = left_over_budget/num_queues;
drivers/net/gianfar.h +2 -0
@@ -1232,10 +1232,12 @@ extern const struct ethtool_ops gfar_ethtool_ops;#ifdef CONFIG_XENOMAI extern void gfar_rt_clean_tx_ring (struct gfar_private *priv); +extern void gfar_rt_clean_rx_ring (struct gfar_private *priv);extern void gfar_rt_init (struct gfar_private *priv);extern void gfar_rt_cleanup (struct gfar_private *priv);#else static inline void gfar_rt_clean_tx_ring (struct gfar_private *priv) {} +static inline void gfar_rt_clean_rx_ring (struct gfar_private *priv) {}static inline void gfar_rt_init (struct gfar_private *priv) {}static inline void gfar_rt_cleanup (struct gfar_private *priv) {}#endif
drivers/net/gianfar_rt.c +56 -4
96 lines not on this page · raw message
Signature · 1 line
1.7.2.5