Netdev List
 help / color / mirror / Atom feed
* [PATCH 2/3] stmmac: update the version
From: Giuseppe CAVALLARO @ 2011-07-19  8:38 UTC (permalink / raw)
  To: netdev; +Cc: Giuseppe Cavallaro
In-Reply-To: <1311064684-20246-1-git-send-email-peppe.cavallaro@st.com>

Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 drivers/net/stmmac/stmmac.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/stmmac/stmmac.h b/drivers/net/stmmac/stmmac.h
index c2b6b8e..0b17429 100644
--- a/drivers/net/stmmac/stmmac.h
+++ b/drivers/net/stmmac/stmmac.h
@@ -20,7 +20,7 @@
   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *******************************************************************************/
 
-#define DRV_MODULE_VERSION	"Nov_2010"
+#define DRV_MODULE_VERSION	"July_2011"
 #include <linux/stmmac.h>
 
 #include "common.h"
-- 
1.7.4.4


^ permalink raw reply related

* [PATCH 1/3] stmmac: unify MAC and PHY configuration parameters
From: Giuseppe CAVALLARO @ 2011-07-19  8:38 UTC (permalink / raw)
  To: netdev; +Cc: Giuseppe Cavallaro, Stuart Menefy

Prior to this change, most PHY configuration parameters were passed
into the STMMAC device as a separate PHY device. As well as being
unusual, this made it difficult to make changes to the MAC/PHY
relationship.

This patch moves all the PHY parameters into the MAC configuration
structure, mainly as a separate structure. This allows us to completly
ignore the MDIO bus attached to a stmmac if desired, and not create
the PHY bus. It also allows the stmmac driver to use a different PHY
from the one it is connected to, for example a fixed PHY or bit banging
PHY.

Also derive the stmmac/PHY connection type (MII/RMII etc) from the
mode can be passed into <platf>_configure_ethernet.
STLinux kernel at git://git.stlinux.com/stm/linux-sh4-2.6.32.y.git
provides several examples how to use this new infrastructure (that
actually is easier to maintain and clearer).

Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 drivers/net/stmmac/stmmac.h      |    6 +--
 drivers/net/stmmac/stmmac_main.c |   95 +++-----------------------------------
 drivers/net/stmmac/stmmac_mdio.c |   83 +++++++++++++++++++++++----------
 include/linux/stmmac.h           |   24 +++++-----
 4 files changed, 77 insertions(+), 131 deletions(-)

diff --git a/drivers/net/stmmac/stmmac.h b/drivers/net/stmmac/stmmac.h
index 2b076b3..c2b6b8e 100644
--- a/drivers/net/stmmac/stmmac.h
+++ b/drivers/net/stmmac/stmmac.h
@@ -56,14 +56,9 @@ struct stmmac_priv {
 	struct stmmac_extra_stats xstats;
 	struct napi_struct napi;
 
-	phy_interface_t phy_interface;
-	int phy_addr;
-	int phy_mask;
-	int (*phy_reset) (void *priv);
 	int rx_coe;
 	int no_csum_insertion;
 
-	int phy_irq;
 	struct phy_device *phydev;
 	int oldlink;
 	int speed;
@@ -71,6 +66,7 @@ struct stmmac_priv {
 	unsigned int flow_ctrl;
 	unsigned int pause;
 	struct mii_bus *mii;
+	int mii_irq[PHY_MAX_ADDR];
 
 	u32 msg_enable;
 	spinlock_t lock;
diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c
index 0e0134e..a11a339 100644
--- a/drivers/net/stmmac/stmmac_main.c
+++ b/drivers/net/stmmac/stmmac_main.c
@@ -49,7 +49,6 @@
 #include "stmmac.h"
 
 #define STMMAC_RESOURCE_NAME	"stmmaceth"
-#define PHY_RESOURCE_NAME	"stmmacphy"
 
 #undef STMMAC_DEBUG
 /*#define STMMAC_DEBUG*/
@@ -305,18 +304,13 @@ static int stmmac_init_phy(struct net_device *dev)
 	priv->speed = 0;
 	priv->oldduplex = -1;
 
-	if (priv->phy_addr == -1) {
-		/* We don't have a PHY, so do nothing */
-		return 0;
-	}
-
 	snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id);
 	snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
-		 priv->phy_addr);
+		 priv->plat->phy_addr);
 	pr_debug("stmmac_init_phy:  trying to attach to %s\n", phy_id);
 
 	phydev = phy_connect(dev, phy_id, &stmmac_adjust_link, 0,
-			priv->phy_interface);
+			     priv->plat->interface);
 
 	if (IS_ERR(phydev)) {
 		pr_err("%s: Could not attach to PHY\n", dev->name);
@@ -335,7 +329,7 @@ static int stmmac_init_phy(struct net_device *dev)
 		return -ENODEV;
 	}
 	pr_debug("stmmac_init_phy:  %s: attached to PHY (UID 0x%x)"
-	       " Link = %d\n", dev->name, phydev->phy_id, phydev->link);
+		 " Link = %d\n", dev->name, phydev->phy_id, phydev->link);
 
 	priv->phydev = phydev;
 
@@ -1543,71 +1537,6 @@ static int stmmac_mac_device_setup(struct net_device *dev)
 	return 0;
 }
 
-static int stmmacphy_dvr_probe(struct platform_device *pdev)
-{
-	struct plat_stmmacphy_data *plat_dat = pdev->dev.platform_data;
-
-	pr_debug("stmmacphy_dvr_probe: added phy for bus %d\n",
-	       plat_dat->bus_id);
-
-	return 0;
-}
-
-static int stmmacphy_dvr_remove(struct platform_device *pdev)
-{
-	return 0;
-}
-
-static struct platform_driver stmmacphy_driver = {
-	.driver = {
-		   .name = PHY_RESOURCE_NAME,
-		   },
-	.probe = stmmacphy_dvr_probe,
-	.remove = stmmacphy_dvr_remove,
-};
-
-/**
- * stmmac_associate_phy
- * @dev: pointer to device structure
- * @data: points to the private structure.
- * Description: Scans through all the PHYs we have registered and checks if
- * any are associated with our MAC.  If so, then just fill in
- * the blanks in our local context structure
- */
-static int stmmac_associate_phy(struct device *dev, void *data)
-{
-	struct stmmac_priv *priv = (struct stmmac_priv *)data;
-	struct plat_stmmacphy_data *plat_dat = dev->platform_data;
-
-	DBG(probe, DEBUG, "%s: checking phy for bus %d\n", __func__,
-		plat_dat->bus_id);
-
-	/* Check that this phy is for the MAC being initialised */
-	if (priv->plat->bus_id != plat_dat->bus_id)
-		return 0;
-
-	/* OK, this PHY is connected to the MAC.
-	   Go ahead and get the parameters */
-	DBG(probe, DEBUG, "%s: OK. Found PHY config\n", __func__);
-	priv->phy_irq =
-	    platform_get_irq_byname(to_platform_device(dev), "phyirq");
-	DBG(probe, DEBUG, "%s: PHY irq on bus %d is %d\n", __func__,
-	    plat_dat->bus_id, priv->phy_irq);
-
-	/* Override with kernel parameters if supplied XXX CRS XXX
-	 * this needs to have multiple instances */
-	if ((phyaddr >= 0) && (phyaddr <= 31))
-		plat_dat->phy_addr = phyaddr;
-
-	priv->phy_addr = plat_dat->phy_addr;
-	priv->phy_mask = plat_dat->phy_mask;
-	priv->phy_interface = plat_dat->interface;
-	priv->phy_reset = plat_dat->phy_reset;
-
-	DBG(probe, DEBUG, "%s: exiting\n", __func__);
-	return 1;	/* forces exit of driver_for_each_device() */
-}
-
 /**
  * stmmac_dvr_probe
  * @pdev: platform device pointer
@@ -1698,14 +1627,10 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto out_plat_exit;
 
-	/* associate a PHY - it is provided by another platform bus */
-	if (!driver_for_each_device
-	    (&(stmmacphy_driver.driver), NULL, (void *)priv,
-	     stmmac_associate_phy)) {
-		pr_err("No PHY device is associated with this MAC!\n");
-		ret = -ENODEV;
-		goto out_unregister;
-	}
+	/* Override with kernel parameters if supplied XXX CRS XXX
+	 * this needs to have multiple instances */
+	if ((phyaddr >= 0) && (phyaddr <= 31))
+		priv->plat->phy_addr = phyaddr;
 
 	pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n"
 	       "\tIO base addr: 0x%p)\n", ndev->name, pdev->name,
@@ -1905,11 +1830,6 @@ static int __init stmmac_init_module(void)
 {
 	int ret;
 
-	if (platform_driver_register(&stmmacphy_driver)) {
-		pr_err("No PHY devices registered!\n");
-		return -ENODEV;
-	}
-
 	ret = platform_driver_register(&stmmac_driver);
 	return ret;
 }
@@ -1920,7 +1840,6 @@ static int __init stmmac_init_module(void)
  */
 static void __exit stmmac_cleanup_module(void)
 {
-	platform_driver_unregister(&stmmacphy_driver);
 	platform_driver_unregister(&stmmac_driver);
 }
 
diff --git a/drivers/net/stmmac/stmmac_mdio.c b/drivers/net/stmmac/stmmac_mdio.c
index 234b406..b1c3ecf 100644
--- a/drivers/net/stmmac/stmmac_mdio.c
+++ b/drivers/net/stmmac/stmmac_mdio.c
@@ -112,9 +112,9 @@ static int stmmac_mdio_reset(struct mii_bus *bus)
 	struct stmmac_priv *priv = netdev_priv(ndev);
 	unsigned int mii_address = priv->hw->mii.addr;
 
-	if (priv->phy_reset) {
+	if (priv->plat->mdio_bus_data->phy_reset) {
 		pr_debug("stmmac_mdio_reset: calling phy_reset\n");
-		priv->phy_reset(priv->plat->bsp_priv);
+		priv->plat->mdio_bus_data->phy_reset(priv->plat->bsp_priv);
 	}
 
 	/* This is a workaround for problems with the STE101P PHY.
@@ -137,30 +137,29 @@ int stmmac_mdio_register(struct net_device *ndev)
 	struct mii_bus *new_bus;
 	int *irqlist;
 	struct stmmac_priv *priv = netdev_priv(ndev);
+	struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
 	int addr, found;
 
+	if (!mdio_bus_data)
+		return 0;
+
 	new_bus = mdiobus_alloc();
 	if (new_bus == NULL)
 		return -ENOMEM;
 
-	irqlist = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
-	if (irqlist == NULL) {
-		err = -ENOMEM;
-		goto irqlist_alloc_fail;
-	}
-
-	/* Assign IRQ to phy at address phy_addr */
-	if (priv->phy_addr != -1)
-		irqlist[priv->phy_addr] = priv->phy_irq;
+	if (mdio_bus_data->irqs)
+		irqlist = mdio_bus_data->irqs;
+	else
+		irqlist = priv->mii_irq;
 
 	new_bus->name = "STMMAC MII Bus";
 	new_bus->read = &stmmac_mdio_read;
 	new_bus->write = &stmmac_mdio_write;
 	new_bus->reset = &stmmac_mdio_reset;
-	snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id);
+	snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", mdio_bus_data->bus_id);
 	new_bus->priv = ndev;
 	new_bus->irq = irqlist;
-	new_bus->phy_mask = priv->phy_mask;
+	new_bus->phy_mask = mdio_bus_data->phy_mask;
 	new_bus->parent = priv->device;
 	err = mdiobus_register(new_bus);
 	if (err != 0) {
@@ -171,18 +170,50 @@ int stmmac_mdio_register(struct net_device *ndev)
 	priv->mii = new_bus;
 
 	found = 0;
-	for (addr = 0; addr < 32; addr++) {
+	for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
 		struct phy_device *phydev = new_bus->phy_map[addr];
 		if (phydev) {
-			if (priv->phy_addr == -1) {
-				priv->phy_addr = addr;
-				phydev->irq = priv->phy_irq;
-				irqlist[addr] = priv->phy_irq;
+			int act = 0;
+			char irq_num[4];
+			char *irq_str;
+
+			/*
+			 * If an IRQ was provided to be assigned after
+			 * the bus probe, do it here.
+			 */
+			if ((mdio_bus_data->irqs == NULL) &&
+			    (mdio_bus_data->probed_phy_irq > 0)) {
+				irqlist[addr] = mdio_bus_data->probed_phy_irq;
+				phydev->irq = mdio_bus_data->probed_phy_irq;
 			}
-			pr_info("%s: PHY ID %08x at %d IRQ %d (%s)%s\n",
-			       ndev->name, phydev->phy_id, addr,
-			       phydev->irq, dev_name(&phydev->dev),
-			       (addr == priv->phy_addr) ? " active" : "");
+
+			/*
+			 * If we're  going to bind the MAC to this PHY bus,
+			 * and no PHY number was provided to the MAC,
+			 * use the one probed here.
+			 */
+			if ((priv->plat->bus_id == mdio_bus_data->bus_id) &&
+			    (priv->plat->phy_addr == -1))
+				priv->plat->phy_addr = addr;
+
+			act = (priv->plat->bus_id == mdio_bus_data->bus_id) &&
+				(priv->plat->phy_addr == addr);
+			switch (phydev->irq) {
+			case PHY_POLL:
+				irq_str = "POLL";
+				break;
+			case PHY_IGNORE_INTERRUPT:
+				irq_str = "IGNORE";
+				break;
+			default:
+				sprintf(irq_num, "%d", phydev->irq);
+				irq_str = irq_num;
+				break;
+			}
+			pr_info("%s: PHY ID %08x at %d IRQ %s (%s)%s\n",
+				ndev->name, phydev->phy_id, addr,
+				irq_str, dev_name(&phydev->dev),
+				act ? " active" : "");
 			found = 1;
 		}
 	}
@@ -191,10 +222,9 @@ int stmmac_mdio_register(struct net_device *ndev)
 		pr_warning("%s: No PHY found\n", ndev->name);
 
 	return 0;
+
 bus_register_fail:
-	kfree(irqlist);
-irqlist_alloc_fail:
-	kfree(new_bus);
+	mdiobus_free(new_bus);
 	return err;
 }
 
@@ -209,7 +239,8 @@ int stmmac_mdio_unregister(struct net_device *ndev)
 
 	mdiobus_unregister(priv->mii);
 	priv->mii->priv = NULL;
-	kfree(priv->mii);
+	mdiobus_free(priv->mii);
+	priv->mii = NULL;
 
 	return 0;
 }
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 05d7756..57e583a 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -28,11 +28,21 @@
 
 #include <linux/platform_device.h>
 
