Linux DSA Net Switch驱动开发

参考

Atheros QCA8337交换芯片驱动开发
Linux虚拟网络设备之bridge(桥)
phy 驱动与 switch 驱动
ALinux网桥的实现分析与使用
DSA switch configuration from userspace

源码分析

基于xilinx petalinux2015.2.1,kernel3.19,QCA8337驱动开发。
设备树初始化,关注dsa,mii-busdsa,ethernetreg三个节点,

//*\net\dsa\dsa.c line570
static int dsa_of_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct device_node *child, *mdio, *ethernet, *port, *link;
	struct mii_bus *mdio_bus;
	struct platform_device *ethernet_dev;
	struct dsa_platform_data *pd;
	struct dsa_chip_data *cd;
	const char *port_name;
	int chip_index, port_index;
	const unsigned int *sw_addr, *port_reg;
	u32 eeprom_len;
	int ret;

	mdio = of_parse_phandle(np, "dsa,mii-bus", 0);
	if (!mdio)
		return -EINVAL;

	mdio_bus = of_mdio_find_bus(mdio);
	if (!mdio_bus)
		return -EINVAL;

	ethernet = of_parse_phandle(np, "dsa,ethernet", 0);
	if (!ethernet)
		return -EINVAL;

	ethernet_dev = of_find_device_by_node(ethernet);
	if (!ethernet_dev)
		return -ENODEV;
...
	chip_index = -1;
	for_each_available_child_of_node(np, child) {
		chip_index++;
		cd = &pd->chip[chip_index];

		cd->of_node = child;
		cd->host_dev = &mdio_bus->dev;

		sw_addr = of_get_property(child, "reg", NULL);
		if (!sw_addr)
			continue;
...
}

设备初始化,

//*\net\dsa\dsa.c line702
static int dsa_probe(struct platform_device *pdev)
{
	struct dsa_platform_data *pd = pdev->dev.platform_data;
	struct net_device *dev;
	struct dsa_switch_tree *dst;
	int i, ret;
...
	if (pdev->dev.of_node) {
		ret = dsa_of_probe(pdev);
		if (ret)
			return ret;

		pd = pdev->dev.platform_data;
	}
...
	for (i = 0; i < pd->nr_chips; i++) {
		struct dsa_switch *ds;

		ds = dsa_switch_setup(dst, i, &pdev->dev, pd->chip[i].host_dev);
		if (IS_ERR(ds)) {
			netdev_err(dev, "[%d]: couldn't create dsa switch instance (error %ld)\n",
				   i, PTR_ERR(ds));
			continue;
		}

		dst->ds[i] = ds;
		if (ds->drv->poll_link != NULL)
			dst->link_poll_needed = 1;
	}
...
	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;

out:
	dsa_of_remove(pdev);

	return ret;
}

重点函数dsa_switch_setup,需要在*\net\dsa目录下添加qca的CONFIG_NET_DSA_TAG_QCA的实现,这一层实现的原因是,交换芯片会给接收和发送的包打上或者去除一个包头header,用来控制包转发packet forwardingdsa_switch_setup也调用了很多驱动的接口函数probesetupset_addr,实现这几个函数,则qca8377的驱动就开发出来了,

//*\net\dsa\dsa.c line178
static struct dsa_switch *
dsa_switch_setup(struct dsa_switch_tree *dst, int index,
		 struct device *parent, struct device *host_dev)
{
	struct dsa_chip_data *pd = dst->pd->chip + index;
	struct dsa_switch_driver *drv;
	struct dsa_switch *ds;
	int ret;
	char *name;
	int i;
	bool valid_name_found = false;
...
	drv = dsa_switch_probe(host_dev, pd->sw_addr, &name);
...
	for (i = 0; i < DSA_MAX_PORTS; i++) {
		char *name;

		name = pd->port_names[i];
		if (name == NULL)
			continue;

		if (!strcmp(name, "cpu")) {
			if (dst->cpu_switch != -1) {
				netdev_err(dst->master_netdev,
					   "multiple cpu ports?!\n");
				ret = -EINVAL;
				goto out;
			}
			dst->cpu_switch = index;
			dst->cpu_port = i;
		} else if (!strcmp(name, "dsa")) {
			ds->dsa_port_mask |= 1 << i;
		} else {
			ds->phys_port_mask |= 1 << i;
		}
		valid_name_found = true;
	}

	if (!valid_name_found && i == DSA_MAX_PORTS) {
		ret = -EINVAL;
		goto out;
	}

	/* Make the built-in MII bus mask match the number of ports,
	 * switch drivers can override this later
	 */
	ds->phys_mii_mask = ds->phys_port_mask;

