All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: DeviceTree and children devices
From: Grant Likely @ 2011-10-24  8:23 UTC (permalink / raw)
  To: balbi; +Cc: Linux Kernel Mailing List, Linux USB Mailing List
In-Reply-To: <20111024081244.GD15288@legolas.emea.dhcp.ti.com>

On Mon, Oct 24, 2011 at 10:12 AM, Felipe Balbi <balbi@ti.com> wrote:
> On Mon, Oct 24, 2011 at 09:58:39AM +0200, Grant Likely wrote:
>> On Mon, Oct 24, 2011 at 9:49 AM, Felipe Balbi <balbi@ti.com> wrote:
>> > diff --git a/drivers/of/platform.c b/drivers/of/platform.c
>> > index ed5a6d3..172d4a9 100644
>> > --- a/drivers/of/platform.c
>> > +++ b/drivers/of/platform.c
>> > @@ -204,7 +204,12 @@ struct platform_device *of_platform_device_create_pdata(
>> >  #if defined(CONFIG_MICROBLAZE)
>> >        dev->archdata.dma_mask = 0xffffffffUL;
>> >  #endif
>> > -       dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
>> > +
>> > +       if (parent)
>> > +               dma_set_coherent_mask(&dev->dev, parent->coherent_dma_mask);
>> > +       else
>> > +               dma_set_coherent_mask(&dev->dev, DMA_BIT_MASK(32));
>> > +
>>
>> Right, this does need to be fixed.  The existing code just matched
>> what the historical powerpc code did, but it is certainly not correct.
>
> should I send patch above correctly ? Or do you want to also solve
> 32-bit coherent mask altogether ? What are your plans for that ? Add a
> separate property to pass coherent_mask size (32-bit, 64-bit, etc) ?

i don't know.  I'm not the expert on how the coherent mask should be
set.  Your patch does look sane as a starting point, but it bears
looking at by someone more cluefull than me.  In particular, someone
should investigate if the dma mask can be calculated from a dma-ranges
property.

g.

^ permalink raw reply

* [PATCH v2] kvm tools: Simplify msi message handling
From: Sasha Levin @ 2011-10-24  9:21 UTC (permalink / raw)
  To: penberg; +Cc: kvm, mingo, asias.hejun, gorcunov, Sasha Levin

This patch simplifies passing around msi messages by using
'struct kvm_irq_routing_msi' for storing of msi messages instead
of passing all msi parameters around.

Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
---
 tools/kvm/hw/pci-shmem.c    |    5 +----
 tools/kvm/include/kvm/irq.h |    4 +++-
 tools/kvm/include/kvm/pci.h |    7 +++----
 tools/kvm/irq.c             |    8 ++++----
 tools/kvm/virtio/pci.c      |   10 ++--------
 5 files changed, 13 insertions(+), 21 deletions(-)

diff --git a/tools/kvm/hw/pci-shmem.c b/tools/kvm/hw/pci-shmem.c
index 2907a66..780a377 100644
--- a/tools/kvm/hw/pci-shmem.c
+++ b/tools/kvm/hw/pci-shmem.c
@@ -124,10 +124,7 @@ int pci_shmem__get_local_irqfd(struct kvm *kvm)
 			return fd;
 
 		if (pci_shmem_pci_device.msix.ctrl & PCI_MSIX_FLAGS_ENABLE) {
-			gsi = irq__add_msix_route(kvm,
-				  msix_table[0].low,
-				  msix_table[0].high,
-				  msix_table[0].data);
+			gsi = irq__add_msix_route(kvm, &msix_table[0].msg);
 		} else {
 			gsi = pci_shmem_pci_device.irq_line;
 		}
diff --git a/tools/kvm/include/kvm/irq.h b/tools/kvm/include/kvm/irq.h
index 401bee9..61f593d 100644
--- a/tools/kvm/include/kvm/irq.h
+++ b/tools/kvm/include/kvm/irq.h
@@ -4,6 +4,8 @@
 #include <linux/types.h>
 #include <linux/rbtree.h>
 #include <linux/list.h>
+#include <linux/kvm.h>
+#include <linux/msi.h>
 
 struct kvm;
 
@@ -24,6 +26,6 @@ int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line);
 struct rb_node *irq__get_pci_tree(void);
 
 void irq__init(struct kvm *kvm);
-int irq__add_msix_route(struct kvm *kvm, u32 low, u32 high, u32 data);
+int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg);
 
 #endif
diff --git a/tools/kvm/include/kvm/pci.h b/tools/kvm/include/kvm/pci.h
index 5ee8005..f71af0b 100644
--- a/tools/kvm/include/kvm/pci.h
+++ b/tools/kvm/include/kvm/pci.h
@@ -2,8 +2,9 @@
 #define KVM__PCI_H
 
 #include <linux/types.h>
-
+#include <linux/kvm.h>
 #include <linux/pci_regs.h>
+#include <linux/msi.h>
 
 /*
  * PCI Configuration Mechanism #1 I/O ports. See Section 3.7.4.1.
@@ -26,9 +27,7 @@ struct pci_config_address {
 };
 
 struct msix_table {
-	u32 low;
-	u32 high;
-	u32 data;
+	struct msi_msg msg;
 	u32 ctrl;
 };
 
diff --git a/tools/kvm/irq.c b/tools/kvm/irq.c
index e35bf18..dc2247e 100644
--- a/tools/kvm/irq.c
+++ b/tools/kvm/irq.c
@@ -167,7 +167,7 @@ void irq__init(struct kvm *kvm)
 		die("Failed setting GSI routes");
 }
 
-int irq__add_msix_route(struct kvm *kvm, u32 low, u32 high, u32 data)
+int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg)
 {
 	int r;
 
@@ -175,9 +175,9 @@ int irq__add_msix_route(struct kvm *kvm, u32 low, u32 high, u32 data)
 		(struct kvm_irq_routing_entry) {
 			.gsi = gsi,
 			.type = KVM_IRQ_ROUTING_MSI,
-			.u.msi.address_lo = low,
-			.u.msi.address_hi = high,
-			.u.msi.data = data,
+			.u.msi.address_hi = msg->address_hi,
+			.u.msi.address_lo = msg->address_lo,
+			.u.msi.data = msg->data,
 		};
 
 	r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing);
diff --git a/tools/kvm/virtio/pci.c b/tools/kvm/virtio/pci.c
index f01851b..73d55a9 100644
--- a/tools/kvm/virtio/pci.c
+++ b/tools/kvm/virtio/pci.c
@@ -126,20 +126,14 @@ static bool virtio_pci__specific_io_out(struct kvm *kvm, struct virtio_pci *vpci
 		case VIRTIO_MSI_CONFIG_VECTOR:
 			vec = vpci->config_vector = ioport__read16(data);
 
-			gsi = irq__add_msix_route(kvm,
-						  vpci->msix_table[vec].low,
-						  vpci->msix_table[vec].high,
-						  vpci->msix_table[vec].data);
+			gsi = irq__add_msix_route(kvm, &vpci->msix_table[vec].msg);
 
 			vpci->config_gsi = gsi;
 			break;
 		case VIRTIO_MSI_QUEUE_VECTOR: {
 			vec = vpci->vq_vector[vpci->queue_selector] = ioport__read16(data);
 
-			gsi = irq__add_msix_route(kvm,
-						  vpci->msix_table[vec].low,
-						  vpci->msix_table[vec].high,
-						  vpci->msix_table[vec].data);
+			gsi = irq__add_msix_route(kvm, &vpci->msix_table[vec].msg);
 			vpci->gsis[vpci->queue_selector] = gsi;
 			break;
 		}
-- 
1.7.7


^ permalink raw reply related

* Re: XFS read hangs in 3.1-rc10
From: Christoph Hellwig @ 2011-10-24  8:22 UTC (permalink / raw)
  To: Simon Kirby; +Cc: linux-kernel, xfs
In-Reply-To: <20111021202857.GB30100@hostway.ca>

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

On Fri, Oct 21, 2011 at 01:28:57PM -0700, Simon Kirby wrote:
> > So we're waiting for the inode to be flushed, aka I/O again.
> 
> But I don't seem to see any queued I/O, hmm.

Well, as far as XFS is concerned the inode is beeing flushed and
the buffer is locked.  It could be stuck in the XFS internal delwri
list because a buffer for example is pinned.

If that is the case the big hammer patch I attached below - probably
not the final issue, but it should fix the hang if that is the case.

> > If this doesn't help I'll probably need to come up with some tracing
> > patches for you.
> 
> It seemes 3.0.7+gregkh's stable-queue queue-3.0 patches seems to be
> running fine without blocking at all on this SSD box, so that should
> narrow it down significantly.
> 
> Hmm, looking at git diff --stat v3.0.7..v3.1-rc10 fs/xfs , maybe not.. :)
> 
> Maybe 3.1 fs/xfs would transplant into 3.0 or vice-versa?

If the patch above doesn't work I'll prepare a backport for you.


[-- Attachment #2: xfs-hang-fix --]
[-- Type: text/plain, Size: 905 bytes --]

Index: linux-2.6/fs/xfs/xfs_sync.c
===================================================================
--- linux-2.6.orig/fs/xfs/xfs_sync.c	2011-10-24 10:02:27.361971264 +0200
+++ linux-2.6/fs/xfs/xfs_sync.c	2011-10-24 10:11:03.301036954 +0200
@@ -764,7 +764,8 @@ xfs_reclaim_inode(
 	struct xfs_perag	*pag,
 	int			sync_mode)
 {
-	int	error;
+	struct xfs_mount	*mp = ip->i_mount;
+	int			error;
 
 restart:
 	error = 0;
@@ -772,6 +773,18 @@ restart:
 	if (!xfs_iflock_nowait(ip)) {
 		if (!(sync_mode & SYNC_WAIT))
 			goto out;
+
+		/*
+		 * If the inode is flush locked we probably had someone else
+		 * push it to the buffer and the buffer is now sitting in
+		 * the delwri list.
+		 *
+		 * Use the big hammer to force it.
+		 */
+		xfs_log_force(mp, XFS_LOG_SYNC);
+		set_bit(XBT_FORCE_FLUSH, &mp->m_ddev_targp->bt_flags);
+		wake_up_process(mp->m_ddev_targp->bt_task);
+
 		xfs_iflock(ip);
 	}
 

[-- Attachment #3: Type: text/plain, Size: 121 bytes --]

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply

* Re: XFS read hangs in 3.1-rc10
From: Christoph Hellwig @ 2011-10-24  8:22 UTC (permalink / raw)
  To: Simon Kirby; +Cc: linux-kernel, xfs
In-Reply-To: <20111021202857.GB30100@hostway.ca>

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

On Fri, Oct 21, 2011 at 01:28:57PM -0700, Simon Kirby wrote:
> > So we're waiting for the inode to be flushed, aka I/O again.
> 
> But I don't seem to see any queued I/O, hmm.

Well, as far as XFS is concerned the inode is beeing flushed and
the buffer is locked.  It could be stuck in the XFS internal delwri
list because a buffer for example is pinned.

If that is the case the big hammer patch I attached below - probably
not the final issue, but it should fix the hang if that is the case.

> > If this doesn't help I'll probably need to come up with some tracing
> > patches for you.
> 
> It seemes 3.0.7+gregkh's stable-queue queue-3.0 patches seems to be
> running fine without blocking at all on this SSD box, so that should
> narrow it down significantly.
> 
> Hmm, looking at git diff --stat v3.0.7..v3.1-rc10 fs/xfs , maybe not.. :)
> 
> Maybe 3.1 fs/xfs would transplant into 3.0 or vice-versa?

If the patch above doesn't work I'll prepare a backport for you.