-/* platform data for platform device structure's platform_data field */
+/* Platfrom data for platform device structure's platform_data field */
+
+struct stmmac_mdio_bus_data {
+	int bus_id;
+	int (*phy_reset)(void *priv);
+	unsigned int phy_mask;
+	int *irqs;		/* List of IRQs, one per PHY */
+	int probed_phy_irq;	/* If irqs is NULL, use this for probed PHY */
+};
 
-/* Private data for the STM on-board ethernet driver */
 struct plat_stmmacenet_data {
 	int bus_id;
+	int phy_addr;
+	int interface;
+	struct stmmac_mdio_bus_data *mdio_bus_data;
 	int pbl;
 	int clk_csr;
 	int has_gmac;
@@ -48,14 +58,4 @@ struct plat_stmmacenet_data {
 	void *custom_cfg;
 	void *bsp_priv;
 };
-
-struct plat_stmmacphy_data {
-	int bus_id;
-	int phy_addr;
-	unsigned int phy_mask;
-	int interface;
-	int (*phy_reset)(void *priv);
-	void *priv;
-};
 #endif
-
-- 
1.7.4.4


^ permalink raw reply related

* Re: [patch net-next-2.6] vlan: introduce ndo_vlan_[enable/disable]
From: Michał Mirosław @ 2011-07-19  8:27 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: netdev, davem, shemminger, eric.dumazet, greearb
In-Reply-To: <CAHXqBFKZ2Y+SgFLFaBD6rpHoVX30PMp1ECwxhie3AAUqjMZ6UQ@mail.gmail.com>

W dniu 19 lipca 2011 10:24 użytkownik Michał Mirosław
<mirqus@gmail.com> napisał:
> W dniu 19 lipca 2011 10:13 użytkownik Jiri Pirko <jpirko@redhat.com> napisał:
>> Tue, Jul 19, 2011 at 09:24:29AM CEST, mirqus@gmail.com wrote:
>>>W dniu 18 lipca 2011 09:13 użytkownik Jiri Pirko <jpirko@redhat.com> napisał:
>>>>  static u32 atl1c_fix_features(struct net_device *netdev, u32 features)
>>>>  {
>>>> +       u32 changed = netdev->features ^ features;
>>>> +
>>>> +       /*
>>>> +        * Since there is no support for separate rx/tx vlan accel
>>>> +        * enable/disable make sure these are always set in pair.
>>>> +        */
>>>> +       if ((changed & NETIF_F_HW_VLAN_TX && features & NETIF_F_HW_VLAN_TX) ||
>>>> +           (changed & NETIF_F_HW_VLAN_RX && features & NETIF_F_HW_VLAN_RX))
>>>> +               features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
>>>> +       else
>>>> +               features &= ~(NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
>>>> +
>>>
>>>You ignored my hint about combined TX/RX offload. Is that on purpose?
>> Sorry but I'm probably missing what you mean.
>
> You could replace above code with:
>
> if (!(features & NETIF_F_HW_VLAN_RX))
>  features &= ~NETIF_F_HW_VLAN_TX;

Or you could invert the test and effect:

  if (features & NETIF_F_HW_VLAN_TX)
    features |= NETIF_F_HW_VLAN_RX;

Best Regards,
Michał Mirosław

^ permalink raw reply

* Re: [patch net-next-2.6] vlan: introduce ndo_vlan_[enable/disable]
From: Michał Mirosław @ 2011-07-19  8:24 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: netdev, davem, shemminger, eric.dumazet, greearb
In-Reply-To: <20110719081332.GA2219@minipsycho>

W dniu 19 lipca 2011 10:13 użytkownik Jiri Pirko <jpirko@redhat.com> napisał:
> Tue, Jul 19, 2011 at 09:24:29AM CEST, mirqus@gmail.com wrote:
>>W dniu 18 lipca 2011 09:13 użytkownik Jiri Pirko <jpirko@redhat.com> napisał:
>>>  static u32 atl1c_fix_features(struct net_device *netdev, u32 features)
>>>  {
>>> +       u32 changed = netdev->features ^ features;
>>> +
>>> +       /*
>>> +        * Since there is no support for separate rx/tx vlan accel
>>> +        * enable/disable make sure these are always set in pair.
>>> +        */
>>> +       if ((changed & NETIF_F_HW_VLAN_TX && features & NETIF_F_HW_VLAN_TX) ||
>>> +           (changed & NETIF_F_HW_VLAN_RX && features & NETIF_F_HW_VLAN_RX))
>>> +               features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
>>> +       else
>>> +               features &= ~(NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
>>> +
>>
>>You ignored my hint about combined TX/RX offload. Is that on purpose?
> Sorry but I'm probably missing what you mean.

You could replace above code with:

if (!(features & NETIF_F_HW_VLAN_RX))
  features &= ~NETIF_F_HW_VLAN_TX;

>>Your code will toggle VLAN acceleration on every
>>netdev_update_features call when user requests one offload on and one
>>off.
>
> Well for hw which cannot no/off rx/tx accel separately I thought that if
> user wants one accel on, the accel should be enabled. According to
> following table (bits set when calling driver's fix_features):
>
>  NETIF_F_HW_VLAN_TX  NETIF_F_HW_VLAN_RX -> enable
>  NETIF_F_HW_VLAN_TX !NETIF_F_HW_VLAN_RX -> enable
> !NETIF_F_HW_VLAN_TX  NETIF_F_HW_VLAN_RX -> enable
> !NETIF_F_HW_VLAN_TX !NETIF_F_HW_VLAN_RX -> disable
>
> This looks logical to me...

If user requests eg. +TX -RX, you will have ndo_fix_features called
with +TX -RX, possibly multiple times. This generates this sequence:

current features: -TX,-RX
  -> changed: TX -> return +TX,+RX
  -> set_features +TX,+TX
current_features: +TX,+RX
  -> changed: RX -> return -TX,-RX
  -> set_features -TX,-RX
...

(And you cannot control when fix_features will be called.)

If you don't agree with the hint above (about forcing TX off when RX
is off, leaving the rest alone), then its better to remove TX from
hw_features and copy it's state from RX in ndo_fix_features. Like
this:

[init]
  netdev->hw_features |= NETIF_F_HW_VLAN_RX;
[fix_features]
  if (features & NETIF_F_HW_VLAN_RX)
    features |= NETIF_F_HW_VLAN_TX;
  else
    features &= ~NETIF_F_HW_VLAN_TX;

Best Regards,
Michał Mirosław

^ permalink raw reply

* Re: [patch net-next-2.6] vlan: introduce ndo_vlan_[enable/disable]
From: Jiri Pirko @ 2011-07-19  8:13 UTC (permalink / raw)
  To: Michał Mirosław
  Cc: netdev, davem, shemminger, eric.dumazet, greearb
In-Reply-To: <CAHXqBFKgZUuLFoe+U+2nT3NVBCaPfY13BsrK=Hxqsw7oiOZe3A@mail.gmail.com>

Tue, Jul 19, 2011 at 09:24:29AM CEST, mirqus@gmail.com wrote:
>W dniu 18 lipca 2011 09:13 użytkownik Jiri Pirko <jpirko@redhat.com> napisał:
>> Sun, Jul 17, 2011 at 11:06:57PM CEST, mirqus@gmail.com wrote:
>>>W dniu 17 lipca 2011 21:44 użytkownik Jiri Pirko <jpirko@redhat.com> napisał:
>>>> Sun, Jul 17, 2011 at 10:36:04AM CEST, mirqus@gmail.com wrote:
>>>>>W dniu 17 lipca 2011 09:30 użytkownik Jiri Pirko <jpirko@redhat.com> napisał:
>>>>>> Sat, Jul 16, 2011 at 04:14:36PM CEST, mirqus@gmail.com wrote:
>>>>>>>2011/7/16 Jiri Pirko <jpirko@redhat.com>:
>>>>>>>> Some devices are not able to enable/disable rx/tw vlan accel separately.
>>>>>>>> they depend on ndo_vlan_rx_register to know if to enable of disable
>>>>>>>> hw accel. And since ndo_vlan_rx_register is going to die soon,
>>>>>>>> this must be resolved.
>>>>>>>>
>>>>>>>> One solution might be to enable accel on device start every time, even
>>>>>>>> if there are no vlan up on. But this would change behaviour and might
>>>>>>>> lead to possible regression (on older devices).
>>>>>>>[...]
>>>>>>>
>>>>>>>Please describe the possible regression. As I see it, there won't be
>>>>>>>any user visible change of behaviour - network code takes care of
>>>>>>>reinserting VLAN tag when necessary. If you think that disabling tag
>>>>>>>stripping is beneficial for cases where no VLANs are configured, it's
>>>>>>>better to do that in netdev_fix_features() for devices which advertise
>>>>>>>NETIF_F_HW_VLAN_RX in hw_features.
>>>>>>
>>>>>> Well I just wanted to preserve current behaviour which is that in many
>>>>>> drivers vlan accel is enabled only if some vid is registered upon the
>>>>>> device and it's disabled again when no vid is registered. I can see
>>>>>> no way to do this with current code after removing ndo_vlan_rx_register.
>>>>>>
>>>>>> I expect unexpected
>>>>>
>>>>>:-D
>>>>>
>>>>>> ... problems on old cards when vlan accel would be
>>>>>> enabled all the time, but maybe I'm wrong...
>>>>>
>>>>>Device has no way of knowing how the system uses VLAN tags, stripped
>>>>>or not. Any problems would be driver problems and since you're making
>>>>>it all use generic code, bugs will hit all drivers simultaneously or
>>>>>(preferably) won't happen at all.
>>>>>
>>>>>> One idea is for device which do not support sepatate rx/tx vlan accel
>>>>>> enabling/disabling they can probably use ndo_fix_features force to
>>>>>> enable/disable rx/tx pair together. That would resolve the situation as
>>>>>> well giving user possibility to turn off vlan accel in case of any issues.
>>>>>
>>>>>That is exactly the idea behind ndo_fix_features.
>>>
>>>> In netdev_fix_features add check if either one of NETIF_F_HW_VLAN_TX or
>>>> NETIF_F_HW_VLAN_RX is set and in that case set the other one. Of course
>>>> this would be done only for devices what do not support separate rx/tx
>>>> vlan on/off. But how to distinguish? NETIF_F_HW_VLAN_BOTH feature flag?
>>>
>>>Not in netdev_fix_features(). This case you describe should be handled
>>>in driver-specific
>>
>> Well since the code would be the same in many drivers I was thinking
>> about putting it in general code...
>>
>> Anyway, would you please look at following example patch and tell me if
>> it looks good to you?
>
>[...]
>>  static u32 atl1c_fix_features(struct net_device *netdev, u32 features)
>>  {
>> +       u32 changed = netdev->features ^ features;
>> +
>> +       /*
>> +        * Since there is no support for separate rx/tx vlan accel
>> +        * enable/disable make sure these are always set in pair.
>> +        */
>> +       if ((changed & NETIF_F_HW_VLAN_TX && features & NETIF_F_HW_VLAN_TX) ||
>> +           (changed & NETIF_F_HW_VLAN_RX && features & NETIF_F_HW_VLAN_RX))
>> +               features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
>> +       else
>> +               features &= ~(NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
>> +
>
>You ignored my hint about combined TX/RX offload. Is that on purpose?

Sorry but I'm probably missing what you mean.

>Your code will toggle VLAN acceleration on every
>netdev_update_features call when user requests one offload on and one
>off.

Well for hw which cannot no/off rx/tx accel separately I thought that if
user wants one accel on, the accel should be enabled. According to
following table (bits set when calling driver's fix_features):

 NETIF_F_HW_VLAN_TX  NETIF_F_HW_VLAN_RX -> enable
 NETIF_F_HW_VLAN_TX !NETIF_F_HW_VLAN_RX -> enable
!NETIF_F_HW_VLAN_TX  NETIF_F_HW_VLAN_RX -> enable
!NETIF_F_HW_VLAN_TX !NETIF_F_HW_VLAN_RX -> disable

This looks logical to me...

>
>BTW, the register flag name (MAC_CTRL_RMV_VLAN) suggests that it
>controls only tag stripping. Was it tested or documented that this
>also links with tag insertion?

comment says "/* enable VLAN tag insert/strip */" therefore it looks
like this register controls both.

>
>[...]
>> +static int atl1c_set_features(struct net_device *netdev, u32 features)
>> +{
>> +       u32 changed = netdev->features ^ features;
>> +
>> +       /*
>> +        * Test for NETIF_F_HW_VLAN_TX as it's paired with NETIF_F_HW_VLAN_RX
>> +        * by atl1c_fix_features.
>> +        */
>> +       if (changed & NETIF_F_HW_VLAN_TX)
>> +               atl1c_vlan_mode(netdev, features);
>> +
>
>Test for RX is better, as it will match the name of control bit
>(MAC_CTRL_RMV_VLAN).

Yeah, why not, I think this does not matter.

>
>Best Regards,
>Michał Mirosław

^ permalink raw reply

* [PATCH] slcan: remove unused 'leased', 'line' and 'pid' fields from the 'slcan' structure
From: Matvejchikov Ilya @ 2011-07-19  7:58 UTC (permalink / raw)
  To: netdev

Signed-off-by: Matvejchikov Ilya <matvejchikov@gmail.com>
---
 drivers/net/can/slcan.c |   10 +---------
 1 files changed, 1 insertions(+), 9 deletions(-)

diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index 1b49df6..805ee29 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -95,10 +95,6 @@ struct slcan {
 	unsigned long		flags;		/* Flag values/ mode etc     */
 #define SLF_INUSE		0		/* Channel in use            */
 #define SLF_ERROR		1               /* Parity, etc. error        */
-
-	unsigned char		leased;
-	dev_t			line;
-	pid_t			pid;
 };

 static struct net_device **slcan_devs;
@@ -462,7 +458,7 @@ static void slc_sync(void)
 			break;

 		sl = netdev_priv(dev);
-		if (sl->tty || sl->leased)
+		if (sl->tty)
 			continue;
 		if (dev->flags & IFF_UP)
 			dev_close(dev);
@@ -565,8 +561,6 @@ static int slcan_open(struct tty_struct *tty)

 	sl->tty = tty;
 	tty->disc_data = sl;
-	sl->line = tty_devnum(tty);
-	sl->pid = current->pid;

 	if (!test_bit(SLF_INUSE, &sl->flags)) {
 		/* Perform the low-level SLCAN initialization. */
@@ -617,8 +611,6 @@ static void slcan_close(struct tty_struct *tty)

 	tty->disc_data = NULL;
 	sl->tty = NULL;
-	if (!sl->leased)
-		sl->line = 0;

 	/* Flush network side */
 	unregister_netdev(sl->dev);
-- 
1.7.6

^ permalink raw reply related

* [PATCH] slip: remove unused 'line' field from the 'slip' structure
From: Matvejchikov Ilya @ 2011-07-19  7:56 UTC (permalink / raw)
  To: netdev

Signed-off-by: Matvejchikov Ilya <matvejchikov@gmail.com>
---
 drivers/net/slip.c |    3 ---
 drivers/net/slip.h |    1 -
 2 files changed, 0 insertions(+), 4 deletions(-)

diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 2f110fb..77c4798 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -823,7 +823,6 @@ static int slip_open(struct tty_struct *tty)

 	sl->tty = tty;
 	tty->disc_data = sl;
-	sl->line = tty_devnum(tty);
 	sl->pid = current->pid;

 	if (!test_bit(SLF_INUSE, &sl->flags)) {
@@ -890,8 +889,6 @@ static void slip_close(struct tty_struct *tty)

 	tty->disc_data = NULL;
 	sl->tty = NULL;
-	if (!sl->leased)
-		sl->line = 0;

 	/* VSV = very important to remove timers */
 #ifdef CONFIG_SLIP_SMART
diff --git a/drivers/net/slip.h b/drivers/net/slip.h
index 914e958..aa0764c 100644
--- a/drivers/net/slip.h
+++ b/drivers/net/slip.h
@@ -90,7 +90,6 @@ struct slip {

   unsigned char		mode;		/* SLIP mode			*/
   unsigned char		leased;
-  dev_t			line;
   pid_t			pid;
 #define SL_MODE_SLIP	0
 #define SL_MODE_CSLIP	1
-- 
1.7.6

^ permalink raw reply related

* Re: [PATCH v2] net: filter: BPF 'JIT' compiler for PPC64
From: Benjamin Herrenschmidt @ 2011-07-19  7:55 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Matt Evans, netdev, linuxppc-dev
In-Reply-To: <1311058260.16961.12.camel@edumazet-laptop>

On Tue, 2011-07-19 at 08:51 +0200, Eric Dumazet wrote:

> > +		case BPF_S_ANC_CPU:
> > +#ifdef CONFIG_SMP
> > +			/*
> > +			 * PACA ptr is r13:
> > +			 * raw_smp_processor_id() = local_paca->paca_index
> > +			 */
> 
> This could break if one day linux supports more than 65536 cpus :)
> 
> > +			PPC_LHZ_OFFS(r_A, 13,
> > +				     offsetof(struct paca_struct, paca_index));
> > +#else
> > +			PPC_LI(r_A, 0);
> > +#endif
> > +			break;

As would our implementation of raw_smp_processor_id() and our
spinlocks :-) I don't think we need to fix that -now- but you are
welcome to add something like a
BUILD_BUG_ON(sizeof(local_paca->paca_index) != 2); as a reminder :-)

Cheers,
Ben.



^ permalink raw reply

* Re: [Patch] bluetooth: make 3 functions in hci_conn.c static
From: Américo Wang @ 2011-07-19  7:29 UTC (permalink / raw)
  To: Linux Kernel Network Developers
  Cc: linux-bluetooth, David S. Miller, Gustavo F. Padovan,
	Marcel Holtmann
In-Reply-To: <CAM_iQpUHynJZBJ29qeu_fv4Rko0=7chE5BrhavOKVyzaTDf28A@mail.gmail.com>

On Tue, Jul 19, 2011 at 3:18 PM, Américo Wang <xiyou.wangcong@gmail.com> wrote:
> hci_acl_connect()
> hci_add_sco()
> hci_conn_enter_sniff_mode()
>
> these three functions can become static as there are no callers outside.
>

Self-NAK.

Seems these 3 functions have no callers just accidentally.

^ permalink raw reply

* Re: [patch net-next-2.6] vlan: introduce ndo_vlan_[enable/disable]
From: Michał Mirosław @ 2011-07-19  7:24 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: netdev, davem, shemminger, eric.dumazet, greearb
In-Reply-To: <20110718071300.GA2244@minipsycho>

W dniu 18 lipca 2011 09:13 użytkownik Jiri Pirko <jpirko@redhat.com> napisał:
> Sun, Jul 17, 2011 at 11:06:57PM CEST, mirqus@gmail.com wrote:
>>W dniu 17 lipca 2011 21:44 użytkownik Jiri Pirko <jpirko@redhat.com> napisał:
>>> Sun, Jul 17, 2011 at 10:36:04AM CEST, mirqus@gmail.com wrote:
>>>>W dniu 17 lipca 2011 09:30 użytkownik Jiri Pirko <jpirko@redhat.com> napisał:
>>>>> Sat, Jul 16, 2011 at 04:14:36PM CEST, mirqus@gmail.com wrote:
>>>>>>2011/7/16 Jiri Pirko <jpirko@redhat.com>:
>>>>>>> Some devices are not able to enable/disable rx/tw vlan accel separately.
>>>>>>> they depend on ndo_vlan_rx_register to know if to enable of disable
>>>>>>> hw accel. And since ndo_vlan_rx_register is going to die soon,
>>>>>>> this must be resolved.
>>>>>>>
>>>>>>> One solution might be to enable accel on device start every time, even
>>>>>>> if there are no vlan up on. But this would change behaviour and might
>>>>>>> lead to possible regression (on older devices).
>>>>>>[...]
>>>>>>
>>>>>>Please describe the possible regression. As I see it, there won't be
>>>>>>any user visible change of behaviour - network code takes care of
>>>>>>reinserting VLAN tag when necessary. If you think that disabling tag
>>>>>>stripping is beneficial for cases where no VLANs are configured, it's
>>>>>>better to do that in netdev_fix_features() for devices which advertise
>>>>>>NETIF_F_HW_VLAN_RX in hw_features.
>>>>>
>>>>> Well I just wanted to preserve current behaviour which is that in many
>>>>> drivers vlan accel is enabled only if some vid is registered upon the
>>>>> device and it's disabled again when no vid is registered. I can see
>>>>> no way to do this with current code after removing ndo_vlan_rx_register.
>>>>>
>>>>> I expect unexpected
>>>>
>>>>:-D
>>>>
>>>>> ... problems on old cards when vlan accel would be
>>>>> enabled all the time, but maybe I'm wrong...
>>>>
>>>>Device has no way of knowing how the system uses VLAN tags, stripped
>>>>or not. Any problems would be driver problems and since you're making
>>>>it all use generic code, bugs will hit all drivers simultaneously or
>>>>(preferably) won't happen at all.
>>>>
>>>>> One idea is for device which do not support sepatate rx/tx vlan accel
>>>>> enabling/disabling they can probably use ndo_fix_features force to
>>>>> enable/disable rx/tx pair together. That would resolve the situation as
>>>>> well giving user possibility to turn off vlan accel in case of any issues.
>>>>
>>>>That is exactly the idea behind ndo_fix_features.
>>
>>> In netdev_fix_features add check if either one of NETIF_F_HW_VLAN_TX or
>>> NETIF_F_HW_VLAN_RX is set and in that case set the other one. Of course
>>> this would be done only for devices what do not support separate rx/tx
>>> vlan on/off. But how to distinguish? NETIF_F_HW_VLAN_BOTH feature flag?
>>
>>Not in netdev_fix_features(). This case you describe should be handled
>>in driver-specific
>
> Well since the code would be the same in many drivers I was thinking
> about putting it in general code...
>
> Anyway, would you please look at following example patch and tell me if
> it looks good to you?

[...]
>  static u32 atl1c_fix_features(struct net_device *netdev, u32 features)
>  {
> +       u32 changed = netdev->features ^ features;
> +
> +       /*
> +        * Since there is no support for separate rx/tx vlan accel
> +        * enable/disable make sure these are always set in pair.
> +        */
> +       if ((changed & NETIF_F_HW_VLAN_TX && features & NETIF_F_HW_VLAN_TX) ||
> +           (changed & NETIF_F_HW_VLAN_RX && features & NETIF_F_HW_VLAN_RX))
> +               features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
> +       else
> +               features &= ~(NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
> +

You ignored my hint about combined TX/RX offload. Is that on purpose?
Your code will toggle VLAN acceleration on every
netdev_update_features call when user requests one offload on and one
off.

BTW, the register flag name (MAC_CTRL_RMV_VLAN) suggests that it
controls only tag stripping. Was it tested or documented that this
also links with tag insertion?

[...]
> +static int atl1c_set_features(struct net_device *netdev, u32 features)
> +{
> +       u32 changed = netdev->features ^ features;
> +
> +       /*
> +        * Test for NETIF_F_HW_VLAN_TX as it's paired with NETIF_F_HW_VLAN_RX
> +        * by atl1c_fix_features.
> +        */
> +       if (changed & NETIF_F_HW_VLAN_TX)
> +               atl1c_vlan_mode(netdev, features);
> +

Test for RX is better, as it will match the name of control bit
(MAC_CTRL_RMV_VLAN).

Best Regards,
Michał Mirosław

^ permalink raw reply

* Re: [PATCH v2] net: filter: BPF 'JIT' compiler for PPC64
From: Matt Evans @ 2011-07-19  7:23 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev, netdev
In-Reply-To: <CBA05A49-86F1-40FF-9244-0E4D29EBBA48@kernel.crashing.org>

On 19/07/11 17:17, Kumar Gala wrote:
> 
> On Jul 19, 2011, at 2:06 AM, Matt Evans wrote:
> 
>> On 19/07/11 16:59, Kumar Gala wrote:
>>>
>>> On Jul 18, 2011, at 9:13 PM, Matt Evans wrote:
>>>
>>>> [snip]
>>>>
>>>> V2: Removed some cut/paste woe in setting SEEN_X even on writes.
>>>>   Merci for le review, Eric!
>>>>
>>>> arch/powerpc/Kconfig                  |    1 +
>>>> arch/powerpc/Makefile                 |    3 +-
>>>> arch/powerpc/include/asm/ppc-opcode.h |   40 ++
>>>> arch/powerpc/net/Makefile             |    4 +
>>>> arch/powerpc/net/bpf_jit.S            |  138 +++++++
>>>
>>> can we rename to bpf_jit_64.S, since this doesn't work on PPC32.
>>>
>>>> arch/powerpc/net/bpf_jit.h            |  227 +++++++++++
>>>> arch/powerpc/net/bpf_jit_comp.c       |  690 +++++++++++++++++++++++++++++++++
>>>
>>> same here, or split between bpf_jit_comp.c (shared between ppc32 & ppc64) and
>>> bpf_jit_comp_64.c
>>
>> A reasonable suggestion -- bpf_jit_64.S certainly.  I think it may not be worth
>> splitting bpf_jit_comp.c until we support both tho?  (I'm thinking
>> bpf_jit_comp_{32,64}.c would just house the stackframe generation code which is
>> the main difference, plus compile-time switched macros for the odd LD vs LWZ.)
> 
> If its most 64-bit specific than just go with bpf_jit_comp_64.c for now.  We can refactor later.

Nah, other way round -- it's almost all agnostic but with a couple of functions
that I was recommending moving out to a _64.c and _32.c later, leaving the bulk
still in bpf_jit_comp.c.


Matt

^ permalink raw reply

* [Patch] bluetooth: make 3 functions in hci_conn.c static
From: Américo Wang @ 2011-07-19  7:18 UTC (permalink / raw)
  To: Linux Kernel Network Developers
  Cc: linux-bluetooth-u79uwXL29TY76Z2rM5mHXA, David S. Miller,
	Gustavo F. Padovan, Marcel Holtmann

[-- Attachment #1: Type: text/plain, Size: 134 bytes --]

hci_acl_connect()
hci_add_sco()
hci_conn_enter_sniff_mode()

these three functions can become static as there are no callers outside.

[-- Attachment #2: net-bluetooth-hci_conn_c-make-static.diff --]
[-- Type: text/x-patch, Size: 4460 bytes --]


Signed-off-by: WANG Cong <xiyou.wangcong@gmail.com>

---
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 6c994c0..608e28b 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -409,9 +409,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
 	return NULL;
 }
 
-void hci_acl_connect(struct hci_conn *conn);
 void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
-void hci_add_sco(struct hci_conn *conn, __u16 handle);
 void hci_setup_sync(struct hci_conn *conn, __u16 handle);
 void hci_sco_setup(struct hci_conn *conn, __u8 status);
 
@@ -428,7 +426,6 @@ int hci_conn_change_link_key(struct hci_conn *conn);
 int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
 
 void hci_conn_enter_active_mode(struct hci_conn *conn);
-void hci_conn_enter_sniff_mode(struct hci_conn *conn);
 
 void hci_conn_hold_device(struct hci_conn *conn);
 void hci_conn_put_device(struct hci_conn *conn);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index bcd158f..983a337 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -72,7 +72,7 @@ static void hci_le_connect_cancel(struct hci_conn *conn)
 	hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
 }
 
-void hci_acl_connect(struct hci_conn *conn)
+static void hci_acl_connect(struct hci_conn *conn)
 {
 	struct hci_dev *hdev = conn->hdev;
 	struct inquiry_entry *ie;
@@ -141,7 +141,7 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
 	hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
 }
 
-void hci_add_sco(struct hci_conn *conn, __u16 handle)
+static void hci_add_sco(struct hci_conn *conn, __u16 handle)
 {
 	struct hci_dev *hdev = conn->hdev;
 	struct hci_cp_add_sco cp;
@@ -260,6 +260,42 @@ static void hci_conn_timeout(unsigned long arg)
 	hci_dev_unlock(hdev);
 }
 
+/* Enter sniff mode */
+static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
+{
+	struct hci_dev *hdev = conn->hdev;
+
+	BT_DBG("conn %p mode %d", conn, conn->mode);
+
+	if (test_bit(HCI_RAW, &hdev->flags))
+		return;
+
+	if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn))
+		return;
+
+	if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF))
+		return;
+
+	if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
+		struct hci_cp_sniff_subrate cp;
+		cp.handle             = cpu_to_le16(conn->handle);
+		cp.max_latency        = cpu_to_le16(0);
+		cp.min_remote_timeout = cpu_to_le16(0);
+		cp.min_local_timeout  = cpu_to_le16(0);
+		hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
+	}
+
+	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
+		struct hci_cp_sniff_mode cp;
+		cp.handle       = cpu_to_le16(conn->handle);
+		cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
+		cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
+		cp.attempt      = cpu_to_le16(4);
+		cp.timeout      = cpu_to_le16(1);
+		hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
+	}
+}
+
 static void hci_conn_idle(unsigned long arg)
 {
 	struct hci_conn *conn = (void *) arg;
@@ -703,42 +739,6 @@ timer:
 			jiffies + msecs_to_jiffies(hdev->idle_timeout));
 }
 
-/* Enter sniff mode */
-void hci_conn_enter_sniff_mode(struct hci_conn *conn)
-{
-	struct hci_dev *hdev = conn->hdev;
-
-	BT_DBG("conn %p mode %d", conn, conn->mode);
-
-	if (test_bit(HCI_RAW, &hdev->flags))
-		return;
-
-	if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn))
-		return;
-
-	if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF))
-		return;
-
-	if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
-		struct hci_cp_sniff_subrate cp;
-		cp.handle             = cpu_to_le16(conn->handle);
-		cp.max_latency        = cpu_to_le16(0);
-		cp.min_remote_timeout = cpu_to_le16(0);
-		cp.min_local_timeout  = cpu_to_le16(0);
-		hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
-	}
-
-	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
-		struct hci_cp_sniff_mode cp;
-		cp.handle       = cpu_to_le16(conn->handle);
-		cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
-		cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
-		cp.attempt      = cpu_to_le16(4);
-		cp.timeout      = cpu_to_le16(1);
-		hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
-	}
-}
-
 /* Drop all connection on the device */
 void hci_conn_hash_flush(struct hci_dev *hdev)
 {

^ permalink raw reply related

* Re: [PATCH v2] net: filter: BPF 'JIT' compiler for PPC64
From: Kumar Gala @ 2011-07-19  7:17 UTC (permalink / raw)
  To: Matt Evans; +Cc: linuxppc-dev, netdev
In-Reply-To: <4E252CFE.4070408@ozlabs.org>


On Jul 19, 2011, at 2:06 AM, Matt Evans wrote:

> On 19/07/11 16:59, Kumar Gala wrote:
>> 
>> On Jul 18, 2011, at 9:13 PM, Matt Evans wrote:
>> 
>>> An implementation of a code generator for BPF programs to speed up packet
>>> filtering on PPC64, inspired by Eric Dumazet's x86-64 version.
>>> 
>>> Filter code is generated as an ABI-compliant function in module_alloc()'d mem
>>> with stackframe & prologue/epilogue generated if required (simple filters don't
>>> need anything more than an li/blr).  The filter's local variables, M[], live in
>>> registers.  Supports all BPF opcodes, although "complicated" loads from negative
>>> packet offsets (e.g. SKF_LL_OFF) are not yet supported.
>>> 
>>> There are a couple of further optimisations left for future work; many-pass
>>> assembly with branch-reach reduction and a register allocator to push M[]
>>> variables into volatile registers would improve the code quality further.
>>> 
>>> This currently supports big-endian 64-bit PowerPC only (but is fairly simple
>>> to port to PPC32 or LE!).
>>> 
>>> Enabled in the same way as x86-64:
>>> 
>>> 	echo 1 > /proc/sys/net/core/bpf_jit_enable
>>> 
>>> Or, enabled with extra debug output:
>>> 
>>> 	echo 2 > /proc/sys/net/core/bpf_jit_enable
>>> 
>>> Signed-off-by: Matt Evans <matt@ozlabs.org>
>>> ---
>>> 
>>> V2: Removed some cut/paste woe in setting SEEN_X even on writes.
>>>   Merci for le review, Eric!
>>> 
>>> arch/powerpc/Kconfig                  |    1 +
>>> arch/powerpc/Makefile                 |    3 +-
>>> arch/powerpc/include/asm/ppc-opcode.h |   40 ++
>>> arch/powerpc/net/Makefile             |    4 +
>>> arch/powerpc/net/bpf_jit.S            |  138 +++++++
>> 
>> can we rename to bpf_jit_64.S, since this doesn't work on PPC32.
>> 
>>> arch/powerpc/net/bpf_jit.h            |  227 +++++++++++
>>> arch/powerpc/net/bpf_jit_comp.c       |  690 +++++++++++++++++++++++++++++++++
>> 
>> same here, or split between bpf_jit_comp.c (shared between ppc32 & ppc64) and
>> bpf_jit_comp_64.c
> 
> A reasonable suggestion -- bpf_jit_64.S certainly.  I think it may not be worth
> splitting bpf_jit_comp.c until we support both tho?  (I'm thinking
> bpf_jit_comp_{32,64}.c would just house the stackframe generation code which is
> the main difference, plus compile-time switched macros for the odd LD vs LWZ.)

If its most 64-bit specific than just go with bpf_jit_comp_64.c for now.  We can refactor later.

> 
> Sorry it's not 32bit-friendly just yet (I knew you'd ask, hehe), I've postponed
> that for when I get a mo :-)