	/*
	 * If the CPU connects to this switch, set the switch tree
	 * tagging protocol to the preferred tagging format of this
	 * switch.
	 */
	if (dst->cpu_switch == index) {
		switch (drv->tag_protocol) {
#ifdef CONFIG_NET_DSA_TAG_DSA
		case DSA_TAG_PROTO_DSA:
			dst->rcv = dsa_netdev_ops.rcv;
			break;
#endif
#ifdef CONFIG_NET_DSA_TAG_EDSA
		case DSA_TAG_PROTO_EDSA:
			dst->rcv = edsa_netdev_ops.rcv;
			break;
#endif
#ifdef CONFIG_NET_DSA_TAG_TRAILER
		case DSA_TAG_PROTO_TRAILER:
			dst->rcv = trailer_netdev_ops.rcv;
			break;
#endif
#ifdef CONFIG_NET_DSA_TAG_BRCM
		case DSA_TAG_PROTO_BRCM:
			dst->rcv = brcm_netdev_ops.rcv;
			break;
#endif
#ifdef CONFIG_NET_DSA_TAG_QCA /*add by xxx*/
		case DSA_TAG_PROTO_QCA:
			dst->rcv = qca_netdev_ops.rcv;
			break;
#endif
		case DSA_TAG_PROTO_NONE:
			break;
		default:
			ret = -ENOPROTOOPT;
			goto out;
		}

		dst->tag_protocol = drv->tag_protocol;
	}

	/*
	 * Do basic register setup.
	 */
	ret = drv->setup(ds);
	if (ret < 0)
		goto out;

	ret = drv->set_addr(ds, dst->master_netdev->dev_addr);
	if (ret < 0)
		goto out;

	ds->slave_mii_bus = mdiobus_alloc();
	if (ds->slave_mii_bus == NULL) {
		ret = -ENOMEM;
		goto out;
	}
	dsa_slave_mii_bus_init(ds);

	ret = mdiobus_register(ds->slave_mii_bus);
	if (ret < 0)
		goto out_free;


	/*
	 * Create network devices for physical switch ports.
	 */
	for (i = 0; i < DSA_MAX_PORTS; i++) {
		struct net_device *slave_dev;

		if (!(ds->phys_port_mask & (1 << i)))
			continue;

		slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]);
		if (slave_dev == NULL) {
			netdev_err(dst->master_netdev, "[%d]: can't create dsa slave device for port %d(%s)\n",
				   index, i, pd->port_names[i]);
			continue;
		}

		ds->ports[i] = slave_dev;
	}
...
}

dsa_slave_create函数,其中dsa_slave_phy_setup配置phy。

struct net_device *
dsa_slave_create(struct dsa_switch *ds, struct device *parent,
		 int port, char *name)
{
...
	ret = dsa_slave_phy_setup(p, slave_dev);
	if (ret) {
		free_netdev(slave_dev);
		return NULL;
	}

	ret = register_netdev(slave_dev);
	if (ret) {
		netdev_err(master, "error %d registering interface %s\n",
			   ret, slave_dev->name);
		phy_disconnect(p->phy);
		free_netdev(slave_dev);
		return NULL;
	}

	netif_carrier_off(slave_dev);

	if (p->phy != NULL) {
		if (ds->drv->get_phy_flags)
			p->phy->dev_flags |= ds->drv->get_phy_flags(ds, port);

		phy_attach(slave_dev, dev_name(&p->phy->dev),
			   PHY_INTERFACE_MODE_GMII);

		p->phy->autoneg = AUTONEG_ENABLE;
		p->phy->speed = 0;
		p->phy->duplex = 0;
		p->phy->advertising = p->phy->supported | ADVERTISED_Autoneg;
	}

	return slave_dev;
}

需要升级以下文件,

*/net/dsa/dsa.c
*/net/dsa/tag_qca.c
*/net/dsa/Kconfig
*/net/dsa/Makefile
*/include/net/dsa.h
*/drivers/net/dsa/qca8k.c
*/drivers/net/dsa/qca8k.h
*/drivers/net/dsa/Kconfig
*/drivers/net/dsa/Makefile

使用

Configuration with tagging support

The tagging based configuration is desired and supported by the majority of DSA switches. These switches are capable to tag incoming and outgoing traffic without using a VLAN based configuration.

single port

# configure each interface
ip addr add 192.0.2.1/30 dev lan1
ip addr add 192.0.2.5/30 dev lan2
ip addr add 192.0.2.9/30 dev lan3

# The master interface needs to be brought up before the slave ports.
ip link set eth0 up