[-- Attachment #2: xfs-hang-fix --]
[-- Type: text/plain, Size: 905 bytes --]

Index: linux-2.6/fs/xfs/xfs_sync.c
===================================================================
--- linux-2.6.orig/fs/xfs/xfs_sync.c	2011-10-24 10:02:27.361971264 +0200
+++ linux-2.6/fs/xfs/xfs_sync.c	2011-10-24 10:11:03.301036954 +0200
@@ -764,7 +764,8 @@ xfs_reclaim_inode(
 	struct xfs_perag	*pag,
 	int			sync_mode)
 {
-	int	error;
+	struct xfs_mount	*mp = ip->i_mount;
+	int			error;
 
 restart:
 	error = 0;
@@ -772,6 +773,18 @@ restart:
 	if (!xfs_iflock_nowait(ip)) {
 		if (!(sync_mode & SYNC_WAIT))
 			goto out;
+
+		/*
+		 * If the inode is flush locked we probably had someone else
+		 * push it to the buffer and the buffer is now sitting in
+		 * the delwri list.
+		 *
+		 * Use the big hammer to force it.
+		 */
+		xfs_log_force(mp, XFS_LOG_SYNC);
+		set_bit(XBT_FORCE_FLUSH, &mp->m_ddev_targp->bt_flags);
+		wake_up_process(mp->m_ddev_targp->bt_task);
+
 		xfs_iflock(ip);
 	}
 

^ permalink raw reply

* Re: [PATCH 2/3] ARM: AT91: IIO: Add AT91 ADC driver.
From: Maxime Ripard @ 2011-10-24  8:21 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD
  Cc: linux-arm-kernel, linux-iio, Patrice Vilchez, Nicolas Ferre
In-Reply-To: <20111023090813.GI2638@game.jcrosoft.org>

Hi,

On 23/10/2011 11:08, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 18:18 Wed 19 Oct     , Maxime Ripard wrote:
>> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
>> Cc: Patrice Vilchez <patrice.vilchez@atmel.com>
>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> please keep me in CC
ACK.

>> +
>> +static int at91adc_channel_init(struct at91adc_state *st)
>> +{
>> +	int ret = 0, i;
>> +	st->channels = kzalloc(sizeof(struct iio_chan_spec) * st->nb_chan,
>> +			       GFP_KERNEL);
>> +	if (st->channels == NULL)
>> +		return -ENOMEM;
>> +
>> +	for (i = 0; i < st->nb_chan; i++) {
>> +		struct iio_chan_spec *chan = st->channels + i;
>> +		chan->type = IIO_VOLTAGE;
>> +		chan->indexed = 1;
>> +		chan->channel = i;
>> +		++ret;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int at91adc_read_raw(struct iio_dev *idev,
>> +			    struct iio_chan_spec const *chan,
>> +			    int *val, int *val2, long mask)
>> +{
>> +	struct at91adc_state *st = iio_priv(idev);
>> +
>> +	switch (mask) {
>> +	case 0:
>> +		mutex_lock(&st->lock);
>> +
>> +		at91adc_reg_write(st->reg_base, AT91_ADC_CHER,
>> +				  AT91_ADC_CH(chan->channel));
>> +		at91adc_reg_write(st->reg_base, AT91_ADC_IER,
>> +				  AT91_ADC_EOC(chan->channel));
>> +		at91adc_reg_write(st->reg_base, AT91_ADC_CR, AT91_ADC_START);
>> +
>> +		wait_event_interruptible(st->wq_data_avail, st->done);
>> +		*val = st->lcdr;
>> +
>> +		at91adc_reg_write(st->reg_base, AT91_ADC_CHDR,
>> +				  AT91_ADC_CH(chan->channel));
>> +		at91adc_reg_write(st->reg_base, AT91_ADC_IDR,
>> +				  AT91_ADC_EOC(chan->channel));
>> +
>> +		st->lcdr = 0;
>> +		st->done = false;
>> +		mutex_unlock(&st->lock);
>> +		return IIO_VAL_INT;
>> +	default:
>> +		break;
>> +	}
>> +	return -EINVAL;
>> +}
>> +
>> +static const struct iio_info at91adc_info = {
>> +	.driver_module = THIS_MODULE,
>> +	.read_raw = &at91adc_read_raw,
>> +};
>> +
>> +static int __devinit at91adc_probe(struct platform_device *pdev)
>> +{
>> +	unsigned int prsc, mstrclk, ticks;
>> +	int ret;
>> +	struct iio_dev *idev;
>> +	struct at91adc_state *st;
>> +	struct resource *res;
>> +	struct at91_adc_data *pdata = pdev->dev.platform_data;
> 	do not refence it copy need for the DT

Ok

>> +
>> +	dev_dbg(&pdev->dev, "AT91ADC probed\n");
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	if (!res) {
>> +		dev_err(&pdev->dev, "No resource defined\n");
>> +		ret = -ENXIO;
>> +		goto error_ret;
>> +	}
>> +
>> +	idev = iio_allocate_device(sizeof(*st));
>> +	if (idev == NULL) {
>> +		dev_err(&pdev->dev, "Failed to allocate memory.\n");
>> +		ret = -ENOMEM;
>> +		goto error_ret;
>> +	}
>> +	platform_set_drvdata(pdev, idev);
>> +
>> +	idev->dev.parent = &pdev->dev;
>> +	idev->name = platform_get_device_id(pdev)->name;
>> +	idev->modes = INDIO_DIRECT_MODE;
>> +	idev->info = &at91adc_info;
>> +
>> +	st = iio_priv(idev);
>> +	st->irq = platform_get_irq(pdev, 0);
>> +	if (st->irq < 0) {
>> +		dev_err(&pdev->dev, "No IRQ ID is designated\n");
>> +		ret = -ENODEV;
>> +		goto error_free_device;
>> +	}
>> +
>> +	if (!request_mem_region(res->start, resource_size(res),
>> +				"AT91 adc registers")) {
>> +		dev_err(&pdev->dev, "Resources are unavailable.\n");
>> +		ret = -EBUSY;
>> +		goto error_free_device;
>> +	}
>> +
>> +	st->reg_base = ioremap(res->start, resource_size(res));
>> +	if (!st->reg_base) {
>> +		dev_err(&pdev->dev, "Failed to map registers.\n");
>> +		ret = -ENOMEM;
>> +		goto error_release_mem;
>> +	}
>> +
>> +	/*
>> +	 * Disable all IRQs before setting up the handler
>> +	 */
>> +	at91adc_reg_write(st->reg_base, AT91_ADC_CR, AT91_ADC_SWRST);
>> +	at91adc_reg_write(st->reg_base, AT91_ADC_IDR, 0xFFFFFFFF);
>> +	ret = request_irq(st->irq,
>> +			  at91adc_eoc_trigger, 0, pdev->dev.driver->name, st);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
>> +		goto error_unmap_reg;
>> +	}
>> +
>> +	st->clk = clk_get(&pdev->dev, "adc_clk");
>> +	if (IS_ERR(st->clk)) {
>> +		dev_err(&pdev->dev, "Failed to get the clock.\n");
>> +		ret = PTR_ERR(st->clk);
>> +		goto error_free_irq;
>> +	}
>> +
>> +	clk_enable(st->clk);
>> +	mstrclk = clk_get_rate(st->clk);
>> +
>> +	if (!pdata) {
>> +		dev_err(&pdev->dev, "No platform data available.\n");
>> +		ret = -EINVAL;
>> +		goto error_free_clk;
>> +	}
>> +
>> +	if (!pdata->adc_clock) {
>> +		dev_err(&pdev->dev, "No ADCClock available.\n");
>> +		ret = -EINVAL;
>> +		goto error_free_clk;
>> +	}
> where is the platform data struct?

In the first patch.

Regards,

-- 
Maxime Ripard, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply

* [PATCH 2/3] ARM: AT91: IIO: Add AT91 ADC driver.
From: Maxime Ripard @ 2011-10-24  8:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111023090813.GI2638@game.jcrosoft.org>

Hi,

On 23/10/2011 11:08, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 18:18 Wed 19 Oct     , Maxime Ripard wrote:
>> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
>> Cc: Patrice Vilchez <patrice.vilchez@atmel.com>
>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> please keep me in CC
ACK.

>> +
>> +static int at91adc_channel_init(struct at91adc_state *st)
>> +{
>> +	int ret = 0, i;
>> +	st->channels = kzalloc(sizeof(struct iio_chan_spec) * st->nb_chan,
>> +			       GFP_KERNEL);
>> +	if (st->channels == NULL)
>> +		return -ENOMEM;
>> +
>> +	for (i = 0; i < st->nb_chan; i++) {
>> +		struct iio_chan_spec *chan = st->channels + i;
>> +		chan->type = IIO_VOLTAGE;
>> +		chan->indexed = 1;
>> +		chan->channel = i;
>> +		++ret;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int at91adc_read_raw(struct iio_dev *idev,
>> +			    struct iio_chan_spec const *chan,
>> +			    int *val, int *val2, long mask)
>> +{
>> +	struct at91adc_state *st = iio_priv(idev);
>> +
>> +	switch (mask) {
>> +	case 0:
>> +		mutex_lock(&st->lock);
>> +
>> +		at91adc_reg_write(st->reg_base, AT91_ADC_CHER,
>> +				  AT91_ADC_CH(chan->channel));
>> +		at91adc_reg_write(st->reg_base, AT91_ADC_IER,
>> +				  AT91_ADC_EOC(chan->channel));
>> +		at91adc_reg_write(st->reg_base, AT91_ADC_CR, AT91_ADC_START);
>> +
>> +		wait_event_interruptible(st->wq_data_avail, st->done);
>> +		*val = st->lcdr;
>> +
>> +		at91adc_reg_write(st->reg_base, AT91_ADC_CHDR,
>> +				  AT91_ADC_CH(chan->channel));
>> +		at91adc_reg_write(st->reg_base, AT91_ADC_IDR,
>> +				  AT91_ADC_EOC(chan->channel));
>> +
>> +		st->lcdr = 0;
>> +		st->done = false;
>> +		mutex_unlock(&st->lock);
>> +		return IIO_VAL_INT;
>> +	default:
>> +		break;
>> +	}
>> +	return -EINVAL;
>> +}
>> +
>> +static const struct iio_info at91adc_info = {
>> +	.driver_module = THIS_MODULE,
>> +	.read_raw = &at91adc_read_raw,
>> +};
>> +
>> +static int __devinit at91adc_probe(struct platform_device *pdev)
>> +{
>> +	unsigned int prsc, mstrclk, ticks;
>> +	int ret;
>> +	struct iio_dev *idev;
>> +	struct at91adc_state *st;
>> +	struct resource *res;
>> +	struct at91_adc_data *pdata = pdev->dev.platform_data;
> 	do not refence it copy need for the DT

Ok

>> +
>> +	dev_dbg(&pdev->dev, "AT91ADC probed\n");
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	if (!res) {
>> +		dev_err(&pdev->dev, "No resource defined\n");
>> +		ret = -ENXIO;
>> +		goto error_ret;
>> +	}
>> +
>> +	idev = iio_allocate_device(sizeof(*st));
>> +	if (idev == NULL) {
>> +		dev_err(&pdev->dev, "Failed to allocate memory.\n");
>> +		ret = -ENOMEM;
>> +		goto error_ret;
>> +	}
>> +	platform_set_drvdata(pdev, idev);
>> +
>> +	idev->dev.parent = &pdev->dev;
>> +	idev->name = platform_get_device_id(pdev)->name;
>> +	idev->modes = INDIO_DIRECT_MODE;
>> +	idev->info = &at91adc_info;
>> +
>> +	st = iio_priv(idev);
>> +	st->irq = platform_get_irq(pdev, 0);
>> +	if (st->irq < 0) {
>> +		dev_err(&pdev->dev, "No IRQ ID is designated\n");
>> +		ret = -ENODEV;
>> +		goto error_free_device;
>> +	}
>> +
>> +	if (!request_mem_region(res->start, resource_size(res),
>> +				"AT91 adc registers")) {
>> +		dev_err(&pdev->dev, "Resources are unavailable.\n");
>> +		ret = -EBUSY;
>> +		goto error_free_device;
>> +	}
>> +
>> +	st->reg_base = ioremap(res->start, resource_size(res));
>> +	if (!st->reg_base) {
>> +		dev_err(&pdev->dev, "Failed to map registers.\n");
>> +		ret = -ENOMEM;
>> +		goto error_release_mem;
>> +	}
>> +
>> +	/*
>> +	 * Disable all IRQs before setting up the handler
>> +	 */
>> +	at91adc_reg_write(st->reg_base, AT91_ADC_CR, AT91_ADC_SWRST);
>> +	at91adc_reg_write(st->reg_base, AT91_ADC_IDR, 0xFFFFFFFF);
>> +	ret = request_irq(st->irq,
>> +			  at91adc_eoc_trigger, 0, pdev->dev.driver->name, st);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
>> +		goto error_unmap_reg;
>> +	}
>> +
>> +	st->clk = clk_get(&pdev->dev, "adc_clk");
>> +	if (IS_ERR(st->clk)) {
>> +		dev_err(&pdev->dev, "Failed to get the clock.\n");
>> +		ret = PTR_ERR(st->clk);
>> +		goto error_free_irq;
>> +	}
>> +
>> +	clk_enable(st->clk);
>> +	mstrclk = clk_get_rate(st->clk);
>> +
>> +	if (!pdata) {
>> +		dev_err(&pdev->dev, "No platform data available.\n");
>> +		ret = -EINVAL;
>> +		goto error_free_clk;
>> +	}
>> +
>> +	if (!pdata->adc_clock) {
>> +		dev_err(&pdev->dev, "No ADCClock available.\n");
>> +		ret = -EINVAL;
>> +		goto error_free_clk;
>> +	}
> where is the platform data struct?

In the first patch.

Regards,

-- 
Maxime Ripard, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply

* [U-Boot] [PATCH 01/39] DEBUG: Fix debug macros
From: Marek Vasut @ 2011-10-24  8:21 UTC (permalink / raw)
  To: u-boot
In-Reply-To: <CAPnjgZ0m8K4mgbfU17JfFXv=BzGsHBku-zn0nh6qg-SD=MqbXQ@mail.gmail.com>

On Monday, October 24, 2011 06:31:19 AM Simon Glass wrote:
> Hi Marek,
> 
> On Fri, Oct 21, 2011 at 5:16 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
> > The current implementation of debug doesn't play well with GCC4.6.
> > This implementation also fixes GCC4.6 complaints about unused variables
> > while maintaining code size.
> > 
> > Signed-off-by: Mike Frysinger <vapier@gentoo.org>
> > Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> > Cc: Wolfgang Denk <wd@denx.de>
> > Cc: Simon Glass <sjg@chromium.org>
> > ---
> >  include/common.h |   20 ++++++++++++--------
> >  1 files changed, 12 insertions(+), 8 deletions(-)
> > 
> > diff --git a/include/common.h b/include/common.h
> > index eb19a44..c3b23551 100644
> > --- a/include/common.h
> > +++ b/include/common.h
> > @@ -116,20 +116,24 @@ typedef volatile unsigned char    vu_char;
> >  #include <flash.h>
> >  #include <image.h>
> > 
> > -#ifdef DEBUG
> > -#define debug(fmt,args...)     printf (fmt ,##args)
> > -#define debugX(level,fmt,args...) if (DEBUG>=level) printf(fmt,##args);
> > -#else
> > -#define debug(fmt,args...)
> > -#define debugX(level,fmt,args...)
> > -#endif /* DEBUG */
> > -
> >  #ifdef DEBUG
> >  # define _DEBUG 1
> >  #else
> >  # define _DEBUG 0
> >  #endif
> > 
> > +#define debug_cond(cond, fmt, args...)         \
> 
> Yes this is much nicer. Could perhaps add a little comment about how
> to use this and to avoid putting debug() inside #ifdef?
> 
> > +       do {                                    \
> > +               if (cond)                       \
> > +                       printf(fmt, ##args);    \
> > +       } while (0)
> > +
> > +#define debug(fmt, args...)                    \
> > +       debug_cond(_DEBUG, fmt, ##args)
> > +
> > +#define debugX(level, fmt, args...)            \
> > +       debug_cond((_DEBUG && DEBUG >= (level)), fmt, ##args)
> > +
> >  /*
> >  * An assertion is run-time check done in debug mode only. If DEBUG is
> > not * defined then it is skipped. If DEBUG is defined and the assertion
> > fails, --
> > 1.7.6.3

Done, I pushed new patchset right now to git://git.denx.de/u-boot-marex.git , 
"debug" branch. It's around 50 patches now.

^ permalink raw reply

* Re: Vanilla-Kernel 3 - page allocation failure
From: Philipp Herz - Profihost AG @ 2011-10-24  8:19 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: David Rientjes, Andi Kleen, s.priebe, linux-kernel
In-Reply-To: <1319443278.2381.2.camel@edumazet-HP-Compaq-6005-Pro-SFF-PC>

Am 24.10.2011 10:01, schrieb Eric Dumazet:
> Le lundi 24 octobre 2011 à 09:21 +0200, Philipp Herz - Profihost AG a
> écrit :
>
>> does that mean that there was no firmware limitation with kernel 2.6.32
>> or that the tg3 module has any "disable warnings" flag matching
>> __GFP_NOWARN?
>>
>
> There is no __GFP_NOWARN trick on tg3.
>
> We tend to prefer to be notified of a memory problem, instead of
> hide ...
yes,
that's exactly what would like to understand in comparison to the 
behavior of kernel 2.6.32.

why does this notification show up now and never did before...

>
> By the way, apparently this driver drops the frame and doesnt increase
> tx_dropped device counter. A patch will follow.
fine

>
> Could you post your full dmesg ?
>
>
Currently i can not provide any further information, 'cause server has 
been restarted.

What exactly are you looking for?

^ permalink raw reply

* [PATCH 1/2] [ARM] mach-types: Re-add apf9328
From: Bedia, Vaibhav @ 2011-10-24  8:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111021180347.GH21648@n2100.arm.linux.org.uk>

> -----Original Message-----
> From: Russell King - ARM Linux [mailto:linux at arm.linux.org.uk]
> Sent: Friday, October 21, 2011 11:34 PM
> To: Bedia, Vaibhav
> Cc: linux-arm-kernel at lists.infradead.org
> Subject: Re: [PATCH 1/2] [ARM] mach-types: Re-add apf9328
> 
> 
> I've just fixed it.

Thanks Russell.

Regards,
Vaibhav
 

^ permalink raw reply

* RE: [GIT PULL for v3.2] OMAP_VOUT: Few cleaups and feature addition
From: Hiremath, Vaibhav @ 2011-10-24  8:18 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media@vger.kernel.org, mchehab@redhat.com
In-Reply-To: <201110240922.45744.laurent.pinchart@ideasonboard.com>


> -----Original Message-----
> From: Laurent Pinchart [mailto:laurent.pinchart@ideasonboard.com]
> Sent: Monday, October 24, 2011 12:53 PM
> To: Hiremath, Vaibhav
> Cc: linux-media@vger.kernel.org; mchehab@redhat.com
> Subject: Re: [GIT PULL for v3.2] OMAP_VOUT: Few cleaups and feature
> addition
> 
> Hi Vaibhav,
> 
> On Saturday 22 October 2011 14:06:24 hvaibhav@ti.com wrote:
> > Hi Mauro,
> >
> > The following changes since commit
> > 35a912455ff5640dc410e91279b03e04045265b2: Mauro Carvalho Chehab (1):
> >         Merge branch 'v4l_for_linus' into staging/for_v3.2
> >
> > are available in the git repository at:
> >
> >   git://arago-project.org/git/people/vaibhav/ti-psp-omap-video.git
> > for-linux-media
> >
> > Archit Taneja (5):
> >       OMAP_VOUT: Fix check in reqbuf for buf_size allocation
> >       OMAP_VOUT: CLEANUP: Remove redundant code from omap_vout_isr
> >       OMAP_VOUT: Fix VSYNC IRQ handling in omap_vout_isr
> >       OMAP_VOUT: Add support for DSI panels
> >       OMAP_VOUT: Increase MAX_DISPLAYS to a larger value
> 
> What about http://patchwork.linuxtv.org/patch/299/ ? Do you plan to push
> it
> through your tree, or should I push it through mine ?
> 
Oops,

Missed it... Thanks for reminding me. 

If you are about to send pull request then go ahead and merge it with your patch-sets. OR I can also send another request for this patch alone.

Thanks,
Vaibhav

> --
> Regards,
> 
> Laurent Pinchart

^ permalink raw reply

* [Cluster-devel] [GFS2 Patch] GFS2: Add readahead to sequential directory traversal
From: Steven Whitehouse @ 2011-10-24  8:17 UTC (permalink / raw)
  To: cluster-devel.redhat.com
In-Reply-To: <8020284c-0013-402a-969c-353671c7ff0c@zmail06.collab.prod.int.phx2.redhat.com>

Hi,

That looks much better, but why not create & pass a file_ra_state in the
NFS getname function so that you don't have to check for it being NULL?
Since that function always reads everything up until the name it is
looking for, it is an ideal place to do readahead as the access will
always be sequential.

Otherwise, it looks good to me,

Steve.

On Fri, 2011-10-21 at 12:53 -0400, Bob Peterson wrote:
> ----- Original Message -----
> | Well it is not called directly from NFS though, only from our getname
> | function. I'd suggest we do something along the following lines:
> | 
> | Create a new structure, something like this:
> | 
> | struct gfs2_dir_ra_state {
> | 	/* Readahead state variables... */
> | };
> | 
> | and then pass that to gfs2_dir_read() in addition to passing the
> | offset.
> | The getname call is trivial, since it always starts at the beginning
> | and
> | reads through sequentially, so it just needs a gfs2_dir_ra_state to
> | be
> | set up to take account of that. The struct gfs2_dir_ra_state can be
> | embedded into the struct gfs2_file, so that gfs2_readdir() just
> | passes a
> | pointer to that.
> | 
> | That will allow us to reset the readahead state upon lseek(SEEK_SET,
> | 0);
> | and also flag whether the accesses become non-sequential.
> | 
> | So I think keeping the state in the struct file and passing it to our
> | gfs2_file_read() function should not be too tricky,
> | 
> | Steve.
> 
> Hi Steve,
> 
> Thanks for the feedback.  How about something like this (follows):
> Instead of creating a new read-ahead structure gfs2_dir_ra_state
> I'm making (non-standard) use of vfs's read-ahead struct in the
> file.
> 
> Regards,
> 
> Bob Peterson
> Red Hat File System
> --
> commit 14e64999c89c7e2801d69b9e877f2fa0bf10ad70
> Author: Bob Peterson <rpeterso@redhat.com>
> Date:   Fri Oct 7 11:55:31 2011 -0500
> 
>     GFS2: Add readahead to sequential directory traversal
>     
>     This patch adds read-ahead capability to GFS2's
>     directory hash table management.  It greatly improves
>     performance for some directory operations.  For example:
>     In one of my file systems that has 1000 directories, each
>     of which has 1000 files, time to execute a recursive
>     ls (time ls -fR /mnt/gfs2 > /dev/null) was reduced
>     from 2m2.814s on a stock kernel to 0m45.938s.
> 
> diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
> index 2045d70..30405d4 100644
> --- a/fs/gfs2/dir.c
> +++ b/fs/gfs2/dir.c
> @@ -76,6 +76,8 @@
>  #define IS_LEAF     1 /* Hashed (leaf) directory */
>  #define IS_DINODE   2 /* Linear (stuffed dinode block) directory */
>  
> +#define MAX_RA_BLOCKS 32 /* max read-ahead blocks */
> +
>  #define gfs2_disk_hash2offset(h) (((u64)(h)) >> 1)
>  #define gfs2_dir_offset2hash(p) ((u32)(((u64)(p)) << 1))
>  
> @@ -1376,6 +1378,50 @@ out:
>  	return error;
>  }
>  
> +/* gfs2_dir_readahead - Issue read-ahead requests for leaf blocks.
> + *
> + * Note: we can't calculate each index like dir_e_read can because we don't
> + * have the leaf, and therefore we don't have the depth, and therefore we
> + * don't have the length. So we have to just read enough ahead to make up
> + * for the loss of information. */
> +static void gfs2_dir_readahead(struct inode *inode, unsigned hsize, u32 index,
> +			       struct file_ra_state *f_ra)
> +{
> +	struct gfs2_inode *ip = GFS2_I(inode);
> +	struct gfs2_glock *gl = ip->i_gl;
> +	struct buffer_head *bh;
> +	u64 blocknr = 0, last;
> +	unsigned count;
> +
> +	/* First check if we've already read-ahead for the whole range. */
> +	if (!f_ra || index + MAX_RA_BLOCKS < f_ra->start)
> +		return;
> +
> +	f_ra->start = max((pgoff_t)index, f_ra->start);
> +	for (count = 0; count < MAX_RA_BLOCKS; count++) {
> +		if (f_ra->start >= hsize) /* if exceeded the hash table */
> +			break;
> +
> +		last = blocknr;
> +		blocknr = be64_to_cpu(ip->i_hash_cache[f_ra->start]);
> +		f_ra->start++;
> +		if (blocknr == last)
> +			continue;
> +
> +		bh = gfs2_getbuf(gl, blocknr, 1);
> +		if (trylock_buffer(bh)) {
> +			if (buffer_uptodate(bh)) {
> +				unlock_buffer(bh);
> +				brelse(bh);
> +				continue;
> +			}
> +			bh->b_end_io = end_buffer_read_sync;
> +			submit_bh(READA | REQ_META, bh);
> +			continue;
> +		}
> +		brelse(bh);
> +	}
> +}
>  
>  /**
>   * dir_e_read - Reads the entries from a directory into a filldir buffer
> @@ -1388,7 +1434,7 @@ out:
>   */
>  
>  static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
> -		      filldir_t filldir)
> +		      filldir_t filldir, struct file_ra_state *f_ra)
>  {
>  	struct gfs2_inode *dip = GFS2_I(inode);
>  	u32 hsize, len = 0;
> @@ -1402,10 +1448,14 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
>  	hash = gfs2_dir_offset2hash(*offset);
>  	index = hash >> (32 - dip->i_depth);
>  
> +	if (f_ra && dip->i_hash_cache == NULL)
> +		f_ra->start = 0;
>  	lp = gfs2_dir_get_hash_table(dip);
>  	if (IS_ERR(lp))
>  		return PTR_ERR(lp);
>  
> +	gfs2_dir_readahead(inode, hsize, index, f_ra);
> +
>  	while (index < hsize) {
>  		error = gfs2_dir_read_leaf(inode, offset, opaque, filldir,
>  					   &copied, &depth,
> @@ -1423,7 +1473,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
>  }
>  
>  int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
> -		  filldir_t filldir)
> +		  filldir_t filldir, struct file_ra_state *f_ra)
>  {
>  	struct gfs2_inode *dip = GFS2_I(inode);
>  	struct gfs2_sbd *sdp = GFS2_SB(inode);
> @@ -1437,7 +1487,7 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
>  		return 0;
>  
>  	if (dip->i_diskflags & GFS2_DIF_EXHASH)
> -		return dir_e_read(inode, offset, opaque, filldir);
> +		return dir_e_read(inode, offset, opaque, filldir, f_ra);
>  
>  	if (!gfs2_is_stuffed(dip)) {
>  		gfs2_consist_inode(dip);
> diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h
> index ff5772f..98c960b 100644
> --- a/fs/gfs2/dir.h
> +++ b/fs/gfs2/dir.h
> @@ -25,7 +25,7 @@ extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
>  			const struct gfs2_inode *ip);
>  extern int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry);
>  extern int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
> -			 filldir_t filldir);
> +			 filldir_t filldir, struct file_ra_state *f_ra);
>  extern int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
>  			  const struct gfs2_inode *nip, unsigned int new_type);
>  
> diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c
> index fe9945f..a581cd2 100644
> --- a/fs/gfs2/export.c
> +++ b/fs/gfs2/export.c
> @@ -118,7 +118,7 @@ static int gfs2_get_name(struct dentry *parent, char *name,
>  	if (error)
>  		return error;
>  
> -	error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir);
> +	error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir, NULL);
>  
>  	gfs2_glock_dq_uninit(&gh);
>  
> diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
> index 92c3db4..c9cbb5f 100644
> --- a/fs/gfs2/file.c
> +++ b/fs/gfs2/file.c
> @@ -96,7 +96,7 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir)
>  		return error;
>  	}
>  
> -	error = gfs2_dir_read(dir, &offset, dirent, filldir);
> +	error = gfs2_dir_read(dir, &offset, dirent, filldir, &file->f_ra);
>  
>  	gfs2_glock_dq_uninit(&d_gh);
>  