:)


^ permalink raw reply

* Re: [PATCH v2] net: filter: BPF 'JIT' compiler for PPC64
From: Matt Evans @ 2011-07-19  7:06 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev, netdev
In-Reply-To: <51978BAA-10A1-483D-B551-CCC2B69C72EA@kernel.crashing.org>

On 19/07/11 16:59, Kumar Gala wrote:
> 
> On Jul 18, 2011, at 9:13 PM, Matt Evans wrote:
> 
>> An implementation of a code generator for BPF programs to speed up packet
>> filtering on PPC64, inspired by Eric Dumazet's x86-64 version.
>>
>> Filter code is generated as an ABI-compliant function in module_alloc()'d mem
>> with stackframe & prologue/epilogue generated if required (simple filters don't
>> need anything more than an li/blr).  The filter's local variables, M[], live in
>> registers.  Supports all BPF opcodes, although "complicated" loads from negative
>> packet offsets (e.g. SKF_LL_OFF) are not yet supported.
>>
>> There are a couple of further optimisations left for future work; many-pass
>> assembly with branch-reach reduction and a register allocator to push M[]
>> variables into volatile registers would improve the code quality further.
>>
>> This currently supports big-endian 64-bit PowerPC only (but is fairly simple
>> to port to PPC32 or LE!).
>>
>> Enabled in the same way as x86-64:
>>
>> 	echo 1 > /proc/sys/net/core/bpf_jit_enable
>>
>> Or, enabled with extra debug output:
>>
>> 	echo 2 > /proc/sys/net/core/bpf_jit_enable
>>
>> Signed-off-by: Matt Evans <matt@ozlabs.org>
>> ---
>>
>> V2: Removed some cut/paste woe in setting SEEN_X even on writes.
>>    Merci for le review, Eric!
>>
>> arch/powerpc/Kconfig                  |    1 +
>> arch/powerpc/Makefile                 |    3 +-
>> arch/powerpc/include/asm/ppc-opcode.h |   40 ++
>> arch/powerpc/net/Makefile             |    4 +
>> arch/powerpc/net/bpf_jit.S            |  138 +++++++
> 
> can we rename to bpf_jit_64.S, since this doesn't work on PPC32.
> 
>> arch/powerpc/net/bpf_jit.h            |  227 +++++++++++
>> arch/powerpc/net/bpf_jit_comp.c       |  690 +++++++++++++++++++++++++++++++++
> 
> same here, or split between bpf_jit_comp.c (shared between ppc32 & ppc64) and
> bpf_jit_comp_64.c