# bring up the slave interfaces
ip link set lan1 up
ip link set lan2 up
ip link set lan3 up

bridge

# The master interface needs to be brought up before the slave ports.
ip link set eth0 up

# bring up the slave interfaces
ip link set lan1 up
ip link set lan2 up
ip link set lan3 up

# create bridge
ip link add name br0 type bridge

# add ports to bridge
ip link set dev lan1 master br0
ip link set dev lan2 master br0
ip link set dev lan3 master br0

# configure the bridge
ip addr add 192.0.2.129/25 dev br0

# bring up the bridge
ip link set dev br0 up

gateway

# The master interface needs to be brought up before the slave ports.
ip link set eth0 up

# bring up the slave interfaces
ip link set wan up
ip link set lan1 up
ip link set lan2 up

# configure the upstream port
ip addr add 192.0.2.1/30 dev wan

# create bridge
ip link add name br0 type bridge

# add ports to bridge
ip link set dev lan1 master br0
ip link set dev lan2 master br0

# configure the bridge
ip addr add 192.0.2.129/25 dev br0

# bring up the bridge
ip link set dev br0 up

Configuration without tagging support

A minority of switches are not capable to use a taging protocol (DSA_TAG_PROTO_NONE). These switches can be configured by a VLAN based configuration.

single port

The configuration can only be set up via VLAN tagging and bridge setup.

# tag traffic on CPU port
ip link add link eth0 name eth0.1 type vlan id 1
ip link add link eth0 name eth0.2 type vlan id 2
ip link add link eth0 name eth0.3 type vlan id 3

# The master interface needs to be brought up before the slave ports.
ip link set eth0 up
ip link set eth0.1 up
ip link set eth0.2 up
ip link set eth0.3 up

# bring up the slave interfaces
ip link set lan1 up
ip link set lan2 up
ip link set lan3 up

# create bridge
ip link add name br0 type bridge

# activate VLAN filtering
ip link set dev br0 type bridge vlan_filtering 1

# add ports to bridges
ip link set dev lan1 master br0
ip link set dev lan2 master br0
ip link set dev lan3 master br0

# tag traffic on ports
bridge vlan add dev lan1 vid 1 pvid untagged
bridge vlan add dev lan2 vid 2 pvid untagged
bridge vlan add dev lan3 vid 3 pvid untagged

# configure the VLANs
ip addr add 192.0.2.1/30 dev eth0.1
ip addr add 192.0.2.5/30 dev eth0.2
ip addr add 192.0.2.9/30 dev eth0.3

# bring up the bridge devices
ip link set br0 up

bridge

# tag traffic on CPU port
ip link add link eth0 name eth0.1 type vlan id 1

# The master interface needs to be brought up before the slave ports.
ip link set eth0 up
ip link set eth0.1 up

# bring up the slave interfaces
ip link set lan1 up
ip link set lan2 up
ip link set lan3 up

# create bridge
ip link add name br0 type bridge

# activate VLAN filtering
ip link set dev br0 type bridge vlan_filtering 1

# add ports to bridge
ip link set dev lan1 master br0
ip link set dev lan2 master br0
ip link set dev lan3 master br0
ip link set eth0.1 master br0

# tag traffic on ports
bridge vlan add dev lan1 vid 1 pvid untagged
bridge vlan add dev lan2 vid 1 pvid untagged
bridge vlan add dev lan3 vid 1 pvid untagged

# configure the bridge
ip addr add 192.0.2.129/25 dev br0

# bring up the bridge
ip link set dev br0 up

gateway

# tag traffic on CPU port
ip link add link eth0 name eth0.1 type vlan id 1
ip link add link eth0 name eth0.2 type vlan id 2

# The master interface needs to be brought up before the slave ports.
ip link set eth0 up
ip link set eth0.1 up
ip link set eth0.2 up

# bring up the slave interfaces
ip link set wan up
ip link set lan1 up
ip link set lan2 up

# create bridge
ip link add name br0 type bridge

# activate VLAN filtering
ip link set dev br0 type bridge vlan_filtering 1

# add ports to bridges
ip link set dev wan master br0
ip link set eth0.1 master br0
ip link set dev lan1 master br0
ip link set dev lan2 master br0

# tag traffic on ports
bridge vlan add dev lan1 vid 1 pvid untagged
bridge vlan add dev lan2 vid 1 pvid untagged
bridge vlan add dev wan vid 2 pvid untagged

# configure the VLANs
ip addr add 192.0.2.1/30 dev eth0.2
ip addr add 192.0.2.129/25 dev br0

# bring up the bridge devices
ip link set br0 up
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值