^ permalink raw reply

* Re: [PATCH v2 3/5] regulator: helper routine to extract regulator_init_data
From: Grant Likely @ 2011-10-24  8:17 UTC (permalink / raw)
  To: Rajendra Nayak
  Cc: Shawn Guo, broonie, patches, tony, devicetree-discuss,
	linux-kernel, linux-omap, lrg, linux-arm-kernel
In-Reply-To: <4EA4FF6B.2080906@ti.com>

On Mon, Oct 24, 2011 at 11:32:19AM +0530, Rajendra Nayak wrote:
> On Friday 21 October 2011 05:28 PM, Shawn Guo wrote:
> >On Fri, Oct 21, 2011 at 02:11:55PM +0530, Rajendra Nayak wrote:
> >[...]
> >>>+       /* find device_node and attach it */
> >>>+       rdev->dev.of_node = of_find_node_by_name(NULL, regulator_desc->name);
> >>
> >>so would this do a complete dt search for every regulator?
> >
> >Yes, with the first param being NULL, tthe entire device tree will be
> >searched.
> >
> >>we would also need the driver names and dt names to match for this to
> >>work, right?
> >>
> >Driver name does not matter.  The key for this search to work is having
> >regulator's name (regulator_desc->name) match device tree node's name,
> >case ignored.
> 
> Mark, whats your take on this? I am somehow not quite sure if we should
> have this limitation put in to match DT node names with whats in the
> driver structs (regulator_desc).

This looks wrong to me.  Matching based on node /name/, particularly
when searching the entire tree, will cause problems.

g.

^ permalink raw reply

* [PATCH v2 3/5] regulator: helper routine to extract regulator_init_data
From: Grant Likely @ 2011-10-24  8:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4EA4FF6B.2080906@ti.com>

On Mon, Oct 24, 2011 at 11:32:19AM +0530, Rajendra Nayak wrote:
> On Friday 21 October 2011 05:28 PM, Shawn Guo wrote:
> >On Fri, Oct 21, 2011 at 02:11:55PM +0530, Rajendra Nayak wrote:
> >[...]
> >>>+       /* find device_node and attach it */
> >>>+       rdev->dev.of_node = of_find_node_by_name(NULL, regulator_desc->name);
> >>
> >>so would this do a complete dt search for every regulator?
> >
> >Yes, with the first param being NULL, tthe entire device tree will be
> >searched.
> >
> >>we would also need the driver names and dt names to match for this to
> >>work, right?
> >>
> >Driver name does not matter.  The key for this search to work is having
> >regulator's name (regulator_desc->name) match device tree node's name,
> >case ignored.
> 
> Mark, whats your take on this? I am somehow not quite sure if we should
> have this limitation put in to match DT node names with whats in the
> driver structs (regulator_desc).

This looks wrong to me.  Matching based on node /name/, particularly
when searching the entire tree, will cause problems.

g.

^ permalink raw reply

* Re: [PATCH v2 3/5] regulator: helper routine to extract regulator_init_data
From: Grant Likely @ 2011-10-24  8:17 UTC (permalink / raw)
  To: Rajendra Nayak
  Cc: patches, tony, devicetree-discuss, broonie, linux-kernel,
	linux-arm-kernel, linux-omap, lrg, Shawn Guo
In-Reply-To: <4EA4FF6B.2080906@ti.com>

On Mon, Oct 24, 2011 at 11:32:19AM +0530, Rajendra Nayak wrote:
> On Friday 21 October 2011 05:28 PM, Shawn Guo wrote:
> >On Fri, Oct 21, 2011 at 02:11:55PM +0530, Rajendra Nayak wrote:
> >[...]
> >>>+       /* find device_node and attach it */
> >>>+       rdev->dev.of_node = of_find_node_by_name(NULL, regulator_desc->name);
> >>
> >>so would this do a complete dt search for every regulator?
> >
> >Yes, with the first param being NULL, tthe entire device tree will be
> >searched.
> >
> >>we would also need the driver names and dt names to match for this to
> >>work, right?
> >>
> >Driver name does not matter.  The key for this search to work is having
> >regulator's name (regulator_desc->name) match device tree node's name,
> >case ignored.
> 
> Mark, whats your take on this? I am somehow not quite sure if we should
> have this limitation put in to match DT node names with whats in the
> driver structs (regulator_desc).

This looks wrong to me.  Matching based on node /name/, particularly
when searching the entire tree, will cause problems.

g.

^ permalink raw reply

* Re: [Qemu-devel] [PATCH 0/2] block: Write out internal caches even with cache=unsafe
From: Kevin Wolf @ 2011-10-24  8:17 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Alexander Graf, qemu-devel, avi
In-Reply-To: <4EA51963.5060904@redhat.com>

Am 24.10.2011 09:53, schrieb Paolo Bonzini:
> On 10/24/2011 09:37 AM, Kevin Wolf wrote:
>>> Why? cache=unsafe is explicitly allowing to s/data/manure/ on
>>> crash.
>>
>> It's surely expected on a host crash, but is it for a qemu crash?
>> cache=unsafe was introduced to avoid fsync() costs, which it still
>> does after this patch.
> 
> I think it's not about "why is it there", but rather about "what is it 
> useful for".  My interpretation of it is "I do not need the image 
> anymore unless the command exits cleanly": VM installations, qemu-img 
> conversions, BDRV_O_SNAPSHOT (doesn't do it yet, but it could).  Even 
> SIGINT and SIGTERM would be excluded from this definition, but they cost 
> nothing so it's nice to include them.

I think another common interpretation is: "I don't run this VM in
production but for development. I want the VM to go faster and I can
recreate the image in the unlikely event that power fails during my
work. But it certainly would be nasty."

>>> If you do this for raw-posix, you need to do it for all protocols.
>>
>> rbd could use it, too, right. Any other protocol I missed?
> 
> NBD could, but it doesn't support flush yet.
> 
> In general, even if it were useful to implement this, I'm not sure this 
> is the best way to implement it.  For example you could simply clear 
> BDRV_O_NO_FLUSH in qcow2_open.

That could work, too. On the other hand I don't like block drivers to
modify their flags. For example, would query-block still provide the
correct cache mode then?

But I think that starting to make exceptions for single block drivers
isn't a good idea anyway. If we want bdrv_flush() to write out all
metadata internal to qemu, I think the approach with checking the flag
in drivers calling things like fsync() is better. The common thing is to
do the flush.

Kevin

^ permalink raw reply

* [patch net-next V4] net: introduce ethernet teaming device
From: Jiri Pirko @ 2011-10-24  8:13 UTC (permalink / raw)
  To: netdev
  Cc: davem, eric.dumazet, bhutchings, shemminger, fubar, andy, tgraf,
	ebiederm, mirqus, kaber, greearb, jesse, fbl, benjamin.poirier,
	jzupka

This patch introduces new network device called team. It supposes to be
very fast, simple, userspace-driven alternative to existing bonding
driver.

Userspace library called libteam with couple of demo apps is available
here:
https://github.com/jpirko/libteam
Note it's still in its dipers atm.

team<->libteam use generic netlink for communication. That and rtnl
suppose to be the only way to configure team device, no sysfs etc.

Python binding basis for libteam was recently introduced (some need
still need to be done on it though). Daemon providing arpmon/miimon
active-backup functionality will be introduced shortly.
All what's necessary is already implemented in kernel team driver.

Signed-off-by: Jiri Pirko <jpirko@redhat.com>

v3->v4:
	- remove redundant synchronize_rcu from __team_change_mode()
	- revert "set and clear of mode_ops happens per pointer, not per
	  byte"
	- extend comment of function __team_change_mode()

v2->v3:
	- team_change_mtu() user rcu version of list traversal to unwind
	- set and clear of mode_ops happens per pointer, not per byte
	- port hashlist changed to be embedded into team structure
	- error branch in team_port_enter() does cleanup now
	- fixed rtln->rtnl

v1->v2:
	- modes are made as modules. Makes team more modular and
	  extendable.
	- several commenters' nitpicks found on v1 were fixed
	- several other bugs were fixed.
	- note I ignored Eric's comment about roundrobin port selector
	  as Eric's way may be easily implemented as another mode (mode
	  "random") in future.
---
 Documentation/networking/team.txt         |    2 +
 MAINTAINERS                               |    7 +
 drivers/net/Kconfig                       |    2 +
 drivers/net/Makefile                      |    1 +
 drivers/net/team/Kconfig                  |   38 +
 drivers/net/team/Makefile                 |    7 +
 drivers/net/team/team.c                   | 1573 +++++++++++++++++++++++++++++
 drivers/net/team/team_mode_activebackup.c |  152 +++
 drivers/net/team/team_mode_roundrobin.c   |  107 ++
 include/linux/Kbuild                      |    1 +
 include/linux/if.h                        |    1 +
 include/linux/if_team.h                   |  231 +++++
 include/linux/rculist.h                   |   14 +
 13 files changed, 2136 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/networking/team.txt
 create mode 100644 drivers/net/team/Kconfig
 create mode 100644 drivers/net/team/Makefile
 create mode 100644 drivers/net/team/team.c
 create mode 100644 drivers/net/team/team_mode_activebackup.c
 create mode 100644 drivers/net/team/team_mode_roundrobin.c
 create mode 100644 include/linux/if_team.h

diff --git a/Documentation/networking/team.txt b/Documentation/networking/team.txt
new file mode 100644
index 0000000..5a01368
--- /dev/null
+++ b/Documentation/networking/team.txt
@@ -0,0 +1,2 @@
+Team devices are driven from userspace via libteam library which is here:
+	https://github.com/jpirko/libteam
diff --git a/MAINTAINERS b/MAINTAINERS
index 5008b08..c33400d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6372,6 +6372,13 @@ W:	http://tcp-lp-mod.sourceforge.net/
 S:	Maintained
 F:	net/ipv4/tcp_lp.c
 
+TEAM DRIVER
+M:	Jiri Pirko <jpirko@redhat.com>
+L:	netdev@vger.kernel.org
+S:	Supported
+F:	drivers/net/team/
+F:	include/linux/if_team.h
+
 TEGRA SUPPORT
 M:	Colin Cross <ccross@android.com>
 M:	Erik Gilling <konkers@android.com>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 583f66c..b3020be 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -125,6 +125,8 @@ config IFB
 	  'ifb1' etc.
 	  Look at the iproute2 documentation directory for usage etc
 
+source "drivers/net/team/Kconfig"
+
 config MACVLAN
 	tristate "MAC-VLAN support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index fa877cd..4e4ebfe 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_NET) += Space.o loopback.o
 obj-$(CONFIG_NETCONSOLE) += netconsole.o
 obj-$(CONFIG_PHYLIB) += phy/
 obj-$(CONFIG_RIONET) += rionet.o
+obj-$(CONFIG_NET_TEAM) += team/
 obj-$(CONFIG_TUN) += tun.o
 obj-$(CONFIG_VETH) += veth.o
 obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
