diff options
| author | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2009-04-29 13:02:41 +0000 | 
|---|---|---|
| committer | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2009-04-29 13:02:41 +0000 | 
| commit | 681d7f126b95ad5640be5c20a71fcebb4528f84e (patch) | |
| tree | bf2e5a40c9eed271312a72385141d249fe64d8f8 /target/linux/generic-2.6/files | |
| parent | fea7cd278b1331261f120b77e4491918fef97598 (diff) | |
Add a driver for Atheros AR8216 switches
Thanks to Vertical Communications, Inc. for providing access to the documentation
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@15482 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/generic-2.6/files')
| -rw-r--r-- | target/linux/generic-2.6/files/drivers/net/phy/ar8216.c | 528 | ||||
| -rw-r--r-- | target/linux/generic-2.6/files/drivers/net/phy/ar8216.h | 147 | 
2 files changed, 675 insertions, 0 deletions
| diff --git a/target/linux/generic-2.6/files/drivers/net/phy/ar8216.c b/target/linux/generic-2.6/files/drivers/net/phy/ar8216.c new file mode 100644 index 000000000..d83845c53 --- /dev/null +++ b/target/linux/generic-2.6/files/drivers/net/phy/ar8216.c @@ -0,0 +1,528 @@ +/* + * ar8216.c: AR8216 switch driver + * + * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/if.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/if_ether.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/netlink.h> +#include <linux/bitops.h> +#include <net/genetlink.h> +#include <linux/switch.h> +#include <linux/delay.h> +#include <linux/phy.h> +#include "ar8216.h" + +#define AR8216_REG_PORT_RATE(_i)	(AR8216_PORT_OFFSET(_i) + 0x000c) +#define AR8216_REG_PORT_PRIO(_i)	(AR8216_PORT_OFFSET(_i) + 0x0010) + +struct ar8216_priv { +	struct switch_dev dev; +	struct phy_device *phy; +	u32 (*read)(struct ar8216_priv *priv, int reg); +	void (*write)(struct ar8216_priv *priv, int reg, u32 val); +	/* all fields below are cleared on reset */ +	bool vlan; +	u8 vlan_id[AR8216_NUM_VLANS]; +	u8 vlan_table[AR8216_NUM_VLANS]; +	u8 vlan_tagged; +	u16 pvid[AR8216_NUM_PORTS]; +}; +static struct switch_dev athdev; + +#define to_ar8216(_dev) container_of(_dev, struct ar8216_priv, dev) + +static inline void +split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) +{ +	regaddr >>= 1; +	*r1 = regaddr & 0x1e; + +	regaddr >>= 5; +	*r2 = regaddr & 0x7; + +	regaddr >>= 3; +	*page = regaddr & 0x1ff; +} + +static u32 +ar8216_mii_read(struct ar8216_priv *priv, int reg) +{ +	struct phy_device *phy = priv->phy; +	u16 r1, r2, page; +	u16 lo, hi; + +	split_addr((u32) reg, &r1, &r2, &page); +	phy->bus->write(phy->bus, 0x18, 0, page); +	lo = phy->bus->read(phy->bus, 0x10 | r2, r1); +	hi = phy->bus->read(phy->bus, 0x10 | r2, r1 + 1); + +	return (hi << 16) | lo; +} + +static void +ar8216_mii_write(struct ar8216_priv *priv, int reg, u32 val) +{ +	struct phy_device *phy = priv->phy; +	u16 r1, r2, r3; +	u16 lo, hi; + +	split_addr((u32) reg, &r1, &r2, &r3); +	phy->bus->write(phy->bus, 0x18, 0, r3); + +	lo = val & 0xffff; +	hi = (u16) (val >> 16); +	phy->bus->write(phy->bus, 0x10 | r2, r1 + 1, hi); +	phy->bus->write(phy->bus, 0x10 | r2, r1, lo); +} + +static u32 +ar8216_rmw(struct ar8216_priv *priv, int reg, u32 mask, u32 val) +{ +	u32 v; + +	v = priv->read(priv, reg); +	v &= ~mask; +	v |= val; +	priv->write(priv, reg, v); + +	return v; +} + +static int +ar8216_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, +                struct switch_val *val) +{ +	struct ar8216_priv *priv = to_ar8216(dev); +	priv->vlan = !!val->value.i; +	return 0; +} + +static int +ar8216_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, +                struct switch_val *val) +{ +	struct ar8216_priv *priv = to_ar8216(dev); +	val->value.i = priv->vlan; +	return 0; +} + + +static int +ar8216_set_pvid(struct switch_dev *dev, int port, int vlan) +{ +	struct ar8216_priv *priv = to_ar8216(dev); +	priv->pvid[port] = vlan; +	return 0; +} + +static int +ar8216_get_pvid(struct switch_dev *dev, int port, int *vlan) +{ +	struct ar8216_priv *priv = to_ar8216(dev); +	*vlan = priv->pvid[port]; +	return 0; +} + +static int +ar8216_set_vid(struct switch_dev *dev, const struct switch_attr *attr, +                struct switch_val *val) +{ +	struct ar8216_priv *priv = to_ar8216(dev); +	priv->vlan_id[val->port_vlan] = val->value.i; +	return 0; +} + +static int +ar8216_get_vid(struct switch_dev *dev, const struct switch_attr *attr, +                struct switch_val *val) +{ +	struct ar8216_priv *priv = to_ar8216(dev); +	val->value.i = priv->vlan_id[val->port_vlan]; +	return 0; +} + + +static struct switch_attr ar8216_globals[] = { +	{ +		.type = SWITCH_TYPE_INT, +		.name = "vlan", +		.description = "Enable VLAN mode", +		.set = ar8216_set_vlan, +		.get = ar8216_get_vlan, +		.max = 1 +	}, +}; + +static struct switch_attr ar8216_port[] = { +}; + +static struct switch_attr ar8216_vlan[] = { +	{ +		.type = SWITCH_TYPE_INT, +		.name = "pvid", +		.description = "VLAN ID", +		.set = ar8216_set_vid, +		.get = ar8216_get_vid, +		.max = 4095, +	}, +}; + + +static int +ar8216_get_ports(struct switch_dev *dev, struct switch_val *val) +{ +	struct ar8216_priv *priv = to_ar8216(dev); +	u8 ports = priv->vlan_table[val->port_vlan]; +	int i; + +	val->len = 0; +	for (i = 0; i < AR8216_NUM_PORTS; i++) { +		struct switch_port *p; + +		if (!(ports & (1 << i))) +			continue; + +		p = &val->value.ports[val->len++]; +		p->id = i; +		if (priv->vlan_tagged & (1 << i)) +			p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); +		else +			p->flags = 0; +	} +	return 0; +} + +static int +ar8216_set_ports(struct switch_dev *dev, struct switch_val *val) +{ +	struct ar8216_priv *priv = to_ar8216(dev); +	u8 *vt = &priv->vlan_table[val->port_vlan]; +	int i, j; + +	*vt = 0; +	for (i = 0; i < val->len; i++) { +		struct switch_port *p = &val->value.ports[i]; + +		if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) +			priv->vlan_tagged |= (1 << p->id); +		else { +			priv->vlan_tagged &= ~(1 << p->id); +			priv->pvid[p->id] = val->port_vlan; + +			/* make sure that an untagged port does not +			 * appear in other vlans */ +			for (j = 0; j < AR8216_NUM_VLANS; j++) { +				if (j == val->port_vlan) +					continue; +				priv->vlan_table[j] &= ~(1 << p->id); +			} +		} + +		*vt |= 1 << p->id; +	} +	return 0; +} + +static int +ar8216_wait_bit(struct ar8216_priv *priv, int reg, u32 mask, u32 val) +{ +	int timeout = 20; + +	while ((priv->read(priv, reg) & mask) != val) { +		if (timeout-- <= 0) { +			printk(KERN_ERR "ar8216: timeout waiting for operation to complete\n"); +			return 1; +		} +	} +	return 0; +} + +static void +ar8216_vtu_op(struct ar8216_priv *priv, u32 op, u32 val) +{ +	if (ar8216_wait_bit(priv, AR8216_REG_VTU, AR8216_VTU_ACTIVE, 0)) +		return; +	if ((op & AR8216_VTU_OP) == AR8216_VTU_OP_LOAD) { +		val &= AR8216_VTUDATA_MEMBER; +		val |= AR8216_VTUDATA_VALID; +		priv->write(priv, AR8216_REG_VTU_DATA, val); +	} +	op |= AR8216_VTU_ACTIVE; +	priv->write(priv, AR8216_REG_VTU, op); +} + +static int +ar8216_hw_apply(struct switch_dev *dev) +{ +	struct ar8216_priv *priv = to_ar8216(dev); +	u8 portmask[AR8216_NUM_PORTS]; +	int i, j; + +	/* flush all vlan translation unit entries */ +	ar8216_vtu_op(priv, AR8216_VTU_OP_FLUSH, 0); + +	memset(portmask, 0, sizeof(portmask)); +	if (priv->vlan) { +		/* calculate the port destination masks and load vlans +		 * into the vlan translation unit */ +		for (j = 0; j < AR8216_NUM_VLANS; j++) { +			u8 vp = priv->vlan_table[j]; + +			if (!vp) +				continue; + +			for (i = 0; i < AR8216_NUM_PORTS; i++) { +				u8 mask = (1 << i); +				if (vp & mask) +					portmask[i] |= vp & ~mask; +			} + +			if (!priv->vlan_table[j]) +				continue; + +			ar8216_vtu_op(priv, +				AR8216_VTU_OP_LOAD | +				(priv->vlan_id[j] << AR8216_VTU_VID_S), +				priv->vlan_table[j]); +		} +	} else { +		/* vlan disabled: +		 * isolate all ports, but connect them to the cpu port */ +		for (i = 0; i < AR8216_NUM_PORTS; i++) { +			if (i == AR8216_PORT_CPU) +				continue; + +			portmask[i] = 1 << AR8216_PORT_CPU; +			portmask[AR8216_PORT_CPU] |= (1 << i); +		} +	} + +	/* update the port destination mask registers and tag settings */ +	for (i = 0; i < AR8216_NUM_PORTS; i++) { +		int egress, ingress; +		int pvid; + +		if (priv->vlan) { +			pvid = priv->vlan_id[priv->pvid[i]]; +		} else { +			pvid = i; +		} + +		if (priv->vlan && (priv->vlan_tagged & (1 << i))) { +			egress = AR8216_OUT_ADD_VLAN; +			ingress = AR8216_IN_PORT_FALLBACK; +		} else { +			egress = AR8216_OUT_STRIP_VLAN; +			ingress = AR8216_IN_SECURE; +		} + +		ar8216_rmw(priv, AR8216_REG_PORT_CTRL(i), +			AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE | +			AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE | +			AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK, +			AR8216_PORT_CTRL_LEARN | +			  (egress << AR8216_PORT_CTRL_VLAN_MODE_S) | +			  (priv->vlan ? AR8216_PORT_CTRL_SINGLE_VLAN : 0) | +			  (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S)); + +		ar8216_rmw(priv, AR8216_REG_PORT_VLAN(i), +			AR8216_PORT_VLAN_DEST_PORTS | AR8216_PORT_VLAN_MODE | +			  AR8216_PORT_VLAN_DEFAULT_ID, +			(portmask[i] << AR8216_PORT_VLAN_DEST_PORTS_S) | +			  (ingress << AR8216_PORT_VLAN_MODE_S) | +			  (pvid << AR8216_PORT_VLAN_DEFAULT_ID_S)); +	} + +	return 0; +} + +static int +ar8216_reset_switch(struct switch_dev *dev) +{ +	struct ar8216_priv *priv = to_ar8216(dev); +	int i; + +	memset(&priv->vlan, 0, sizeof(struct ar8216_priv) - +		offsetof(struct ar8216_priv, vlan)); +	for (i = 0; i < AR8216_NUM_VLANS; i++) { +		priv->vlan_id[i] = i; +	} +	for (i = 0; i < AR8216_NUM_PORTS; i++) { +		/* Enable port learning and tx */ +		priv->write(priv, AR8216_REG_PORT_CTRL(i), +			AR8216_PORT_CTRL_LEARN | +			(4 << AR8216_PORT_CTRL_STATE_S)); + +		priv->write(priv, AR8216_REG_PORT_VLAN(i), 0); + +		/* Configure all PHYs */ +		if (i == AR8216_PORT_CPU) { +			priv->write(priv, AR8216_REG_PORT_STATUS(i), +				AR8216_PORT_STATUS_LINK_UP | +				AR8216_PORT_STATUS_SPEED | +				AR8216_PORT_STATUS_TXMAC | +				AR8216_PORT_STATUS_RXMAC | +				AR8216_PORT_STATUS_DUPLEX); +		} else { +			priv->write(priv, AR8216_REG_PORT_STATUS(i), +				AR8216_PORT_STATUS_LINK_AUTO); +		} +	} +	/* XXX: undocumented magic from atheros, required! */ +	priv->write(priv, 0x38, 0xc000050e); +	return ar8216_hw_apply(dev); +} + +static int +ar8216_config_init(struct phy_device *pdev) +{ +	struct ar8216_priv *priv; +	int ret; + +	printk("%s: AR8216 PHY driver attached.\n", pdev->attached_dev->name); +	pdev->supported = ADVERTISED_100baseT_Full; +	pdev->advertising = ADVERTISED_100baseT_Full; + +	priv = kzalloc(sizeof(struct ar8216_priv), GFP_KERNEL); +	if (priv == NULL) +		return -ENOMEM; + +	priv->phy = pdev; +	priv->read = ar8216_mii_read; +	priv->write = ar8216_mii_write; +	memcpy(&priv->dev, &athdev, sizeof(struct switch_dev)); +	pdev->priv = priv; +	if ((ret = register_switch(&priv->dev, pdev->attached_dev)) < 0) { +		kfree(priv); +		goto done; +	} + +	ret = ar8216_reset_switch(&priv->dev); +done: +	return ret; +} + +static int +ar8216_read_status(struct phy_device *phydev) +{ +	struct ar8216_priv *priv = phydev->priv; + +	phydev->speed = SPEED_100; +	phydev->duplex = DUPLEX_FULL; +	phydev->state = PHY_UP; + +	/* flush the address translation unit */ +	if (ar8216_wait_bit(priv, AR8216_REG_ATU, AR8216_ATU_ACTIVE, 0)) +		return -ETIMEDOUT; + +	priv->write(priv, AR8216_REG_ATU, AR8216_ATU_OP_FLUSH); + +	return 0; +} + +static int +ar8216_config_aneg(struct phy_device *phydev) +{ +	return 0; +} + +static int +ar8216_probe(struct phy_device *pdev) +{ +	struct ar8216_priv priv; + +	u8 id, rev; +	u32 val; + +	priv.phy = pdev; +	val = ar8216_mii_read(&priv, AR8216_REG_CTRL); +	rev = val & 0xff; +	id = (val >> 8) & 0xff; +	if ((id != 1) || (rev != 1)) +		return -ENODEV; + +	return 0; +} + +static void +ar8216_remove(struct phy_device *pdev) +{ +	struct ar8216_priv *priv = pdev->priv; + +	if (!priv) +		return; + +	unregister_switch(&priv->dev); +	kfree(priv); +} + +/* template */ +static struct switch_dev athdev = { +	.name = "Atheros AR8216", +	.cpu_port = AR8216_PORT_CPU, +	.ports = AR8216_NUM_PORTS, +	.vlans = AR8216_NUM_VLANS, +	.attr_global = { +		.attr = ar8216_globals, +		.n_attr = ARRAY_SIZE(ar8216_globals), +	}, +	.attr_port = { +		.attr = ar8216_port, +		.n_attr = ARRAY_SIZE(ar8216_port), +	}, +	.attr_vlan = { +		.attr = ar8216_vlan, +		.n_attr = ARRAY_SIZE(ar8216_vlan), +	}, +	.get_port_pvid = ar8216_get_pvid, +	.set_port_pvid = ar8216_set_pvid, +	.get_vlan_ports = ar8216_get_ports, +	.set_vlan_ports = ar8216_set_ports, +	.apply_config = ar8216_hw_apply, +	.reset_switch = ar8216_reset_switch, +}; + +static struct phy_driver ar8216_driver = { +	.name		= "Atheros AR8216", +	.features	= PHY_BASIC_FEATURES, +	.probe		= ar8216_probe, +	.remove		= ar8216_remove, +	.config_init	= &ar8216_config_init, +	.config_aneg	= &ar8216_config_aneg, +	.read_status	= &ar8216_read_status, +	.driver		= { .owner = THIS_MODULE }, +}; + +int __init +ar8216_init(void) +{ +	return phy_driver_register(&ar8216_driver); +} + +void __exit +ar8216_exit(void) +{ +	phy_driver_unregister(&ar8216_driver); +} + +module_init(ar8216_init); +module_exit(ar8216_exit); +MODULE_LICENSE("GPL"); + diff --git a/target/linux/generic-2.6/files/drivers/net/phy/ar8216.h b/target/linux/generic-2.6/files/drivers/net/phy/ar8216.h new file mode 100644 index 000000000..a729ac442 --- /dev/null +++ b/target/linux/generic-2.6/files/drivers/net/phy/ar8216.h @@ -0,0 +1,147 @@ +/* + * ar8216.h: AR8216 switch driver + * + * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#ifndef __AR8216_H +#define __AR8216_H + +#define BITS(_s, _n)	(((1UL << (_n)) - 1) << _s) + +#define AR8216_PORT_CPU	0 +#define AR8216_NUM_PORTS	6 +#define AR8216_NUM_VLANS	16 + +#define AR8216_REG_CTRL			0x0000 +#define   AR8216_CTRL_RESET		BIT(31) + +#define AR8216_REG_VTU			0x0040 +#define   AR8216_VTU_OP			BITS(0, 3) +#define   AR8216_VTU_OP_NOOP		0x0 +#define   AR8216_VTU_OP_FLUSH		0x1 +#define   AR8216_VTU_OP_LOAD		0x2 +#define   AR8216_VTU_OP_PURGE		0x3 +#define   AR8216_VTU_OP_REMOVE_PORT	0x4 +#define   AR8216_VTU_ACTIVE		BIT(3) +#define   AR8216_VTU_FULL		BIT(4) +#define   AR8216_VTU_PORT		BITS(8, 4) +#define   AR8216_VTU_PORT_S		8 +#define   AR8216_VTU_VID		BITS(16, 12) +#define   AR8216_VTU_VID_S		16 +#define   AR8216_VTU_PRIO		BITS(28, 3) +#define   AR8216_VTU_PRIO_S		28 +#define   AR8216_VTU_PRIO_EN		BIT(31) + +#define AR8216_REG_VTU_DATA		0x0044 +#define   AR8216_VTUDATA_MEMBER		BITS(0, 10) +#define   AR8216_VTUDATA_VALID		BIT(11) + +#define AR8216_REG_ATU			0x0050 +#define   AR8216_ATU_OP			BITS(0, 3) +#define   AR8216_ATU_OP_NOOP		0x0 +#define   AR8216_ATU_OP_FLUSH		0x1 +#define   AR8216_ATU_OP_LOAD		0x2 +#define   AR8216_ATU_OP_PURGE		0x3 +#define   AR8216_ATU_OP_FLUSH_LOCKED	0x4 +#define   AR8216_ATU_OP_FLUSH_UNICAST	0x5 +#define   AR8216_ATU_OP_GET_NEXT	0x6 +#define   AR8216_ATU_ACTIVE		BIT(3) +#define   AR8216_ATU_PORT_NUM		BITS(8, 4) +#define   AR8216_ATU_FULL_VIO		BIT(12) +#define   AR8216_ATU_ADDR4		BIT(16, 8) +#define   AR8216_ATU_ADDR5		BIT(24, 8) + +#define AR8216_REG_ATU_DATA		0x0054 +#define   AR8216_ATU_ADDR3		BIT(0, 8) +#define   AR8216_ATU_ADDR2		BIT(8, 8) +#define   AR8216_ATU_ADDR1		BIT(16, 8) +#define   AR8216_ATU_ADDR0		BIT(24, 8) + +#define AR8216_PORT_OFFSET(_i)		(0x0100 * (i + 1)) +#define AR8216_REG_PORT_STATUS(_i)	(AR8216_PORT_OFFSET(_i) + 0x0000) +#define   AR8216_PORT_STATUS_SPEED	BIT(0) +#define   AR8216_PORT_STATUS_SPEED_ERR	BIT(1) +#define   AR8216_PORT_STATUS_TXMAC	BIT(2) +#define   AR8216_PORT_STATUS_RXMAC	BIT(3) +#define   AR8216_PORT_STATUS_TXFLOW	BIT(4) +#define   AR8216_PORT_STATUS_RXFLOW	BIT(5) +#define   AR8216_PORT_STATUS_DUPLEX	BIT(6) +#define   AR8216_PORT_STATUS_LINK_UP	BIT(8) +#define   AR8216_PORT_STATUS_LINK_AUTO	BIT(9) +#define   AR8216_PORT_STATUS_LINK_PAUSE	BIT(10) + +#define AR8216_REG_PORT_CTRL(_i)	(AR8216_PORT_OFFSET(_i) + 0x0004) + +/* port forwarding state */ +#define   AR8216_PORT_CTRL_STATE	BITS(0, 3) +#define   AR8216_PORT_CTRL_STATE_S	0 + +#define   AR8216_PORT_CTRL_LEARN_LOCK	BIT(7) + +/* egress 802.1q mode */ +#define   AR8216_PORT_CTRL_VLAN_MODE	BITS(8, 2) +#define   AR8216_PORT_CTRL_VLAN_MODE_S	8 + +#define   AR8216_PORT_CTRL_IGMP_SNOOP	BIT(10) +#define   AR8216_PORT_CTRL_HEADER	BIT(11) +#define   AR8216_PORT_CTRL_MAC_LOOP	BIT(12) +#define   AR8216_PORT_CTRL_SINGLE_VLAN	BIT(13) +#define   AR8216_PORT_CTRL_LEARN	BIT(14) +#define   AR8216_PORT_CTRL_MIRROR_TX	BIT(16) +#define   AR8216_PORT_CTRL_MIRROR_RX	BIT(17) + +#define AR8216_REG_PORT_VLAN(_i)	(AR8216_PORT_OFFSET(_i) + 0x0008) + +#define   AR8216_PORT_VLAN_DEFAULT_ID	BITS(0, 12) +#define   AR8216_PORT_VLAN_DEFAULT_ID_S	0 + +#define   AR8216_PORT_VLAN_DEST_PORTS	BITS(16, 9) +#define   AR8216_PORT_VLAN_DEST_PORTS_S	16 + +/* bit0 added to the priority field of egress frames */ +#define   AR8216_PORT_VLAN_TX_PRIO	BIT(27) + +/* port default priority */ +#define   AR8216_PORT_VLAN_PRIORITY	BITS(28, 2) +#define   AR8216_PORT_VLAN_PRIORITY_S	28 + +/* ingress 802.1q mode */ +#define   AR8216_PORT_VLAN_MODE		BITS(30, 2) +#define   AR8216_PORT_VLAN_MODE_S	30 + +/* ingress 802.1q mode */ +enum { +	AR8216_IN_PORT_ONLY = 0, +	AR8216_IN_PORT_FALLBACK = 1, +	AR8216_IN_VLAN_ONLY = 2, +	AR8216_IN_SECURE = 3 +}; + +/* egress 802.1q mode */ +enum { +	AR8216_OUT_KEEP = 0, +	AR8216_OUT_STRIP_VLAN = 1, +	AR8216_OUT_ADD_VLAN = 2 +}; + +/* port forwarding state */ +enum { +	AR8216_PORT_STATE_DISABLED = 0, +	AR8216_PORT_STATE_BLOCK = 1, +	AR8216_PORT_STATE_LISTEN = 2, +	AR8216_PORT_STATE_LEARN = 3, +	AR8216_PORT_STATE_FORWARD = 4 +}; + +#endif | 
