diff options
| author | Ingo Molnar <mingo@elte.hu> | 2009-03-30 23:53:32 +0200 | 
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-03-30 23:53:32 +0200 | 
| commit | 65fb0d23fcddd8697c871047b700c78817bdaa43 (patch) | |
| tree | 119e6e5f276622c4c862f6c9b6d795264ba1603a /net/dsa/dsa.c | |
| parent | 8c083f081d0014057901c68a0a3e0f8ca7ac8d23 (diff) | |
| parent | dfbbe89e197a77f2c8046a51c74e33e35f878080 (diff) | |
Merge branch 'linus' into cpumask-for-linus
Conflicts:
	arch/x86/kernel/cpu/common.c
Diffstat (limited to 'net/dsa/dsa.c')
| -rw-r--r-- | net/dsa/dsa.c | 177 | 
1 files changed, 109 insertions, 68 deletions
| diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 33e99462023..71489f69a42 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -1,6 +1,6 @@  /*   * net/dsa/dsa.c - Hardware switch handling - * Copyright (c) 2008 Marvell Semiconductor + * Copyright (c) 2008-2009 Marvell Semiconductor   *   * 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 @@ -67,12 +67,13 @@ dsa_switch_probe(struct mii_bus *bus, int sw_addr, char **_name)  /* basic switch operations **************************************************/  static struct dsa_switch * -dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd, -		 struct mii_bus *bus, struct net_device *dev) +dsa_switch_setup(struct dsa_switch_tree *dst, int index, +		 struct device *parent, struct mii_bus *bus)  { +	struct dsa_chip_data *pd = dst->pd->chip + index; +	struct dsa_switch_driver *drv;  	struct dsa_switch *ds;  	int ret; -	struct dsa_switch_driver *drv;  	char *name;  	int i; @@ -81,11 +82,12 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,  	 */  	drv = dsa_switch_probe(bus, pd->sw_addr, &name);  	if (drv == NULL) { -		printk(KERN_ERR "%s: could not detect attached switch\n", -		       dev->name); +		printk(KERN_ERR "%s[%d]: could not detect attached switch\n", +		       dst->master_netdev->name, index);  		return ERR_PTR(-EINVAL);  	} -	printk(KERN_INFO "%s: detected a %s switch\n", dev->name, name); +	printk(KERN_INFO "%s[%d]: detected a %s switch\n", +		dst->master_netdev->name, index, name);  	/* @@ -95,18 +97,16 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,  	if (ds == NULL)  		return ERR_PTR(-ENOMEM); -	ds->pd = pd; -	ds->master_netdev = dev; -	ds->master_mii_bus = bus; - +	ds->dst = dst; +	ds->index = index; +	ds->pd = dst->pd->chip + index;  	ds->drv = drv; -	ds->tag_protocol = drv->tag_protocol; +	ds->master_mii_bus = bus;  	/*  	 * Validate supplied switch configuration.  	 */ -	ds->cpu_port = -1;  	for (i = 0; i < DSA_MAX_PORTS; i++) {  		char *name; @@ -115,32 +115,28 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,  			continue;  		if (!strcmp(name, "cpu")) { -			if (ds->cpu_port != -1) { +			if (dst->cpu_switch != -1) {  				printk(KERN_ERR "multiple cpu ports?!\n");  				ret = -EINVAL;  				goto out;  			} -			ds->cpu_port = i; +			dst->cpu_switch = index; +			dst->cpu_port = i; +		} else if (!strcmp(name, "dsa")) { +			ds->dsa_port_mask |= 1 << i;  		} else { -			ds->valid_port_mask |= 1 << i; +			ds->phys_port_mask |= 1 << i;  		}  	} -	if (ds->cpu_port == -1) { -		printk(KERN_ERR "no cpu port?!\n"); -		ret = -EINVAL; -		goto out; -	} -  	/* -	 * If we use a tagging format that doesn't have an ethertype -	 * field, make sure that all packets from this point on get -	 * sent to the tag format's receive function.  (Which will -	 * discard received packets until we set ds->ports[] below.) +	 * If the CPU connects to this switch, set the switch tree +	 * tagging protocol to the preferred tagging format of this +	 * switch.  	 */ -	wmb(); -	dev->dsa_ptr = (void *)ds; +	if (ds->dst->cpu_switch == index) +		ds->dst->tag_protocol = drv->tag_protocol;  	/* @@ -150,7 +146,7 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,  	if (ret < 0)  		goto out; -	ret = drv->set_addr(ds, dev->dev_addr); +	ret = drv->set_addr(ds, dst->master_netdev->dev_addr);  	if (ret < 0)  		goto out; @@ -169,18 +165,18 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,  	/*  	 * Create network devices for physical switch ports.  	 */ -	wmb();  	for (i = 0; i < DSA_MAX_PORTS; i++) {  		struct net_device *slave_dev; -		if (!(ds->valid_port_mask & (1 << i))) +		if (!(ds->phys_port_mask & (1 << i)))  			continue;  		slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]);  		if (slave_dev == NULL) { -			printk(KERN_ERR "%s: can't create dsa slave " -			       "device for port %d(%s)\n", -			       dev->name, i, pd->port_names[i]); +			printk(KERN_ERR "%s[%d]: can't create dsa " +			       "slave device for port %d(%s)\n", +			       dst->master_netdev->name, +			       index, i, pd->port_names[i]);  			continue;  		} @@ -192,7 +188,6 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,  out_free:  	mdiobus_free(ds->slave_mii_bus);  out: -	dev->dsa_ptr = NULL;  	kfree(ds);  	return ERR_PTR(ret);  } @@ -212,35 +207,42 @@ static void dsa_switch_destroy(struct dsa_switch *ds)   */  bool dsa_uses_dsa_tags(void *dsa_ptr)  { -	struct dsa_switch *ds = dsa_ptr; +	struct dsa_switch_tree *dst = dsa_ptr; -	return !!(ds->tag_protocol == htons(ETH_P_DSA)); +	return !!(dst->tag_protocol == htons(ETH_P_DSA));  }  bool dsa_uses_trailer_tags(void *dsa_ptr)  { -	struct dsa_switch *ds = dsa_ptr; +	struct dsa_switch_tree *dst = dsa_ptr; -	return !!(ds->tag_protocol == htons(ETH_P_TRAILER)); +	return !!(dst->tag_protocol == htons(ETH_P_TRAILER));  }  /* link polling *************************************************************/  static void dsa_link_poll_work(struct work_struct *ugly)  { -	struct dsa_switch *ds; +	struct dsa_switch_tree *dst; +	int i; + +	dst = container_of(ugly, struct dsa_switch_tree, link_poll_work); -	ds = container_of(ugly, struct dsa_switch, link_poll_work); +	for (i = 0; i < dst->pd->nr_chips; i++) { +		struct dsa_switch *ds = dst->ds[i]; -	ds->drv->poll_link(ds); -	mod_timer(&ds->link_poll_timer, round_jiffies(jiffies + HZ)); +		if (ds != NULL && ds->drv->poll_link != NULL) +			ds->drv->poll_link(ds); +	} + +	mod_timer(&dst->link_poll_timer, round_jiffies(jiffies + HZ));  } -static void dsa_link_poll_timer(unsigned long _ds) +static void dsa_link_poll_timer(unsigned long _dst)  { -	struct dsa_switch *ds = (void *)_ds; +	struct dsa_switch_tree *dst = (void *)_dst; -	schedule_work(&ds->link_poll_work); +	schedule_work(&dst->link_poll_work);  } @@ -303,18 +305,14 @@ static int dsa_probe(struct platform_device *pdev)  	static int dsa_version_printed;  	struct dsa_platform_data *pd = pdev->dev.platform_data;  	struct net_device *dev; -	struct mii_bus *bus; -	struct dsa_switch *ds; +	struct dsa_switch_tree *dst; +	int i;  	if (!dsa_version_printed++)  		printk(KERN_NOTICE "Distributed Switch Architecture "  			"driver version %s\n", dsa_driver_version); -	if (pd == NULL || pd->mii_bus == NULL || pd->netdev == NULL) -		return -EINVAL; - -	bus = dev_to_mii_bus(pd->mii_bus); -	if (bus == NULL) +	if (pd == NULL || pd->netdev == NULL)  		return -EINVAL;  	dev = dev_to_net_device(pd->netdev); @@ -326,36 +324,79 @@ static int dsa_probe(struct platform_device *pdev)  		return -EEXIST;  	} -	ds = dsa_switch_setup(&pdev->dev, pd, bus, dev); -	if (IS_ERR(ds)) { +	dst = kzalloc(sizeof(*dst), GFP_KERNEL); +	if (dst == NULL) {  		dev_put(dev); -		return PTR_ERR(ds); +		return -ENOMEM;  	} -	if (ds->drv->poll_link != NULL) { -		INIT_WORK(&ds->link_poll_work, dsa_link_poll_work); -		init_timer(&ds->link_poll_timer); -		ds->link_poll_timer.data = (unsigned long)ds; -		ds->link_poll_timer.function = dsa_link_poll_timer; -		ds->link_poll_timer.expires = round_jiffies(jiffies + HZ); -		add_timer(&ds->link_poll_timer); +	platform_set_drvdata(pdev, dst); + +	dst->pd = pd; +	dst->master_netdev = dev; +	dst->cpu_switch = -1; +	dst->cpu_port = -1; + +	for (i = 0; i < pd->nr_chips; i++) { +		struct mii_bus *bus; +		struct dsa_switch *ds; + +		bus = dev_to_mii_bus(pd->chip[i].mii_bus); +		if (bus == NULL) { +			printk(KERN_ERR "%s[%d]: no mii bus found for " +				"dsa switch\n", dev->name, i); +			continue; +		} + +		ds = dsa_switch_setup(dst, i, &pdev->dev, bus); +		if (IS_ERR(ds)) { +			printk(KERN_ERR "%s[%d]: couldn't create dsa switch " +				"instance (error %ld)\n", dev->name, i, +				PTR_ERR(ds)); +			continue; +		} + +		dst->ds[i] = ds; +		if (ds->drv->poll_link != NULL) +			dst->link_poll_needed = 1;  	} -	platform_set_drvdata(pdev, ds); +	/* +	 * If we use a tagging format that doesn't have an ethertype +	 * field, make sure that all packets from this point on get +	 * sent to the tag format's receive function. +	 */ +	wmb(); +	dev->dsa_ptr = (void *)dst; + +	if (dst->link_poll_needed) { +		INIT_WORK(&dst->link_poll_work, dsa_link_poll_work); +		init_timer(&dst->link_poll_timer); +		dst->link_poll_timer.data = (unsigned long)dst; +		dst->link_poll_timer.function = dsa_link_poll_timer; +		dst->link_poll_timer.expires = round_jiffies(jiffies + HZ); +		add_timer(&dst->link_poll_timer); +	}  	return 0;  }  static int dsa_remove(struct platform_device *pdev)  { -	struct dsa_switch *ds = platform_get_drvdata(pdev); +	struct dsa_switch_tree *dst = platform_get_drvdata(pdev); +	int i; -	if (ds->drv->poll_link != NULL) -		del_timer_sync(&ds->link_poll_timer); +	if (dst->link_poll_needed) +		del_timer_sync(&dst->link_poll_timer);  	flush_scheduled_work(); -	dsa_switch_destroy(ds); +	for (i = 0; i < dst->pd->nr_chips; i++) { +		struct dsa_switch *ds = dst->ds[i]; + +		if (ds != NULL) +			dsa_switch_destroy(ds); +	}  	return 0;  } | 