diff --git a/drivers/net/team/Kconfig b/drivers/net/team/Kconfig
new file mode 100644
index 0000000..70a43a6
--- /dev/null
+++ b/drivers/net/team/Kconfig
@@ -0,0 +1,38 @@
+menuconfig NET_TEAM
+	tristate "Ethernet team driver support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	---help---
+	  This allows one to create virtual interfaces that teams together
+	  multiple ethernet devices.
+
+	  Team devices can be added using the "ip" command from the
+	  iproute2 package:
+
+	  "ip link add link [ address MAC ] [ NAME ] type team"
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called team.
+
+if NET_TEAM
+
+config NET_TEAM_MODE_ROUNDROBIN
+	tristate "Round-robin mode support"
+	depends on NET_TEAM
+	---help---
+	  Basic mode where port used for transmitting packets is selected in
+	  round-robin fashion using packet counter.
+
+	  To compile this team mode as a module, choose M here: the module
+	  will be called team_mode_roundrobin.
+
+config NET_TEAM_MODE_ACTIVEBACKUP
+	tristate "Active-backup mode support"
+	depends on NET_TEAM
+	---help---
+	  Only one port is active at a time and the rest of ports are used
+	  for backup.
+
+	  To compile this team mode as a module, choose M here: the module
+	  will be called team_mode_activebackup.
+
+endif # NET_TEAM
diff --git a/drivers/net/team/Makefile b/drivers/net/team/Makefile
new file mode 100644
index 0000000..85f2028
--- /dev/null
+++ b/drivers/net/team/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the network team driver
+#
+
+obj-$(CONFIG_NET_TEAM) += team.o
+obj-$(CONFIG_NET_TEAM_MODE_ROUNDROBIN) += team_mode_roundrobin.o
+obj-$(CONFIG_NET_TEAM_MODE_ACTIVEBACKUP) += team_mode_activebackup.o
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
new file mode 100644
index 0000000..acfef4c
--- /dev/null
+++ b/drivers/net/team/team.c
@@ -0,0 +1,1573 @@
+/*
+ * net/drivers/team/team.c - Network team device driver
+ * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/rcupdate.h>
+#include <linux/errno.h>
+#include <linux/ctype.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/socket.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/rtnetlink.h>
+#include <net/genetlink.h>
+#include <net/netlink.h>
+#include <linux/if_team.h>
+
+#define DRV_NAME "team"
+
+
+/**********
+ * Helpers
+ **********/
+
+#define team_port_exists(dev) (dev->priv_flags & IFF_TEAM_PORT)
+
+static struct team_port *team_port_get_rcu(const struct net_device *dev)
+{
+	struct team_port *port = rcu_dereference(dev->rx_handler_data);
+
+	return team_port_exists(dev) ? port : NULL;
+}
+
+static struct team_port *team_port_get_rtnl(const struct net_device *dev)
+{
+	struct team_port *port = rtnl_dereference(dev->rx_handler_data);
+
+	return team_port_exists(dev) ? port : NULL;
+}
+
+/*
+ * Since the ability to change mac address for open port device is tested in
+ * team_port_add, this function can be called without control of return value
+ */
+static int __set_port_mac(struct net_device *port_dev,
+			  const unsigned char *dev_addr)
+{
+	struct sockaddr addr;
+
+	memcpy(addr.sa_data, dev_addr, ETH_ALEN);
+	addr.sa_family = ARPHRD_ETHER;
+	return dev_set_mac_address(port_dev, &addr);
+}
+
+int team_port_set_orig_mac(struct team_port *port)
+{
+	return __set_port_mac(port->dev, port->orig.dev_addr);
+}
+EXPORT_SYMBOL(team_port_set_orig_mac);
+
+int team_port_set_team_mac(struct team_port *port)
+{
+	return __set_port_mac(port->dev, port->team->dev->dev_addr);
+}
+EXPORT_SYMBOL(team_port_set_team_mac);
+
+
+/*******************
+ * Options handling
+ *******************/
+
+void team_options_register(struct team *team, struct team_option *option,
+			   size_t option_count)
+{
+	int i;
+
+	for (i = 0; i < option_count; i++, option++)
+		list_add_tail(&option->list, &team->option_list);
+}
+EXPORT_SYMBOL(team_options_register);
+
+static void __team_options_change_check(struct team *team,
+					struct team_option *changed_option);
+
+static void __team_options_unregister(struct team *team,
+				      struct team_option *option,
+				      size_t option_count)
+{
+	int i;
+
+	for (i = 0; i < option_count; i++, option++)
+		list_del(&option->list);
+}
+
+void team_options_unregister(struct team *team, struct team_option *option,
+			     size_t option_count)
+{
+	__team_options_unregister(team, option, option_count);
+	__team_options_change_check(team, NULL);
+}
+EXPORT_SYMBOL(team_options_unregister);
+
+static int team_option_get(struct team *team, struct team_option *option,
+			   void *arg)
+{
+	return option->getter(team, arg);
+}
+
+static int team_option_set(struct team *team, struct team_option *option,
+			   void *arg)
+{
+	int err;
+
+	err = option->setter(team, arg);
+	if (err)
+		return err;
+
+	__team_options_change_check(team, option);
+	return err;
+}
+
+/****************
+ * Mode handling
+ ****************/
+
+static LIST_HEAD(mode_list);
+static DEFINE_SPINLOCK(mode_list_lock);
+
+static struct team_mode *__find_mode(const char *kind)
+{
+	struct team_mode *mode;
+
+	list_for_each_entry(mode, &mode_list, list) {
+		if (strcmp(mode->kind, kind) == 0)
+			return mode;
+	}
+	return NULL;
+}
+
+static bool is_good_mode_name(const char *name)
+{
+	while (*name != '\0') {
+		if (!isalpha(*name) && !isdigit(*name) && *name != '_')
+			return false;
+		name++;
+	}
+	return true;
+}
+
+int team_mode_register(struct team_mode *mode)
+{
+	int err = 0;
+
+	if (!is_good_mode_name(mode->kind) ||
+	    mode->priv_size > TEAM_MODE_PRIV_SIZE)
+		return -EINVAL;
+	spin_lock(&mode_list_lock);
+	if (__find_mode(mode->kind)) {
+		err = -EEXIST;
+		goto unlock;
+	}
+	list_add_tail(&mode->list, &mode_list);
+unlock:
+	spin_unlock(&mode_list_lock);
+	return err;
+}
+EXPORT_SYMBOL(team_mode_register);
+
+int team_mode_unregister(struct team_mode *mode)
+{
+	spin_lock(&mode_list_lock);
+	list_del_init(&mode->list);
+	spin_unlock(&mode_list_lock);
+	return 0;
+}
+EXPORT_SYMBOL(team_mode_unregister);
+
+static struct team_mode *team_mode_get(const char *kind)
+{
+	struct team_mode *mode;
+
+	spin_lock(&mode_list_lock);
+	mode = __find_mode(kind);
+	if (!mode) {
+		spin_unlock(&mode_list_lock);
+		request_module("team-mode-%s", kind);
+		spin_lock(&mode_list_lock);
+		mode = __find_mode(kind);
+	}
+	if (mode)
+		if (!try_module_get(mode->owner))
+			mode = NULL;
+
+	spin_unlock(&mode_list_lock);
+	return mode;
+}
+
+static void team_mode_put(const char *kind)
+{
+	struct team_mode *mode;
+
+	spin_lock(&mode_list_lock);
+	mode = __find_mode(kind);
+	BUG_ON(!mode);
+	module_put(mode->owner);
+	spin_unlock(&mode_list_lock);
+}
+
+/*
+ * We can benefit from the fact that it's ensured no port is present
+ * at the time of mode change. Therefore no packets are in fly so there's no
+ * need to set mode operations in any special way.
+ */
+static int __team_change_mode(struct team *team,
+			      const struct team_mode *new_mode)
+{
+	/* Check if mode was previously set and do cleanup if so */
+	if (team->mode_kind) {
+		void (*exit_op)(struct team *team) = team->mode_ops.exit;
+
+		/* Clear ops area so no callback is called any longer */
+		memset(&team->mode_ops, 0, sizeof(struct team_mode_ops));
+
+		if (exit_op)
+			exit_op(team);
+		team_mode_put(team->mode_kind);
+		team->mode_kind = NULL;
+		/* zero private data area */
+		memset(&team->mode_priv, 0,
+		       sizeof(struct team) - offsetof(struct team, mode_priv));
+	}
+
+	if (!new_mode)
+		return 0;
+
+	if (new_mode->ops->init) {
+		int err;
+
+		err = new_mode->ops->init(team);
+		if (err)
+			return err;
+	}
+
+	team->mode_kind = new_mode->kind;
+	memcpy(&team->mode_ops, new_mode->ops, sizeof(struct team_mode_ops));
+
+	return 0;
+}
+
+static int team_change_mode(struct team *team, const char *kind)
+{
+	struct team_mode *new_mode;
+	struct net_device *dev = team->dev;
+	int err;
+
+	if (!list_empty(&team->port_list)) {
+		netdev_err(dev, "No ports can be present during mode change\n");
+		return -EBUSY;
+	}
+
+	if (team->mode_kind && strcmp(team->mode_kind, kind) == 0) {
+		netdev_err(dev, "Unable to change to the same mode the team is in\n");
+		return -EINVAL;
+	}
+
+	new_mode = team_mode_get(kind);
+	if (!new_mode) {
+		netdev_err(dev, "Mode \"%s\" not found\n", kind);
+		return -EINVAL;
+	}
+
+	err = __team_change_mode(team, new_mode);
+	if (err) {
+		netdev_err(dev, "Failed to change to mode \"%s\"\n", kind);
+		team_mode_put(kind);
+		return err;
+	}
+
+	netdev_info(dev, "Mode changed to \"%s\"\n", kind);
+	return 0;
+}
+
+
+/************************
+ * Rx path frame handler
+ ************************/
+
+/* note: already called with rcu_read_lock */
+static rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
+{
+	struct sk_buff *skb = *pskb;
+	struct team_port *port;
+	struct team *team;
+	rx_handler_result_t res = RX_HANDLER_ANOTHER;
+
+	skb = skb_share_check(skb, GFP_ATOMIC);
+	if (!skb)
+		return RX_HANDLER_CONSUMED;
+
+	*pskb = skb;
+
+	port = team_port_get_rcu(skb->dev);
+	team = port->team;
+
+	if (team->mode_ops.receive)
+		res = team->mode_ops.receive(team, port, skb);
+
+	if (res == RX_HANDLER_ANOTHER) {
+		struct team_pcpu_stats *pcpu_stats;
+
+		pcpu_stats = this_cpu_ptr(team->pcpu_stats);
+		u64_stats_update_begin(&pcpu_stats->syncp);
+		pcpu_stats->rx_packets++;
+		pcpu_stats->rx_bytes += skb->len;
+		if (skb->pkt_type == PACKET_MULTICAST)
+			pcpu_stats->rx_multicast++;
+		u64_stats_update_end(&pcpu_stats->syncp);
+
+		skb->dev = team->dev;
+	} else {
+		this_cpu_inc(team->pcpu_stats->rx_dropped);
+	}
+
+	return res;
+}
+
+
+/****************
+ * Port handling
+ ****************/
+
+static bool team_port_find(const struct team *team,
+			   const struct team_port *port)
+{
+	struct team_port *cur;
+
+	list_for_each_entry(cur, &team->port_list, list)
+		if (cur == port)
+			return true;
+	return false;
+}
+
+/*
+ * Add/delete port to the team port list. Write guarded by rtnl_lock.
+ * Takes care of correct port->index setup (might be racy).
+ */
+static void team_port_list_add_port(struct team *team,
+				    struct team_port *port)
+{
+	port->index = team->port_count++;
+	hlist_add_head_rcu(&port->hlist,
+			   team_port_index_hash(team, port->index));
+	list_add_tail_rcu(&port->list, &team->port_list);
+}
+
+static void __reconstruct_port_hlist(struct team *team, int rm_index)
+{
+	int i;
+	struct team_port *port;
+
+	for (i = rm_index + 1; i < team->port_count; i++) {
+		port = team_get_port_by_index_rcu(team, i);
+		hlist_del_rcu(&port->hlist);
+		port->index--;
+		hlist_add_head_rcu(&port->hlist,
+				   team_port_index_hash(team, port->index));
+	}
+}
+
+static void team_port_list_del_port(struct team *team,
+				   struct team_port *port)
+{
+	int rm_index = port->index;
+
+	hlist_del_rcu(&port->hlist);
+	list_del_rcu(&port->list);
+	__reconstruct_port_hlist(team, rm_index);
+	team->port_count--;
+}
+
+#define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \
+			    NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \
+			    NETIF_F_HIGHDMA | NETIF_F_LRO)
+
+static void __team_compute_features(struct team *team)
+{
+	struct team_port *port;
+	u32 vlan_features = TEAM_VLAN_FEATURES;
+	unsigned short max_hard_header_len = ETH_HLEN;
+
+	list_for_each_entry(port, &team->port_list, list) {
+		vlan_features = netdev_increment_features(vlan_features,
+					port->dev->vlan_features,
+					TEAM_VLAN_FEATURES);
+
+		if (port->dev->hard_header_len > max_hard_header_len)
+			max_hard_header_len = port->dev->hard_header_len;
+	}
+
+	team->dev->vlan_features = vlan_features;
+	team->dev->hard_header_len = max_hard_header_len;
+
+	netdev_change_features(team->dev);
+}
+
+static void team_compute_features(struct team *team)
+{
+	spin_lock(&team->lock);
+	__team_compute_features(team);
+	spin_unlock(&team->lock);
+}
+
+static int team_port_enter(struct team *team, struct team_port *port)
+{
+	int err = 0;
+
+	dev_hold(team->dev);
+	port->dev->priv_flags |= IFF_TEAM_PORT;
+	if (team->mode_ops.port_enter) {
+		err = team->mode_ops.port_enter(team, port);
+		if (err) {
+			netdev_err(team->dev, "Device %s failed to enter team mode\n",
+				   port->dev->name);
+			goto err_port_enter;
+		}
+	}
+
+	return 0;
+
+err_port_enter:
+	port->dev->priv_flags &= ~IFF_TEAM_PORT;
+	dev_put(team->dev);
+
+	return err;
+}
+
+static void team_port_leave(struct team *team, struct team_port *port)
+{
+	if (team->mode_ops.port_leave)
+		team->mode_ops.port_leave(team, port);
+	port->dev->priv_flags &= ~IFF_TEAM_PORT;
+	dev_put(team->dev);
+}
+
+static void __team_port_change_check(struct team_port *port, bool linkup);
+
+static int team_port_add(struct team *team, struct net_device *port_dev)
+{
+	struct net_device *dev = team->dev;
+	struct team_port *port;
+	char *portname = port_dev->name;
+	char tmp_addr[ETH_ALEN];
+	int err;
+
+	if (port_dev->flags & IFF_LOOPBACK ||
+	    port_dev->type != ARPHRD_ETHER) {
+		netdev_err(dev, "Device %s is of an unsupported type\n",
+			   portname);
+		return -EINVAL;
+	}
+
+	if (team_port_exists(port_dev)) {
+		netdev_err(dev, "Device %s is already a port "
+				"of a team device\n", portname);
+		return -EBUSY;
+	}
+
+	if (port_dev->flags & IFF_UP) {
+		netdev_err(dev, "Device %s is up. Set it down before adding it as a team port\n",
+			   portname);
+		return -EBUSY;
+	}
+
+	port = kzalloc(sizeof(struct team_port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	port->dev = port_dev;
+	port->team = team;
+
+	port->orig.mtu = port_dev->mtu;
+	err = dev_set_mtu(port_dev, dev->mtu);
+	if (err) {
+		netdev_dbg(dev, "Error %d calling dev_set_mtu\n", err);
+		goto err_set_mtu;
+	}
+
+	memcpy(port->orig.dev_addr, port_dev->dev_addr, ETH_ALEN);
+	random_ether_addr(tmp_addr);
+	err = __set_port_mac(port_dev, tmp_addr);
+	if (err) {
+		netdev_dbg(dev, "Device %s mac addr set failed\n",
+			   portname);
+		goto err_set_mac_rand;
+	}
+
+	err = dev_open(port_dev);
+	if (err) {
+		netdev_dbg(dev, "Device %s opening failed\n",
+			   portname);
+		goto err_dev_open;
+	}
+
+	err = team_port_set_orig_mac(port);
+	if (err) {
+		netdev_dbg(dev, "Device %s mac addr set failed - Device does not support addr change when it's opened\n",
+			   portname);
+		goto err_set_mac_opened;
+	}
+
+	err = team_port_enter(team, port);
+	if (err) {
+		netdev_err(dev, "Device %s failed to enter team mode\n",
+			   portname);
+		goto err_port_enter;
+	}
+
+	err = netdev_set_master(port_dev, dev);
+	if (err) {
+		netdev_err(dev, "Device %s failed to set master\n", portname);
+		goto err_set_master;
+	}
+
+	err = netdev_rx_handler_register(port_dev, team_handle_frame,
+					 port);
+	if (err) {
+		netdev_err(dev, "Device %s failed to register rx_handler\n",
+			   portname);
+		goto err_handler_register;
+	}
+
+	team_port_list_add_port(team, port);
+	__team_compute_features(team);
+	__team_port_change_check(port, !!netif_carrier_ok(port_dev));
+
+	netdev_info(dev, "Port device %s added\n", portname);
+
+	return 0;
+
+err_handler_register:
+	netdev_set_master(port_dev, NULL);
+
+err_set_master:
+	team_port_leave(team, port);
+
+err_port_enter:
+err_set_mac_opened:
+	dev_close(port_dev);
+
+err_dev_open:
+	team_port_set_orig_mac(port);
+
+err_set_mac_rand:
+	dev_set_mtu(port_dev, port->orig.mtu);
+
+err_set_mtu:
+	kfree(port);
+
+	return err;
+}
+
+static int team_port_del(struct team *team, struct net_device *port_dev)
+{
+	struct net_device *dev = team->dev;
+	struct team_port *port;
+	char *portname = port_dev->name;
+
+	port = team_port_get_rtnl(port_dev);
+	if (!port || !team_port_find(team, port)) {
+		netdev_err(dev, "Device %s does not act as a port of this team\n",
+			   portname);
+		return -ENOENT;
+	}
+
+	__team_port_change_check(port, false);
+	team_port_list_del_port(team, port);
+	netdev_rx_handler_unregister(port_dev);
+	netdev_set_master(port_dev, NULL);
+	team_port_leave(team, port);
+	dev_close(port_dev);
+	team_port_set_orig_mac(port);
+	dev_set_mtu(port_dev, port->orig.mtu);
+	synchronize_rcu();
+	kfree(port);
+	netdev_info(dev, "Port device %s removed\n", portname);
+	__team_compute_features(team);
+
+	return 0;
+}
+
+
+/*****************
+ * Net device ops
+ *****************/
+
+static const char team_no_mode_kind[] = "*NOMODE*";
+
+static int team_mode_option_get(struct team *team, void *arg)
+{
+	const char **str = arg;
+
+	*str = team->mode_kind ? team->mode_kind : team_no_mode_kind;
+	return 0;
+}
+
+static int team_mode_option_set(struct team *team, void *arg)
+{
+	const char **str = arg;
+
+	return team_change_mode(team, *str);
+}
+
+static struct team_option team_options[] = {
+	{
+		.name = "mode",
+		.type = TEAM_OPTION_TYPE_STRING,
+		.getter = team_mode_option_get,
+		.setter = team_mode_option_set,
+	},
+};
+
+static int team_init(struct net_device *dev)
+{
+	struct team *team = netdev_priv(dev);
+	int i;
+
+	team->dev = dev;
+	spin_lock_init(&team->lock);
+
+	team->pcpu_stats = alloc_percpu(struct team_pcpu_stats);
+	if (!team->pcpu_stats)
+		return -ENOMEM;
+
+	for (i = 0; i < TEAM_PORT_HASHENTRIES; i++)
+		INIT_HLIST_HEAD(&team->port_hlist[i]);
+	INIT_LIST_HEAD(&team->port_list);
+
+	INIT_LIST_HEAD(&team->option_list);
+	team_options_register(team, team_options, ARRAY_SIZE(team_options));
+	netif_carrier_off(dev);
+
+	return 0;
+}
+
+static void team_uninit(struct net_device *dev)
+{
+	struct team *team = netdev_priv(dev);
+	struct team_port *port;
+	struct team_port *tmp;
+
+	spin_lock(&team->lock);
+	list_for_each_entry_safe(port, tmp, &team->port_list, list)
+		team_port_del(team, port->dev);
+
+	__team_change_mode(team, NULL); /* cleanup */
+	__team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
+	spin_unlock(&team->lock);
+}
+
+static void team_destructor(struct net_device *dev)
+{
+	struct team *team = netdev_priv(dev);
+
+	free_percpu(team->pcpu_stats);
+	free_netdev(dev);
+}
+
+static int team_open(struct net_device *dev)
+{
+	netif_carrier_on(dev);
+	return 0;
+}
+
+static int team_close(struct net_device *dev)
+{
+	netif_carrier_off(dev);
+	return 0;
+}
+
+/*
+ * note: already called with rcu_read_lock
+ */
+static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct team *team = netdev_priv(dev);
+	bool tx_success = false;
+	unsigned int len = skb->len;
+
+	/*
+	 * Ensure transmit function is called only in case there is at least
+	 * one port present.
+	 */
+	if (likely(!list_empty(&team->port_list) && team->mode_ops.transmit))
+		tx_success = team->mode_ops.transmit(team, skb);
+	if (tx_success) {
+		struct team_pcpu_stats *pcpu_stats;
+
+		pcpu_stats = this_cpu_ptr(team->pcpu_stats);
+		u64_stats_update_begin(&pcpu_stats->syncp);
+		pcpu_stats->tx_packets++;
+		pcpu_stats->tx_bytes += len;
+		u64_stats_update_end(&pcpu_stats->syncp);
+	} else {
+		this_cpu_inc(team->pcpu_stats->tx_dropped);
+	}
+
+	return NETDEV_TX_OK;
+}
+
+static void team_change_rx_flags(struct net_device *dev, int change)
+{
+	struct team *team = netdev_priv(dev);
+	struct team_port *port;
+	int inc;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(port, &team->port_list, list) {
+		if (change & IFF_PROMISC) {
+			inc = dev->flags & IFF_PROMISC ? 1 : -1;
+			dev_set_promiscuity(port->dev, inc);
+		}
+		if (change & IFF_ALLMULTI) {
+			inc = dev->flags & IFF_ALLMULTI ? 1 : -1;
+			dev_set_allmulti(port->dev, inc);
+		}
+	}
+	rcu_read_unlock();
+}
+
+static void team_set_rx_mode(struct net_device *dev)
+{
+	struct team *team = netdev_priv(dev);
+	struct team_port *port;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(port, &team->port_list, list) {
+		dev_uc_sync(port->dev, dev);
+		dev_mc_sync(port->dev, dev);
+	}
+	rcu_read_unlock();
+}
+
+static int team_set_mac_address(struct net_device *dev, void *p)
+{
+	struct team *team = netdev_priv(dev);
+	struct team_port *port;
+	struct sockaddr *addr = p;
+
+	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+	rcu_read_lock();
+	list_for_each_entry_rcu(port, &team->port_list, list)
+		if (team->mode_ops.port_change_mac)
+			team->mode_ops.port_change_mac(team, port);
+	rcu_read_unlock();
+	return 0;
+}
+
+static int team_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct team *team = netdev_priv(dev);
+	struct team_port *port;
+	int err;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(port, &team->port_list, list) {
+		err = dev_set_mtu(port->dev, new_mtu);
+		if (err) {
+			netdev_err(dev, "Device %s failed to change mtu",
+				   port->dev->name);
+			goto unwind;
+		}
+	}
+	rcu_read_unlock();
+
+	dev->mtu = new_mtu;
+
+	return 0;
+
+unwind:
+	list_for_each_entry_continue_reverse_rcu(port, &team->port_list, list)
+		dev_set_mtu(port->dev, dev->mtu);
+
+	rcu_read_unlock();
+	return err;
+}
+
+static struct rtnl_link_stats64 *
+team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
+{
+	struct team *team = netdev_priv(dev);
+	struct team_pcpu_stats *p;
+	u64 rx_packets, rx_bytes, rx_multicast, tx_packets, tx_bytes;
+	u32 rx_dropped = 0, tx_dropped = 0;
+	unsigned int start;
+	int i;
+
+	for_each_possible_cpu(i) {
+		p = per_cpu_ptr(team->pcpu_stats, i);
+		do {
+			start = u64_stats_fetch_begin_bh(&p->syncp);
+			rx_packets	= p->rx_packets;
+			rx_bytes	= p->rx_bytes;
+			rx_multicast	= p->rx_multicast;
+			tx_packets	= p->tx_packets;
+			tx_bytes	= p->tx_bytes;
+		} while (u64_stats_fetch_retry_bh(&p->syncp, start));
+
+		stats->rx_packets	+= rx_packets;
+		stats->rx_bytes		+= rx_bytes;
+		stats->multicast	+= rx_multicast;
+		stats->tx_packets	+= tx_packets;
+		stats->tx_bytes		+= tx_bytes;
+		/*
+		 * rx_dropped & tx_dropped are u32, updated
+		 * without syncp protection.
+		 */
+		rx_dropped	+= p->rx_dropped;
+		tx_dropped	+= p->tx_dropped;
+	}
+	stats->rx_dropped	= rx_dropped;
+	stats->tx_dropped	= tx_dropped;
+	return stats;
+}
+
+static void team_vlan_rx_add_vid(struct net_device *dev, uint16_t vid)
+{
+	struct team *team = netdev_priv(dev);
+	struct team_port *port;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(port, &team->port_list, list) {
+		const struct net_device_ops *ops = port->dev->netdev_ops;
+
+		ops->ndo_vlan_rx_add_vid(port->dev, vid);
+	}
+	rcu_read_unlock();
+}
+
+static void team_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
+{
+	struct team *team = netdev_priv(dev);
+	struct team_port *port;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(port, &team->port_list, list) {
+		const struct net_device_ops *ops = port->dev->netdev_ops;
+
+		ops->ndo_vlan_rx_kill_vid(port->dev, vid);
+	}
+	rcu_read_unlock();
+}
+
+static int team_add_slave(struct net_device *dev, struct net_device *port_dev)
+{
+	struct team *team = netdev_priv(dev);
+	int err;
+
+	spin_lock(&team->lock);
+	err = team_port_add(team, port_dev);
+	spin_unlock(&team->lock);
+	return err;
+}
+
+static int team_del_slave(struct net_device *dev, struct net_device *port_dev)
+{
+	struct team *team = netdev_priv(dev);
+	int err;
+
+	spin_lock(&team->lock);
+	err = team_port_del(team, port_dev);
+	spin_unlock(&team->lock);
+	return err;
+}
+
+static const struct net_device_ops team_netdev_ops = {
+	.ndo_init		= team_init,
+	.ndo_uninit		= team_uninit,
+	.ndo_open		= team_open,
+	.ndo_stop		= team_close,
+	.ndo_start_xmit		= team_xmit,
+	.ndo_change_rx_flags	= team_change_rx_flags,
+	.ndo_set_rx_mode	= team_set_rx_mode,
+	.ndo_set_mac_address	= team_set_mac_address,
+	.ndo_change_mtu		= team_change_mtu,
+	.ndo_get_stats64	= team_get_stats64,
+	.ndo_vlan_rx_add_vid	= team_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= team_vlan_rx_kill_vid,
+	.ndo_add_slave		= team_add_slave,
+	.ndo_del_slave		= team_del_slave,
+};
+
+
+/***********************
+ * rt netlink interface
+ ***********************/
+
+static void team_setup(struct net_device *dev)
+{
+	ether_setup(dev);
+
+	dev->netdev_ops = &team_netdev_ops;
+	dev->destructor	= team_destructor;
+	dev->tx_queue_len = 0;
+	dev->flags |= IFF_MULTICAST;
+	dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
+
+	/*
+	 * Indicate we support unicast address filtering. That way core won't
+	 * bring us to promisc mode in case a unicast addr is added.
+	 * Let this up to underlay drivers.
+	 */
+	dev->priv_flags |= IFF_UNICAST_FLT;
+
+	dev->features |= NETIF_F_LLTX;
+	dev->features |= NETIF_F_GRO;
+	dev->hw_features = NETIF_F_HW_VLAN_TX |
+			   NETIF_F_HW_VLAN_RX |
+			   NETIF_F_HW_VLAN_FILTER;
+
+	dev->features |= dev->hw_features;
+}
+
+static int team_newlink(struct net *src_net, struct net_device *dev,
+			struct nlattr *tb[], struct nlattr *data[])
+{
+	int err;
+
+	if (tb[IFLA_ADDRESS] == NULL)
+		random_ether_addr(dev->dev_addr);
+
+	err = register_netdevice(dev);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int team_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+	if (tb[IFLA_ADDRESS]) {
+		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+			return -EINVAL;
+		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+			return -EADDRNOTAVAIL;
+	}
+	return 0;
+}
+
+static struct rtnl_link_ops team_link_ops __read_mostly = {
+	.kind		= DRV_NAME,
+	.priv_size	= sizeof(struct team),
+	.setup		= team_setup,
+	.newlink	= team_newlink,
+	.validate	= team_validate,
+};
+
+
+/***********************************
+ * Generic netlink custom interface
+ ***********************************/
+
+static struct genl_family team_nl_family = {
+	.id		= GENL_ID_GENERATE,
+	.name		= TEAM_GENL_NAME,
+	.version	= TEAM_GENL_VERSION,
+	.maxattr	= TEAM_ATTR_MAX,
+	.netnsok	= true,
+};
+
+static const struct nla_policy team_nl_policy[TEAM_ATTR_MAX + 1] = {
+	[TEAM_ATTR_UNSPEC]			= { .type = NLA_UNSPEC, },
+	[TEAM_ATTR_TEAM_IFINDEX]		= { .type = NLA_U32 },
+	[TEAM_ATTR_LIST_OPTION]			= { .type = NLA_NESTED },
+	[TEAM_ATTR_LIST_PORT]			= { .type = NLA_NESTED },
+};
+
+static const struct nla_policy
+team_nl_option_policy[TEAM_ATTR_OPTION_MAX + 1] = {
+	[TEAM_ATTR_OPTION_UNSPEC]		= { .type = NLA_UNSPEC, },
+	[TEAM_ATTR_OPTION_NAME] = {
+		.type = NLA_STRING,
+		.len = TEAM_STRING_MAX_LEN,
+	},
+	[TEAM_ATTR_OPTION_CHANGED]		= { .type = NLA_FLAG },
+	[TEAM_ATTR_OPTION_TYPE]			= { .type = NLA_U8 },
+	[TEAM_ATTR_OPTION_DATA] = {
+		.type = NLA_BINARY,
+		.len = TEAM_STRING_MAX_LEN,
+	},
+};
+
+static int team_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)
+{
+	struct sk_buff *msg;
+	void *hdr;
+	int err;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
+			  &team_nl_family, 0, TEAM_CMD_NOOP);
+	if (IS_ERR(hdr)) {
+		err = PTR_ERR(hdr);
+		goto err_msg_put;
+	}
+
+	genlmsg_end(msg, hdr);
+
+	return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid);
+
+err_msg_put:
+	nlmsg_free(msg);
+
+	return err;
+}
+
+/*
+ * Netlink cmd functions should be locked by following two functions.
+ * To ensure team_uninit would not be called in between, hold rcu_read_lock
+ * all the time.
+ */
+static struct team *team_nl_team_get(struct genl_info *info)
+{
+	struct net *net = genl_info_net(info);
+	int ifindex;
+	struct net_device *dev;
+	struct team *team;
+
+	if (!info->attrs[TEAM_ATTR_TEAM_IFINDEX])
+		return NULL;
+
+	ifindex = nla_get_u32(info->attrs[TEAM_ATTR_TEAM_IFINDEX]);
+	rcu_read_lock();
+	dev = dev_get_by_index_rcu(net, ifindex);
+	if (!dev || dev->netdev_ops != &team_netdev_ops) {
+		rcu_read_unlock();
+		return NULL;
+	}
+
+	team = netdev_priv(dev);
+	spin_lock(&team->lock);
+	return team;
+}
+
+static void team_nl_team_put(struct team *team)
+{
+	spin_unlock(&team->lock);
+	rcu_read_unlock();
+}
+
+static int team_nl_send_generic(struct genl_info *info, struct team *team,
+				int (*fill_func)(struct sk_buff *skb,
+						 struct genl_info *info,
+						 int flags, struct team *team))
+{
+	struct sk_buff *skb;
+	int err;
+
+	skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	err = fill_func(skb, info, NLM_F_ACK, team);
+	if (err < 0)
+		goto err_fill;
+
+	err = genlmsg_unicast(genl_info_net(info), skb, info->snd_pid);
+	return err;
+
+err_fill:
+	nlmsg_free(skb);
+	return err;
+}
+
+static int team_nl_fill_options_get_changed(struct sk_buff *skb,
+					    u32 pid, u32 seq, int flags,
+					    struct team *team,
+					    struct team_option *changed_option)
+{
+	struct nlattr *option_list;
+	void *hdr;
+	struct team_option *option;
+
+	hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags,
+			  TEAM_CMD_OPTIONS_GET);
+	if (IS_ERR(hdr))
+		return PTR_ERR(hdr);
+
+	NLA_PUT_U32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex);
+	option_list = nla_nest_start(skb, TEAM_ATTR_LIST_OPTION);
+	if (!option_list)
+		return -EMSGSIZE;
+
+	list_for_each_entry(option, &team->option_list, list) {
+		struct nlattr *option_item;
+		long arg;
+
+		option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION);
+		if (!option_item)
+			goto nla_put_failure;
+		NLA_PUT_STRING(skb, TEAM_ATTR_OPTION_NAME, option->name);
+		if (option == changed_option)
+			NLA_PUT_FLAG(skb, TEAM_ATTR_OPTION_CHANGED);
+		switch (option->type) {
+		case TEAM_OPTION_TYPE_U32:
+			NLA_PUT_U8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32);
+			team_option_get(team, option, &arg);
+			NLA_PUT_U32(skb, TEAM_ATTR_OPTION_DATA, arg);
+			break;
+		case TEAM_OPTION_TYPE_STRING:
+			NLA_PUT_U8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING);
+			team_option_get(team, option, &arg);
+			NLA_PUT_STRING(skb, TEAM_ATTR_OPTION_DATA,
+				       (char *) arg);
+			break;
+		default:
+			BUG();
+		}
+		nla_nest_end(skb, option_item);
+	}
+
+	nla_nest_end(skb, option_list);
+	return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+	genlmsg_cancel(skb, hdr);
+	return -EMSGSIZE;
+}
+
+static int team_nl_fill_options_get(struct sk_buff *skb,
+				    struct genl_info *info, int flags,
+				    struct team *team)
+{
+	return team_nl_fill_options_get_changed(skb, info->snd_pid,
+						info->snd_seq, NLM_F_ACK,
+						team, NULL);
+}
+
+static int team_nl_cmd_options_get(struct sk_buff *skb, struct genl_info *info)
+{
+	struct team *team;
+	int err;
+
+	team = team_nl_team_get(info);
+	if (!team)
+		return -EINVAL;
+
+	err = team_nl_send_generic(info, team, team_nl_fill_options_get);
+
+	team_nl_team_put(team);
+
+	return err;
+}
+
+static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
+{
+	struct team *team;
+	int err = 0;
+	int i;
+	struct nlattr *nl_option;
+
+	team = team_nl_team_get(info);
+	if (!team)
+		return -EINVAL;
+
+	err = -EINVAL;
+	if (!info->attrs[TEAM_ATTR_LIST_OPTION]) {
+		err = -EINVAL;
+		goto team_put;
+	}
+
+	nla_for_each_nested(nl_option, info->attrs[TEAM_ATTR_LIST_OPTION], i) {
+		struct nlattr *mode_attrs[TEAM_ATTR_OPTION_MAX + 1];
+		enum team_option_type opt_type;
+		struct team_option *option;
+		char *opt_name;
+		bool opt_found = false;
+
+		if (nla_type(nl_option) != TEAM_ATTR_ITEM_OPTION) {
+			err = -EINVAL;
+			goto team_put;
+		}
+		err = nla_parse_nested(mode_attrs, TEAM_ATTR_OPTION_MAX,
+				       nl_option, team_nl_option_policy);
+		if (err)
+			goto team_put;
+		if (!mode_attrs[TEAM_ATTR_OPTION_NAME] ||
+		    !mode_attrs[TEAM_ATTR_OPTION_TYPE] ||
+		    !mode_attrs[TEAM_ATTR_OPTION_DATA]) {
+			err = -EINVAL;
+			goto team_put;
+		}
+		switch (nla_get_u8(mode_attrs[TEAM_ATTR_OPTION_TYPE])) {
+		case NLA_U32:
+			opt_type = TEAM_OPTION_TYPE_U32;
+			break;
+		case NLA_STRING:
+			opt_type = TEAM_OPTION_TYPE_STRING;
+			break;
+		default:
+			goto team_put;
+		}
+
+		opt_name = nla_data(mode_attrs[TEAM_ATTR_OPTION_NAME]);
+		list_for_each_entry(option, &team->option_list, list) {
+			long arg;
+			struct nlattr *opt_data_attr;
+
+			if (option->type != opt_type ||
+			    strcmp(option->name, opt_name))
+				continue;
+			opt_found = true;
+			opt_data_attr = mode_attrs[TEAM_ATTR_OPTION_DATA];
+			switch (opt_type) {
+			case TEAM_OPTION_TYPE_U32:
+				arg = nla_get_u32(opt_data_attr);
+				break;
+			case TEAM_OPTION_TYPE_STRING:
+				arg = (long) nla_data(opt_data_attr);
+				break;
+			default:
+				BUG();
+			}
+			err = team_option_set(team, option, &arg);
+			if (err)
+				goto team_put;
+		}
+		if (!opt_found) {
+			err = -ENOENT;
+			goto team_put;
+		}
+	}
+
+team_put:
+	team_nl_team_put(team);
+
+	return err;
+}
+
+static int team_nl_fill_port_list_get_changed(struct sk_buff *skb,
+					      u32 pid, u32 seq, int flags,
+					      struct team *team,
+					      struct team_port *changed_port)
+{
+	struct nlattr *port_list;
+	void *hdr;
+	struct team_port *port;
+
+	hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags,
+			  TEAM_CMD_PORT_LIST_GET);
+	if (IS_ERR(hdr))
+		return PTR_ERR(hdr);
+
+	NLA_PUT_U32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex);
+	port_list = nla_nest_start(skb, TEAM_ATTR_LIST_PORT);
+	if (!port_list)
+		return -EMSGSIZE;
+
+	list_for_each_entry_rcu(port, &team->port_list, list) {
+		struct nlattr *port_item;
+
+		port_item = nla_nest_start(skb, TEAM_ATTR_ITEM_PORT);
+		if (!port_item)
+			goto nla_put_failure;
+		NLA_PUT_U32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex);
+		if (port == changed_port)
+			NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_CHANGED);
+		if (port->linkup)
+			NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_LINKUP);
+		NLA_PUT_U32(skb, TEAM_ATTR_PORT_SPEED, port->speed);
+		NLA_PUT_U8(skb, TEAM_ATTR_PORT_DUPLEX, port->duplex);
+		nla_nest_end(skb, port_item);
+	}
+
+	nla_nest_end(skb, port_list);
+	return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+	genlmsg_cancel(skb, hdr);
+	return -EMSGSIZE;
+}
+
+static int team_nl_fill_port_list_get(struct sk_buff *skb,
+				      struct genl_info *info, int flags,
+				      struct team *team)
+{
+	return team_nl_fill_port_list_get_changed(skb, info->snd_pid,
+						  info->snd_seq, NLM_F_ACK,
+						  team, NULL);
+}
+
+static int team_nl_cmd_port_list_get(struct sk_buff *skb,
+				     struct genl_info *info)
+{
+	struct team *team;
+	int err;
+
+	team = team_nl_team_get(info);
+	if (!team)
+		return -EINVAL;
+
+	err = team_nl_send_generic(info, team, team_nl_fill_port_list_get);
+
+	team_nl_team_put(team);
+
+	return err;
+}
+
+static struct genl_ops team_nl_ops[] = {
+	{
+		.cmd = TEAM_CMD_NOOP,
+		.doit = team_nl_cmd_noop,
+		.policy = team_nl_policy,
+	},
+	{
+		.cmd = TEAM_CMD_OPTIONS_SET,
+		.doit = team_nl_cmd_options_set,
+		.policy = team_nl_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = TEAM_CMD_OPTIONS_GET,
+		.doit = team_nl_cmd_options_get,
+		.policy = team_nl_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = TEAM_CMD_PORT_LIST_GET,
+		.doit = team_nl_cmd_port_list_get,
+		.policy = team_nl_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+};
+
+static struct genl_multicast_group team_change_event_mcgrp = {
+	.name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME,
+};
+
+static int team_nl_send_event_options_get(struct team *team,
+					  struct team_option *changed_option)
+{
+	struct sk_buff *skb;
+	int err;
+	struct net *net = dev_net(team->dev);
+
+	skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	err = team_nl_fill_options_get_changed(skb, 0, 0, 0, team,
+					       changed_option);
+	if (err < 0)
+		goto err_fill;
+
+	err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
+				      GFP_KERNEL);
+	return err;
+
+err_fill:
+	nlmsg_free(skb);
+	return err;
+}
+
+static int team_nl_send_event_port_list_get(struct team_port *port)
+{
+	struct sk_buff *skb;
+	int err;
+	struct net *net = dev_net(port->team->dev);
+
+	skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	err = team_nl_fill_port_list_get_changed(skb, 0, 0, 0,
+						 port->team, port);
+	if (err < 0)
+		goto err_fill;
+
+	err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
+				      GFP_KERNEL);
+	return err;
+
+err_fill:
+	nlmsg_free(skb);
+	return err;
+}
+
+static int team_nl_init(void)
+{
+	int err;
+
+	err = genl_register_family_with_ops(&team_nl_family, team_nl_ops,
+					    ARRAY_SIZE(team_nl_ops));
+	if (err)
+		return err;
+
+	err = genl_register_mc_group(&team_nl_family, &team_change_event_mcgrp);
+	if (err)
+		goto err_change_event_grp_reg;
+
+	return 0;
+
+err_change_event_grp_reg:
+	genl_unregister_family(&team_nl_family);
+
+	return err;
+}
+
+static void team_nl_fini(void)
+{
+	genl_unregister_family(&team_nl_family);
+}
+
+
+/******************
+ * Change checkers
+ ******************/
+
+static void __team_options_change_check(struct team *team,
+					struct team_option *changed_option)
+{
+	int err;
+
+	err = team_nl_send_event_options_get(team, changed_option);
+	if (err)
+		netdev_warn(team->dev, "Failed to send options change via netlink\n");
+}
+
+/* rtnl lock is held */
+static void __team_port_change_check(struct team_port *port, bool linkup)
+{
+	int err;
+
+	if (port->linkup == linkup)
+		return;
+
+	port->linkup = linkup;
+	if (linkup) {
+		struct ethtool_cmd ecmd;
+
+		err = __ethtool_get_settings(port->dev, &ecmd);
+		if (!err) {
+			port->speed = ethtool_cmd_speed(&ecmd);
+			port->duplex = ecmd.duplex;
+			goto send_event;
+		}
+	}
+	port->speed = 0;
+	port->duplex = 0;
+
+send_event:
+	err = team_nl_send_event_port_list_get(port);
+	if (err)
+		netdev_warn(port->team->dev, "Failed to send port change of device %s via netlink\n",
+			    port->dev->name);
+
+}
+
+static void team_port_change_check(struct team_port *port, bool linkup)
+{
+	struct team *team = port->team;
+
+	spin_lock(&team->lock);
+	__team_port_change_check(port, linkup);
+	spin_unlock(&team->lock);
+}
+
+/************************************
+ * Net device notifier event handler
+ ************************************/
+
+static int team_device_event(struct notifier_block *unused,
+			     unsigned long event, void *ptr)
+{
+	struct net_device *dev = (struct net_device *) ptr;
+	struct team_port *port;
+
+	port = team_port_get_rtnl(dev);
+	if (!port)
+		return NOTIFY_DONE;
+
+	switch (event) {
+	case NETDEV_UP:
+		if (netif_carrier_ok(dev))
+			team_port_change_check(port, true);
+	case NETDEV_DOWN:
+		team_port_change_check(port, false);
+	case NETDEV_CHANGE:
+		if (netif_running(port->dev))
+			team_port_change_check(port,
+					       !!netif_carrier_ok(port->dev));
+		break;
+	case NETDEV_UNREGISTER:
+		team_del_slave(port->team->dev, dev);
+		break;
+	case NETDEV_FEAT_CHANGE:
+		team_compute_features(port->team);
+		break;
+	case NETDEV_CHANGEMTU:
+		/* Forbid to change mtu of underlaying device */
+		return NOTIFY_BAD;
+	case NETDEV_CHANGEADDR:
+		/* Forbid to change addr of underlaying device */
+		return NOTIFY_BAD;
+	case NETDEV_PRE_TYPE_CHANGE:
+		/* Forbid to change type of underlaying device */
+		return NOTIFY_BAD;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block team_notifier_block __read_mostly = {
+	.notifier_call = team_device_event,
+};
+
+
+/***********************
+ * Module init and exit
+ ***********************/
+
+static int __init team_module_init(void)
+{
+	int err;
+
+	register_netdevice_notifier(&team_notifier_block);
+
+	err = rtnl_link_register(&team_link_ops);
+	if (err)
+		goto err_rtnl_reg;
+
+	err = team_nl_init();
+	if (err)
+		goto err_nl_init;
+
+	return 0;
+
+err_nl_init:
+	rtnl_link_unregister(&team_link_ops);
+
+err_rtnl_reg:
+	unregister_netdevice_notifier(&team_notifier_block);
+
+	return err;
+}
+
+static void __exit team_module_exit(void)
+{
+	team_nl_fini();
+	rtnl_link_unregister(&team_link_ops);
+	unregister_netdevice_notifier(&team_notifier_block);
+}
+
+module_init(team_module_init);
+module_exit(team_module_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
+MODULE_DESCRIPTION("Ethernet team device driver");
+MODULE_ALIAS_RTNL_LINK(DRV_NAME);
diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c
new file mode 100644
index 0000000..1aa2bfb
--- /dev/null
+++ b/drivers/net/team/team_mode_activebackup.c
@@ -0,0 +1,152 @@
+/*
+ * net/drivers/team/team_mode_activebackup.c - Active-backup mode for team
+ * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <net/rtnetlink.h>
+#include <linux/if_team.h>
+
+struct ab_priv {
+	struct team_port __rcu *active_port;
+};
+
+static struct ab_priv *ab_priv(struct team *team)
+{
+	return (struct ab_priv *) &team->mode_priv;
+}
+
+static rx_handler_result_t ab_receive(struct team *team, struct team_port *port,
+				      struct sk_buff *skb) {
+	struct team_port *active_port;
+
+	active_port = rcu_dereference(ab_priv(team)->active_port);
+	if (active_port != port)
+		return RX_HANDLER_EXACT;
+	return RX_HANDLER_ANOTHER;
+}
+
+static bool ab_transmit(struct team *team, struct sk_buff *skb)
+{
+	struct team_port *active_port;
+
+	active_port = rcu_dereference(ab_priv(team)->active_port);
+	if (unlikely(!active_port))
+		goto drop;
+	skb->dev = active_port->dev;
+	if (dev_queue_xmit(skb))
+		return false;
+	return true;
+
+drop:
+	dev_kfree_skb(skb);
+	return false;
+}
+
+static void ab_port_leave(struct team *team, struct team_port *port)
+{
+	if (ab_priv(team)->active_port == port)
+		rcu_assign_pointer(ab_priv(team)->active_port, NULL);
+}
+
+static void ab_port_change_mac(struct team *team, struct team_port *port)
+{
+	if (ab_priv(team)->active_port == port)
+		team_port_set_team_mac(port);
+}
+
+static int ab_active_port_get(struct team *team, void *arg)
+{
+	u32 *ifindex = arg;
+
+	*ifindex = 0;
+	if (ab_priv(team)->active_port)
+		*ifindex = ab_priv(team)->active_port->dev->ifindex;
+	return 0;
+}
+
+static int ab_active_port_set(struct team *team, void *arg)
+{
+	u32 *ifindex = arg;
+	struct team_port *port;
+
+	list_for_each_entry_rcu(port, &team->port_list, list) {
+		if (port->dev->ifindex == *ifindex) {
+			struct team_port *ac_port = ab_priv(team)->active_port;
+
+			/* rtnl_lock needs to be held when setting macs */
+			rtnl_lock();
+			if (ac_port)
+				team_port_set_orig_mac(ac_port);
+			rcu_assign_pointer(ab_priv(team)->active_port, port);
+			team_port_set_team_mac(port);
+			rtnl_unlock();
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+static struct team_option ab_options[] = {
+	{
+		.name = "activeport",
+		.type = TEAM_OPTION_TYPE_U32,
+		.getter = ab_active_port_get,
+		.setter = ab_active_port_set,
+	},
+};
+
+int ab_init(struct team *team)
+{
+	team_options_register(team, ab_options, ARRAY_SIZE(ab_options));
+	return 0;
+}
+
+void ab_exit(struct team *team)
+{
+	team_options_unregister(team, ab_options, ARRAY_SIZE(ab_options));
+}
+
+static const struct team_mode_ops ab_mode_ops = {
+	.init			= ab_init,
+	.exit			= ab_exit,
+	.receive		= ab_receive,
+	.transmit		= ab_transmit,
+	.port_leave		= ab_port_leave,
+	.port_change_mac	= ab_port_change_mac,
+};
+
+static struct team_mode ab_mode = {
+	.kind		= "activebackup",
+	.owner		= THIS_MODULE,
+	.priv_size	= sizeof(struct ab_priv),
+	.ops		= &ab_mode_ops,
+};
+
+static int __init ab_init_module(void)
+{
+	return team_mode_register(&ab_mode);
+}
+
+static void __exit ab_cleanup_module(void)
+{
+	team_mode_unregister(&ab_mode);
+}
+
+module_init(ab_init_module);
+module_exit(ab_cleanup_module);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
+MODULE_DESCRIPTION("Active-backup mode for team");
+MODULE_ALIAS("team-mode-activebackup");
diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c
new file mode 100644
index 0000000..0374052
--- /dev/null
+++ b/drivers/net/team/team_mode_roundrobin.c
@@ -0,0 +1,107 @@
+/*
+ * net/drivers/team/team_mode_roundrobin.c - Round-robin mode for team
+ * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/if_team.h>
+
+struct rr_priv {
+	unsigned int sent_packets;
+};
+
+static struct rr_priv *rr_priv(struct team *team)
+{
+	return (struct rr_priv *) &team->mode_priv;
+}
+
+static struct team_port *__get_first_port_up(struct team *team,
+					     struct team_port *port)
+{
+	struct team_port *cur;
+
+	if (port->linkup)
+		return port;
+	cur = port;
+	list_for_each_entry_continue_rcu(cur, &team->port_list, list)
+		if (cur->linkup)
+			return cur;
+	list_for_each_entry_rcu(cur, &team->port_list, list) {
+		if (cur == port)
+			break;
+		if (cur->linkup)
+			return cur;
+	}
+	return NULL;
+}
+
+static bool rr_transmit(struct team *team, struct sk_buff *skb)
+{
+	struct team_port *port;
+	int port_index;
+
+	port_index = rr_priv(team)->sent_packets++ % team->port_count;
+	port = team_get_port_by_index_rcu(team, port_index);
+	port = __get_first_port_up(team, port);
+	if (unlikely(!port))
+		goto drop;
+	skb->dev = port->dev;
+	if (dev_queue_xmit(skb))
+		return false;
+	return true;
+
+drop:
+	dev_kfree_skb(skb);
+	return false;
+}
+
+static int rr_port_enter(struct team *team, struct team_port *port)
+{
+	return team_port_set_team_mac(port);
+}
+
+static void rr_port_change_mac(struct team *team, struct team_port *port)
+{
+	team_port_set_team_mac(port);
+}
+
+static const struct team_mode_ops rr_mode_ops = {
+	.transmit		= rr_transmit,
+	.port_enter		= rr_port_enter,
+	.port_change_mac	= rr_port_change_mac,
+};
+
+static struct team_mode rr_mode = {
+	.kind		= "roundrobin",
+	.owner		= THIS_MODULE,
+	.priv_size	= sizeof(struct rr_priv),
+	.ops		= &rr_mode_ops,
+};
+
+static int __init rr_init_module(void)
+{
+	return team_mode_register(&rr_mode);
+}
+
+static void __exit rr_cleanup_module(void)
+{
+	team_mode_unregister(&rr_mode);
+}
+
+module_init(rr_init_module);
+module_exit(rr_cleanup_module);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
+MODULE_DESCRIPTION("Round-robin mode for team");
+MODULE_ALIAS("team-mode-roundrobin");
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 619b565..0b091b3 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -185,6 +185,7 @@ header-y += if_pppol2tp.h
 header-y += if_pppox.h
 header-y += if_slip.h
 header-y += if_strip.h
+header-y += if_team.h
 header-y += if_tr.h
 header-y += if_tun.h
 header-y += if_tunnel.h
diff --git a/include/linux/if.h b/include/linux/if.h
index db20bd4..06b6ef6 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -79,6 +79,7 @@
 #define IFF_TX_SKB_SHARING	0x10000	/* The interface supports sharing
 					 * skbs on transmit */
 #define IFF_UNICAST_FLT	0x20000		/* Supports unicast filtering	*/
+#define IFF_TEAM_PORT	0x40000		/* device used as team port */
 
 #define IF_GET_IFACE	0x0001		/* for querying only */
 #define IF_GET_PROTO	0x0002
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
new file mode 100644
index 0000000..d133ac3
--- /dev/null
+++ b/include/linux/if_team.h
@@ -0,0 +1,231 @@
+/*
+ * include/linux/if_team.h - Network team device driver header
+ * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _LINUX_IF_TEAM_H_
+#define _LINUX_IF_TEAM_H_
+
+#ifdef __KERNEL__
+
+struct team_pcpu_stats {
+	u64			rx_packets;
+	u64			rx_bytes;
+	u64			rx_multicast;
+	u64			tx_packets;
+	u64			tx_bytes;
+	struct u64_stats_sync	syncp;
+	u32			rx_dropped;
+	u32			tx_dropped;
+};
+
+struct team;
+
+struct team_port {
+	struct net_device *dev;
+	struct hlist_node hlist; /* node in hash list */
+	struct list_head list; /* node in ordinary list */
+	struct team *team;
+	int index;
+
+	/*
+	 * A place for storing original values of the device before it
+	 * become a port.
+	 */
+	struct {
+		unsigned char dev_addr[MAX_ADDR_LEN];
+		unsigned int mtu;
+	} orig;
+
+	bool linkup;
+	u32 speed;
+	u8 duplex;
+
+	struct rcu_head rcu;
+};
+
+struct team_mode_ops {
+	int (*init)(struct team *team);
+	void (*exit)(struct team *team);
+	rx_handler_result_t (*receive)(struct team *team,
+				       struct team_port *port,
+				       struct sk_buff *skb);
+	bool (*transmit)(struct team *team, struct sk_buff *skb);
+	int (*port_enter)(struct team *team, struct team_port *port);
+	void (*port_leave)(struct team *team, struct team_port *port);
+	void (*port_change_mac)(struct team *team, struct team_port *port);
+};
+
+enum team_option_type {
+	TEAM_OPTION_TYPE_U32,
+	TEAM_OPTION_TYPE_STRING,
+};
+
+struct team_option {
+	struct list_head list;
+	const char *name;
+	enum team_option_type type;
+	int (*getter)(struct team *team, void *arg);
+	int (*setter)(struct team *team, void *arg);
+};
+
+struct team_mode {
+	struct list_head list;
+	const char *kind;
+	struct module *owner;
+	size_t priv_size;
+	const struct team_mode_ops *ops;
+};
+
+#define TEAM_PORT_HASHBITS 4
+#define TEAM_PORT_HASHENTRIES (1 << TEAM_PORT_HASHBITS)
+
+#define TEAM_MODE_PRIV_LONGS 4
+#define TEAM_MODE_PRIV_SIZE (sizeof(long) * TEAM_MODE_PRIV_LONGS)
+
+struct team {
+	struct net_device *dev; /* associated netdevice */
+	struct team_pcpu_stats __percpu *pcpu_stats;
+
+	spinlock_t lock; /* used for overall locking, e.g. port lists write */
+
+	/*
+	 * port lists with port count
+	 */
+	int port_count;
+	struct hlist_head port_hlist[TEAM_PORT_HASHENTRIES];
+	struct list_head port_list;
+
+	struct list_head option_list;
+
+	const char *mode_kind;
+	struct team_mode_ops mode_ops;
+	long mode_priv[TEAM_MODE_PRIV_LONGS];
+};
+
+static inline struct hlist_head *team_port_index_hash(struct team *team,
+						      int port_index)
+{
+	return &team->port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)];
+}
+
+static inline struct team_port *team_get_port_by_index_rcu(struct team *team,
+							   int port_index)
+{
+	struct hlist_node *p;
+	struct team_port *port;
+	struct hlist_head *head = team_port_index_hash(team, port_index);
+
+	hlist_for_each_entry_rcu(port, p, head, hlist)
+		if (port->index == port_index)
+			return port;
+	return NULL;
+}
+
+extern int team_port_set_orig_mac(struct team_port *port);
+extern int team_port_set_team_mac(struct team_port *port);
+extern void team_options_register(struct team *team,
+				  struct team_option *option,
+				  size_t option_count);
+extern void team_options_unregister(struct team *team,
+				    struct team_option *option,
+				    size_t option_count);
+extern int team_mode_register(struct team_mode *mode);
+extern int team_mode_unregister(struct team_mode *mode);
+
+#endif /* __KERNEL__ */
+
+#define TEAM_STRING_MAX_LEN 32
+
+/**********************************
+ * NETLINK_GENERIC netlink family.
+ **********************************/
+
+enum {
+	TEAM_CMD_NOOP,
+	TEAM_CMD_OPTIONS_SET,
+	TEAM_CMD_OPTIONS_GET,
+	TEAM_CMD_PORT_LIST_GET,
+
+	__TEAM_CMD_MAX,
+	TEAM_CMD_MAX = (__TEAM_CMD_MAX - 1),
+};
+
+enum {
+	TEAM_ATTR_UNSPEC,
+	TEAM_ATTR_TEAM_IFINDEX,		/* u32 */
+	TEAM_ATTR_LIST_OPTION,		/* nest */
+	TEAM_ATTR_LIST_PORT,		/* nest */
+
+	__TEAM_ATTR_MAX,
+	TEAM_ATTR_MAX = __TEAM_ATTR_MAX - 1,
+};
+
+/* Nested layout of get/set msg:
+ *
+ *	[TEAM_ATTR_LIST_OPTION]
+ *		[TEAM_ATTR_ITEM_OPTION]
+ *			[TEAM_ATTR_OPTION_*], ...
+ *		[TEAM_ATTR_ITEM_OPTION]
+ *			[TEAM_ATTR_OPTION_*], ...
+ *		...
+ *	[TEAM_ATTR_LIST_PORT]
+ *		[TEAM_ATTR_ITEM_PORT]
+ *			[TEAM_ATTR_PORT_*], ...
+ *		[TEAM_ATTR_ITEM_PORT]
+ *			[TEAM_ATTR_PORT_*], ...
+ *		...
+ */
+
+enum {
+	TEAM_ATTR_ITEM_OPTION_UNSPEC,
+	TEAM_ATTR_ITEM_OPTION,		/* nest */
+
+	__TEAM_ATTR_ITEM_OPTION_MAX,
+	TEAM_ATTR_ITEM_OPTION_MAX = __TEAM_ATTR_ITEM_OPTION_MAX - 1,
+};
+
+enum {
+	TEAM_ATTR_OPTION_UNSPEC,
+	TEAM_ATTR_OPTION_NAME,		/* string */
+	TEAM_ATTR_OPTION_CHANGED,	/* flag */
+	TEAM_ATTR_OPTION_TYPE,		/* u8 */
+	TEAM_ATTR_OPTION_DATA,		/* dynamic */
+
+	__TEAM_ATTR_OPTION_MAX,
+	TEAM_ATTR_OPTION_MAX = __TEAM_ATTR_OPTION_MAX - 1,
+};
+
+enum {
+	TEAM_ATTR_ITEM_PORT_UNSPEC,
+	TEAM_ATTR_ITEM_PORT,		/* nest */
+
+	__TEAM_ATTR_ITEM_PORT_MAX,
+	TEAM_ATTR_ITEM_PORT_MAX = __TEAM_ATTR_ITEM_PORT_MAX - 1,
+};
+
+enum {
+	TEAM_ATTR_PORT_UNSPEC,
+	TEAM_ATTR_PORT_IFINDEX,		/* u32 */
+	TEAM_ATTR_PORT_CHANGED,		/* flag */
+	TEAM_ATTR_PORT_LINKUP,		/* flag */
+	TEAM_ATTR_PORT_SPEED,		/* u32 */
+	TEAM_ATTR_PORT_DUPLEX,		/* u8 */
+
+	__TEAM_ATTR_PORT_MAX,
+	TEAM_ATTR_PORT_MAX = __TEAM_ATTR_PORT_MAX - 1,
+};
+
+/*
+ * NETLINK_GENERIC related info
+ */
+#define TEAM_GENL_NAME "team"
+#define TEAM_GENL_VERSION 0x1
+#define TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME "change_event"
+
+#endif /* _LINUX_IF_TEAM_H_ */
diff --git a/include/linux/rculist.h b/include/linux/rculist.h
index d079290..7586b2c 100644
--- a/include/linux/rculist.h
+++ b/include/linux/rculist.h
@@ -288,6 +288,20 @@ static inline void list_splice_init_rcu(struct list_head *list,
 	     pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
 
 /**
+ * list_for_each_entry_continue_reverse_rcu - iterate backwards from the given point
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse_rcu(pos, head, member)	\
+	for (pos = list_entry_rcu(pos->member.prev, typeof(*pos), member); \
+	     &pos->member != (head);	\
+	     pos = list_entry_rcu(pos->member.prev, typeof(*pos), member))
+
+/**
  * hlist_del_rcu - deletes entry from hash list without re-initialization
  * @n: the element to delete from the hash list.
  *
-- 
1.7.6

^ permalink raw reply related

* Re: DeviceTree and children devices
From: Felipe Balbi @ 2011-10-24  8:12 UTC (permalink / raw)
  To: Grant Likely; +Cc: balbi, Linux Kernel Mailing List, Linux USB Mailing List
In-Reply-To: <CACxGe6v0kHNyO81XapR=jGEa8ZgJrUxN2EEiqW7c18NdurGNkg@mail.gmail.com>

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

On Mon, Oct 24, 2011 at 09:58:39AM +0200, Grant Likely wrote:
> On Mon, Oct 24, 2011 at 9:49 AM, Felipe Balbi <balbi@ti.com> wrote:
> > On Mon, Oct 24, 2011 at 09:41:24AM +0200, Grant Likely wrote:
> >> On Mon, Oct 24, 2011 at 09:42:28AM +0300, Felipe Balbi wrote:
> >> > then I can drop the dwc3 platform_device allocation and all of that
> >> > resource copying, etc.
> >> >
> >> > What do you think ?
> >>
> >> Looks reasonable to me.  of_platform_populate() should be able to
> >> handle the device generation for you here.
> >
> > Ok cool I looking into that and it handles everything I need. There are
> > only three issues which I see:
> >
> > a) it hardcoded DMA mask to 32-bit. Right ?
> > b) it's not using dma_set_coherent_mask()
> > c) in case parent is a valid pointer, shouldn't it copy DMA mask from
> >        parent ?
> >
> > I mean (doesn't solve (a) above):
> >
> > diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> > index ed5a6d3..172d4a9 100644
> > --- a/drivers/of/platform.c
> > +++ b/drivers/of/platform.c
> > @@ -204,7 +204,12 @@ struct platform_device *of_platform_device_create_pdata(
> >  #if defined(CONFIG_MICROBLAZE)
> >        dev->archdata.dma_mask = 0xffffffffUL;
> >  #endif
> > -       dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
> > +
> > +       if (parent)
> > +               dma_set_coherent_mask(&dev->dev, parent->coherent_dma_mask);
> > +       else
> > +               dma_set_coherent_mask(&dev->dev, DMA_BIT_MASK(32));
> > +
> 
> Right, this does need to be fixed.  The existing code just matched
> what the historical powerpc code did, but it is certainly not correct.

should I send patch above correctly ? Or do you want to also solve
32-bit coherent mask altogether ? What are your plans for that ? Add a
separate property to pass coherent_mask size (32-bit, 64-bit, etc) ?

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [Qemu-devel] build with trace enabled is broken by the commit c572f23a3e7180dbeab5e86583e43ea2afed6271 hw/9pfs: Introduce tracing for 9p pdu handlers
From: Aneesh Kumar K.V @ 2011-10-24  8:11 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: Max Filippov, Harsh Prateek Bora, qemu-devel
In-Reply-To: <87wrbuud6y.fsf@linux.vnet.ibm.com>

On Mon, 24 Oct 2011 11:46:21 +0530, "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> wrote:
> On Sun, 23 Oct 2011 15:54:59 +0200, Jan Kiszka <jan.kiszka@web.de> wrote:
> > On 2011-10-21 17:10, Aneesh Kumar K.V wrote:
> > > On Thu, 20 Oct 2011 23:20:54 +0400, Max Filippov <jcmvbkbc@gmail.com> wrote:
> > >> Hi.
> > >>
> > >> Current git head build with trace enabled is broken by the commit c572f23a3e7180dbeab5e86583e43ea2afed6271 hw/9pfs: Introduce tracing for 9p pdu handlers.
> > >> Error messages:
> > >>
> > >> In file included from trace.c:2:0:
> > >> trace.h: In function ‘trace_v9fs_attach’:
> > >> trace.h:2850:9: error: too many arguments for format [-Werror=format-extra-args]
> > >> trace.h: In function ‘trace_v9fs_wstat’:
> > >> trace.h:3039:9: error: too many arguments for format [-Werror=format-extra-args]
> > >> trace.h: In function ‘trace_v9fs_mkdir’:
> > >> trace.h:3088:9: error: too many arguments for format [-Werror=format-extra-args]
> > >> trace.h: In function ‘trace_v9fs_mkdir_return’:
> > >> trace.h:3095:9: error: too many arguments for format [-Werror=format-extra-args]
> > >> cc1: all warnings being treated as errors
> > >>
> > >> Prototypes in the trace-events do not match format strings, e.g.
> > >>
> > >> v9fs_attach(uint16_t tag, uint8_t id, int32_t fid, int32_t afid, char* uname, char* aname) "tag %d id %d fid %d afid %d aname %s"
> > >>
> > >> The following patch fixes it, but I'm not sure the format lines are appropriate.
> > > 
> > > Can you send the patch with signed-off-by: I will add it in the next
> > > pull request.
> > 
> > There are more breakages with tracing enabled:
> > 
> >   CC    libhw64/9pfs/virtio-9p.o
> > cc1: warnings being treated as errors
> > /data/qemu/hw/9pfs/virtio-9p.c: In function ‘v9fs_create’:
> > /data/qemu/hw/9pfs/virtio-9p.c:2225:9: error: ‘iounit’ may be used uninitialized in this function                                                                                                                                            
> > /data/qemu/hw/9pfs/virtio-9p.c: In function ‘v9fs_readdir’:
> > /data/qemu/hw/9pfs/virtio-9p.c:2063:13: error: ‘count’ may be used uninitialized in this function                                                                                                                                            
> > /data/qemu/hw/9pfs/virtio-9p.c: In function ‘v9fs_xattrwalk’:
> > /data/qemu/hw/9pfs/virtio-9p.c:3103:13: error: ‘size’ may be used uninitialized in this function                                                                                                                                             
> > /data/qemu/hw/9pfs/virtio-9p.c: In function ‘v9fs_lcreate’:
> > /data/qemu/hw/9pfs/virtio-9p.c:1730:13: error: ‘iounit’ may be used uninitialized in this function                                                                                                                                           
> > /data/qemu/hw/9pfs/virtio-9p.c: In function ‘v9fs_open’:
> > /data/qemu/hw/9pfs/virtio-9p.c:1651:9: error: ‘iounit’ may be used uninitialized in this function                                                                                                                                            
> > 
> > Not sure what the undefined variables are supposed to contain for the
> > trace output, so I refrain from writing any patch.
> 
> Ok i am testing VirtFS tracing and will send a patch that should fix these
> issues. Sorry for all inconvenience. Even though i do test on
> three different distros, all of them were done without tracing enabled.

Can you try this patch. I will still like to get more testing tracing
all 9p operations and making sure python script is correct.

commit fe80ec13e59b581cba530e923e20df3fe9957177
Author: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Date:   Mon Oct 24 11:49:17 2011 +0530

    hw/9pfs: Make VirtTFS work correctly
    
    this patch fix multiple issues with VitFS tracing.
    a) Add tracepoint to the correct code path. We handle error in complete_pdu
    b) Fix indentation in python script
    c) Fix variable naming issue in python script
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index aab3beb..8b6813f 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -969,7 +969,7 @@ static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
         if (s->proto_version == V9FS_PROTO_2000L) {
             id = P9_RLERROR;
         }
-        trace_complete_pdu(pdu->tag, pdu->id, err); /* Trace ERROR */
+        trace_v9fs_rerror(pdu->tag, pdu->id, err); /* Trace ERROR */
     }
 
     /* fill out the header */