A reasonable suggestion -- bpf_jit_64.S certainly.  I think it may not be worth
splitting bpf_jit_comp.c until we support both tho?  (I'm thinking
bpf_jit_comp_{32,64}.c would just house the stackframe generation code which is
the main difference, plus compile-time switched macros for the odd LD vs LWZ.)

Sorry it's not 32bit-friendly just yet (I knew you'd ask, hehe), I've postponed
that for when I get a mo :-)

Cheers,


Matt

^ permalink raw reply

* Re: [PATCH v2] net: filter: BPF 'JIT' compiler for PPC64
From: Kumar Gala @ 2011-07-19  6:59 UTC (permalink / raw)
  To: Matt Evans; +Cc: linuxppc-dev, netdev
In-Reply-To: <4E24E867.9050909@ozlabs.org>


On Jul 18, 2011, at 9:13 PM, Matt Evans wrote:

> An implementation of a code generator for BPF programs to speed up packet
> filtering on PPC64, inspired by Eric Dumazet's x86-64 version.
> 
> Filter code is generated as an ABI-compliant function in module_alloc()'d mem
> with stackframe & prologue/epilogue generated if required (simple filters don't
> need anything more than an li/blr).  The filter's local variables, M[], live in
> registers.  Supports all BPF opcodes, although "complicated" loads from negative
> packet offsets (e.g. SKF_LL_OFF) are not yet supported.
> 
> There are a couple of further optimisations left for future work; many-pass
> assembly with branch-reach reduction and a register allocator to push M[]
> variables into volatile registers would improve the code quality further.
> 
> This currently supports big-endian 64-bit PowerPC only (but is fairly simple
> to port to PPC32 or LE!).
> 
> Enabled in the same way as x86-64:
> 
> 	echo 1 > /proc/sys/net/core/bpf_jit_enable
> 
> Or, enabled with extra debug output:
> 
> 	echo 2 > /proc/sys/net/core/bpf_jit_enable
> 
> Signed-off-by: Matt Evans <matt@ozlabs.org>
> ---
> 
> V2: Removed some cut/paste woe in setting SEEN_X even on writes.
>    Merci for le review, Eric!
> 
> arch/powerpc/Kconfig                  |    1 +
> arch/powerpc/Makefile                 |    3 +-
> arch/powerpc/include/asm/ppc-opcode.h |   40 ++
> arch/powerpc/net/Makefile             |    4 +
> arch/powerpc/net/bpf_jit.S            |  138 +++++++

can we rename to bpf_jit_64.S, since this doesn't work on PPC32.

> arch/powerpc/net/bpf_jit.h            |  227 +++++++++++
> arch/powerpc/net/bpf_jit_comp.c       |  690 +++++++++++++++++++++++++++++++++

same here, or split between bpf_jit_comp.c (shared between ppc32 & ppc64) and bpf_jit_comp_64.c

- k


^ permalink raw reply

* Re: [PATCH v2] net: filter: BPF 'JIT' compiler for PPC64
From: Eric Dumazet @ 2011-07-19  6:51 UTC (permalink / raw)
  To: Matt Evans; +Cc: linuxppc-dev, netdev
In-Reply-To: <4E24E867.9050909@ozlabs.org>

Le mardi 19 juillet 2011 à 12:13 +1000, Matt Evans a écrit :
> An implementation of a code generator for BPF programs to speed up packet
> filtering on PPC64, inspired by Eric Dumazet's x86-64 version.
> 
> Filter code is generated as an ABI-compliant function in module_alloc()'d mem
> with stackframe & prologue/epilogue generated if required (simple filters don't
> need anything more than an li/blr).  The filter's local variables, M[], live in
> registers.  Supports all BPF opcodes, although "complicated" loads from negative
> packet offsets (e.g. SKF_LL_OFF) are not yet supported.
> 
> There are a couple of further optimisations left for future work; many-pass
> assembly with branch-reach reduction and a register allocator to push M[]
> variables into volatile registers would improve the code quality further.
> 
> This currently supports big-endian 64-bit PowerPC only (but is fairly simple
> to port to PPC32 or LE!).
> 
> Enabled in the same way as x86-64:
> 
> 	echo 1 > /proc/sys/net/core/bpf_jit_enable
> 
> Or, enabled with extra debug output:
> 
> 	echo 2 > /proc/sys/net/core/bpf_jit_enable
> 
> Signed-off-by: Matt Evans <matt@ozlabs.org>
> ---
> 
> V2: Removed some cut/paste woe in setting SEEN_X even on writes.
>     Merci for le review, Eric!
> 
>  arch/powerpc/Kconfig                  |    1 +
>  arch/powerpc/Makefile                 |    3 +-
>  arch/powerpc/include/asm/ppc-opcode.h |   40 ++
>  arch/powerpc/net/Makefile             |    4 +
>  arch/powerpc/net/bpf_jit.S            |  138 +++++++
>  arch/powerpc/net/bpf_jit.h            |  227 +++++++++++
>  arch/powerpc/net/bpf_jit_comp.c       |  690 +++++++++++++++++++++++++++++++++
>  7 files changed, 1102 insertions(+), 1 deletions(-)
> 

> +		case BPF_S_ANC_CPU:
> +#ifdef CONFIG_SMP
> +			/*
> +			 * PACA ptr is r13:
> +			 * raw_smp_processor_id() = local_paca->paca_index
> +			 */

This could break if one day linux supports more than 65536 cpus :)

> +			PPC_LHZ_OFFS(r_A, 13,
> +				     offsetof(struct paca_struct, paca_index));
> +#else
> +			PPC_LI(r_A, 0);
> +#endif
> +			break;
> +
> +
> +		case BPF_S_LDX_B_MSH:
> +			/*
> +			 * x86 version drops packet (RET 0) when K<0, whereas
> +			 * interpreter does allow K<0 (__load_pointer, special
> +			 * ancillary data).
> +			 */

Hmm, thanks I'll take a look at this.

> +			func = sk_load_byte_msh;
> +			goto common_load;
> +			break;
> +
> +			/*** Jump and branches ***/

> +		default:
> +			/* The filter contains something cruel & unusual.
> +			 * We don't handle it, but also there shouldn't be
> +			 * anything missing from our list.
> +			 */
> +			pr_err("BPF filter opcode %04x (@%d) unsupported\n",
> +			       filter[i].code, i);

You should at least ratelimit this message ?

On x86_64 I chose to silently fall back to interpretor for a "complex
filter" or "unsupported opcode".

> +			return -ENOTSUPP;
> +		}
> +
> +	}
> +	/* Set end-of-body-code address for exit. */
> +	addrs[i] = ctx->idx * 4;
> +
> +	return 0;
> +}
> +



^ permalink raw reply

* Re: ath: Unable to reset channel (2412 MHz), reset status -5
From: Mohammed Shafi @ 2011-07-19  6:46 UTC (permalink / raw)
  To: Justin P. Mattock
  Cc: netdev@vger.kernel.org, linux-wireless,
	linux-kernel@vger.kernel.org
In-Reply-To: <4E2525BA.4090902@gmail.com>

