|
@@ -11,6 +11,7 @@
|
|
* GNU General Public License for more details.
|
|
* GNU General Public License for more details.
|
|
*
|
|
*
|
|
*/
|
|
*/
|
|
|
|
+#include <linux/dsa/lan9303.h>
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/list.h>
|
|
#include <linux/list.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
@@ -39,6 +40,23 @@
|
|
*/
|
|
*/
|
|
|
|
|
|
#define LAN9303_TAG_LEN 4
|
|
#define LAN9303_TAG_LEN 4
|
|
|
|
+# define LAN9303_TAG_TX_USE_ALR BIT(3)
|
|
|
|
+# define LAN9303_TAG_TX_STP_OVERRIDE BIT(4)
|
|
|
|
+#define eth_stp_addr eth_reserved_addr_base
|
|
|
|
+
|
|
|
|
+/* Decide whether to transmit using ALR lookup, or transmit directly to
|
|
|
|
+ * port using tag. ALR learning is performed only when using ALR lookup.
|
|
|
|
+ * If the two external ports are bridged and the packet is not STP BPDU,
|
|
|
|
+ * then use ALR lookup to allow ALR learning on CPU port.
|
|
|
|
+ * Otherwise transmit directly to port with STP state override.
|
|
|
|
+ * See also: lan9303_separate_ports() and lan9303.pdf 6.4.10.1
|
|
|
|
+ */
|
|
|
|
+static int lan9303_xmit_use_arl(struct dsa_port *dp, u8 *dest_addr)
|
|
|
|
+{
|
|
|
|
+ struct lan9303 *chip = dp->ds->priv;
|
|
|
|
+
|
|
|
|
+ return chip->is_bridged && !ether_addr_equal(dest_addr, eth_stp_addr);
|
|
|
|
+}
|
|
|
|
|
|
static struct sk_buff *lan9303_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
static struct sk_buff *lan9303_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
{
|
|
{
|
|
@@ -62,7 +80,10 @@ static struct sk_buff *lan9303_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
|
|
|
|
lan9303_tag = (u16 *)(skb->data + 2 * ETH_ALEN);
|
|
lan9303_tag = (u16 *)(skb->data + 2 * ETH_ALEN);
|
|
lan9303_tag[0] = htons(ETH_P_8021Q);
|
|
lan9303_tag[0] = htons(ETH_P_8021Q);
|
|
- lan9303_tag[1] = htons(dp->index | BIT(4));
|
|
|
|
|
|
+ lan9303_tag[1] = lan9303_xmit_use_arl(dp, skb->data) ?
|
|
|
|
+ LAN9303_TAG_TX_USE_ALR :
|
|
|
|
+ dp->index | LAN9303_TAG_TX_STP_OVERRIDE;
|
|
|
|
+ lan9303_tag[1] = htons(lan9303_tag[1]);
|
|
|
|
|
|
return skb;
|
|
return skb;
|
|
}
|
|
}
|