@@ -1332,11 +1332,11 @@ static void v9fs_attach(void *opaque)
     }
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
+    trace_v9fs_attach_return(pdu->tag, pdu->id,
+                             qid.type, qid.version, qid.path);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_attach_return(pdu->tag, pdu->id,
-                             qid.type, qid.version, qid.path);
     complete_pdu(s, pdu, err);
     v9fs_string_free(&uname);
     v9fs_string_free(&aname);
@@ -1371,13 +1371,12 @@ static void v9fs_stat(void *opaque)
     }
     offset += pdu_marshal(pdu, offset, "wS", 0, &v9stat);
     err = offset;
+    trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
+                           v9stat.atime, v9stat.mtime, v9stat.length);
     v9fs_stat_free(&v9stat);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
-                           v9stat.atime, v9stat.mtime, v9stat.length);
-
     complete_pdu(s, pdu, err);
 }
 
@@ -1421,13 +1420,12 @@ static void v9fs_getattr(void *opaque)
     }
     retval = offset;
     retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
-out:
-    put_fid(pdu, fidp);
-out_nofid:
     trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
                               v9stat_dotl.st_mode, v9stat_dotl.st_uid,
                               v9stat_dotl.st_gid);
-
+out:
+    put_fid(pdu, fidp);
+out_nofid:
     complete_pdu(s, pdu, retval);
 }
 
