kernel: rewrite the phy packet hook, put it in the network stack to avoid having to keep non-upstream ethernet driver changes
SVN-Revision: 31637
This commit is contained in:
		| @@ -1,70 +0,0 @@ | ||||
| --- a/drivers/net/ethernet/ti/cpmac.c | ||||
| +++ b/drivers/net/ethernet/ti/cpmac.c | ||||
| @@ -373,6 +373,7 @@ static struct sk_buff *cpmac_rx_one(stru | ||||
|  				    struct cpmac_desc *desc) | ||||
|  { | ||||
|  	struct sk_buff *skb, *result = NULL; | ||||
| +	int offset; | ||||
|   | ||||
|  	if (unlikely(netif_msg_hw(priv))) | ||||
|  		cpmac_dump_desc(priv->dev, desc); | ||||
| @@ -384,10 +385,15 @@ static struct sk_buff *cpmac_rx_one(stru | ||||
|  		return NULL; | ||||
|  	} | ||||
|   | ||||
| -	skb = netdev_alloc_skb_ip_align(priv->dev, CPMAC_SKB_SIZE); | ||||
| +	skb = netdev_alloc_skb(priv->dev, CPMAC_SKB_SIZE); | ||||
|  	if (likely(skb)) { | ||||
| +		offset = 2; | ||||
| +		if (priv->phy) { | ||||
| +			offset += priv->phy->pkt_align; | ||||
| +		} | ||||
| +		skb_reserve(skb, offset); | ||||
| + | ||||
|  		skb_put(desc->skb, desc->datalen); | ||||
| -		desc->skb->protocol = eth_type_trans(desc->skb, priv->dev); | ||||
|  		skb_checksum_none_assert(desc->skb); | ||||
|  		priv->dev->stats.rx_packets++; | ||||
|  		priv->dev->stats.rx_bytes += desc->datalen; | ||||
| @@ -459,7 +465,12 @@ static int cpmac_poll(struct napi_struct | ||||
|   | ||||
|  		skb = cpmac_rx_one(priv, desc); | ||||
|  		if (likely(skb)) { | ||||
| -			netif_receive_skb(skb); | ||||
| +			if (priv->phy->netif_receive_skb) { | ||||
| +				priv->phy->netif_receive_skb(skb); | ||||
| +			} else { | ||||
| +				skb->protocol = eth_type_trans(skb, priv->dev); | ||||
| +				netif_receive_skb(skb); | ||||
| +			} | ||||
|  			received++; | ||||
|  		} | ||||
|  		desc = desc->next; | ||||
| @@ -952,7 +963,7 @@ static void cpmac_adjust_link(struct net | ||||
|   | ||||
|  static int cpmac_open(struct net_device *dev) | ||||
|  { | ||||
| -	int i, size, res; | ||||
| +	int i, size, res, offset; | ||||
|  	struct cpmac_priv *priv = netdev_priv(dev); | ||||
|  	struct resource *mem; | ||||
|  	struct cpmac_desc *desc; | ||||
| @@ -991,11 +1002,17 @@ static int cpmac_open(struct net_device | ||||
|   | ||||
|  	priv->rx_head = &priv->desc_ring[CPMAC_QUEUES]; | ||||
|  	for (i = 0, desc = priv->rx_head; i < priv->ring_size; i++, desc++) { | ||||
| -		skb = netdev_alloc_skb_ip_align(dev, CPMAC_SKB_SIZE); | ||||
| +		skb = netdev_alloc_skb(dev, CPMAC_SKB_SIZE); | ||||
|  		if (unlikely(!skb)) { | ||||
|  			res = -ENOMEM; | ||||
|  			goto fail_desc; | ||||
|  		} | ||||
| +		offset = 2; | ||||
| +		if (priv->phy) { | ||||
| +			offset += priv->phy->pkt_align; | ||||
| +		} | ||||
| +		skb_reserve(skb, offset); | ||||
| + | ||||
|  		desc->skb = skb; | ||||
|  		desc->data_mapping = dma_map_single(&dev->dev, skb->data, | ||||
|  						    CPMAC_SKB_SIZE, | ||||
| @@ -102,6 +102,7 @@ CONFIG_CSRC_R4K_LIB=y | ||||
| CONFIG_DECOMPRESS_LZMA=y | ||||
| CONFIG_DMA_NONCOHERENT=y | ||||
| CONFIG_EARLY_PRINTK=y | ||||
| CONFIG_ETHERNET_PACKET_MANGLE=y | ||||
| CONFIG_GENERIC_ATOMIC64=y | ||||
| CONFIG_GENERIC_CLOCKEVENTS=y | ||||
| CONFIG_GENERIC_CLOCKEVENTS_BUILD=y | ||||
|   | ||||
| @@ -196,28 +196,24 @@ static void ag71xx_ring_rx_clean(struct ag71xx *ag) | ||||
| 		} | ||||
| } | ||||
|  | ||||
| static int ag71xx_rx_reserve(struct ag71xx *ag) | ||||
| struct sk_buff *ag71xx_rx_alloc(struct ag71xx *ag) | ||||
| { | ||||
| 	int reserve = 0; | ||||
| 	/* | ||||
| 	 * On AR71xx/AR91xx packets must be 4-byte aligned. | ||||
| 	 * | ||||
| 	 * When using builtin AR8216 support, hardware adds a 2-byte header, | ||||
| 	 * so we don't need any extra alignment in that case. | ||||
| 	 */ | ||||
| 	if (!ag71xx_get_pdata(ag)->is_ar724x || ag71xx_has_ar8216(ag)) | ||||
| 		return netdev_alloc_skb(ag->dev, AG71XX_RX_PKT_SIZE); | ||||
|  | ||||
| 	if (ag71xx_get_pdata(ag)->is_ar724x) { | ||||
| 		if (!ag71xx_has_ar8216(ag)) | ||||
| 			reserve = 2; | ||||
|  | ||||
| 		if (ag->phy_dev) | ||||
| 			reserve += 4 - (ag->phy_dev->pkt_align % 4); | ||||
|  | ||||
| 		reserve %= 4; | ||||
| 	} | ||||
|  | ||||
| 	return reserve + AG71XX_RX_PKT_RESERVE; | ||||
| 	return netdev_alloc_skb_ip_align(ag->dev, AG71XX_RX_PKT_SIZE); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int ag71xx_ring_rx_init(struct ag71xx *ag) | ||||
| { | ||||
| 	struct ag71xx_ring *ring = &ag->rx_ring; | ||||
| 	unsigned int reserve = ag71xx_rx_reserve(ag); | ||||
| 	unsigned int i; | ||||
| 	int ret; | ||||
|  | ||||
| @@ -235,15 +231,13 @@ static int ag71xx_ring_rx_init(struct ag71xx *ag) | ||||
| 		struct sk_buff *skb; | ||||
| 		dma_addr_t dma_addr; | ||||
|  | ||||
| 		skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE + reserve); | ||||
| 		skb = ag71xx_rx_alloc(ag); | ||||
| 		if (!skb) { | ||||
| 			ret = -ENOMEM; | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		skb->dev = ag->dev; | ||||
| 		skb_reserve(skb, reserve); | ||||
|  | ||||
| 		dma_addr = dma_map_single(&ag->dev->dev, skb->data, | ||||
| 					  AG71XX_RX_PKT_SIZE, | ||||
| 					  DMA_FROM_DEVICE); | ||||
| @@ -265,7 +259,6 @@ static int ag71xx_ring_rx_init(struct ag71xx *ag) | ||||
| static int ag71xx_ring_rx_refill(struct ag71xx *ag) | ||||
| { | ||||
| 	struct ag71xx_ring *ring = &ag->rx_ring; | ||||
| 	unsigned int reserve = ag71xx_rx_reserve(ag); | ||||
| 	unsigned int count; | ||||
|  | ||||
| 	count = 0; | ||||
| @@ -278,11 +271,10 @@ static int ag71xx_ring_rx_refill(struct ag71xx *ag) | ||||
| 			dma_addr_t dma_addr; | ||||
| 			struct sk_buff *skb; | ||||
|  | ||||
| 			skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE + reserve); | ||||
| 			skb = ag71xx_rx_alloc(ag); | ||||
| 			if (skb == NULL) | ||||
| 				break; | ||||
|  | ||||
| 			skb_reserve(skb, reserve); | ||||
| 			skb->dev = ag->dev; | ||||
|  | ||||
| 			dma_addr = dma_map_single(&ag->dev->dev, skb->data, | ||||
| @@ -914,13 +906,9 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) | ||||
| 		} else { | ||||
| 			skb->dev = dev; | ||||
| 			skb->ip_summed = CHECKSUM_NONE; | ||||
| 			if (ag->phy_dev) { | ||||
| 				ag->phy_dev->netif_receive_skb(skb); | ||||
| 			} else { | ||||
| 			skb->protocol = eth_type_trans(skb, dev); | ||||
| 			netif_receive_skb(skb); | ||||
| 		} | ||||
| 		} | ||||
|  | ||||
| 		ring->buf[i].skb = NULL; | ||||
| 		done++; | ||||
|   | ||||
| @@ -34,6 +34,7 @@ CONFIG_CSRC_R4K_LIB=y | ||||
| CONFIG_DECOMPRESS_LZMA=y | ||||
| CONFIG_DMA_NONCOHERENT=y | ||||
| CONFIG_EARLY_PRINTK=y | ||||
| CONFIG_ETHERNET_PACKET_MANGLE=y | ||||
| CONFIG_GENERIC_ATOMIC64=y | ||||
| CONFIG_GENERIC_CLOCKEVENTS=y | ||||
| CONFIG_GENERIC_CLOCKEVENTS_BUILD=y | ||||
|   | ||||
| @@ -32,7 +32,7 @@ | ||||
| +obj-$(CONFIG_NET_VENDOR_AR231X) += ar231x.o | ||||
| --- /dev/null | ||||
| +++ b/drivers/net/ethernet/ar231x/ar231x.c | ||||
| @@ -0,0 +1,1282 @@ | ||||
| @@ -0,0 +1,1279 @@ | ||||
| +/* | ||||
| + * ar231x.c: Linux driver for the Atheros AR231x Ethernet device. | ||||
| + * | ||||
| @@ -784,7 +784,7 @@ | ||||
| +		if (sp->rx_skb[idx]) | ||||
| +			break; | ||||
| + | ||||
| +		skb = netdev_alloc_skb(dev, AR2313_BUFSIZE); | ||||
| +		skb = netdev_alloc_skb_ip_align(dev, AR2313_BUFSIZE); | ||||
| +		if (!skb) { | ||||
| +			printk("\n\n\n\n %s: No memory in system\n\n\n\n", | ||||
| +				   __FUNCTION__); | ||||
| @@ -795,7 +795,6 @@ | ||||
| +		 * Make sure IP header starts on a fresh cache line. | ||||
| +		 */ | ||||
| +		skb->dev = dev; | ||||
| +		skb_reserve(skb, RX_OFFSET); | ||||
| +		sp->rx_skb[idx] = skb; | ||||
| + | ||||
| +		rd = (ar231x_descr_t *) & sp->rx_ring[idx]; | ||||
| @@ -867,7 +866,7 @@ | ||||
| + | ||||
| +		} else { | ||||
| +			/* alloc new buffer. */ | ||||
| +			skb_new = netdev_alloc_skb(dev, AR2313_BUFSIZE + RX_OFFSET); | ||||
| +			skb_new = netdev_alloc_skb_ip_align(dev, AR2313_BUFSIZE); | ||||
| +			if (skb_new != NULL) { | ||||
| + | ||||
| +				skb = sp->rx_skb[idx]; | ||||
| @@ -881,8 +880,6 @@ | ||||
| +				netif_rx(skb); | ||||
| + | ||||
| +				skb_new->dev = dev; | ||||
| +				/* 16 bit align */ | ||||
| +				skb_reserve(skb_new, RX_OFFSET); | ||||
| +				/* reset descriptor's curr_addr */ | ||||
| +				rxdesc->addr = virt_to_phys(skb_new->data); | ||||
| + | ||||
|   | ||||
| @@ -1,70 +0,0 @@ | ||||
| --- a/drivers/net/ethernet/ar231x/ar231x.c | ||||
| +++ b/drivers/net/ethernet/ar231x/ar231x.c | ||||
| @@ -745,6 +745,7 @@ static void ar231x_load_rx_ring(struct n | ||||
|  	for (i = 0; i < nr_bufs; i++) { | ||||
|  		struct sk_buff *skb; | ||||
|  		ar231x_descr_t *rd; | ||||
| +		int offset = RX_OFFSET; | ||||
|   | ||||
|  		if (sp->rx_skb[idx]) | ||||
|  			break; | ||||
| @@ -760,7 +761,9 @@ static void ar231x_load_rx_ring(struct n | ||||
|  		 * Make sure IP header starts on a fresh cache line. | ||||
|  		 */ | ||||
|  		skb->dev = dev; | ||||
| -		skb_reserve(skb, RX_OFFSET); | ||||
| +		if (sp->phy_dev) | ||||
| +			offset += sp->phy_dev->pkt_align; | ||||
| +		skb_reserve(skb, offset); | ||||
|  		sp->rx_skb[idx] = skb; | ||||
|   | ||||
|  		rd = (ar231x_descr_t *) & sp->rx_ring[idx]; | ||||
| @@ -834,20 +837,23 @@ static int ar231x_rx_int(struct net_devi | ||||
|  			/* alloc new buffer. */ | ||||
|  			skb_new = netdev_alloc_skb(dev, AR2313_BUFSIZE + RX_OFFSET); | ||||
|  			if (skb_new != NULL) { | ||||
| +				int offset; | ||||
|   | ||||
|  				skb = sp->rx_skb[idx]; | ||||
|  				/* set skb */ | ||||
|  				skb_put(skb, | ||||
|  						((status >> DMA_RX_LEN_SHIFT) & 0x3fff) - CRC_LEN); | ||||
| - | ||||
|  				dev->stats.rx_bytes += skb->len; | ||||
| -				skb->protocol = eth_type_trans(skb, dev); | ||||
| -				/* pass the packet to upper layers */ | ||||
| -				netif_rx(skb); | ||||
|   | ||||
| +				/* pass the packet to upper layers */ | ||||
| +				sp->rx(skb); | ||||
|  				skb_new->dev = dev; | ||||
| + | ||||
|  				/* 16 bit align */ | ||||
| -				skb_reserve(skb_new, RX_OFFSET); | ||||
| +				offset = RX_OFFSET; | ||||
| +				if (sp->phy_dev) | ||||
| +					offset += sp->phy_dev->pkt_align; | ||||
| +				skb_reserve(skb_new, offset); | ||||
|  				/* reset descriptor's curr_addr */ | ||||
|  				rxdesc->addr = virt_to_phys(skb_new->data); | ||||
|   | ||||
| @@ -1258,6 +1264,8 @@ static int ar231x_mdiobus_probe (struct  | ||||
|  		return PTR_ERR(phydev); | ||||
|  	} | ||||
|   | ||||
| +	sp->rx = phydev->netif_rx; | ||||
| + | ||||
|  	/* mask with MAC supported features */ | ||||
|  	phydev->supported &= (SUPPORTED_10baseT_Half | ||||
|  		| SUPPORTED_10baseT_Full | ||||
| --- a/drivers/net/ethernet/ar231x/ar231x.h | ||||
| +++ b/drivers/net/ethernet/ar231x/ar231x.h | ||||
| @@ -222,6 +222,8 @@ typedef struct { | ||||
|   */ | ||||
|  struct ar231x_private { | ||||
|  	struct net_device *dev; | ||||
| +	int (*rx)(struct sk_buff *skb); | ||||
| + | ||||
|  	int version; | ||||
|  	u32 mb[2]; | ||||
|   | ||||
| @@ -43,21 +43,7 @@ | ||||
|  	kfree(dev); | ||||
|  	return 0; | ||||
|  } | ||||
| @@ -846,7 +864,12 @@ static int ar231x_rx_int(struct net_devi | ||||
|  				dev->stats.rx_bytes += skb->len; | ||||
|   | ||||
|  				/* pass the packet to upper layers */ | ||||
| -				sp->rx(skb); | ||||
| +				if (sp->rx) { | ||||
| +					sp->rx(skb); | ||||
| +				} else { | ||||
| +					skb->protocol = eth_type_trans(skb, skb->dev); | ||||
| +					netif_rx(skb); | ||||
| +				} | ||||
|  				skb_new->dev = dev; | ||||
|   | ||||
|  				/* 16 bit align */ | ||||
| @@ -1142,6 +1165,9 @@ static int ar231x_ioctl(struct net_devic | ||||
| @@ -1133,6 +1151,9 @@ static int ar231x_ioctl(struct net_devic | ||||
|  	struct ar231x_private *sp = netdev_priv(dev); | ||||
|  	int ret; | ||||
|   | ||||
|   | ||||
| @@ -221,8 +221,8 @@ ar8216_read_port_link(struct ar8216_priv *priv, int port, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int | ||||
| ar8216_mangle_tx(struct sk_buff *skb, struct net_device *dev) | ||||
| static struct sk_buff * | ||||
| ar8216_mangle_tx(struct net_device *dev, struct sk_buff *skb) | ||||
| { | ||||
| 	struct ar8216_priv *priv = dev->phy_ptr; | ||||
| 	unsigned char *buf; | ||||
| @@ -243,32 +243,27 @@ ar8216_mangle_tx(struct sk_buff *skb, struct net_device *dev) | ||||
| 	buf[1] = 0x80; | ||||
|  | ||||
| send: | ||||
| 	return priv->ndo_old->ndo_start_xmit(skb, dev); | ||||
| 	return skb; | ||||
|  | ||||
| error: | ||||
| 	dev_kfree_skb_any(skb); | ||||
| 	return 0; | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| static int | ||||
| ar8216_mangle_rx(struct sk_buff *skb, int napi) | ||||
| static void | ||||
| ar8216_mangle_rx(struct net_device *dev, struct sk_buff *skb) | ||||
| { | ||||
| 	struct ar8216_priv *priv; | ||||
| 	struct net_device *dev; | ||||
| 	unsigned char *buf; | ||||
| 	int port, vlan; | ||||
|  | ||||
| 	dev = skb->dev; | ||||
| 	if (!dev) | ||||
| 		goto error; | ||||
|  | ||||
| 	priv = dev->phy_ptr; | ||||
| 	if (!priv) | ||||
| 		goto error; | ||||
| 		return; | ||||
|  | ||||
| 	/* don't strip the header if vlan mode is disabled */ | ||||
| 	if (!priv->vlan) | ||||
| 		goto recv; | ||||
| 		return; | ||||
|  | ||||
| 	/* strip header, get vlan id */ | ||||
| 	buf = skb->data; | ||||
| @@ -276,13 +271,13 @@ ar8216_mangle_rx(struct sk_buff *skb, int napi) | ||||
|  | ||||
| 	/* check for vlan header presence */ | ||||
| 	if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00)) | ||||
| 		goto recv; | ||||
| 		return; | ||||
|  | ||||
| 	port = buf[0] & 0xf; | ||||
|  | ||||
| 	/* no need to fix up packets coming from a tagged source */ | ||||
| 	if (priv->vlan_tagged & (1 << port)) | ||||
| 		goto recv; | ||||
| 		return; | ||||
|  | ||||
| 	/* lookup port vid from local table, the switch passes an invalid vlan id */ | ||||
| 	vlan = priv->vlan_id[priv->pvid[port]]; | ||||
| @@ -290,31 +285,6 @@ ar8216_mangle_rx(struct sk_buff *skb, int napi) | ||||
| 	buf[14 + 2] &= 0xf0; | ||||
| 	buf[14 + 2] |= vlan >> 8; | ||||
| 	buf[15 + 2] = vlan & 0xff; | ||||
|  | ||||
| recv: | ||||
| 	skb->protocol = eth_type_trans(skb, skb->dev); | ||||
|  | ||||
| 	if (napi) | ||||
| 		return netif_receive_skb(skb); | ||||
| 	else | ||||
| 		return netif_rx(skb); | ||||
|  | ||||
| error: | ||||
| 	/* no vlan? eat the packet! */ | ||||
| 	dev_kfree_skb_any(skb); | ||||
| 	return NET_RX_DROP; | ||||
| } | ||||
|  | ||||
| static int | ||||
| ar8216_netif_rx(struct sk_buff *skb) | ||||
| { | ||||
| 	return ar8216_mangle_rx(skb, 0); | ||||
| } | ||||
|  | ||||
| static int | ||||
| ar8216_netif_receive_skb(struct sk_buff *skb) | ||||
| { | ||||
| 	return ar8216_mangle_rx(skb, 1); | ||||
| } | ||||
|  | ||||
| static int | ||||
| @@ -1356,13 +1326,9 @@ ar8216_config_init(struct phy_device *pdev) | ||||
|  | ||||
| 	/* VID fixup only needed on ar8216 */ | ||||
| 	if (pdev->addr == 0 && priv->chip_type == AR8216) { | ||||
| 		pdev->pkt_align = 2; | ||||
| 		pdev->netif_receive_skb = ar8216_netif_receive_skb; | ||||
| 		pdev->netif_rx = ar8216_netif_rx; | ||||
| 		priv->ndo_old = dev->netdev_ops; | ||||
| 		memcpy(&priv->ndo, priv->ndo_old, sizeof(struct net_device_ops)); | ||||
| 		priv->ndo.ndo_start_xmit = ar8216_mangle_tx; | ||||
| 		dev->netdev_ops = &priv->ndo; | ||||
| 		dev->priv_flags |= IFF_NO_IP_ALIGN; | ||||
| 		dev->eth_mangle_rx = ar8216_mangle_rx; | ||||
| 		dev->eth_mangle_tx = ar8216_mangle_tx; | ||||
| 	} | ||||
|  | ||||
| 	priv->init = false; | ||||
| @@ -1443,8 +1409,10 @@ ar8216_remove(struct phy_device *pdev) | ||||
| 	if (!priv) | ||||
| 		return; | ||||
|  | ||||
| 	if (priv->ndo_old && dev) | ||||
| 		dev->netdev_ops = priv->ndo_old; | ||||
| 	dev->priv_flags &= ~IFF_NO_IP_ALIGN; | ||||
| 	dev->eth_mangle_rx = NULL; | ||||
| 	dev->eth_mangle_tx = NULL; | ||||
|  | ||||
| 	if (pdev->addr == 0) | ||||
| 		unregister_switch(&priv->dev); | ||||
| 	kfree(priv); | ||||
|   | ||||
| @@ -41,8 +41,7 @@ MODULE_LICENSE("GPL"); | ||||
| #define MVSWITCH_MAGIC 0x88E6060 | ||||
|  | ||||
| struct mvswitch_priv { | ||||
| 	const struct net_device_ops *ndo_old; | ||||
| 	struct net_device_ops ndo; | ||||
| 	netdev_features_t orig_features; | ||||
| 	u8 vlans[16]; | ||||
| }; | ||||
|  | ||||
| @@ -61,8 +60,8 @@ w16(struct phy_device *phydev, int addr, int reg, u16 val) | ||||
| } | ||||
|  | ||||
|  | ||||
| static int | ||||
| mvswitch_mangle_tx(struct sk_buff *skb, struct net_device *dev) | ||||
| static struct sk_buff * | ||||
| mvswitch_mangle_tx(struct net_device *dev, struct sk_buff *skb) | ||||
| { | ||||
| 	struct mvswitch_priv *priv; | ||||
| 	char *buf = NULL; | ||||
| @@ -132,7 +131,7 @@ mvswitch_mangle_tx(struct sk_buff *skb, struct net_device *dev) | ||||
| 	)); | ||||
| #endif | ||||
|  | ||||
| 	return priv->ndo_old->ndo_start_xmit(skb, dev); | ||||
| 	return skb; | ||||
|  | ||||
| error_expand: | ||||
| 	if (net_ratelimit()) | ||||
| @@ -141,25 +140,20 @@ error_expand: | ||||
| error: | ||||
| 	/* any errors? drop the packet! */ | ||||
| 	dev_kfree_skb_any(skb); | ||||
| 	return 0; | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| static int | ||||
| mvswitch_mangle_rx(struct sk_buff *skb, int napi) | ||||
| static void | ||||
| mvswitch_mangle_rx(struct net_device *dev, struct sk_buff *skb) | ||||
| { | ||||
| 	struct mvswitch_priv *priv; | ||||
| 	struct net_device *dev; | ||||
| 	int vlan = -1; | ||||
| 	unsigned char *buf; | ||||
| 	int vlan = -1; | ||||
| 	int i; | ||||
|  | ||||
| 	dev = skb->dev; | ||||
| 	if (!dev) | ||||
| 		goto error; | ||||
|  | ||||
| 	priv = dev->phy_ptr; | ||||
| 	if (!priv) | ||||
| 		goto error; | ||||
| 	if (WARN_ON_ONCE(!priv)) | ||||
| 		return; | ||||
|  | ||||
| #ifdef HEADER_MODE | ||||
| 	buf = skb->data; | ||||
| @@ -167,7 +161,7 @@ mvswitch_mangle_rx(struct sk_buff *skb, int napi) | ||||
| #else | ||||
| 	buf = skb->data + skb->len - MV_TRAILER_SIZE; | ||||
| 	if (buf[0] != 0x80) | ||||
| 		goto error; | ||||
| 		return; | ||||
| #endif | ||||
|  | ||||
| 	/* look for the vlan matching the incoming port */ | ||||
| @@ -177,33 +171,9 @@ mvswitch_mangle_rx(struct sk_buff *skb, int napi) | ||||
| 	} | ||||
|  | ||||
| 	if (vlan == -1) | ||||
| 		goto error; | ||||
|  | ||||
| 	skb->protocol = eth_type_trans(skb, skb->dev); | ||||
| 		return; | ||||
|  | ||||
| 	__vlan_hwaccel_put_tag(skb, vlan); | ||||
| 	if (napi) | ||||
| 		return netif_receive_skb(skb); | ||||
| 	else | ||||
| 		return netif_rx(skb); | ||||
|  | ||||
| error: | ||||
| 	/* no vlan? eat the packet! */ | ||||
| 	dev_kfree_skb_any(skb); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int | ||||
| mvswitch_netif_rx(struct sk_buff *skb) | ||||
| { | ||||
| 	return mvswitch_mangle_rx(skb, 0); | ||||
| } | ||||
|  | ||||
| static int | ||||
| mvswitch_netif_receive_skb(struct sk_buff *skb) | ||||
| { | ||||
| 	return mvswitch_mangle_rx(skb, 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -331,16 +301,12 @@ mvswitch_config_init(struct phy_device *pdev) | ||||
| 		MV_SWITCHCTL_DROP | ||||
| 	); | ||||
|  | ||||
| 	/* hook into the tx function */ | ||||
| 	priv->ndo_old = dev->netdev_ops; | ||||
| 	memcpy(&priv->ndo, priv->ndo_old, sizeof(struct net_device_ops)); | ||||
| 	priv->ndo.ndo_start_xmit = mvswitch_mangle_tx; | ||||
| 	dev->netdev_ops = &priv->ndo; | ||||
| 	dev->eth_mangle_rx = mvswitch_mangle_rx; | ||||
| 	dev->eth_mangle_tx = mvswitch_mangle_tx; | ||||
| 	priv->orig_features = dev->features; | ||||
|  | ||||
| 	pdev->pkt_align = 2; | ||||
| 	pdev->netif_receive_skb = mvswitch_netif_receive_skb; | ||||
| 	pdev->netif_rx = mvswitch_netif_rx; | ||||
| #ifdef HEADER_MODE | ||||
| 	dev->priv_flags |= IFF_NO_IP_ALIGN; | ||||
| 	dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX; | ||||
| #else | ||||
| 	dev->features |= NETIF_F_HW_VLAN_RX; | ||||
| @@ -387,11 +353,11 @@ mvswitch_remove(struct phy_device *pdev) | ||||
| 	struct mvswitch_priv *priv = to_mvsw(pdev); | ||||
| 	struct net_device *dev = pdev->attached_dev; | ||||
|  | ||||
| 	/* restore old netdev ops */ | ||||
| 	if (priv->ndo_old && dev) | ||||
| 		dev->netdev_ops = priv->ndo_old; | ||||
| 	dev->phy_ptr = NULL; | ||||
| 	dev->features &= ~NETIF_F_HW_VLAN_RX; | ||||
| 	dev->eth_mangle_rx = NULL; | ||||
| 	dev->eth_mangle_tx = NULL; | ||||
| 	dev->features = priv->orig_features; | ||||
| 	dev->priv_flags &= ~IFF_NO_IP_ALIGN; | ||||
| 	kfree(priv); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,63 +1,167 @@ | ||||
| --- a/drivers/net/phy/phy_device.c | ||||
| +++ b/drivers/net/phy/phy_device.c | ||||
| @@ -149,6 +149,18 @@ int phy_scan_fixups(struct phy_device *p | ||||
|  } | ||||
|  EXPORT_SYMBOL(phy_scan_fixups); | ||||
|   | ||||
| +static int generic_receive_skb(struct sk_buff *skb) | ||||
| +{ | ||||
| +	skb->protocol = eth_type_trans(skb, skb->dev); | ||||
| +	return netif_receive_skb(skb); | ||||
| +} | ||||
| + | ||||
| +static int generic_rx(struct sk_buff *skb) | ||||
| +{ | ||||
| +	skb->protocol = eth_type_trans(skb, skb->dev); | ||||
| +	return netif_rx(skb); | ||||
| +} | ||||
| + | ||||
|  static struct phy_device* phy_device_create(struct mii_bus *bus, | ||||
|  					    int addr, int phy_id) | ||||
|  { | ||||
| @@ -180,6 +192,8 @@ static struct phy_device* phy_device_cre | ||||
|  	dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr); | ||||
|   | ||||
|  	dev->state = PHY_DOWN; | ||||
| +	dev->netif_receive_skb = &generic_receive_skb; | ||||
| +	dev->netif_rx = &generic_rx; | ||||
|   | ||||
|  	mutex_init(&dev->lock); | ||||
|  	INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); | ||||
| --- a/include/linux/phy.h | ||||
| +++ b/include/linux/phy.h | ||||
| @@ -334,6 +334,20 @@ struct phy_device { | ||||
|  	void (*adjust_link)(struct net_device *dev); | ||||
|   | ||||
|  	void (*adjust_state)(struct net_device *dev); | ||||
| + | ||||
| +	/* | ||||
| +	 * By default these point to the original functions | ||||
| +	 * with the same name. adding them to the phy_device | ||||
| +	 * allows the phy driver to override them for packet | ||||
| +	 * mangling if the ethernet driver supports it | ||||
| +	 * This is required to support some really horrible | ||||
| +	 * switches such as the Marvell 88E6060 | ||||
| +	 */ | ||||
| +	int (*netif_receive_skb)(struct sk_buff *skb); | ||||
| +	int (*netif_rx)(struct sk_buff *skb); | ||||
| + | ||||
| +	/* alignment offset for packets */ | ||||
| +	int pkt_align; | ||||
|  }; | ||||
|  #define to_phy_device(d) container_of(d, struct phy_device, dev) | ||||
|   | ||||
| --- a/include/linux/netdevice.h | ||||
| +++ b/include/linux/netdevice.h | ||||
| @@ -1158,6 +1158,7 @@ struct net_device { | ||||
| @@ -1103,6 +1103,11 @@ struct net_device { | ||||
|  	const struct net_device_ops *netdev_ops; | ||||
|  	const struct ethtool_ops *ethtool_ops; | ||||
|   | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE | ||||
| +	void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb); | ||||
| +	struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb); | ||||
| +#endif | ||||
| + | ||||
|  	/* Hardware header description */ | ||||
|  	const struct header_ops *header_ops; | ||||
|   | ||||
| @@ -1158,6 +1163,9 @@ struct net_device { | ||||
|  	void			*ax25_ptr;	/* AX.25 specific data */ | ||||
|  	struct wireless_dev	*ieee80211_ptr;	/* IEEE 802.11 specific data, | ||||
|  						   assign before registering */ | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE | ||||
| +	void			*phy_ptr; /* PHY device specific data */ | ||||
| +#endif | ||||
|   | ||||
|  /* | ||||
|   * Cache lines mostly used on receive path (including eth_type_trans()) | ||||
| --- a/include/linux/if.h | ||||
| +++ b/include/linux/if.h | ||||
| @@ -79,6 +79,7 @@ | ||||
|  #define IFF_TX_SKB_SHARING	0x10000	/* The interface supports sharing | ||||
|  					 * skbs on transmit */ | ||||
|  #define IFF_UNICAST_FLT	0x20000		/* Supports unicast filtering	*/ | ||||
| +#define IFF_NO_IP_ALIGN	0x40000		/* do not ip-align allocated rx pkts */ | ||||
|   | ||||
|  #define IF_GET_IFACE	0x0001		/* for querying only */ | ||||
|  #define IF_GET_PROTO	0x0002 | ||||
| --- a/include/linux/skbuff.h | ||||
| +++ b/include/linux/skbuff.h | ||||
| @@ -1636,6 +1636,10 @@ extern struct sk_buff *dev_alloc_skb(uns | ||||
|  extern struct sk_buff *__netdev_alloc_skb(struct net_device *dev, | ||||
|  		unsigned int length, gfp_t gfp_mask); | ||||
|   | ||||
| +extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, | ||||
| +		unsigned int length, gfp_t gfp); | ||||
| + | ||||
| + | ||||
|  /** | ||||
|   *	netdev_alloc_skb - allocate an skbuff for rx on a specific device | ||||
|   *	@dev: network device to receive on | ||||
| @@ -1655,16 +1659,6 @@ static inline struct sk_buff *netdev_all | ||||
|  	return __netdev_alloc_skb(dev, length, GFP_ATOMIC); | ||||
|  } | ||||
|   | ||||
| -static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, | ||||
| -		unsigned int length, gfp_t gfp) | ||||
| -{ | ||||
| -	struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); | ||||
| - | ||||
| -	if (NET_IP_ALIGN && skb) | ||||
| -		skb_reserve(skb, NET_IP_ALIGN); | ||||
| -	return skb; | ||||
| -} | ||||
| - | ||||
|  static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, | ||||
|  		unsigned int length) | ||||
|  { | ||||
| --- a/net/Kconfig | ||||
| +++ b/net/Kconfig | ||||
| @@ -23,6 +23,12 @@ menuconfig NET | ||||
|   | ||||
|  if NET | ||||
|   | ||||
| +config ETHERNET_PACKET_MANGLE | ||||
| +	bool | ||||
| +	help | ||||
| +	  This option can be selected by phy drivers that need to mangle | ||||
| +	  packets going in or out of an ethernet device. | ||||
| + | ||||
|  config WANT_COMPAT_NETLINK_MESSAGES | ||||
|  	bool | ||||
|  	help | ||||
| --- a/net/core/dev.c | ||||
| +++ b/net/core/dev.c | ||||
| @@ -2224,9 +2224,19 @@ int dev_hard_start_xmit(struct sk_buff * | ||||
|  			} | ||||
|  		} | ||||
|   | ||||
| -		skb_len = skb->len; | ||||
| -		rc = ops->ndo_start_xmit(skb, dev); | ||||
| -		trace_net_dev_xmit(skb, rc, dev, skb_len); | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE | ||||
| +		if (!dev->eth_mangle_tx || | ||||
| +		    (skb = dev->eth_mangle_tx(dev, skb)) != NULL) | ||||
| +#else | ||||
| +		if (1) | ||||
| +#endif | ||||
| +		{ | ||||
| +			skb_len = skb->len; | ||||
| +			rc = ops->ndo_start_xmit(skb, dev); | ||||
| +			trace_net_dev_xmit(skb, rc, dev, skb_len); | ||||
| +		} else { | ||||
| +			rc = NETDEV_TX_OK; | ||||
| +		} | ||||
|  		if (rc == NETDEV_TX_OK) | ||||
|  			txq_trans_update(txq); | ||||
|  		return rc; | ||||
| @@ -2246,9 +2256,19 @@ gso: | ||||
|  		if (dev->priv_flags & IFF_XMIT_DST_RELEASE) | ||||
|  			skb_dst_drop(nskb); | ||||
|   | ||||
| -		skb_len = nskb->len; | ||||
| -		rc = ops->ndo_start_xmit(nskb, dev); | ||||
| -		trace_net_dev_xmit(nskb, rc, dev, skb_len); | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE | ||||
| +		if (!dev->eth_mangle_tx || | ||||
| +		    (nskb = dev->eth_mangle_tx(dev, nskb)) != NULL) | ||||
| +#else | ||||
| +		if (1) | ||||
| +#endif | ||||
| +		{ | ||||
| +			skb_len = nskb->len; | ||||
| +			rc = ops->ndo_start_xmit(nskb, dev); | ||||
| +			trace_net_dev_xmit(nskb, rc, dev, skb_len); | ||||
| +		} else { | ||||
| +			rc = NETDEV_TX_OK; | ||||
| +		} | ||||
|  		if (unlikely(rc != NETDEV_TX_OK)) { | ||||
|  			if (rc & ~NETDEV_TX_MASK) | ||||
|  				goto out_kfree_gso_skb; | ||||
| --- a/net/core/skbuff.c | ||||
| +++ b/net/core/skbuff.c | ||||
| @@ -271,6 +271,22 @@ struct sk_buff *__netdev_alloc_skb(struc | ||||
|  } | ||||
|  EXPORT_SYMBOL(__netdev_alloc_skb); | ||||
|   | ||||
| +struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, | ||||
| +		unsigned int length, gfp_t gfp) | ||||
| +{ | ||||
| +	struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); | ||||
| + | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE | ||||
| +	if (dev->priv_flags & IFF_NO_IP_ALIGN) | ||||
| +		return skb; | ||||
| +#endif | ||||
| + | ||||
| +	if (NET_IP_ALIGN && skb) | ||||
| +		skb_reserve(skb, NET_IP_ALIGN); | ||||
| +	return skb; | ||||
| +} | ||||
| +EXPORT_SYMBOL(__netdev_alloc_skb_ip_align); | ||||
| + | ||||
|  void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, | ||||
|  		int size) | ||||
|  { | ||||
| --- a/net/ethernet/eth.c | ||||
| +++ b/net/ethernet/eth.c | ||||
| @@ -160,6 +160,12 @@ __be16 eth_type_trans(struct sk_buff *sk | ||||
|  	struct ethhdr *eth; | ||||
|   | ||||
|  	skb->dev = dev; | ||||
| + | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE | ||||
| +	if (dev->eth_mangle_rx) | ||||
| +		dev->eth_mangle_rx(dev, skb); | ||||
| +#endif | ||||
| + | ||||
|  	skb_reset_mac_header(skb); | ||||
|  	skb_pull_inline(skb, ETH_HLEN); | ||||
|  	eth = eth_hdr(skb); | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| --- a/drivers/net/phy/Kconfig | ||||
| +++ b/drivers/net/phy/Kconfig | ||||
| @@ -113,6 +113,9 @@ config ADM6996_PHY | ||||
| @@ -113,6 +113,10 @@ config ADM6996_PHY | ||||
|  	  Currently supports the ADM6996FC and ADM6996M switches. | ||||
|  	  Support for FC is very limited. | ||||
|   | ||||
| +config MVSWITCH_PHY | ||||
| +	tristate "Driver for Marvell 88E6060 switches" | ||||
| +	select ETHERNET_PACKET_MANGLE | ||||
| + | ||||
|  config FIXED_PHY | ||||
|  	bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| --- a/drivers/net/phy/Kconfig | ||||
| +++ b/drivers/net/phy/Kconfig | ||||
| @@ -116,6 +116,10 @@ config ADM6996_PHY | ||||
|  config MVSWITCH_PHY | ||||
| @@ -117,6 +117,10 @@ config MVSWITCH_PHY | ||||
|  	tristate "Driver for Marvell 88E6060 switches" | ||||
|  	select ETHERNET_PACKET_MANGLE | ||||
|   | ||||
| +config IP17XX_PHY | ||||
| +	tristate "Driver for IC+ IP17xx switches" | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| --- a/drivers/net/phy/Kconfig | ||||
| +++ b/drivers/net/phy/Kconfig | ||||
| @@ -120,6 +120,10 @@ config IP17XX_PHY | ||||
| @@ -121,6 +121,11 @@ config IP17XX_PHY | ||||
|  	tristate "Driver for IC+ IP17xx switches" | ||||
|  	select SWCONFIG | ||||
|   | ||||
| +config AR8216_PHY | ||||
| +	tristate "Driver for Atheros AR8216 switches" | ||||
| +	select ETHERNET_PACKET_MANGLE | ||||
| +	select SWCONFIG | ||||
| + | ||||
|  config FIXED_PHY | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| --- a/drivers/net/phy/Kconfig | ||||
| +++ b/drivers/net/phy/Kconfig | ||||
| @@ -124,6 +124,10 @@ config AR8216_PHY | ||||
|  	tristate "Driver for Atheros AR8216 switches" | ||||
| @@ -126,6 +126,10 @@ config AR8216_PHY | ||||
|  	select ETHERNET_PACKET_MANGLE | ||||
|  	select SWCONFIG | ||||
|   | ||||
| +config RTL8306_PHY | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| --- a/drivers/net/phy/Kconfig | ||||
| +++ b/drivers/net/phy/Kconfig | ||||
| @@ -166,4 +166,29 @@ config MDIO_OCTEON | ||||
| @@ -168,4 +168,29 @@ config MDIO_OCTEON | ||||
|   | ||||
|  	  If in doubt, say Y. | ||||
|   | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| --- a/drivers/net/phy/Kconfig | ||||
| +++ b/drivers/net/phy/Kconfig | ||||
| @@ -183,6 +183,10 @@ config RTL8366RB_PHY | ||||
| @@ -185,6 +185,10 @@ config RTL8366RB_PHY | ||||
|  	tristate "Driver for the Realtek RTL8366RB switch" | ||||
|  	select SWCONFIG | ||||
|   | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| --- a/drivers/net/phy/Kconfig | ||||
| +++ b/drivers/net/phy/Kconfig | ||||
| @@ -128,6 +128,11 @@ config RTL8306_PHY | ||||
| @@ -130,6 +130,11 @@ config RTL8306_PHY | ||||
|  	tristate "Driver for Realtek RTL8306S switches" | ||||
|  	select SWCONFIG | ||||
|   | ||||
|   | ||||
| @@ -1,63 +1,175 @@ | ||||
| --- a/drivers/net/phy/phy_device.c | ||||
| +++ b/drivers/net/phy/phy_device.c | ||||
| @@ -149,6 +149,18 @@ int phy_scan_fixups(struct phy_device *p | ||||
|  } | ||||
|  EXPORT_SYMBOL(phy_scan_fixups); | ||||
|   | ||||
| +static int generic_receive_skb(struct sk_buff *skb) | ||||
| +{ | ||||
| +	skb->protocol = eth_type_trans(skb, skb->dev); | ||||
| +	return netif_receive_skb(skb); | ||||
| +} | ||||
| + | ||||
| +static int generic_rx(struct sk_buff *skb) | ||||
| +{ | ||||
| +	skb->protocol = eth_type_trans(skb, skb->dev); | ||||
| +	return netif_rx(skb); | ||||
| +} | ||||
| + | ||||
|  static struct phy_device* phy_device_create(struct mii_bus *bus, | ||||
|  					    int addr, int phy_id) | ||||
|  { | ||||
| @@ -180,6 +192,8 @@ static struct phy_device* phy_device_cre | ||||
|  	dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr); | ||||
|   | ||||
|  	dev->state = PHY_DOWN; | ||||
| +	dev->netif_receive_skb = &generic_receive_skb; | ||||
| +	dev->netif_rx = &generic_rx; | ||||
|   | ||||
|  	mutex_init(&dev->lock); | ||||
|  	INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); | ||||
| --- a/include/linux/phy.h | ||||
| +++ b/include/linux/phy.h | ||||
| @@ -339,6 +339,20 @@ struct phy_device { | ||||
|  	void (*adjust_link)(struct net_device *dev); | ||||
|   | ||||
|  	void (*adjust_state)(struct net_device *dev); | ||||
| + | ||||
| +	/* | ||||
| +	 * By default these point to the original functions | ||||
| +	 * with the same name. adding them to the phy_device | ||||
| +	 * allows the phy driver to override them for packet | ||||
| +	 * mangling if the ethernet driver supports it | ||||
| +	 * This is required to support some really horrible | ||||
| +	 * switches such as the Marvell 88E6060 | ||||
| +	 */ | ||||
| +	int (*netif_receive_skb)(struct sk_buff *skb); | ||||
| +	int (*netif_rx)(struct sk_buff *skb); | ||||
| + | ||||
| +	/* alignment offset for packets */ | ||||
| +	int pkt_align; | ||||
|  }; | ||||
|  #define to_phy_device(d) container_of(d, struct phy_device, dev) | ||||
|   | ||||
| --- a/include/linux/netdevice.h | ||||
| +++ b/include/linux/netdevice.h | ||||
| @@ -1134,6 +1134,7 @@ struct net_device { | ||||
| @@ -1078,6 +1078,11 @@ struct net_device { | ||||
|  	const struct net_device_ops *netdev_ops; | ||||
|  	const struct ethtool_ops *ethtool_ops; | ||||
|   | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE | ||||
| +	void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb); | ||||
| +	struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb); | ||||
| +#endif | ||||
| + | ||||
|  	/* Hardware header description */ | ||||
|  	const struct header_ops *header_ops; | ||||
|   | ||||
| @@ -1134,6 +1139,9 @@ struct net_device { | ||||
|  	void			*ax25_ptr;	/* AX.25 specific data */ | ||||
|  	struct wireless_dev	*ieee80211_ptr;	/* IEEE 802.11 specific data, | ||||
|  						   assign before registering */ | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE | ||||
| +	void			*phy_ptr; /* PHY device specific data */ | ||||
| +#endif | ||||
|   | ||||
|  /* | ||||
|   * Cache lines mostly used on receive path (including eth_type_trans()) | ||||
| --- a/include/linux/if.h | ||||
| +++ b/include/linux/if.h | ||||
| @@ -80,6 +80,7 @@ | ||||
|  					 * skbs on transmit */ | ||||
|  #define IFF_UNICAST_FLT	0x20000		/* Supports unicast filtering	*/ | ||||
|  #define IFF_TEAM_PORT	0x40000		/* device used as team port */ | ||||
| +#define IFF_NO_IP_ALIGN	0x80000		/* do not ip-align allocated rx pkts */ | ||||
|   | ||||
|  #define IF_GET_IFACE	0x0001		/* for querying only */ | ||||
|  #define IF_GET_PROTO	0x0002 | ||||
| --- a/include/linux/skbuff.h | ||||
| +++ b/include/linux/skbuff.h | ||||
| @@ -1661,6 +1661,10 @@ extern struct sk_buff *dev_alloc_skb(uns | ||||
|  extern struct sk_buff *__netdev_alloc_skb(struct net_device *dev, | ||||
|  		unsigned int length, gfp_t gfp_mask); | ||||
|   | ||||
| +extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, | ||||
| +		unsigned int length, gfp_t gfp); | ||||
| + | ||||
| + | ||||
|  /** | ||||
|   *	netdev_alloc_skb - allocate an skbuff for rx on a specific device | ||||
|   *	@dev: network device to receive on | ||||
| @@ -1680,16 +1684,6 @@ static inline struct sk_buff *netdev_all | ||||
|  	return __netdev_alloc_skb(dev, length, GFP_ATOMIC); | ||||
|  } | ||||
|   | ||||
| -static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, | ||||
| -		unsigned int length, gfp_t gfp) | ||||
| -{ | ||||
| -	struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); | ||||
| - | ||||
| -	if (NET_IP_ALIGN && skb) | ||||
| -		skb_reserve(skb, NET_IP_ALIGN); | ||||
| -	return skb; | ||||
| -} | ||||
| - | ||||
|  static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, | ||||
|  		unsigned int length) | ||||
|  { | ||||
| --- a/net/Kconfig | ||||
| +++ b/net/Kconfig | ||||
| @@ -23,6 +23,12 @@ menuconfig NET | ||||
|   | ||||
|  if NET | ||||
|   | ||||
| +config ETHERNET_PACKET_MANGLE | ||||
| +	bool | ||||
| +	help | ||||
| +	  This option can be selected by phy drivers that need to mangle | ||||
| +	  packets going in or out of an ethernet device. | ||||
| + | ||||
|  config WANT_COMPAT_NETLINK_MESSAGES | ||||
|  	bool | ||||
|  	help | ||||
| --- a/net/core/dev.c | ||||
| +++ b/net/core/dev.c | ||||
| @@ -2246,9 +2246,19 @@ int dev_hard_start_xmit(struct sk_buff * | ||||
|  			} | ||||
|  		} | ||||
|   | ||||
| -		skb_len = skb->len; | ||||
| -		rc = ops->ndo_start_xmit(skb, dev); | ||||
| -		trace_net_dev_xmit(skb, rc, dev, skb_len); | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE | ||||
| +		if (!dev->eth_mangle_tx || | ||||
| +		    (skb = dev->eth_mangle_tx(dev, skb)) != NULL) | ||||
| +#else | ||||
| +		if (1) | ||||
| +#endif | ||||
| +		{ | ||||
| +			skb_len = skb->len; | ||||
| +			rc = ops->ndo_start_xmit(skb, dev); | ||||
| +			trace_net_dev_xmit(skb, rc, dev, skb_len); | ||||
| +		} else { | ||||
| +			rc = NETDEV_TX_OK; | ||||
| +		} | ||||
|  		if (rc == NETDEV_TX_OK) | ||||
|  			txq_trans_update(txq); | ||||
|  		return rc; | ||||
| @@ -2268,9 +2278,19 @@ gso: | ||||
|  		if (dev->priv_flags & IFF_XMIT_DST_RELEASE) | ||||
|  			skb_dst_drop(nskb); | ||||
|   | ||||
| -		skb_len = nskb->len; | ||||
| -		rc = ops->ndo_start_xmit(nskb, dev); | ||||
| -		trace_net_dev_xmit(nskb, rc, dev, skb_len); | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE | ||||
| +		if (!dev->eth_mangle_tx || | ||||
| +		    (nskb = dev->eth_mangle_tx(dev, nskb)) != NULL) | ||||
| +#else | ||||
| +		if (1) | ||||
| +#endif | ||||
| +		{ | ||||
| +			skb_len = nskb->len; | ||||
| +			rc = ops->ndo_start_xmit(nskb, dev); | ||||
| +			trace_net_dev_xmit(nskb, rc, dev, skb_len); | ||||
| +		} else { | ||||
| +			rc = NETDEV_TX_OK; | ||||
| +		} | ||||
|  		if (unlikely(rc != NETDEV_TX_OK)) { | ||||
|  			if (rc & ~NETDEV_TX_MASK) | ||||
|  				goto out_kfree_gso_skb; | ||||
| --- a/net/core/skbuff.c | ||||
| +++ b/net/core/skbuff.c | ||||
| @@ -58,6 +58,7 @@ | ||||
|  #include <linux/scatterlist.h> | ||||
|  #include <linux/errqueue.h> | ||||
|  #include <linux/prefetch.h> | ||||
| +#include <linux/if.h> | ||||
|   | ||||
|  #include <net/protocol.h> | ||||
|  #include <net/dst.h> | ||||
| @@ -320,6 +321,22 @@ struct sk_buff *__netdev_alloc_skb(struc | ||||
|  } | ||||
|  EXPORT_SYMBOL(__netdev_alloc_skb); | ||||
|   | ||||
| +struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, | ||||
| +		unsigned int length, gfp_t gfp) | ||||
| +{ | ||||
| +	struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); | ||||
| + | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE | ||||
| +	if (dev->priv_flags & IFF_NO_IP_ALIGN) | ||||
| +		return skb; | ||||
| +#endif | ||||
| + | ||||
| +	if (NET_IP_ALIGN && skb) | ||||
| +		skb_reserve(skb, NET_IP_ALIGN); | ||||
| +	return skb; | ||||
| +} | ||||
| +EXPORT_SYMBOL(__netdev_alloc_skb_ip_align); | ||||
| + | ||||
|  void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, | ||||
|  		int size) | ||||
|  { | ||||
| --- a/net/ethernet/eth.c | ||||
| +++ b/net/ethernet/eth.c | ||||
| @@ -160,6 +160,12 @@ __be16 eth_type_trans(struct sk_buff *sk | ||||
|  	struct ethhdr *eth; | ||||
|   | ||||
|  	skb->dev = dev; | ||||
| + | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE | ||||
| +	if (dev->eth_mangle_rx) | ||||
| +		dev->eth_mangle_rx(dev, skb); | ||||
| +#endif | ||||
| + | ||||
|  	skb_reset_mac_header(skb); | ||||
|  	skb_pull_inline(skb, ETH_HLEN); | ||||
|  	eth = eth_hdr(skb); | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| --- a/drivers/net/phy/Kconfig | ||||
| +++ b/drivers/net/phy/Kconfig | ||||
| @@ -113,6 +113,9 @@ config ADM6996_PHY | ||||
| @@ -113,6 +113,10 @@ config ADM6996_PHY | ||||
|  	  Currently supports the ADM6996FC and ADM6996M switches. | ||||
|  	  Support for FC is very limited. | ||||
|   | ||||
| +config MVSWITCH_PHY | ||||
| +	tristate "Driver for Marvell 88E6060 switches" | ||||
| +	select ETHERNET_PACKET_MANGLE | ||||
| + | ||||
|  config FIXED_PHY | ||||
|  	bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| --- a/drivers/net/phy/Kconfig | ||||
| +++ b/drivers/net/phy/Kconfig | ||||
| @@ -116,6 +116,10 @@ config ADM6996_PHY | ||||
|  config MVSWITCH_PHY | ||||
| @@ -117,6 +117,10 @@ config MVSWITCH_PHY | ||||
|  	tristate "Driver for Marvell 88E6060 switches" | ||||
|  	select ETHERNET_PACKET_MANGLE | ||||
|   | ||||
| +config IP17XX_PHY | ||||
| +	tristate "Driver for IC+ IP17xx switches" | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| --- a/drivers/net/phy/Kconfig | ||||
| +++ b/drivers/net/phy/Kconfig | ||||
| @@ -120,6 +120,10 @@ config IP17XX_PHY | ||||
| @@ -121,6 +121,11 @@ config IP17XX_PHY | ||||
|  	tristate "Driver for IC+ IP17xx switches" | ||||
|  	select SWCONFIG | ||||
|   | ||||
| +config AR8216_PHY | ||||
| +	tristate "Driver for Atheros AR8216 switches" | ||||
| +	select ETHERNET_PACKET_MANGLE | ||||
| +	select SWCONFIG | ||||
| + | ||||
|  config FIXED_PHY | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| --- a/drivers/net/phy/Kconfig | ||||
| +++ b/drivers/net/phy/Kconfig | ||||
| @@ -124,6 +124,10 @@ config AR8216_PHY | ||||
|  	tristate "Driver for Atheros AR8216 switches" | ||||
| @@ -126,6 +126,10 @@ config AR8216_PHY | ||||
|  	select ETHERNET_PACKET_MANGLE | ||||
|  	select SWCONFIG | ||||
|   | ||||
| +config RTL8306_PHY | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| --- a/drivers/net/phy/Kconfig | ||||
| +++ b/drivers/net/phy/Kconfig | ||||
| @@ -166,6 +166,31 @@ config MDIO_OCTEON | ||||
| @@ -168,6 +168,31 @@ config MDIO_OCTEON | ||||
|   | ||||
|  	  If in doubt, say Y. | ||||
|   | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| --- a/drivers/net/phy/Kconfig | ||||
| +++ b/drivers/net/phy/Kconfig | ||||
| @@ -183,6 +183,10 @@ config RTL8366RB_PHY | ||||
| @@ -185,6 +185,10 @@ config RTL8366RB_PHY | ||||
|  	tristate "Driver for the Realtek RTL8366RB switch" | ||||
|  	select SWCONFIG | ||||
|   | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| --- a/drivers/net/phy/Kconfig | ||||
| +++ b/drivers/net/phy/Kconfig | ||||
| @@ -128,6 +128,11 @@ config RTL8306_PHY | ||||
| @@ -130,6 +130,11 @@ config RTL8306_PHY | ||||
|  	tristate "Driver for Realtek RTL8306S switches" | ||||
|  	select SWCONFIG | ||||
|   | ||||
|   | ||||
| @@ -1,17 +0,0 @@ | ||||
| --- a/drivers/net/ethernet/lantiq_etop.c | ||||
| +++ b/drivers/net/ethernet/lantiq_etop.c | ||||
| @@ -188,8 +188,12 @@ ltq_etop_hw_receive(struct ltq_etop_chan | ||||
|   | ||||
|  	skb_put(skb, len); | ||||
|  	skb->dev = ch->netdev; | ||||
| -	skb->protocol = eth_type_trans(skb, ch->netdev); | ||||
| -	netif_receive_skb(skb); | ||||
| +	if (priv->phydev && priv->phydev->netif_receive_skb) { | ||||
| +		priv->phydev->netif_receive_skb(skb); | ||||
| +	} else { | ||||
| +		skb->protocol = eth_type_trans(skb, ch->netdev); | ||||
| +		netif_receive_skb(skb); | ||||
| +	} | ||||
|  } | ||||
|   | ||||
|  static int | ||||
		Reference in New Issue
	
	Block a user
	 Felix Fietkau
					Felix Fietkau