On Tue, Jul 19, 2011 at 12:05 PM, Justin P. Mattock
<justinmattock@gmail.com> wrote:
> On 07/18/2011 11:25 PM, Mohammed Shafi wrote:
>>
>> On Tue, Jul 19, 2011 at 11:43 AM, Justin P. Mattock
>> <justinmattock@gmail.com>  wrote:
>>>
>>> seems with the latest Mainline I am getting the ath9k carpping out after
>>> a
>>> while of streaming(dmesg below)..:
>>> http://fpaste.org/D7wM/
>>>
>>> will try a bisect if I have the time..
>>
>> I will try to recreate here with 3.0.0-rc7-wl, we can get more
>> information by ath9k debug=0xffffffff.
>> thanks.
>>
>
> cool!
> seems to fire off randomly over here.

I have got AR5416, will try with that.

-- 
shafi

^ permalink raw reply

* Re: ath: Unable to reset channel (2412 MHz), reset status -5
From: Justin P. Mattock @ 2011-07-19  6:35 UTC (permalink / raw)
  To: Mohammed Shafi
  Cc: netdev@vger.kernel.org, linux-wireless,
	linux-kernel@vger.kernel.org
In-Reply-To: <CAD2nsn12vOXv-msWR+GF7edz3Q26P-pb4H-SO4rf2RHjC7mG+w@mail.gmail.com>

On 07/18/2011 11:25 PM, Mohammed Shafi wrote:
> On Tue, Jul 19, 2011 at 11:43 AM, Justin P. Mattock
> <justinmattock@gmail.com>  wrote:
>> seems with the latest Mainline I am getting the ath9k carpping out after a
>> while of streaming(dmesg below)..:
>> http://fpaste.org/D7wM/
>>
>> will try a bisect if I have the time..
>
> I will try to recreate here with 3.0.0-rc7-wl, we can get more
> information by ath9k debug=0xffffffff.
> thanks.
>

cool!
seems to fire off randomly over here.

Justin P. Mattock

^ permalink raw reply

* Re: ath: Unable to reset channel (2412 MHz), reset status -5
From: Mohammed Shafi @ 2011-07-19  6:25 UTC (permalink / raw)
  To: Justin P. Mattock
  Cc: netdev@vger.kernel.org, linux-wireless,
	linux-kernel@vger.kernel.org
In-Reply-To: <4E252076.1050309@gmail.com>

On Tue, Jul 19, 2011 at 11:43 AM, Justin P. Mattock
<justinmattock@gmail.com> wrote:
> seems with the latest Mainline I am getting the ath9k carpping out after a
> while of streaming(dmesg below)..:
> http://fpaste.org/D7wM/
>
> will try a bisect if I have the time..

I will try to recreate here with 3.0.0-rc7-wl, we can get more
information by ath9k debug=0xffffffff.
thanks.

-- 
shafi

^ permalink raw reply

* ath: Unable to reset channel (2412 MHz), reset status -5
From: Justin P. Mattock @ 2011-07-19  6:13 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

seems with the latest Mainline I am getting the ath9k carpping out after 
a while of streaming(dmesg below)..:
http://fpaste.org/D7wM/

will try a bisect if I have the time..

Justin P. Mattock
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" 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

* [PATCH v2] net: filter: BPF 'JIT' compiler for PPC64
From: Matt Evans @ 2011-07-19  2:13 UTC (permalink / raw)
  To: linuxppc-dev, netdev
In-Reply-To: <4E23E5C3.1070209@ozlabs.org>

An implementation of a code generator for BPF programs to speed up packet
filtering on PPC64, inspired by Eric Dumazet's x86-64 version.

Filter code is generated as an ABI-compliant function in module_alloc()'d mem
with stackframe & prologue/epilogue generated if required (simple filters don't
need anything more than an li/blr).  The filter's local variables, M[], live in
registers.  Supports all BPF opcodes, although "complicated" loads from negative
packet offsets (e.g. SKF_LL_OFF) are not yet supported.

There are a couple of further optimisations left for future work; many-pass
assembly with branch-reach reduction and a register allocator to push M[]
variables into volatile registers would improve the code quality further.

This currently supports big-endian 64-bit PowerPC only (but is fairly simple
to port to PPC32 or LE!).

Enabled in the same way as x86-64:

	echo 1 > /proc/sys/net/core/bpf_jit_enable

Or, enabled with extra debug output:

	echo 2 > /proc/sys/net/core/bpf_jit_enable

Signed-off-by: Matt Evans <matt@ozlabs.org>
---

V2: Removed some cut/paste woe in setting SEEN_X even on writes.
    Merci for le review, Eric!

 arch/powerpc/Kconfig                  |    1 +
 arch/powerpc/Makefile                 |    3 +-
 arch/powerpc/include/asm/ppc-opcode.h |   40 ++
 arch/powerpc/net/Makefile             |    4 +
 arch/powerpc/net/bpf_jit.S            |  138 +++++++
 arch/powerpc/net/bpf_jit.h            |  227 +++++++++++
 arch/powerpc/net/bpf_jit_comp.c       |  690 +++++++++++++++++++++++++++++++++
 7 files changed, 1102 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 2729c66..39860fc 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -134,6 +134,7 @@ config PPC
 	select GENERIC_IRQ_SHOW_LEVEL
 	select HAVE_RCU_TABLE_FREE if SMP
 	select HAVE_SYSCALL_TRACEPOINTS
+	select HAVE_BPF_JIT if PPC64
 
 config EARLY_PRINTK
 	bool
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index b7212b6..b94740f 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -154,7 +154,8 @@ core-y				+= arch/powerpc/kernel/ \
 				   arch/powerpc/lib/ \
 				   arch/powerpc/sysdev/ \
 				   arch/powerpc/platforms/ \
-				   arch/powerpc/math-emu/
+				   arch/powerpc/math-emu/ \
+				   arch/powerpc/net/
 core-$(CONFIG_XMON)		+= arch/powerpc/xmon/
 core-$(CONFIG_KVM) 		+= arch/powerpc/kvm/
 
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index e472659..e980faa 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -71,6 +71,42 @@
 #define PPC_INST_ERATSX			0x7c000126
 #define PPC_INST_ERATSX_DOT		0x7c000127
 
+/* Misc instructions for BPF compiler */
+#define PPC_INST_LD			0xe8000000
+#define PPC_INST_LHZ			0xa0000000
+#define PPC_INST_LWZ			0x80000000
+#define PPC_INST_STD			0xf8000000
+#define PPC_INST_STDU			0xf8000001
+#define PPC_INST_MFLR			0x7c0802a6
+#define PPC_INST_MTLR			0x7c0803a6
+#define PPC_INST_CMPWI			0x2c000000
+#define PPC_INST_CMPDI			0x2c200000
+#define PPC_INST_CMPLW			0x7c000040
+#define PPC_INST_CMPLWI			0x28000000
+#define PPC_INST_ADDI			0x38000000
+#define PPC_INST_ADDIS			0x3c000000
+#define PPC_INST_ADD			0x7c000214
+#define PPC_INST_SUB			0x7c000050
+#define PPC_INST_BLR			0x4e800020
+#define PPC_INST_BLRL			0x4e800021
+#define PPC_INST_MULLW			0x7c0001d6
+#define PPC_INST_MULHWU			0x7c000016
+#define PPC_INST_MULLI			0x1c000000
+#define PPC_INST_DIVWU			0x7c0003d6
+#define PPC_INST_RLWINM			0x54000000
+#define PPC_INST_RLDICR			0x78000004
+#define PPC_INST_SLW			0x7c000030
+#define PPC_INST_SRW			0x7c000430
+#define PPC_INST_AND			0x7c000038
+#define PPC_INST_ANDDOT			0x7c000039
+#define PPC_INST_OR			0x7c000378
+#define PPC_INST_ANDI			0x70000000
+#define PPC_INST_ORI			0x60000000
+#define PPC_INST_ORIS			0x64000000
+#define PPC_INST_NEG			0x7c0000d0
+#define PPC_INST_BRANCH			0x48000000
+#define PPC_INST_BRANCH_COND		0x40800000
+
 /* macros to insert fields into opcodes */
 #define __PPC_RA(a)	(((a) & 0x1f) << 16)
 #define __PPC_RB(b)	(((b) & 0x1f) << 11)
@@ -83,6 +119,10 @@
 #define __PPC_T_TLB(t)	(((t) & 0x3) << 21)
 #define __PPC_WC(w)	(((w) & 0x3) << 21)
 #define __PPC_WS(w)	(((w) & 0x1f) << 11)