@@ -1605,6 +1603,7 @@ static void v9fs_walk(void *opaque)
         v9fs_path_copy(&newfidp->path, &path);
     }
     err = v9fs_walk_marshal(pdu, nwnames, qids);
+    trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
 out:
     put_fid(pdu, fidp);
     if (newfidp) {
@@ -1613,7 +1612,6 @@ out:
     v9fs_path_free(&dpath);
     v9fs_path_free(&path);
 out_nofid:
-    trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
     complete_pdu(s, pdu, err);
     if (nwnames && nwnames <= P9_MAXWELEM) {
         for (name_idx = 0; name_idx < nwnames; name_idx++) {
@@ -1648,10 +1646,10 @@ static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path)
 static void v9fs_open(void *opaque)
 {
     int flags;
-    int iounit;
     int32_t fid;
     int32_t mode;
     V9fsQID qid;
+    int iounit = 0;
     ssize_t err = 0;
     size_t offset = 7;
     struct stat stbuf;
@@ -1709,11 +1707,11 @@ static void v9fs_open(void *opaque)
         offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
         err = offset;
     }
+    trace_v9fs_open_return(pdu->tag, pdu->id,
+                           qid.type, qid.version, qid.path, iounit);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_open_return(pdu->tag, pdu->id,
-                           qid.type, qid.version, qid.path, iounit);
     complete_pdu(s, pdu, err);
 }
 
@@ -1759,11 +1757,11 @@ static void v9fs_lcreate(void *opaque)
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
     err = offset;
+    trace_v9fs_lcreate_return(pdu->tag, pdu->id,
+                              qid.type, qid.version, qid.path, iounit);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_lcreate_return(pdu->tag, pdu->id,
-                              qid.type, qid.version, qid.path, iounit);
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -1978,10 +1976,10 @@ static void v9fs_read(void *opaque)
     } else {
         err = -EINVAL;
     }
+    trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
     complete_pdu(s, pdu, err);
 }
 
@@ -2090,10 +2088,10 @@ static void v9fs_readdir(void *opaque)
     retval = offset;
     retval += pdu_marshal(pdu, offset, "d", count);
     retval += count;
+    trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
     complete_pdu(s, pdu, retval);
 }
 
@@ -2202,10 +2200,10 @@ static void v9fs_write(void *opaque)
     } while (total < count && len > 0);
     offset += pdu_marshal(pdu, offset, "d", total);
     err = offset;
+    trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
     complete_pdu(s, pdu, err);
 }
 
@@ -2362,11 +2360,11 @@ static void v9fs_create(void *opaque)
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
     err = offset;
+    trace_v9fs_create_return(pdu->tag, pdu->id,
+                             qid.type, qid.version, qid.path, iounit);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-   trace_v9fs_create_return(pdu->tag, pdu->id,
-                            qid.type, qid.version, qid.path, iounit);
    complete_pdu(pdu->s, pdu, err);
    v9fs_string_free(&name);
    v9fs_string_free(&extension);
@@ -2401,11 +2399,11 @@ static void v9fs_symlink(void *opaque)
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
+    trace_v9fs_symlink_return(pdu->tag, pdu->id,
+                              qid.type, qid.version, qid.path);
 out:
     put_fid(pdu, dfidp);
 out_nofid:
-    trace_v9fs_symlink_return(pdu->tag, pdu->id,
-                              qid.type, qid.version, qid.path);
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
     v9fs_string_free(&symname);
@@ -2950,10 +2948,11 @@ static void v9fs_mknod(void *opaque)
     stat_to_qid(&stbuf, &qid);
     err = offset;
     err += pdu_marshal(pdu, offset, "Q", &qid);
+    trace_v9fs_mknod_return(pdu->tag, pdu->id,
+                            qid.type, qid.version, qid.path);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_mknod_return(pdu->tag, pdu->id, qid.type, qid.version, qid.path);
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -3049,12 +3048,11 @@ static void v9fs_getlock(void *opaque)
                           glock->start, glock->length, glock->proc_id,
                           &glock->client_id);
     err = offset;
+    trace_v9fs_getlock_return(pdu->tag, pdu->id, glock->type, glock->start,
+                              glock->length, glock->proc_id);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_getlock_return(pdu->tag, pdu->id, glock->type, glock->start,
-                              glock->length, glock->proc_id);
-
     complete_pdu(s, pdu, err);
     v9fs_string_free(&glock->client_id);
     g_free(glock);
@@ -3089,11 +3087,11 @@ static void v9fs_mkdir(void *opaque)
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
+    trace_v9fs_mkdir_return(pdu->tag, pdu->id,
+                            qid.type, qid.version, qid.path, err);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_mkdir_return(pdu->tag, pdu->id,
-                            qid.type, qid.version, qid.path, err);
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -3183,13 +3181,13 @@ static void v9fs_xattrwalk(void *opaque)
         offset += pdu_marshal(pdu, offset, "q", size);
         err = offset;
     }
+    trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
 out:
     put_fid(pdu, file_fidp);
     if (xattr_fidp) {
         put_fid(pdu, xattr_fidp);
     }
 out_nofid:
-    trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -3260,11 +3258,11 @@ static void v9fs_readlink(void *opaque)
     }
     offset += pdu_marshal(pdu, offset, "s", &target);
     err = offset;
+    trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
     v9fs_string_free(&target);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
     complete_pdu(pdu->s, pdu, err);
 }
 
diff --git a/scripts/analyse-9p-simpletrace.py b/scripts/analyse-9p-simpletrace.py
index 4358d6b..5beec06 100755
--- a/scripts/analyse-9p-simpletrace.py
+++ b/scripts/analyse-9p-simpletrace.py
@@ -7,11 +7,11 @@
 import simpletrace
 
 class VirtFSRequestTracker(simpletrace.Analyzer):
-	def begin(self):
-		print "Pretty printing 9p simpletrace log ..."
+        def begin(self):
+                print "Pretty printing 9p simpletrace log ..."
 
-        def complete_pdu(self, tag, id, err):
-                print "ERROR (tag =", tag, ", id =", id, ",err =", err, ")"
+        def v9fs_rerror(self, tag, id, err):
+                print "RERROR (tag =", tag, ", id =", id, ",err =", err, ")"
 
         def v9fs_version(self, tag, id, msize, version):
                 print "TVERSION (tag =", tag, ", msize =", msize, ", version =", version, ")"
@@ -22,121 +22,121 @@ class VirtFSRequestTracker(simpletrace.Analyzer):
         def v9fs_attach(self, tag, id, fid, afid, uname, aname):
                 print "TATTACH (tag =", tag, ", fid =", fid, ", afid =", afid, ", uname =", uname, ", aname =", aname, ")"
 
-	def v9fs_attach_return(self, tag, id, type, verison, path):
-		print "RATTACH (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "})"
+        def v9fs_attach_return(self, tag, id, type, version, path):
+                print "RATTACH (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "})"
 
-	def v9fs_stat(self, tag, id, fid):
-		print "TSTAT (tag =", tag, ", fid =", fid, ")"
+        def v9fs_stat(self, tag, id, fid):
+                print "TSTAT (tag =", tag, ", fid =", fid, ")"
 
-	def v9fs_stat_return(self, tag, id, mode, atime, mtime, length):
-		print "RSTAT (tag =", tag, ", mode =", mode, ", atime =", atime, ", mtime =", mtime, ", length =", length, ")"
+        def v9fs_stat_return(self, tag, id, mode, atime, mtime, length):
+                print "RSTAT (tag =", tag, ", mode =", mode, ", atime =", atime, ", mtime =", mtime, ", length =", length, ")"
 
-	def v9fs_getattr(self, tag, id, fid, request_mask):
-		print "TGETATTR (tag =", tag, ", fid =", fid, ", request_mask =", hex(request_mask), ")"
+        def v9fs_getattr(self, tag, id, fid, request_mask):
+                print "TGETATTR (tag =", tag, ", fid =", fid, ", request_mask =", hex(request_mask), ")"
 
-	def v9fs_getattr_return(self, tag, id, result_mask, mode, uid, gid):
-		print "RGETATTR (tag =", tag, ", result_mask =", hex(result_mask), ", mode =", oct(mode), ", uid =", uid, ", gid =", gid, ")"
+        def v9fs_getattr_return(self, tag, id, result_mask, mode, uid, gid):
+                print "RGETATTR (tag =", tag, ", result_mask =", hex(result_mask), ", mode =", oct(mode), ", uid =", uid, ", gid =", gid, ")"
 
-	def v9fs_walk(self, tag, id, fid, newfid, nwnames):
-		print "TWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", nwnames =", nwnames, ")"
+        def v9fs_walk(self, tag, id, fid, newfid, nwnames):
+                print "TWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", nwnames =", nwnames, ")"
 
-	def v9fs_walk_return(self, tag, id, nwnames, qids):
-		print "RWALK (tag =", tag, ", nwnames =", nwnames, ", qids =", hex(qids), ")"
+        def v9fs_walk_return(self, tag, id, nwnames, qids):
+                print "RWALK (tag =", tag, ", nwnames =", nwnames, ", qids =", hex(qids), ")"
 
-	def v9fs_open(self, tag, id, fid, mode):
-		print "TOPEN (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ")"
+        def v9fs_open(self, tag, id, fid, mode):
+                print "TOPEN (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ")"
 
-	def v9fs_open_return(self, tag, id, type, version, path, iounit):
-		print "ROPEN (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
+        def v9fs_open_return(self, tag, id, type, version, path, iounit):
+                print "ROPEN (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
 
-	def v9fs_lcreate(self, tag, id, dfid, flags, mode, gid):
-		print "TLCREATE (tag =", tag, ", dfid =", dfid, ", flags =", oct(flags), ", mode =", oct(mode), ", gid =", gid, ")"
+        def v9fs_lcreate(self, tag, id, dfid, flags, mode, gid):
+                print "TLCREATE (tag =", tag, ", dfid =", dfid, ", flags =", oct(flags), ", mode =", oct(mode), ", gid =", gid, ")"
 
-	def v9fs_lcreate_return(self, id, type, version, path, iounit):
-		print "RLCREATE (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
+        def v9fs_lcreate_return(self, tag, id, type, version, path, iounit):
+                print "RLCREATE (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
 
-	def v9fs_fsync(self, tag, id, fid, datasync):
-		print "TFSYNC (tag =", tag, ", fid =", fid, ", datasync =", datasync, ")"
+        def v9fs_fsync(self, tag, id, fid, datasync):
+                print "TFSYNC (tag =", tag, ", fid =", fid, ", datasync =", datasync, ")"
 
-	def v9fs_clunk(self, tag, id, fid):
-		print "TCLUNK (tag =", tag, ", fid =", fid, ")"
+        def v9fs_clunk(self, tag, id, fid):
+                print "TCLUNK (tag =", tag, ", fid =", fid, ")"
 
-	def v9fs_read(self, tag, id, fid, off, max_count):
-		print "TREAD (tag =", tag, ", fid =", fid, ", off =", off, ", max_count =", max_count, ")"
+        def v9fs_read(self, tag, id, fid, off, max_count):
+                print "TREAD (tag =", tag, ", fid =", fid, ", off =", off, ", max_count =", max_count, ")"
 
-	def v9fs_read_return(self, tag, id, count, err):
-		print "RREAD (tag =", tag, ", count =", count, ", err =", err, ")"
+        def v9fs_read_return(self, tag, id, count, err):
+                print "RREAD (tag =", tag, ", count =", count, ", err =", err, ")"
 
-	def v9fs_readdir(self, tag, id, fid, offset, max_count):
-		print "TREADDIR (tag =", tag, ", fid =", fid, ", offset =", offset, ", max_count =", max_count, ")"
+        def v9fs_readdir(self, tag, id, fid, offset, max_count):
+                print "TREADDIR (tag =", tag, ", fid =", fid, ", offset =", offset, ", max_count =", max_count, ")"
 
-	def v9fs_readdir_return(self, tag, id, count, retval):
-		print "RREADDIR (tag =", tag, ", count =", count, ", retval =", retval, ")"
+        def v9fs_readdir_return(self, tag, id, count, retval):
+                print "RREADDIR (tag =", tag, ", count =", count, ", retval =", retval, ")"
 
-	def v9fs_write(self, tag, id, fid, off, count, cnt):
-		print "TWRITE (tag =", tag, ", fid =", fid, ", off =", off, ", count =", count, ", cnt =", cnt, ")"
+        def v9fs_write(self, tag, id, fid, off, count, cnt):
+                print "TWRITE (tag =", tag, ", fid =", fid, ", off =", off, ", count =", count, ", cnt =", cnt, ")"
 
-	def v9fs_write_return(self, tag, id, total, err):
-		print "RWRITE (tag =", tag, ", total =", total, ", err =", err, ")"
+        def v9fs_write_return(self, tag, id, total, err):
+                print "RWRITE (tag =", tag, ", total =", total, ", err =", err, ")"
 
-	def v9fs_create(self, tag, id, fid, perm, name, mode):
-		print "TCREATE (tag =", tag, ", fid =", fid, ", perm =", oct(perm), ", name =", name, ", mode =", oct(mode), ")"
+        def v9fs_create(self, tag, id, fid, name, perm, mode):
+                print "TCREATE (tag =", tag, ", fid =", fid, ", perm =", oct(perm), ", name =", name, ", mode =", oct(mode), ")"
 
-	def v9fs_create_return(self, tag, id, type, verison, path, iounit):
-		print "RCREATE (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
+        def v9fs_create_return(self, tag, id, type, verison, path, iounit):
+                print "RCREATE (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
 
-	def v9fs_symlink(self, tag, id, fid, name, symname, gid):
-		print "TSYMLINK (tag =", tag, ", fid =", fid, ", name =", name, ", symname =", symname, ", gid =", gid, ")"
+        def v9fs_symlink(self, tag, id, fid, name, symname, gid):
+                print "TSYMLINK (tag =", tag, ", fid =", fid, ", name =", name, ", symname =", symname, ", gid =", gid, ")"
 
-	def v9fs_symlink_return(self, tag, id, type, version, path):
-		print "RSYMLINK (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "})"
+        def v9fs_symlink_return(self, tag, id, type, version, path):
+                print "RSYMLINK (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "})"
 
-	def v9fs_flush(self, tag, id, flush_tag):
-		print "TFLUSH (tag =", tag, ", flush_tag =", flush_tag, ")"
+        def v9fs_flush(self, tag, id, flush_tag):
+                print "TFLUSH (tag =", tag, ", flush_tag =", flush_tag, ")"
 
-	def v9fs_link(self, tag, id, dfid, oldfid, name):
-		print "TLINK (tag =", tag, ", dfid =", dfid, ", oldfid =", oldfid, ", name =", name, ")"
+        def v9fs_link(self, tag, id, dfid, oldfid, name):
+                print "TLINK (tag =", tag, ", dfid =", dfid, ", oldfid =", oldfid, ", name =", name, ")"
 
-	def v9fs_remove(self, tag, id, fid):
-		print "TREMOVE (tag =", tag, ", fid =", fid, ")"
+        def v9fs_remove(self, tag, id, fid):
+                print "TREMOVE (tag =", tag, ", fid =", fid, ")"
 
-	def v9fs_wstat(self, tag, id, fid, mode, atime, mtime):
-		print "TWSTAT (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", atime =", atime, "mtime =", mtime, ")"
+        def v9fs_wstat(self, tag, id, fid, mode, atime, mtime):
+                print "TWSTAT (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", atime =", atime, "mtime =", mtime, ")"
 
-	def v9fs_mknod(self, tag, id, fid, mode, major, minor):
-		print "TMKNOD (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", major =", major, ", minor =", minor, ")"
+        def v9fs_mknod(self, tag, id, fid, mode, major, minor):
+                print "TMKNOD (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", major =", major, ", minor =", minor, ")"
 
-	def v9fs_lock(self, tag, id, fid, type, start, length):
-		print "TLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")"
+        def v9fs_lock(self, tag, id, fid, type, start, length):
+                print "TLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")"
 
-	def v9fs_lock_return(self, tag, id, status):
-		print "RLOCK (tag =", tag, ", status =", status, ")"
+        def v9fs_lock_return(self, tag, id, status):
+                print "RLOCK (tag =", tag, ", status =", status, ")"
 
-	def v9fs_getlock(self, tag, id, fid, type, start, length):
-		print "TGETLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")"
+        def v9fs_getlock(self, tag, id, fid, type, start, length):
+                print "TGETLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")"
 
-	def v9fs_getlock_return(self, tag, id, type, start, length, proc_id):
-		print "RGETLOCK (tag =", tag, "type =", type, ", start =", start, ", length =", length, ", proc_id =", proc_id,  ")"
+        def v9fs_getlock_return(self, tag, id, type, start, length, proc_id):
+                print "RGETLOCK (tag =", tag, "type =", type, ", start =", start, ", length =", length, ", proc_id =", proc_id,  ")"
 
-	def v9fs_mkdir(self, tag, id, fid, name, mode, gid):
-		print "TMKDIR (tag =", tag, ", fid =", fid, ", name =", name, ", mode =", mode, ", gid =", gid, ")"
+        def v9fs_mkdir(self, tag, id, fid, name, mode, gid):
+                print "TMKDIR (tag =", tag, ", fid =", fid, ", name =", name, ", mode =", mode, ", gid =", gid, ")"
 