+#define __PPC_SH(s)	__PPC_WS(s)
+#define __PPC_MB(s)	(((s) & 0x1f) << 6)
+#define __PPC_ME(s)	(((s) & 0x1f) << 1)
+#define __PPC_BI(s)	(((s) & 0x1f) << 16)
 
 /*
  * Only use the larx hint bit on 64bit CPUs. e500v1/v2 based CPUs will treat a
diff --git a/arch/powerpc/net/Makefile b/arch/powerpc/net/Makefile
new file mode 100644
index 0000000..90568c3
--- /dev/null
+++ b/arch/powerpc/net/Makefile
@@ -0,0 +1,4 @@
+#
+# Arch-specific network modules
+#
+obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o
diff --git a/arch/powerpc/net/bpf_jit.S b/arch/powerpc/net/bpf_jit.S
new file mode 100644
index 0000000..ff4506e
--- /dev/null
+++ b/arch/powerpc/net/bpf_jit.S
@@ -0,0 +1,138 @@
+/* bpf_jit.S: Packet/header access helper functions
+ * for PPC64 BPF compiler.
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#include <asm/ppc_asm.h>
+#include "bpf_jit.h"
+
+/*
+ * All of these routines are called directly from generated code,
+ * whose register usage is:
+ *
+ * r3		skb
+ * r4,r5	A,X
+ * r6		*** address parameter to helper ***
+ * r7-r10	scratch
+ * r14		skb->data
+ * r15		skb headlen
+ * r16-31	M[]
+ */
+
+/*
+ * To consider: These helpers are so small it could be better to just
+ * generate them inline.  Inline code can do the simple headlen check
+ * then branch directly to slow_path_XXX if required.  (In fact, could
+ * load a spare GPR with the address of slow_path_generic and pass size
+ * as an argument, making the call site a mtlr, li and bllr.)
+ *
+ * Technically, the "is addr < 0" check is unnecessary & slowing down
+ * the ABS path, as it's statically checked on generation.
+ */
+	.globl	sk_load_word
+sk_load_word:
+	cmpdi	r_addr, 0
+	blt	bpf_error
+	/* Are we accessing past headlen? */
+	subi	r_scratch1, r_HL, 4
+	cmpd	r_scratch1, r_addr
+	blt	bpf_slow_path_word
+	/* Nope, just hitting the header.  cr0 here is eq or gt! */
+	lwzx	r_A, r_D, r_addr
+	/* When big endian we don't need to byteswap. */
+	blr	/* Return success, cr0 != LT */
+
+	.globl	sk_load_half
+sk_load_half:
+	cmpdi	r_addr, 0
+	blt	bpf_error
+	subi	r_scratch1, r_HL, 2
+	cmpd	r_scratch1, r_addr
+	blt	bpf_slow_path_half
+	lhzx	r_A, r_D, r_addr
+	blr
+
+	.globl	sk_load_byte
+sk_load_byte:
+	cmpdi	r_addr, 0
+	blt	bpf_error
+	cmpd	r_HL, r_addr
+	ble	bpf_slow_path_byte
+	lbzx	r_A, r_D, r_addr
+	blr
+
+/*
+ * BPF_S_LDX_B_MSH: ldxb  4*([offset]&0xf)
+ * r_addr is the offset value, already known positive
+ */
+	.globl sk_load_byte_msh
+sk_load_byte_msh:
+	cmpd	r_HL, r_addr
+	ble	bpf_slow_path_byte_msh
+	lbzx	r_X, r_D, r_addr
+	rlwinm	r_X, r_X, 2, 32-4-2, 31-2
+	blr
+
+bpf_error:
+	/* Entered with cr0 = lt */
+	li	r3, 0
+	/* Generated code will 'blt epilogue', returning 0. */
+	blr
+
+/* Call out to skb_copy_bits:
+ * We'll need to back up our volatile regs first; we have
+ * local variable space at r1+(BPF_PPC_STACK_BASIC).
+ * Allocate a new stack frame here to remain ABI-compliant in
+ * stashing LR.
+ */
+#define bpf_slow_path_common(SIZE)				\
+	mflr	r0;						\
+	std	r0, 16(r1);					\
+	/* R3 goes in parameter space of caller's frame */	\
+	std	r_skb, (BPF_PPC_STACKFRAME+48)(r1);		\
+	std	r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1);		\
+	std	r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1);		\
+	addi	r5, r1, BPF_PPC_STACK_BASIC+(2*8);		\
+	stdu	r1, -BPF_PPC_SLOWPATH_FRAME(r1);		\
+	/* R3 = r_skb, as passed */				\
+	mr	r4, r_addr;					\
+	li	r6, SIZE;					\
+	bl	skb_copy_bits;					\
+	/* R3 = 0 on success */					\
+	addi	r1, r1, BPF_PPC_SLOWPATH_FRAME;			\
+	ld	r0, 16(r1);					\
+	ld	r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1);		\
+	ld	r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1);		\
+	mtlr	r0;						\
+	cmpdi	r3, 0;						\
+	blt	bpf_error;	/* cr0 = LT */			\
+	ld	r_skb, (BPF_PPC_STACKFRAME+48)(r1);		\
+	/* Great success! */
+
+bpf_slow_path_word:
+	bpf_slow_path_common(4)
+	/* Data value is on stack, and cr0 != LT */
+	lwz	r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
+	blr
+
+bpf_slow_path_half:
+	bpf_slow_path_common(2)
+	lhz	r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
+	blr
+
+bpf_slow_path_byte:
+	bpf_slow_path_common(1)
+	lbz	r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
+	blr
+
+bpf_slow_path_byte_msh:
+	bpf_slow_path_common(1)
+	lbz	r_X, BPF_PPC_STACK_BASIC+(2*8)(r1)
+	rlwinm	r_X, r_X, 2, 32-4-2, 31-2
+	blr
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
new file mode 100644
index 0000000..af1ab5e
--- /dev/null
+++ b/arch/powerpc/net/bpf_jit.h
@@ -0,0 +1,227 @@
+/* bpf_jit.h: BPF JIT compiler for PPC64
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+#ifndef _BPF_JIT_H
+#define _BPF_JIT_H
+
+#define BPF_PPC_STACK_LOCALS	32
+#define BPF_PPC_STACK_BASIC	(48+64)
+#define BPF_PPC_STACK_SAVE	(18*8)
+#define BPF_PPC_STACKFRAME	(BPF_PPC_STACK_BASIC+BPF_PPC_STACK_LOCALS+ \
+				 BPF_PPC_STACK_SAVE)
+#define BPF_PPC_SLOWPATH_FRAME	(48+64)
+
+/*
+ * Generated code register usage:
+ *
+ * As normal PPC C ABI (e.g. r1=sp, r2=TOC), with:
+ *
+ * skb		r3	(Entry parameter)
+ * A register	r4
+ * X register	r5
+ * addr param	r6
+ * r7-r10	scratch
+ * skb->data	r14
+ * skb headlen	r15	(skb->len - skb->data_len)
+ * m[0]		r16
+ * m[...]	...
+ * m[15]	r31
+ */
+#define r_skb		3
+#define r_ret		3
+#define r_A		4
+#define r_X		5
+#define r_addr		6
+#define r_scratch1	7
+#define r_D		14
+#define r_HL		15
+#define r_M		16
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Assembly helpers from arch/powerpc/net/bpf_jit.S:
+ */
+extern u8 sk_load_word[], sk_load_half[], sk_load_byte[], sk_load_byte_msh[];
+
+#define FUNCTION_DESCR_SIZE	24
+
+/*
+ * 16-bit immediate helper macros: HA() is for use with sign-extending instrs
+ * (e.g. LD, ADDI).  If the bottom 16 bits is "-ve", add another bit into the
+ * top half to negate the effect (i.e. 0xffff + 1 = 0x(1)0000).
+ */
+#define IMM_H(i)		((uintptr_t)(i)>>16)
+#define IMM_HA(i)		(((uintptr_t)(i)>>16) +			      \
+				 (((uintptr_t)(i) & 0x8000) >> 15))
+#define IMM_L(i)		((uintptr_t)(i) & 0xffff)
+
+#define PLANT_INSTR(d, idx, instr)					      \
+	do { if (d) { (d)[idx] = instr; } idx++; } while (0)
+#define EMIT(instr)		PLANT_INSTR(image, ctx->idx, instr)
+
+#define PPC_NOP()		EMIT(PPC_INST_NOP)
+#define PPC_BLR()		EMIT(PPC_INST_BLR)
+#define PPC_BLRL()		EMIT(PPC_INST_BLRL)
+#define PPC_MTLR(r)		EMIT(PPC_INST_MTLR | __PPC_RT(r))
+#define PPC_ADDI(d, a, i)	EMIT(PPC_INST_ADDI | __PPC_RT(d) |	      \
+				     __PPC_RA(a) | IMM_L(i))
+#define PPC_MR(d, a)		PPC_OR(d, a, a)
+#define PPC_LI(r, i)		PPC_ADDI(r, 0, i)
+#define PPC_ADDIS(d, a, i)	EMIT(PPC_INST_ADDIS |			      \
+				     __PPC_RS(d) | __PPC_RA(a) | IMM_L(i))
+#define PPC_LIS(r, i)		PPC_ADDIS(r, 0, i)
+#define PPC_STD(r, base, i)	EMIT(PPC_INST_STD | __PPC_RS(r) |	      \
+				     __PPC_RA(base) | ((i) & 0xfffc))
+
+#define PPC_LD(r, base, i)	EMIT(PPC_INST_LD | __PPC_RT(r) |	      \
+				     __PPC_RA(base) | IMM_L(i))
+#define PPC_LWZ(r, base, i)	EMIT(PPC_INST_LWZ | __PPC_RT(r) |	      \
+				     __PPC_RA(base) | IMM_L(i))
+#define PPC_LHZ(r, base, i)	EMIT(PPC_INST_LHZ | __PPC_RT(r) |	      \
+				     __PPC_RA(base) | IMM_L(i))
+/* Convenience helpers for the above with 'far' offsets: */
+#define PPC_LD_OFFS(r, base, i) do { if ((i) < 32768) PPC_LD(r, base, i);     \
+		else {	PPC_ADDIS(r, base, IMM_HA(i));			      \
+			PPC_LD(r, r, IMM_L(i)); } } while(0)
+
+#define PPC_LWZ_OFFS(r, base, i) do { if ((i) < 32768) PPC_LWZ(r, base, i);   \
+		else {	PPC_ADDIS(r, base, IMM_HA(i));			      \
+			PPC_LWZ(r, r, IMM_L(i)); } } while(0)
+
+#define PPC_LHZ_OFFS(r, base, i) do { if ((i) < 32768) PPC_LHZ(r, base, i);   \
+		else {	PPC_ADDIS(r, base, IMM_HA(i));			      \
+			PPC_LHZ(r, r, IMM_L(i)); } } while(0)
+
+#define PPC_CMPWI(a, i)		EMIT(PPC_INST_CMPWI | __PPC_RA(a) | IMM_L(i))
+#define PPC_CMPDI(a, i)		EMIT(PPC_INST_CMPDI | __PPC_RA(a) | IMM_L(i))
+#define PPC_CMPLWI(a, i)	EMIT(PPC_INST_CMPLWI | __PPC_RA(a) | IMM_L(i))
+#define PPC_CMPLW(a, b)		EMIT(PPC_INST_CMPLW | __PPC_RA(a) | __PPC_RB(b))
+
+#define PPC_SUB(d, a, b)	EMIT(PPC_INST_SUB | __PPC_RT(d) |	      \
+				     __PPC_RB(a) | __PPC_RA(b))
+#define PPC_ADD(d, a, b)	EMIT(PPC_INST_ADD | __PPC_RT(d) |	      \
+				     __PPC_RA(a) | __PPC_RB(b))
+#define PPC_MUL(d, a, b)	EMIT(PPC_INST_MULLW | __PPC_RT(d) |	      \
+				     __PPC_RA(a) | __PPC_RB(b))
+#define PPC_MULHWU(d, a, b)	EMIT(PPC_INST_MULHWU | __PPC_RT(d) |	      \
+				     __PPC_RA(a) | __PPC_RB(b))
+#define PPC_MULI(d, a, i)	EMIT(PPC_INST_MULLI | __PPC_RT(d) |	      \
+				     __PPC_RA(a) | IMM_L(i))
+#define PPC_DIVWU(d, a, b)	EMIT(PPC_INST_DIVWU | __PPC_RT(d) |	      \
+				     __PPC_RA(a) | __PPC_RB(b))
+#define PPC_AND(d, a, b)	EMIT(PPC_INST_AND | __PPC_RA(d) |	      \
+				     __PPC_RS(a) | __PPC_RB(b))
+#define PPC_ANDI(d, a, i)	EMIT(PPC_INST_ANDI | __PPC_RA(d) |	      \
+				     __PPC_RS(a) | IMM_L(i))
+#define PPC_AND_DOT(d, a, b)	EMIT(PPC_INST_ANDDOT | __PPC_RA(d) |	      \
+				     __PPC_RS(a) | __PPC_RB(b))
+#define PPC_OR(d, a, b)		EMIT(PPC_INST_OR | __PPC_RA(d) |	      \
+				     __PPC_RS(a) | __PPC_RB(b))
+#define PPC_ORI(d, a, i)	EMIT(PPC_INST_ORI | __PPC_RA(d) |	      \
+				     __PPC_RS(a) | IMM_L(i))
+#define PPC_ORIS(d, a, i)	EMIT(PPC_INST_ORIS | __PPC_RA(d) |	      \
+				     __PPC_RS(a) | IMM_L(i))
+#define PPC_SLW(d, a, s)	EMIT(PPC_INST_SLW | __PPC_RA(d) |	      \
+				     __PPC_RS(a) | __PPC_RB(s))
+#define PPC_SRW(d, a, s)	EMIT(PPC_INST_SRW | __PPC_RA(d) |	      \
+				     __PPC_RS(a) | __PPC_RB(s))
+/* slwi = rlwinm Rx, Ry, n, 0, 31-n */
+#define PPC_SLWI(d, a, i)	EMIT(PPC_INST_RLWINM | __PPC_RA(d) |	      \
+				     __PPC_RS(a) | __PPC_SH(i) |	      \
+				     __PPC_MB(0) | __PPC_ME(31-(i)))
+/* srwi = rlwinm Rx, Ry, 32-n, n, 31 */
+#define PPC_SRWI(d, a, i)	EMIT(PPC_INST_RLWINM | __PPC_RA(d) |	      \
+				     __PPC_RS(a) | __PPC_SH(32-(i)) |	      \
+				     __PPC_MB(i) | __PPC_ME(31))
+/* sldi = rldicr Rx, Ry, n, 63-n */
+#define PPC_SLDI(d, a, i)	EMIT(PPC_INST_RLDICR | __PPC_RA(d) |	      \
+				     __PPC_RS(a) | __PPC_SH(i) |	      \
+				     __PPC_MB(63-(i)) | (((i) & 0x20) >> 4))
+#define PPC_NEG(d, a)		EMIT(PPC_INST_NEG | __PPC_RT(d) | __PPC_RA(a))
+
+/* Long jump; (unconditional 'branch') */
+#define PPC_JMP(dest)		EMIT(PPC_INST_BRANCH |			      \
+				     (((dest) - (ctx->idx * 4)) & 0x03fffffc))
+/* "cond" here covers BO:BI fields. */
+#define PPC_BCC_SHORT(cond, dest)	EMIT(PPC_INST_BRANCH_COND |	      \
+					     (((cond) & 0x3ff) << 16) |	      \
+					     (((dest) - (ctx->idx * 4)) &     \
+					      0xfffc))
+#define PPC_LI32(d, i)		do { PPC_LI(d, IMM_L(i));		      \
+		if ((u32)(uintptr_t)(i) >= 32768) {			      \
+			PPC_ADDIS(d, d, IMM_HA(i));			      \
+		} } while(0)
+#define PPC_LI64(d, i)		do {					      \
+		if (!((uintptr_t)(i) & 0xffffffff00000000ULL))		      \
+			PPC_LI32(d, i);					      \
+		else {							      \
+			PPC_LIS(d, ((uintptr_t)(i) >> 48));		      \
+			if ((uintptr_t)(i) & 0x0000ffff00000000ULL)	      \
+				PPC_ORI(d, d,				      \
+					((uintptr_t)(i) >> 32) & 0xffff);     \
+			PPC_SLDI(d, d, 32);				      \
+			if ((uintptr_t)(i) & 0x00000000ffff0000ULL)	      \
+				PPC_ORIS(d, d,				      \
+					 ((uintptr_t)(i) >> 16) & 0xffff);    \
+			if ((uintptr_t)(i) & 0x000000000000ffffULL)	      \
+				PPC_ORI(d, d, (uintptr_t)(i) & 0xffff);	      \
+		} } while (0);
+
+static inline bool is_nearbranch(int offset)
+{
+	return (offset < 32768) && (offset >= -32768);
+}
+
+/*
+ * The fly in the ointment of code size changing from pass to pass is
+ * avoided by padding the short branch case with a NOP.	 If code size differs
+ * with different branch reaches we will have the issue of code moving from
+ * one pass to the next and will need a few passes to converge on a stable
+ * state.
+ */
+#define PPC_BCC(cond, dest)	do {					      \
+		if (is_nearbranch((dest) - (ctx->idx * 4))) {		      \
+			PPC_BCC_SHORT(cond, dest);			      \
+			PPC_NOP();					      \
+		} else {						      \
+			/* Flip the 'T or F' bit to invert comparison */      \
+			PPC_BCC_SHORT(cond ^ COND_CMP_TRUE, (ctx->idx+2)*4);  \
+			PPC_JMP(dest);					      \
+		} } while(0)
+
+/* To create a branch condition, select a bit of cr0... */
+#define CR0_LT		0
+#define CR0_GT		1
+#define CR0_EQ		2
+/* ...and modify BO[3] */
+#define COND_CMP_TRUE	0x100
+#define COND_CMP_FALSE	0x000
+/* Together, they make all required comparisons: */
+#define COND_GT		(CR0_GT | COND_CMP_TRUE)
+#define COND_GE		(CR0_LT | COND_CMP_FALSE)
+#define COND_EQ		(CR0_EQ | COND_CMP_TRUE)
+#define COND_NE		(CR0_EQ | COND_CMP_FALSE)
+#define COND_LT		(CR0_LT | COND_CMP_TRUE)
+
+#define SEEN_DATAREF 0x10000 /* might call external helpers */
+#define SEEN_XREG    0x20000 /* X reg is used */
+#define SEEN_MEM     0x40000 /* SEEN_MEM+(1<<n) = use mem[n] for temporary
+			      * storage */
+#define SEEN_MEM_MSK 0x0ffff
+
+struct codegen_context {
+	unsigned int seen;
+	unsigned int idx;
+	int pc_ret0; /* bpf index of first RET #0 instruction (if any) */
+};
+
+#endif
+
+#endif
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
new file mode 100644
index 0000000..2cb2566
--- /dev/null
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -0,0 +1,690 @@
+/* bpf_jit_comp.c: BPF JIT compiler for PPC64
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation
+ *
+ * Based on the x86 BPF compiler, by Eric Dumazet (eric.dumazet@gmail.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+#include <linux/moduleloader.h>
+#include <asm/cacheflush.h>
+#include <linux/netdevice.h>
+#include <linux/filter.h>
+#include "bpf_jit.h"
+
+#ifndef __BIG_ENDIAN
+/* There are endianness assumptions herein. */
+#error "Little-endian PPC not supported in BPF compiler"
+#endif
+
+int bpf_jit_enable __read_mostly;
+
+
+static inline void bpf_flush_icache(void *start, void *end)
+{
+	smp_wmb();
+	flush_icache_range((unsigned long)start, (unsigned long)end);
+}
+
+static void bpf_jit_build_prologue(struct sk_filter *fp, u32 *image,
+				   struct codegen_context *ctx)
+{
+	int i;
+	const struct sock_filter *filter = fp->insns;
+
+	if (ctx->seen & (SEEN_MEM | SEEN_DATAREF)) {
+		/* Make stackframe */
+		if (ctx->seen & SEEN_DATAREF) {
+			/* If we call any helpers (for loads), save LR */
+			EMIT(PPC_INST_MFLR | __PPC_RT(0));
+			PPC_STD(0, 1, 16);
+
+			/* Back up non-volatile regs. */
+			PPC_STD(r_D, 1, -(8*(32-r_D)));
+			PPC_STD(r_HL, 1, -(8*(32-r_HL)));
+		}
+		if (ctx->seen & SEEN_MEM) {
+			/*
+			 * Conditionally save regs r15-r31 as some will be used
+			 * for M[] data.
+			 */
+			for (i = r_M; i < (r_M+16); i++) {
+				if (ctx->seen & (1 << (i-r_M)))
+					PPC_STD(i, 1, -(8*(32-i)));
+			}
+		}
+		EMIT(PPC_INST_STDU | __PPC_RS(1) | __PPC_RA(1) |
+		     (-BPF_PPC_STACKFRAME & 0xfffc));
+	}
+
+	if (ctx->seen & SEEN_DATAREF) {
+		/*
+		 * If this filter needs to access skb data,
+		 * prepare r_D and r_HL:
+		 *  r_HL = skb->len - skb->data_len
+		 *  r_D	 = skb->data
+		 */
+		PPC_LWZ_OFFS(r_scratch1, r_skb, offsetof(struct sk_buff,
+							 data_len));
+		PPC_LWZ_OFFS(r_HL, r_skb, offsetof(struct sk_buff, len));
+		PPC_SUB(r_HL, r_HL, r_scratch1);
+		PPC_LD_OFFS(r_D, r_skb, offsetof(struct sk_buff, data));
+	}
+
+	if (ctx->seen & SEEN_XREG) {
+		/*
+		 * TODO: Could also detect whether first instr. sets X and
+		 * avoid this (as below, with A).
+		 */
+		PPC_LI(r_X, 0);
+	}
+
+	switch (filter[0].code) {
+	case BPF_S_RET_K:
+	case BPF_S_LD_W_LEN:
+	case BPF_S_ANC_PROTOCOL:
+	case BPF_S_ANC_IFINDEX:
+	case BPF_S_ANC_MARK:
+	case BPF_S_ANC_RXHASH:
+	case BPF_S_ANC_CPU:
+	case BPF_S_ANC_QUEUE:
+	case BPF_S_LD_W_ABS:
+	case BPF_S_LD_H_ABS:
+	case BPF_S_LD_B_ABS:
+		/* first instruction sets A register (or is RET 'constant') */
+		break;
+	default:
+		/* make sure we dont leak kernel information to user */
+		PPC_LI(r_A, 0);
+	}
+}
+
+static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
+{
+	int i;
+
+	if (ctx->seen & (SEEN_MEM | SEEN_DATAREF)) {
+		PPC_ADDI(1, 1, BPF_PPC_STACKFRAME);
+		if (ctx->seen & SEEN_DATAREF) {
+			PPC_LD(0, 1, 16);
+			PPC_MTLR(0);
+			PPC_LD(r_D, 1, -(8*(32-r_D)));
+			PPC_LD(r_HL, 1, -(8*(32-r_HL)));
+		}
+		if (ctx->seen & SEEN_MEM) {
+			/* Restore any saved non-vol registers */
+			for (i = r_M; i < (r_M+16); i++) {
+				if (ctx->seen & (1 << (i-r_M)))
+					PPC_LD(i, 1, -(8*(32-i)));
+			}
+		}
+	}
+	/* The RETs have left a return value in R3. */
+
+	PPC_BLR();
+}
+
+/* Assemble the body code between the prologue & epilogue. */
+static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
+			      struct codegen_context *ctx,
+			      unsigned int *addrs)
+{
+	const struct sock_filter *filter = fp->insns;
+	int flen = fp->len;
+	u8 *func;
+	unsigned int true_cond;
+	int i;
+
+	/* Start of epilogue code */
+	unsigned int exit_addr = addrs[flen];
+
+	for (i = 0; i < flen; i++) {
+		unsigned int K = filter[i].k;
+
+		/*
+		 * addrs[] maps a BPF bytecode address into a real offset from
+		 * the start of the body code.
+		 */
+		addrs[i] = ctx->idx * 4;
+
+		switch (filter[i].code) {
+			/*** ALU ops ***/
+		case BPF_S_ALU_ADD_X: /* A += X; */
+			ctx->seen |= SEEN_XREG;
+			PPC_ADD(r_A, r_A, r_X);
+			break;
+		case BPF_S_ALU_ADD_K: /* A += K; */
+			if (!K)
+				break;
+			PPC_ADDI(r_A, r_A, IMM_L(K));
+			if (K >= 32768)
+				PPC_ADDIS(r_A, r_A, IMM_HA(K));
+			break;
+		case BPF_S_ALU_SUB_X: /* A -= X; */
+			ctx->seen |= SEEN_XREG;
+			PPC_SUB(r_A, r_A, r_X);
+			break;
+		case BPF_S_ALU_SUB_K: /* A -= K */
+			if (!K)
+				break;
+			PPC_ADDI(r_A, r_A, IMM_L(-K));
+			if (K >= 32768)
+				PPC_ADDIS(r_A, r_A, IMM_HA(-K));
+			break;
+		case BPF_S_ALU_MUL_X: /* A *= X; */
+			ctx->seen |= SEEN_XREG;
+			PPC_MUL(r_A, r_A, r_X);
+			break;
+		case BPF_S_ALU_MUL_K: /* A *= K */
+			if (K < 32768)
+				PPC_MULI(r_A, r_A, K);
+			else {
+				PPC_LI32(r_scratch1, K);
+				PPC_MUL(r_A, r_A, r_scratch1);
+			}
+			break;
+		case BPF_S_ALU_DIV_X: /* A /= X; */
+			ctx->seen |= SEEN_XREG;
+			PPC_CMPWI(r_X, 0);
+			if (ctx->pc_ret0 != -1) {
+				PPC_BCC(COND_EQ, addrs[ctx->pc_ret0]);
+			} else {
+				/*
+				 * Exit, returning 0; first pass hits here
+				 * (longer worst-case code size).
+				 */
+				PPC_BCC_SHORT(COND_NE, (ctx->idx*4)+12);
+				PPC_LI(r_ret, 0);
+				PPC_JMP(exit_addr);
+			}
+			PPC_DIVWU(r_A, r_A, r_X);
+			break;
+		case BPF_S_ALU_DIV_K: /* A = reciprocal_divide(A, K); */
+			PPC_LI32(r_scratch1, K);
+			/* Top 32 bits of 64bit result -> A */
+			PPC_MULHWU(r_A, r_A, r_scratch1);
+			break;
+		case BPF_S_ALU_AND_X:
+			ctx->seen |= SEEN_XREG;
+			PPC_AND(r_A, r_A, r_X);
+			break;
+		case BPF_S_ALU_AND_K:
+			if (!IMM_H(K))
+				PPC_ANDI(r_A, r_A, K);
+			else {
+				PPC_LI32(r_scratch1, K);
+				PPC_AND(r_A, r_A, r_scratch1);
+			}
+			break;
+		case BPF_S_ALU_OR_X:
+			ctx->seen |= SEEN_XREG;
+			PPC_OR(r_A, r_A, r_X);
+			break;
+		case BPF_S_ALU_OR_K:
+			if (IMM_L(K))
+				PPC_ORI(r_A, r_A, IMM_L(K));
+			if (K >= 65536)
+				PPC_ORIS(r_A, r_A, IMM_H(K));
+			break;
+		case BPF_S_ALU_LSH_X: /* A <<= X; */
+			ctx->seen |= SEEN_XREG;
+			PPC_SLW(r_A, r_A, r_X);
+			break;
+		case BPF_S_ALU_LSH_K:
+			if (K == 0)
+				break;
+			else
+				PPC_SLWI(r_A, r_A, K);
+			break;
+		case BPF_S_ALU_RSH_X: /* A >>= X; */
+			ctx->seen |= SEEN_XREG;
+			PPC_SRW(r_A, r_A, r_X);
+			break;
+		case BPF_S_ALU_RSH_K: /* A >>= K; */
+			if (K == 0)
+				break;
+			else
+				PPC_SRWI(r_A, r_A, K);
+			break;
+		case BPF_S_ALU_NEG:
+			PPC_NEG(r_A, r_A);
+			break;
+		case BPF_S_RET_K:
+			PPC_LI32(r_ret, K);
+			if (!K) {
+				if (ctx->pc_ret0 == -1)
+					ctx->pc_ret0 = i;
+			}
+			/*
+			 * If this isn't the very last instruction, branch to
+			 * the epilogue if we've stuff to clean up.  Otherwise,
+			 * if there's nothing to tidy, just return.  If we /are/
+			 * the last instruction, we're about to fall through to
+			 * the epilogue to return.
+			 */
+			if (i != flen - 1) {
+				/*
+				 * Note: 'seen' is properly valid only on pass
+				 * #2.	Both parts of this conditional are the
+				 * same instruction size though, meaning the
+				 * first pass will still correctly determine the
+				 * code size/addresses.
+				 */
+				if (ctx->seen)
+					PPC_JMP(exit_addr);
+				else
+					PPC_BLR();
+			}
+			break;
+		case BPF_S_RET_A:
+			PPC_MR(r_ret, r_A);
+			if (i != flen - 1) {
+				if (ctx->seen)
+					PPC_JMP(exit_addr);
+				else
+					PPC_BLR();
+			}
+			break;
+		case BPF_S_MISC_TAX: /* X = A */
+			PPC_MR(r_X, r_A);
+			break;
+		case BPF_S_MISC_TXA: /* A = X */
+			ctx->seen |= SEEN_XREG;
+			PPC_MR(r_A, r_X);
+			break;
+
+			/*** Constant loads/M[] access ***/
+		case BPF_S_LD_IMM: /* A = K */
+			PPC_LI32(r_A, K);
+			break;
+		case BPF_S_LDX_IMM: /* X = K */
+			PPC_LI32(r_X, K);
+			break;
+		case BPF_S_LD_MEM: /* A = mem[K] */
+			PPC_MR(r_A, r_M + (K & 0xf));
+			ctx->seen |= SEEN_MEM | (1<<(K & 0xf));
+			break;
+		case BPF_S_LDX_MEM: /* X = mem[K] */
+			PPC_MR(r_X, r_M + (K & 0xf));
+			ctx->seen |= SEEN_MEM | (1<<(K & 0xf));
+			break;
+		case BPF_S_ST: /* mem[K] = A */
+			PPC_MR(r_M + (K & 0xf), r_A);
+			ctx->seen |= SEEN_MEM | (1<<(K & 0xf));
+			break;
+		case BPF_S_STX: /* mem[K] = X */
+			PPC_MR(r_M + (K & 0xf), r_X);
+			ctx->seen |= SEEN_XREG | SEEN_MEM | (1<<(K & 0xf));
+			break;
+		case BPF_S_LD_W_LEN: /*	A = skb->len; */
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
+			PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, len));
+			break;
+		case BPF_S_LDX_W_LEN: /* X = skb->len; */
+			PPC_LWZ_OFFS(r_X, r_skb, offsetof(struct sk_buff, len));
+			break;
+
+			/*** Ancillary info loads ***/
+
+			/* None of the BPF_S_ANC* codes appear to be passed by
+			 * sk_chk_filter().  The interpreter and the x86 BPF
+			 * compiler implement them so we do too -- they may be
+			 * planted in future.
+			 */
+		case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
+						  protocol) != 2);
+			PPC_LHZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
+							  protocol));
+			/* ntohs is a NOP with BE loads. */
+			break;
+		case BPF_S_ANC_IFINDEX:
+			PPC_LD_OFFS(r_scratch1, r_skb, offsetof(struct sk_buff,
+								dev));
+			PPC_CMPDI(r_scratch1, 0);
+			if (ctx->pc_ret0 != -1) {
+				PPC_BCC(COND_EQ, addrs[ctx->pc_ret0]);
+			} else {
+				/* Exit, returning 0; first pass hits here. */
+				PPC_BCC_SHORT(COND_NE, (ctx->idx*4)+12);
+				PPC_LI(r_ret, 0);
+				PPC_JMP(exit_addr);
+			}
+			BUILD_BUG_ON(FIELD_SIZEOF(struct net_device,
+						  ifindex) != 4);
+			PPC_LWZ_OFFS(r_A, r_scratch1,
+				     offsetof(struct net_device, ifindex));
+			break;
+		case BPF_S_ANC_MARK:
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
+			PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
+							  mark));
+			break;
+		case BPF_S_ANC_RXHASH:
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
+			PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
+							  rxhash));
+			break;
+		case BPF_S_ANC_QUEUE:
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
+						  queue_mapping) != 2);
+			PPC_LHZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
+							  queue_mapping));
+			break;
+		case BPF_S_ANC_CPU:
+#ifdef CONFIG_SMP
+			/*
+			 * PACA ptr is r13:
+			 * raw_smp_processor_id() = local_paca->paca_index
+			 */
+			PPC_LHZ_OFFS(r_A, 13,
+				     offsetof(struct paca_struct, paca_index));
+#else
+			PPC_LI(r_A, 0);
+#endif
+			break;
+
+			/*** Absolute loads from packet header/data ***/
+		case BPF_S_LD_W_ABS:
+			func = sk_load_word;
+			goto common_load;
+		case BPF_S_LD_H_ABS:
+			func = sk_load_half;
+			goto common_load;
+		case BPF_S_LD_B_ABS:
+			func = sk_load_byte;
+		common_load:
+			/*
+			 * Load from [K].  Reference with the (negative)
+			 * SKF_NET_OFF/SKF_LL_OFF offsets is unsupported.
+			 */
+			ctx->seen |= SEEN_DATAREF;
+			if ((int)K < 0)
+				return -ENOTSUPP;
+			PPC_LI64(r_scratch1, func);
+			PPC_MTLR(r_scratch1);
+			PPC_LI32(r_addr, K);
+			PPC_BLRL();
+			/*
+			 * Helper returns 'lt' condition on error, and an
+			 * appropriate return value in r3
+			 */
+			PPC_BCC(COND_LT, exit_addr);
+			break;
+
+			/*** Indirect loads from packet header/data ***/
+		case BPF_S_LD_W_IND:
+			func = sk_load_word;
+			goto common_load_ind;
+		case BPF_S_LD_H_IND:
+			func = sk_load_half;
+			goto common_load_ind;
+		case BPF_S_LD_B_IND:
+			func = sk_load_byte;
+		common_load_ind:
+			/*
+			 * Load from [X + K].  Negative offsets are tested for
+			 * in the helper functions, and result in a 'ret 0'.
+			 */
+			ctx->seen |= SEEN_DATAREF | SEEN_XREG;
+			PPC_LI64(r_scratch1, func);
+			PPC_MTLR(r_scratch1);
+			PPC_ADDI(r_addr, r_X, IMM_L(K));
+			if (K >= 32768)
+				PPC_ADDIS(r_addr, r_addr, IMM_HA(K));
+			PPC_BLRL();
+			/* If error, cr0.LT set */
+			PPC_BCC(COND_LT, exit_addr);
+			break;
+
+		case BPF_S_LDX_B_MSH:
+			/*
+			 * x86 version drops packet (RET 0) when K<0, whereas
+			 * interpreter does allow K<0 (__load_pointer, special
+			 * ancillary data).
+			 */
+			func = sk_load_byte_msh;
+			goto common_load;
+			break;
+
+			/*** Jump and branches ***/
+		case BPF_S_JMP_JA:
+			if (K != 0)
+				PPC_JMP(addrs[i + 1 + K]);
+			break;
+
+		case BPF_S_JMP_JGT_K:
+		case BPF_S_JMP_JGT_X:
+			true_cond = COND_GT;
+			goto cond_branch;
+		case BPF_S_JMP_JGE_K:
+		case BPF_S_JMP_JGE_X:
+			true_cond = COND_GE;
+			goto cond_branch;
+		case BPF_S_JMP_JEQ_K:
+		case BPF_S_JMP_JEQ_X:
+			true_cond = COND_EQ;
+			goto cond_branch;
+		case BPF_S_JMP_JSET_K:
+		case BPF_S_JMP_JSET_X:
+			true_cond = COND_NE;
+			/* Fall through */
+		cond_branch:
+			/* same targets, can avoid doing the test :) */
+			if (filter[i].jt == filter[i].jf) {
+				if (filter[i].jt > 0)
+					PPC_JMP(addrs[i + 1 + filter[i].jt]);
+				break;
+			}
+
+			switch (filter[i].code) {
+			case BPF_S_JMP_JGT_X:
+			case BPF_S_JMP_JGE_X:
+			case BPF_S_JMP_JEQ_X:
+				ctx->seen |= SEEN_XREG;
+				PPC_CMPLW(r_A, r_X);
+				break;
+			case BPF_S_JMP_JSET_X:
+				ctx->seen |= SEEN_XREG;
+				PPC_AND_DOT(r_scratch1, r_A, r_X);
+				break;
+			case BPF_S_JMP_JEQ_K:
+			case BPF_S_JMP_JGT_K:
+			case BPF_S_JMP_JGE_K:
+				if (K < 32768)
+					PPC_CMPLWI(r_A, K);
+				else {
+					PPC_LI32(r_scratch1, K);
+					PPC_CMPLW(r_A, r_scratch1);
+				}
+				break;
+			case BPF_S_JMP_JSET_K:
+				if (K < 32768)
+					/* PPC_ANDI is /only/ dot-form */
+					PPC_ANDI(r_scratch1, r_A, K);
+				else {
+					PPC_LI32(r_scratch1, K);
+					PPC_AND_DOT(r_scratch1, r_A,
+						    r_scratch1);
+				}
+				break;
+			}
+			/* Sometimes branches are constructed "backward", with
+			 * the false path being the branch and true path being
+			 * a fallthrough to the next instruction.
+			 */
+			if (filter[i].jt == 0)
+				/* Swap the sense of the branch */
+				PPC_BCC(true_cond ^ COND_CMP_TRUE,
+					addrs[i + 1 + filter[i].jf]);
+			else {
+				PPC_BCC(true_cond, addrs[i + 1 + filter[i].jt]);
+				if (filter[i].jf != 0)
+					PPC_JMP(addrs[i + 1 + filter[i].jf]);
+			}
+			break;
+		default:
+			/* The filter contains something cruel & unusual.
+			 * We don't handle it, but also there shouldn't be
+			 * anything missing from our list.
+			 */
+			pr_err("BPF filter opcode %04x (@%d) unsupported\n",
+			       filter[i].code, i);
+			return -ENOTSUPP;
+		}
+
+	}
+	/* Set end-of-body-code address for exit. */
+	addrs[i] = ctx->idx * 4;
+
+	return 0;
+}
+
+void bpf_jit_compile(struct sk_filter *fp)
+{
+	unsigned int proglen;
+	unsigned int alloclen;
+	u32 *image = NULL;
+	u32 *code_base;
+	unsigned int *addrs;
+	struct codegen_context cgctx;
+	int pass;
+	int flen = fp->len;
+
+	if (!bpf_jit_enable)
+		return;
+
+	addrs = kzalloc((flen+1) * sizeof(*addrs), GFP_KERNEL);
+	if (addrs == NULL)
+		return;
+
+	/*
+	 * There are multiple assembly passes as the generated code will change
+	 * size as it settles down, figuring out the max branch offsets/exit
+	 * paths required.
+	 *
+	 * The range of standard conditional branches is +/- 32Kbytes.	Since
+	 * BPF_MAXINSNS = 4096, we can only jump from (worst case) start to
+	 * finish with 8 bytes/instruction.  Not feasible, so long jumps are
+	 * used, distinct from short branches.
+	 *
+	 * Current:
+	 *
+	 * For now, both branch types assemble to 2 words (short branches padded
+	 * with a NOP); this is less efficient, but assembly will always complete
+	 * after exactly 3 passes:
+	 *
+	 * First pass: No code buffer; Program is "faux-generated" -- no code
+	 * emitted but maximum size of output determined (and addrs[] filled
+	 * in).	 Also, we note whether we use M[], whether we use skb data, etc.
+	 * All generation choices assumed to be 'worst-case', e.g. branches all
+	 * far (2 instructions), return path code reduction not available, etc.
+	 *
+	 * Second pass: Code buffer allocated with size determined previously.
+	 * Prologue generated to support features we have seen used.  Exit paths
+	 * determined and addrs[] is filled in again, as code may be slightly
+	 * smaller as a result.
+	 *
+	 * Third pass: Code generated 'for real', and branch destinations
+	 * determined from now-accurate addrs[] map.
+	 *
+	 * Ideal:
+	 *
+	 * If we optimise this, near branches will be shorter.	On the
+	 * first assembly pass, we should err on the side of caution and
+	 * generate the biggest code.  On subsequent passes, branches will be
+	 * generated short or long and code size will reduce.  With smaller
+	 * code, more branches may fall into the short category, and code will
+	 * reduce more.
+	 *
+	 * Finally, if we see one pass generate code the same size as the
+	 * previous pass we have converged and should now generate code for
+	 * real.  Allocating at the end will also save the memory that would
+	 * otherwise be wasted by the (small) current code shrinkage.
+	 * Preferably, we should do a small number of passes (e.g. 5) and if we
+	 * haven't converged by then, get impatient and force code to generate
+	 * as-is, even if the odd branch would be left long.  The chances of a
+	 * long jump are tiny with all but the most enormous of BPF filter
+	 * inputs, so we should usually converge on the third pass.
+	 */
+
+	cgctx.idx = 0;
+	cgctx.seen = 0;
+	cgctx.pc_ret0 = -1;
+	/* Scouting faux-generate pass 0 */
+	if (bpf_jit_build_body(fp, 0, &cgctx, addrs))
+		/* We hit something illegal or unsupported. */
+		goto out;
+
+	/*
+	 * Pretend to build prologue, given the features we've seen.  This will
+	 * update ctgtx.idx as it pretends to output instructions, then we can
+	 * calculate total size from idx.
+	 */
+	bpf_jit_build_prologue(fp, 0, &cgctx);
+	bpf_jit_build_epilogue(0, &cgctx);
+
+	proglen = cgctx.idx * 4;
+	alloclen = proglen + FUNCTION_DESCR_SIZE;
+	image = module_alloc(max_t(unsigned int, alloclen,
+				   sizeof(struct work_struct)));
+	if (!image)
+		goto out;
+
+	code_base = image + (FUNCTION_DESCR_SIZE/4);
+
+	/* Code generation passes 1-2 */
+	for (pass = 1; pass < 3; pass++) {
+		/* Now build the prologue, body code & epilogue for real. */
+		cgctx.idx = 0;
+		bpf_jit_build_prologue(fp, code_base, &cgctx);
+		bpf_jit_build_body(fp, code_base, &cgctx, addrs);
+		bpf_jit_build_epilogue(code_base, &cgctx);
+
+		if (bpf_jit_enable > 1)
+			pr_info("Pass %d: shrink = %d, seen = 0x%x\n", pass,
+				proglen - (cgctx.idx * 4), cgctx.seen);
+	}
+
+	if (bpf_jit_enable > 1)
+		pr_info("flen=%d proglen=%u pass=%d image=%p\n",
+		       flen, proglen, pass, image);
+
+	if (image) {
+		if (bpf_jit_enable > 1)
+			print_hex_dump(KERN_ERR, "JIT code: ",
+				       DUMP_PREFIX_ADDRESS,
+				       16, 1, code_base,
+				       proglen, false);
+
+		bpf_flush_icache(code_base, code_base + (proglen/4));
+		/* Function descriptor nastiness: Address + TOC */
+		((u64 *)image)[0] = (u64)code_base;
+		((u64 *)image)[1] = local_paca->kernel_toc;
+		fp->bpf_func = (void *)image;
+	}
+out:
+	kfree(addrs);
+	return;
+}
+
+static void jit_free_defer(struct work_struct *arg)
+{
+	module_free(NULL, arg);
+}
+
+/* run from softirq, we must use a work_struct to call
+ * module_free() from process context
+ */
+void bpf_jit_free(struct sk_filter *fp)
+{
+	if (fp->bpf_func != sk_run_filter) {
+		struct work_struct *work = (struct work_struct *)fp->bpf_func;
+
+		INIT_WORK(work, jit_free_defer);
+		schedule_work(work);
+	}
+}

^ permalink raw reply related

* Re: ping6
From: Jérôme Poulin @ 2011-07-19  2:06 UTC (permalink / raw)
  To: eric; +Cc: netdev
In-Reply-To: <CALJXSJqwiW0b-uM0YzNnPG1V3sR3q9J4M9_hhufK+ZFWW=Gdrg@mail.gmail.com>

On Mon, Jul 18, 2011 at 4:23 PM, <eric@certus.bz> wrote:
>
> I've found what I think is a bug in the ping6 tool. Without the -n option,
> it puts the hostname inside the parenthesis instead of the resolved ip

I guess this is on purpose as IPv6 has very long IP and hostnames
should be used when possible, also, it does not show the hostname you
typed but the resolved RDNS of the IP as in:

jerome@MobileCPU ~ $ ping6 www.google.ca
PING www.google.ca(iad04s01-in-x63.1e100.net) 56 data bytes
64 bytes from iad04s01-in-x63.1e100.net: icmp_seq=1 ttl=55 time=57.7 ms

^ permalink raw reply

* ICMP Redirect not working
From: Vikas Aggarwal @ 2011-07-19  2:02 UTC (permalink / raw)
  To: netdev

Hi All,
Seems there is a problem with ICMP Redirect handling in linux kernel
(icmp.c/icmp_redirect() ?). I tried testing against  linux kernels
2.6.32.13  and  2.6.23.1-42.