-	def v9fs_mkdir_return(self, tag, id, type, version, path, err):
-		print "RMKDIR (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, err =", err, ")"
+        def v9fs_mkdir_return(self, tag, id, type, version, path, err):
+                print "RMKDIR (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, err =", err, ")"
 
-	def v9fs_xattrwalk(self, tag, id, fid, newfid, name):
-		print "TXATTRWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", xattr name =", name, ")"
+        def v9fs_xattrwalk(self, tag, id, fid, newfid, name):
+                print "TXATTRWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", xattr name =", name, ")"
 
-	def v9fs_xattrwalk_return(self, tag, id, size):
-		print "RXATTRWALK (tag =", tag, ", xattrsize  =", size, ")"
+        def v9fs_xattrwalk_return(self, tag, id, size):
+                print "RXATTRWALK (tag =", tag, ", xattrsize  =", size, ")"
 
-	def v9fs_xattrcreate(self, tag, id, fid, name, size, flags):
-		print "TXATTRCREATE (tag =", tag, ", fid =", fid, ", name =", name, ", xattrsize =", size, ", flags =", flags, ")"
+        def v9fs_xattrcreate(self, tag, id, fid, name, size, flags):
+                print "TXATTRCREATE (tag =", tag, ", fid =", fid, ", name =", name, ", xattrsize =", size, ", flags =", flags, ")"
 
-	def v9fs_readlink(self, tag, id, fid):
-		print "TREADLINK (tag =", tag, ", fid =", fid, ")"
+        def v9fs_readlink(self, tag, id, fid):
+                print "TREADLINK (tag =", tag, ", fid =", fid, ")"
 
-	def v9fs_readlink_return(self, tag, id, target):
-		print "RREADLINK (tag =", tag, ", target =", target, ")"
+        def v9fs_readlink_return(self, tag, id, target):
+                print "RREADLINK (tag =", tag, ", target =", target, ")"
 
 simpletrace.run(VirtFSRequestTracker())
diff --git a/trace-events b/trace-events
index 7f9cec4..0f0a6b0 100644
--- a/trace-events
+++ b/trace-events
@@ -554,7 +554,7 @@ open_eth_desc_read(uint32_t addr, uint32_t v) "DESC[%04x] -> %08x"
 open_eth_desc_write(uint32_t addr, uint32_t v) "DESC[%04x] <- %08x"
 
 # hw/9pfs/virtio-9p.c
-complete_pdu(uint16_t tag, uint8_t id, int err) "tag %d id %d err %d"
+v9fs_rerror(uint16_t tag, uint8_t id, int err) "tag %d id %d err %d"
 v9fs_version(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s"
 v9fs_version_return(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s"
 v9fs_attach(uint16_t tag, uint8_t id, int32_t fid, int32_t afid, char* uname, char* aname) "tag %u id %u fid %d afid %d uname %s aname %s"

^ permalink raw reply related

* Re: [PATCH meta-oe] memtester: Import from OE classic
From: Paul Menzel @ 2011-10-24  8:05 UTC (permalink / raw)
  To: openembedded-devel
In-Reply-To: <1319427652-9401-1-git-send-email-joelagnel@ti.com>

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

Koen,


could you please wait at least a day until merging the patches to get
time for proper review.


Am Sonntag, den 23.10.2011, 22:40 -0500 schrieb Joel A Fernandes:

Joel, when importing recipes please add the corresponding commit ID too
as required by the commit guide lines [1].

> Added LIC_FILES_CHKSUM
> 
> Signed-off-by: Joel A Fernandes <joelagnel@ti.com>
> ---
> This package is required by the beaglebone-tester
> 
>  .../memtester/files/Makefile.patch                 |   15 +++++++++++
>  .../recipes-benchmark/memtester/memtester_4.1.3.bb |   27 ++++++++++++++++++++
>  2 files changed, 42 insertions(+), 0 deletions(-)
>  create mode 100644 meta-oe/recipes-benchmark/memtester/files/Makefile.patch
>  create mode 100644 meta-oe/recipes-benchmark/memtester/memtester_4.1.3.bb
> 
> diff --git a/meta-oe/recipes-benchmark/memtester/files/Makefile.patch b/meta-oe/recipes-benchmark/memtester/files/Makefile.patch
> new file mode 100644
> index 0000000..57a0464
> --- /dev/null
> +++ b/meta-oe/recipes-benchmark/memtester/files/Makefile.patch

Please add a patch header.

> @@ -0,0 +1,15 @@
> +Index: memtester-4.0.5/Makefile
> +===================================================================
> +--- memtester-4.0.5.orig/Makefile	2005-03-14 06:02:30.000000000 -0800
> ++++ memtester-4.0.5/Makefile	2006-07-08 23:53:42.000000000 -0700
> +@@ -24,8 +24,8 @@
> + auto-ccld.sh: \
> + conf-cc conf-ld warn-auto.sh
> + 	( cat warn-auto.sh; \
> +-	echo CC=\'`head -1 conf-cc`\'; \
> +-	echo LD=\'`head -1 conf-ld`\' \
> ++	echo CC=\'`head -n 1 conf-cc`\'; \
> ++	echo LD=\'`head -n 1 conf-ld`\' \
> + 	) > auto-ccld.sh
> + 
> + compile: \
> diff --git a/meta-oe/recipes-benchmark/memtester/memtester_4.1.3.bb b/meta-oe/recipes-benchmark/memtester/memtester_4.1.3.bb
> new file mode 100644
> index 0000000..9f4e53e
> --- /dev/null
> +++ b/meta-oe/recipes-benchmark/memtester/memtester_4.1.3.bb
> @@ -0,0 +1,27 @@
> +SECTION = "console/utils"
> +DESCRIPTION = "Utility to test for faulty memory subsystem"
> +LICENSE = "GPLv2"

The ordering is wrong and the field `HOMEPAGE` is missing [3].

> +
> +LIC_FILES_CHKSUM = "file://COPYING;md5=0636e73ff0215e8d672dc4c32c317bb3"
> +
> +SRC_URI = "http://pyropus.ca/software/memtester/old-versions/memtester-${PV}.tar.gz"
> +SRC_URI += "file://Makefile.patch"
> +
> +SRC_URI[md5sum] = "e562451620cf5343016950462bc0dc38"
> +SRC_URI[sha256sum] = "ac56f0b6d6d6e58bcf2a3fa7f2c9b29894f5177871f21115a1906c535106acf6"
> +
> +S = "${WORKDIR}/memtester-${PV}"

This is the default.

> +
> +do_compile () {
> +	echo '${CC} ${CFLAGS} -DPOSIX -c' > conf-cc
> +	echo '${CC} ${LDFLAGS}' > conf-ld
> +	oe_runmake
> +}
> +
> +do_install () {
> +	install -d ${D}${bindir}
> +	install -d ${D}${mandir}/man8
> +	install -m 0755 memtester ${D}${bindir}/
> +	install -m 0755 memtester.8 ${D}${mandir}/man8/
> +}
> +

No empty line at the end is needed.

I fixed some of the above in OE classic. Please fix the issues mentioned
above in meta-oe with follow-up patches.


Thanks,

Paul


[1] http://www.openembedded.org/wiki/Commit_Patch_Message_Guidelines#Importing_from_Elsewhere
[2] http://git.openembedded.org/openembedded/tree/recipes/memtester?id=07e215db9870db1a0f88edb328024781eb9ac852
[3] http://wiki.openembedded.org/index.php/Styleguide

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 205 bytes --]

^ permalink raw reply

* Re: [linux-lvm] Changing dev_t-devname mapping in lvmlib seems to be problematic
From: Matecki, Lukas @ 2011-10-24  8:10 UTC (permalink / raw)
  To: LVM general discussion and development
In-Reply-To: <CAJJYPdkzu_SXGjuoUmfMVOA_UJhAFsnZWf8z41pfGUxJFMT6xA@mail.gmail.com>

Hallo List,

We are using LVM with SAN and multipathd. I try to setup mirroring with LVM. So I do pv create on a mpath device. vgcreate, add the pv to the vg, create a lv and setup a mirror with this:

lvconvert -m1 vg<name>/lv<name> /dev/mapper/mpath0 --mirrorlog core

My intention is to create a logical volume which can handle SAN Disk failure.

But in this shown setup i get a error (unavailable logical volume) when one of the san LUNS is missing.

Can this system work or did i need to setup a mdadm device before pvcreate ?

Hope you can help me because Redhat can't... them sitting two weeks on this error / miss configuration without any solution...

Greetings

Luke

^ permalink raw reply

* Re: [PATCH 1/3] ARM: Samsung: Move timer irq numbers to end of linux irq space
From: Kukjin Kim @ 2011-10-24  8:09 UTC (permalink / raw)
  To: Grant Likely
  Cc: Kukjin Kim, 'Changhwan Youn', 'Thomas Abraham',
	devicetree-discuss, linux-samsung-soc, linux-arm-kernel,
	rob.herring, patches, 'Nicolas Pitre'
In-Reply-To: <20111021194517.GA3722@ponder.secretlab.ca>


On 10/21/11 21:45, Grant Likely wrote:
> On Fri, Oct 21, 2011 at 06:56:52PM +0900, Kukjin Kim wrote:
>> Changhwan Youn wrote:
>>>
>>> Hi Thomas,
>>>
>>> All UART_IRQ_RXD, TXD, ERR of Samsung's platforms are also statically
>>> mapped to linux irq numbers 16 to 31. These interrupts also need proper
>> handling.
>>>
>>> Best regards,
>>> Changhwan Youn
>>>
>>
>> Hi all,
>>
>> Hmm, I'd like to apply Thomas' device tree series for EXYNOS4 and Samsung
>> stuff for upcoming merge window but there are still some comments on some
>> stuff and that should be fixed before applying. In addition I need to keep
>> the ordering to apply them to avoid conflicts. But as you know, v3.1 is now
>> close at hand and we don't have enough time for it now :(
>>
>> I will leave tomorrow morning (KST) for KS. I will talk to Grant Likely
>> about this in Prague :)
>
> One of the goals I have for the hacking summit is to get as much of
> the outstanding DT patches queued up and into linux-next.
>
OK.

I talked to Grant at ARM Subarch Workshop.

I will apply Thomas' DT patches into Samsung tree and it will be sent to 
upstream via arm-soc for upcoming merge window v3.2 and if any fixing is 
required, we will do it during -rc.

Thomas, if any problems during apply, let you know.

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply

* [PATCH 1/3] ARM: Samsung: Move timer irq numbers to end of linux irq space
From: Kukjin Kim @ 2011-10-24  8:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111021194517.GA3722@ponder.secretlab.ca>


On 10/21/11 21:45, Grant Likely wrote:
> On Fri, Oct 21, 2011 at 06:56:52PM +0900, Kukjin Kim wrote:
>> Changhwan Youn wrote:
>>>
>>> Hi Thomas,
>>>
>>> All UART_IRQ_RXD, TXD, ERR of Samsung's platforms are also statically
>>> mapped to linux irq numbers 16 to 31. These interrupts also need proper
>> handling.
>>>
>>> Best regards,
>>> Changhwan Youn
>>>
>>
>> Hi all,
>>
>> Hmm, I'd like to apply Thomas' device tree series for EXYNOS4 and Samsung
>> stuff for upcoming merge window but there are still some comments on some
>> stuff and that should be fixed before applying. In addition I need to keep
>> the ordering to apply them to avoid conflicts. But as you know, v3.1 is now
>> close at hand and we don't have enough time for it now :(
>>
>> I will leave tomorrow morning (KST) for KS. I will talk to Grant Likely
>> about this in Prague :)
>
> One of the goals I have for the hacking summit is to get as much of
> the outstanding DT patches queued up and into linux-next.
>
OK.

I talked to Grant at ARM Subarch Workshop.

I will apply Thomas' DT patches into Samsung tree and it will be sent to 
upstream via arm-soc for upcoming merge window v3.2 and if any fixing is 
required, we will do it during -rc.

Thomas, if any problems during apply, let you know.

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply

* Re: Linux 3.1-rc9
From: Martin Schwidefsky @ 2011-10-24  8:08 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Ingo Molnar, Simon Kirby, Peter Zijlstra,
	Linux Kernel Mailing List, Dave Jones, Thomas Gleixner
In-Reply-To: <CA+55aFyybeTZvzSU4L=hV1Y6+wXn2ZkuZF9R+vAj6MRVC+MmBQ@mail.gmail.com>

On Mon, 24 Oct 2011 09:51:09 +0200
Linus Torvalds <torvalds@linux-foundation.org> wrote:

> On Mon, Oct 24, 2011 at 9:48 AM, Martin Schwidefsky
> <schwidefsky@de.ibm.com> wrote:
> >
> > These types are still there because cputime_t can be u32 or u64. E.g. this
> >
> >  timer->expires.cpu = 0;
> >
> > will give the following sparse warning
> >
> >  kernel/posix-cpu-timers.c:463:46: warning: implicit cast to nocast type
> 
> Ok, we should probably special-case zero for that case too (we
> consider zero to be very special - it's not only the NULL pointer, but
> 0 is special for the bitwise types etc). So this is very arguably a
> sparse issue: casting zero is special.

Ok, cool. In that case I'll cook up a patch without cputime_t & cputime64_t
and put it on the cputime branch on git390.

-- 
blue skies,
   Martin.

"Reality continues to ruin my life." - Calvin.


^ permalink raw reply

* Re: [PATCH] mmc: mmci: Improve runtime PM support
From: Ulf Hansson @ 2011-10-24  8:05 UTC (permalink / raw)
  To: Sebastian Rasmussen, Russell King - ARM Linux
  Cc: linux-mmc@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	Lee Jones
In-Reply-To: <CAAgDR1OT=+xgQTNwmTz=9XwzpbhjeZ6F-mxnVGhOAPSAR3JiFQ@mail.gmail.com>

Sebastian Rasmussen wrote:
> Hi!
> 
>> Err, no.  You're not allowed to power down the card between commands
>> unless the card has been removed or been has finished with.
>>
>> If you power down the card (which you _are_ doing by writing zero to
>> the MMCIPOWER register), then you have to do a full setup of the card
>> when you resume.
> 
> MCIPower is according to ARM PL180 TRM signalling to an external power
> supply to turn on/off (MCIPWR), whether to use open-drain (MCIROD),
> what voltage to use (MCIVDD) and whether the card is clocked (MCICLK).
> 
> According ST-Ericsson's public PL180 derivative spec[1] it seems to work
> roughly in same way (but renaming the register SDI_PWR and the signals
> SDIPWR & SDICLK). However, there is no SDIVDD as the derivative can not
> signal desired voltage level externally (there are no bits in SDI_PWR for this).
> This makes it plausible that SDIPWR may not be routed externally either.
> Can you verify this as there are no signal routing diagrams in the spec..?
> 

The hole idea with this PM patch is to make sure the vcore regulator and 
the clock are disabled in runtime_suspend to be able to save a huge 
amount of current in "idle" mode.

Disabling the vcore regulator will sooner or later (depending on your 
regulator tree) mean that that power to the controller is actually cut, 
which then means that all registers will be "cleared" including the 
MCIPWR. So the actual reason for clearing the registers in the 
runtime_suspend function is because of two reasons.

1. Set the controller in a known state so no "magic" things happens when 
we are runtime suspended, for example getting an IRQ.

2. Save power by disabling the clock etc. The actual power to the 
controller does not have to be cut just because we have disabled the 
vore regulator.

If the ARM PL180 TRM prevent us from from doing this kind of operations 
in runtime_suspend, we must think of an alternative solution which just 
apply for ST-Ericssons derivative of PL180. THIS IS VERY IMPORTANT to be 
able to implement a proper power management solution.

Please check this Russell, this is VERY IMPORTANT!


> This leads me to believe that writing 0 to SDI_PWR/MMC in actual practice
> doesn't really do much but disabling the clock to the card (and for
> ST-Ericsson's PL180, disable direction signalling to the external level
> shifter). Clearing bit 8 of MCIClock/SDI_CLKCR also disables the clock.
> 
> I guess the patch would appeal more to Russell if mmci_runtime_suspend()
> only cleared MCIMask0/SDI_MASK0 and MCIClock/SDI_CLKCR and left
> MCIPower/SDI_PWR unchanged. It may be the case that the signal direction
> bits need to be cleared for the ST-Ericsson PL180, but I haven't yet verified
> this on my Snowball dev board yet.

This is according the comment above not feasible, since the vcore 
regulator to the controller is disabled all registers will be "cleared" 
anyway.

> 
>  / Sebastian
> 
> [1] http://www.stericsson.com/developers/DM00030004_AP9500_reference_manual_rev1.pdf
> 

BR
Ulf Hansson

^ permalink raw reply

* [PATCH] mmc: mmci: Improve runtime PM support
From: Ulf Hansson @ 2011-10-24  8:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAAgDR1OT=+xgQTNwmTz=9XwzpbhjeZ6F-mxnVGhOAPSAR3JiFQ@mail.gmail.com>

Sebastian Rasmussen wrote:
> Hi!
> 
>> Err, no.  You're not allowed to power down the card between commands
>> unless the card has been removed or been has finished with.
>>
>> If you power down the card (which you _are_ doing by writing zero to
>> the MMCIPOWER register), then you have to do a full setup of the card
>> when you resume.
> 
> MCIPower is according to ARM PL180 TRM signalling to an external power
> supply to turn on/off (MCIPWR), whether to use open-drain (MCIROD),
> what voltage to use (MCIVDD) and whether the card is clocked (MCICLK).
> 
> According ST-Ericsson's public PL180 derivative spec[1] it seems to work
> roughly in same way (but renaming the register SDI_PWR and the signals
> SDIPWR & SDICLK). However, there is no SDIVDD as the derivative can not
> signal desired voltage level externally (there are no bits in SDI_PWR for this).
> This makes it plausible that SDIPWR may not be routed externally either.
> Can you verify this as there are no signal routing diagrams in the spec..?
> 

The hole idea with this PM patch is to make sure the vcore regulator and 
the clock are disabled in runtime_suspend to be able to save a huge 
amount of current in "idle" mode.

Disabling the vcore regulator will sooner or later (depending on your 
regulator tree) mean that that power to the controller is actually cut, 
which then means that all registers will be "cleared" including the 
MCIPWR. So the actual reason for clearing the registers in the 
runtime_suspend function is because of two reasons.

1. Set the controller in a known state so no "magic" things happens when 
we are runtime suspended, for example getting an IRQ.

2. Save power by disabling the clock etc. The actual power to the 
controller does not have to be cut just because we have disabled the 
vore regulator.

If the ARM PL180 TRM prevent us from from doing this kind of operations 
in runtime_suspend, we must think of an alternative solution which just 
apply for ST-Ericssons derivative of PL180. THIS IS VERY IMPORTANT to be 
able to implement a proper power management solution.

Please check this Russell, this is VERY IMPORTANT!


> This leads me to believe that writing 0 to SDI_PWR/MMC in actual practice
> doesn't really do much but disabling the clock to the card (and for
> ST-Ericsson's PL180, disable direction signalling to the external level
> shifter). Clearing bit 8 of MCIClock/SDI_CLKCR also disables the clock.
> 
> I guess the patch would appeal more to Russell if mmci_runtime_suspend()
> only cleared MCIMask0/SDI_MASK0 and MCIClock/SDI_CLKCR and left
> MCIPower/SDI_PWR unchanged. It may be the case that the signal direction
> bits need to be cleared for the ST-Ericsson PL180, but I haven't yet verified
> this on my Snowball dev board yet.

This is according the comment above not feasible, since the vcore 
regulator to the controller is disabled all registers will be "cleared" 
anyway.

> 
>  / Sebastian
> 
> [1] http://www.stericsson.com/developers/DM00030004_AP9500_reference_manual_rev1.pdf
> 

BR
Ulf Hansson

^ permalink raw reply


This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.