Description:
1) A host sends ICMP echo request to linux based gateway.
2) ICMP redirect is sent by linux gateway  in response to ICMP request.
3) But instead of  copying exactly the same  Internet header of original ICMP
request into ICMP redirect response -
    a) Linux IP stack incorrectly first decrements the TTL (0x40 --> 0x3F)
    b) Then recalculates the checksum to 0x2387
4) This results in wrong ICMP redirect response from linux gateway to the  host.

14:33:58.195347 0:14:c1:f:b:ee 0:f:b7:10:77:a6 ip 78: 172.16.0.10 >
172.17.0.11: icmp: echo request (ttl 64, id 0, len 64)
                   4500 0040 0000 0000 4001 2287 ac10 000a
                   ac11 000b 0800 e535 0001 0000 4175 746f
                   6d61 7465 6420 4e65 7477 6f72 6b20 5661
                   6c69 6461 7469 6f6e 204c 6962 7261 7279

14:33:58.195443 0:f:b7:10:77:a6 0:14:c1:f:b:ee ip 106: 172.16.0.1 >
172.16.0.10: icmp: redirect 172.17.0.11 to host 172.16.0.11 for 172.16.0.10 >
172.17.0.11: icmp: echo request (ttl 63, id 0, len 64) [tos 0xc0]  (ttl 64, id
14608, len 92)
                   45c0 005c 3910 0000 4001 e8a5 ac10 0001
                   ac10 000a 0501 4ee3 ac10 000b 4500 0040
                   0000 0000 3f01 2387 ac10 000a ac11 000b
                   0800 e535 0001 0000 4175 746f 6d61 7465
                   6420 4e65 7477 6f72 6b20 5661 6c69 6461
                   7469

Or otherwise please help me understand why host will not like the
above ICMP redirect response from the linux gateway.

RFC 792 : Page 11
Redirect Message
    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     Type      |     Code      |          Checksum             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                 Gateway Internet Address                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      Internet Header + 64 bits of Original Data Datagram      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

regards
Vikas Aggarwal

^ permalink raw reply

* Re: [PATCH 00/45] Update bna driver version to 3.0.2.0
From: David Miller @ 2011-07-19  1:58 UTC (permalink / raw)
  To: rmody; +Cc: netdev, adapter_linux_open_src_team
In-Reply-To: <E5313AF6F2BFD14293E5FD0F94750F86A83BDF4A00@HQ1-EXCH01.corp.brocade.com>

From: Rasesh Mody <rmody@brocade.com>
Date: Mon, 18 Jul 2011 17:48:03 -0700

> We wanted to avoid submitting developing code that could break
> upstream driver due to partial changes.

So what you're saying is that if only some of the patches are applied
the driver will not work properly?

That's not allowed either, your set of changes must be fully
bisectable meaning that at any point in the series the driver
must still compile and work properly.

You guys need to sort out how you guys submit your changes.

When you have 4 patches ready to go, post them immediately.

Because if there are fundamental problem with the first 4,
everything else that depends upon them will need to change.

^ permalink raw reply

* Re: [PATCH] net: filter: BPF 'JIT' compiler for PPC64
From: Matt Evans @ 2011-07-19  1:21 UTC (permalink / raw)
  To: David Miller; +Cc: eric.dumazet, netdev, linuxppc-dev
In-Reply-To: <20110718.124248.1462465498024218250.davem@davemloft.net>

On 19/07/11 05:42, David Miller wrote:
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Mon, 18 Jul 2011 10:39:35 +0200
> 
>> So in PPC SEEN_XREG only is to be set of X is read, not if written.
>>
>> So you dont have to set SEEN_XREG bit in this part :
> 
> Matt, do you want to integrate changes based upon Eric's feedback
> here or do you want me to apply your patch as-is for now?

Thanks, but no worries; I will send a v2 in a sec.  Eric's comments are spot-on,
and there are a couple of other areas that the brainfart should really be
polished out of, too.  :-)


Cheers,


Matt

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox