1a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller/* niu.c: Neptune ethernet driver.
2a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller *
3be0c007ac64f880a946995d6d1fc654acc81484dDavid S. Miller * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net)
4a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller */
5a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches
8a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/module.h>
9a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/init.h>
10a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h>
11a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/pci.h>
12a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/dma-mapping.h>
13a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/netdevice.h>
14a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/ethtool.h>
15a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/etherdevice.h>
16a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/platform_device.h>
17a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/delay.h>
18a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/bitops.h>
19a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/mii.h>
2001789349ee52e4a3faf376f1485303d9723c4f1fJiri Pirko#include <linux/if.h>
21a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/if_ether.h>
22a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/if_vlan.h>
23a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/ip.h>
24a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/in.h>
25a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/ipv6.h>
26a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/log2.h>
27a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/jiffies.h>
28a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/crc32.h>
29ccffad25b5136958d4769ed6de5e87992dd9c65cJiri Pirko#include <linux/list.h>
305a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
31a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
32a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/io.h>
33a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include <linux/of_device.h>
34a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
35a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#include "niu.h"
36a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
37a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define DRV_MODULE_NAME		"niu"
383cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller#define DRV_MODULE_VERSION	"1.1"
393cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller#define DRV_MODULE_RELDATE	"Apr 22, 2010"
40a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
41a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic char version[] __devinitdata =
42a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
43a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
44a3138df9f20e726c517f8df7387b5d83f5df5566David S. MillerMODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
45a3138df9f20e726c517f8df7387b5d83f5df5566David S. MillerMODULE_DESCRIPTION("NIU ethernet driver");
46a3138df9f20e726c517f8df7387b5d83f5df5566David S. MillerMODULE_LICENSE("GPL");
47a3138df9f20e726c517f8df7387b5d83f5df5566David S. MillerMODULE_VERSION(DRV_MODULE_VERSION);
48a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
49a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#ifndef readq
50a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic u64 readq(void __iomem *reg)
51a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
52e23a59e1ca6d177a57a7791b3629db93ff1d9813David S. Miller	return ((u64) readl(reg)) | (((u64) readl(reg + 4UL)) << 32);
53a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
54a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
55a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void writeq(u64 val, void __iomem *reg)
56a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
57a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	writel(val & 0xffffffff, reg);
58a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	writel(val >> 32, reg + 0x4UL);
59a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
60a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif
61a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
62a3aa18842a5303fc28fcc4d57dbd16618bd830a0Alexey Dobriyanstatic DEFINE_PCI_DEVICE_TABLE(niu_pci_tbl) = {
63a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{PCI_DEVICE(PCI_VENDOR_ID_SUN, 0xabcd)},
64a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{}
65a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
66a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
67a3138df9f20e726c517f8df7387b5d83f5df5566David S. MillerMODULE_DEVICE_TABLE(pci, niu_pci_tbl);
68a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
69a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define NIU_TX_TIMEOUT			(5 * HZ)
70a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
71a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define nr64(reg)		readq(np->regs + (reg))
72a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define nw64(reg, val)		writeq((val), np->regs + (reg))
73a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
74a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define nr64_mac(reg)		readq(np->mac_regs + (reg))
75a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define nw64_mac(reg, val)	writeq((val), np->mac_regs + (reg))
76a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
77a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define nr64_ipp(reg)		readq(np->regs + np->ipp_off + (reg))
78a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define nw64_ipp(reg, val)	writeq((val), np->regs + np->ipp_off + (reg))
79a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
80a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define nr64_pcs(reg)		readq(np->regs + np->pcs_off + (reg))
81a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define nw64_pcs(reg, val)	writeq((val), np->regs + np->pcs_off + (reg))
82a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
83a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define nr64_xpcs(reg)		readq(np->regs + np->xpcs_off + (reg))
84a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define nw64_xpcs(reg, val)	writeq((val), np->regs + np->xpcs_off + (reg))
85a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
86a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define NIU_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
87a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
88a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_debug;
89a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int debug = -1;
90a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millermodule_param(debug, int, 0);
91a3138df9f20e726c517f8df7387b5d83f5df5566David S. MillerMODULE_PARM_DESC(debug, "NIU debug level");
92a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
93a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define niu_lock_parent(np, flags) \
94a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_lock_irqsave(&np->parent->lock, flags)
95a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define niu_unlock_parent(np, flags) \
96a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_unlock_irqrestore(&np->parent->lock, flags)
97a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
985fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Workustatic int serdes_init_10g_serdes(struct niu *np);
995fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
100a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __niu_wait_bits_clear_mac(struct niu *np, unsigned long reg,
101a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				     u64 bits, int limit, int delay)
102a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
103a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (--limit >= 0) {
104a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u64 val = nr64_mac(reg);
105a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
106a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!(val & bits))
107a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
108a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		udelay(delay);
109a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
110a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (limit < 0)
111a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
112a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
113a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
114a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
115a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __niu_set_and_wait_clear_mac(struct niu *np, unsigned long reg,
116a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					u64 bits, int limit, int delay,
117a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					const char *reg_name)
118a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
119a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
120a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
121a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(reg, bits);
122a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = __niu_wait_bits_clear_mac(np, reg, bits, limit, delay);
123a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
124f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "bits (%llx) of register %s would not clear, val[%llx]\n",
125f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   (unsigned long long)bits, reg_name,
126f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   (unsigned long long)nr64_mac(reg));
127a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
128a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
129a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
130a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define niu_set_and_wait_clear_mac(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \
131a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller({	BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
132a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	__niu_set_and_wait_clear_mac(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \
133a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller})
134a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
135a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __niu_wait_bits_clear_ipp(struct niu *np, unsigned long reg,
136a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				     u64 bits, int limit, int delay)
137a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
138a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (--limit >= 0) {
139a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u64 val = nr64_ipp(reg);
140a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
141a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!(val & bits))
142a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
143a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		udelay(delay);
144a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
145a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (limit < 0)
146a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
147a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
148a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
149a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
150a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __niu_set_and_wait_clear_ipp(struct niu *np, unsigned long reg,
151a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					u64 bits, int limit, int delay,
152a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					const char *reg_name)
153a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
154a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
155a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
156a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
157a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_ipp(reg);
158a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= bits;
159a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_ipp(reg, val);
160a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
161a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = __niu_wait_bits_clear_ipp(np, reg, bits, limit, delay);
162a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
163f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "bits (%llx) of register %s would not clear, val[%llx]\n",
164f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   (unsigned long long)bits, reg_name,
165f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   (unsigned long long)nr64_ipp(reg));
166a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
167a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
168a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
169a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define niu_set_and_wait_clear_ipp(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \
170a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller({	BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
171a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	__niu_set_and_wait_clear_ipp(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \
172a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller})
173a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
174a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __niu_wait_bits_clear(struct niu *np, unsigned long reg,
175a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 u64 bits, int limit, int delay)
176a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
177a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (--limit >= 0) {
178a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u64 val = nr64(reg);
179a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
180a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!(val & bits))
181a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
182a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		udelay(delay);
183a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
184a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (limit < 0)
185a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
186a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
187a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
188a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
189a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define niu_wait_bits_clear(NP, REG, BITS, LIMIT, DELAY) \
190a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller({	BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
191a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	__niu_wait_bits_clear(NP, REG, BITS, LIMIT, DELAY); \
192a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller})
193a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
194a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __niu_set_and_wait_clear(struct niu *np, unsigned long reg,
195a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    u64 bits, int limit, int delay,
196a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    const char *reg_name)
197a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
198a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
199a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
200a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(reg, bits);
201a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = __niu_wait_bits_clear(np, reg, bits, limit, delay);
202a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
203f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "bits (%llx) of register %s would not clear, val[%llx]\n",
204f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   (unsigned long long)bits, reg_name,
205f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   (unsigned long long)nr64(reg));
206a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
207a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
208a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
209a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define niu_set_and_wait_clear(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \
210a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller({	BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
211a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	__niu_set_and_wait_clear(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \
212a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller})
213a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
214a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_ldg_rearm(struct niu *np, struct niu_ldg *lp, int on)
215a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
216a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = (u64) lp->timer;
217a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
218a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on)
219a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= LDG_IMGMT_ARM;
220a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
221a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(LDG_IMGMT(lp->ldg_num), val);
222a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
223a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
224a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_ldn_irq_enable(struct niu *np, int ldn, int on)
225a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
226a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long mask_reg, bits;
227a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
228a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
229a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (ldn < 0 || ldn > LDN_MAX)
230a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
231a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
232a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (ldn < 64) {
233a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mask_reg = LD_IM0(ldn);
234a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		bits = LD_IM0_MASK;
235a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
236a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mask_reg = LD_IM1(ldn - 64);
237a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		bits = LD_IM1_MASK;
238a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
239a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
240a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(mask_reg);
241a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on)
242a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~bits;
243a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
244a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= bits;
245a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(mask_reg, val);
246a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
247a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
248a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
249a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
250a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_enable_ldn_in_ldg(struct niu *np, struct niu_ldg *lp, int on)
251a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
252a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent = np->parent;
253a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
254a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
255a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i <= LDN_MAX; i++) {
256a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int err;
257a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
258a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (parent->ldg_map[i] != lp->ldg_num)
259a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			continue;
260a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
261a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_ldn_irq_enable(np, i, on);
262a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
263a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
264a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
265a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
266a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
267a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
268a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_enable_interrupts(struct niu *np, int on)
269a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
270a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
271a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
272a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_ldg; i++) {
273a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct niu_ldg *lp = &np->ldg[i];
274a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int err;
275a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
276a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_enable_ldn_in_ldg(np, lp, on);
277a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
278a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
279a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
280a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_ldg; i++)
281a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_ldg_rearm(np, &np->ldg[i], on);
282a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
283a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
284a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
285a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
286a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic u32 phy_encode(u32 type, int port)
287a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
288807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet	return type << (port * 2);
289a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
290a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
291a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic u32 phy_decode(u32 val, int port)
292a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
293a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return (val >> (port * 2)) & PORT_TYPE_MASK;
294a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
295a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
296a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int mdio_wait(struct niu *np)
297a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
298a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int limit = 1000;
299a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
300a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
301a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (--limit > 0) {
302a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val = nr64(MIF_FRAME_OUTPUT);
303a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if ((val >> MIF_FRAME_OUTPUT_TA_SHIFT) & 0x1)
304a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return val & MIF_FRAME_OUTPUT_DATA;
305a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
306a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		udelay(10);
307a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
308a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
309a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return -ENODEV;
310a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
311a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
312a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int mdio_read(struct niu *np, int port, int dev, int reg)
313a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
314a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
315a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
316a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(MIF_FRAME_OUTPUT, MDIO_ADDR_OP(port, dev, reg));
317a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_wait(np);
318a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
319a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
320a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
321a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(MIF_FRAME_OUTPUT, MDIO_READ_OP(port, dev));
322a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return mdio_wait(np);
323a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
324a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
325a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int mdio_write(struct niu *np, int port, int dev, int reg, int data)
326a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
327a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
328a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
329a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(MIF_FRAME_OUTPUT, MDIO_ADDR_OP(port, dev, reg));
330a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_wait(np);
331a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
332a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
333a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
334a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(MIF_FRAME_OUTPUT, MDIO_WRITE_OP(port, dev, data));
335a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_wait(np);
336a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
337a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
338a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
339a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
340a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
341a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
342a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int mii_read(struct niu *np, int port, int reg)
343a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
344a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(MIF_FRAME_OUTPUT, MII_READ_OP(port, reg));
345a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return mdio_wait(np);
346a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
347a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
348a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int mii_write(struct niu *np, int port, int reg, int data)
349a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
350a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
351a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
352a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(MIF_FRAME_OUTPUT, MII_WRITE_OP(port, reg, data));
353a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_wait(np);
354a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
355a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
356a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
357a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
358a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
359a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
360a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int esr2_set_tx_cfg(struct niu *np, unsigned long channel, u32 val)
361a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
362a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
363a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
364a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
365a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 ESR2_TI_PLL_TX_CFG_L(channel),
366a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 val & 0xffff);
367a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err)
368a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
369a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 ESR2_TI_PLL_TX_CFG_H(channel),
370a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 val >> 16);
371a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
372a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
373a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
374a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int esr2_set_rx_cfg(struct niu *np, unsigned long channel, u32 val)
375a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
376a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
377a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
378a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
379a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 ESR2_TI_PLL_RX_CFG_L(channel),
380a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 val & 0xffff);
381a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err)
382a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
383a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 ESR2_TI_PLL_RX_CFG_H(channel),
384a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 val >> 16);
385a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
386a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
387a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
388a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller/* Mode is always 10G fiber.  */
389e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Beherastatic int serdes_init_niu_10g_fiber(struct niu *np)
390a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
391a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_link_config *lp = &np->link_config;
392a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u32 tx_cfg, rx_cfg;
393a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long i;
394a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
395a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tx_cfg = (PLL_TX_CFG_ENTX | PLL_TX_CFG_SWING_1375MV);
396a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rx_cfg = (PLL_RX_CFG_ENRX | PLL_RX_CFG_TERM_0P8VDDT |
397a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		  PLL_RX_CFG_ALIGN_ENA | PLL_RX_CFG_LOS_LTHRESH |
398a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		  PLL_RX_CFG_EQ_LP_ADAPTIVE);
399a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
400a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (lp->loopback_mode == LOOPBACK_PHY) {
401a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u16 test_cfg = PLL_TEST_CFG_LOOPBACK_CML_DIS;
402a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
403a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
404a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			   ESR2_TI_PLL_TEST_CFG_L, test_cfg);
405a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
406a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		tx_cfg |= PLL_TX_CFG_ENTEST;
407a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rx_cfg |= PLL_RX_CFG_ENTEST;
408a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
409a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
410a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* Initialize all 4 lanes of the SERDES.  */
411a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < 4; i++) {
412a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int err = esr2_set_tx_cfg(np, i, tx_cfg);
413a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
414a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
415a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
416a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
417a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < 4; i++) {
418a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int err = esr2_set_rx_cfg(np, i, rx_cfg);
419a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
420a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
421a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
422a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
423a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
424a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
425a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
426e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Beherastatic int serdes_init_niu_1g_serdes(struct niu *np)
427e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera{
428e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	struct niu_link_config *lp = &np->link_config;
429e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	u16 pll_cfg, pll_sts;
430e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	int max_retry = 100;
43151e0f058c496ef2ca5362c16a53ce1ce454d0817Ingo Molnar	u64 uninitialized_var(sig), mask, val;
432e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	u32 tx_cfg, rx_cfg;
433e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	unsigned long i;
434e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	int err;
435e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
436e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	tx_cfg = (PLL_TX_CFG_ENTX | PLL_TX_CFG_SWING_1375MV |
437e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		  PLL_TX_CFG_RATE_HALF);
438e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	rx_cfg = (PLL_RX_CFG_ENRX | PLL_RX_CFG_TERM_0P8VDDT |
439e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		  PLL_RX_CFG_ALIGN_ENA | PLL_RX_CFG_LOS_LTHRESH |
440e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		  PLL_RX_CFG_RATE_HALF);
441e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
442e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	if (np->port == 0)
443e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		rx_cfg |= PLL_RX_CFG_EQ_LP_ADAPTIVE;
444e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
445e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	if (lp->loopback_mode == LOOPBACK_PHY) {
446e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		u16 test_cfg = PLL_TEST_CFG_LOOPBACK_CML_DIS;
447e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
448e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
449e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			   ESR2_TI_PLL_TEST_CFG_L, test_cfg);
450e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
451e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		tx_cfg |= PLL_TX_CFG_ENTEST;
452e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		rx_cfg |= PLL_RX_CFG_ENTEST;
453e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
454e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
455e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	/* Initialize PLL for 1G */
456e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	pll_cfg = (PLL_CFG_ENPLL | PLL_CFG_MPY_8X);
457e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
458e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
459e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			 ESR2_TI_PLL_CFG_L, pll_cfg);
460e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	if (err) {
461f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "NIU Port %d %s() mdio write to ESR2_TI_PLL_CFG_L failed\n",
462f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   np->port, __func__);
463e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		return err;
464e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
465e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
466e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	pll_sts = PLL_CFG_ENPLL;
467e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
468e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
469e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			 ESR2_TI_PLL_STS_L, pll_sts);
470e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	if (err) {
471f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "NIU Port %d %s() mdio write to ESR2_TI_PLL_STS_L failed\n",
472f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   np->port, __func__);
473e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		return err;
474e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
475e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
476e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	udelay(200);
477e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
478e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	/* Initialize all 4 lanes of the SERDES.  */
479e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	for (i = 0; i < 4; i++) {
480e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		err = esr2_set_tx_cfg(np, i, tx_cfg);
481e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		if (err)
482e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			return err;
483e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
484e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
485e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	for (i = 0; i < 4; i++) {
486e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		err = esr2_set_rx_cfg(np, i, rx_cfg);
487e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		if (err)
488e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			return err;
489e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
490e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
491e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	switch (np->port) {
492e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	case 0:
493e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		val = (ESR_INT_SRDY0_P0 | ESR_INT_DET0_P0);
494e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		mask = val;
495e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		break;
496e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
497e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	case 1:
498e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		val = (ESR_INT_SRDY0_P1 | ESR_INT_DET0_P1);
499e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		mask = val;
500e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		break;
501e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
502e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	default:
503e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		return -EINVAL;
504e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
505e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
506e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	while (max_retry--) {
507e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		sig = nr64(ESR_INT_SIGNALS);
508e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		if ((sig & mask) == val)
509e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			break;
510e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
511e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		mdelay(500);
512e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
513e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
514e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	if ((sig & mask) != val) {
515f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "Port %u signal bits [%08x] are not [%08x]\n",
516f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   np->port, (int)(sig & mask), (int)val);
517e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		return -ENODEV;
518e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
519e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
520e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	return 0;
521e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera}
522e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
523e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Beherastatic int serdes_init_niu_10g_serdes(struct niu *np)
524e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera{
525e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	struct niu_link_config *lp = &np->link_config;
526e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	u32 tx_cfg, rx_cfg, pll_cfg, pll_sts;
527e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	int max_retry = 100;
52851e0f058c496ef2ca5362c16a53ce1ce454d0817Ingo Molnar	u64 uninitialized_var(sig), mask, val;
529e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	unsigned long i;
530e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	int err;
531e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
532e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	tx_cfg = (PLL_TX_CFG_ENTX | PLL_TX_CFG_SWING_1375MV);
533e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	rx_cfg = (PLL_RX_CFG_ENRX | PLL_RX_CFG_TERM_0P8VDDT |
534e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		  PLL_RX_CFG_ALIGN_ENA | PLL_RX_CFG_LOS_LTHRESH |
535e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		  PLL_RX_CFG_EQ_LP_ADAPTIVE);
536e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
537e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	if (lp->loopback_mode == LOOPBACK_PHY) {
538e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		u16 test_cfg = PLL_TEST_CFG_LOOPBACK_CML_DIS;
539e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
540e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
541e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			   ESR2_TI_PLL_TEST_CFG_L, test_cfg);
542e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
543e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		tx_cfg |= PLL_TX_CFG_ENTEST;
544e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		rx_cfg |= PLL_RX_CFG_ENTEST;
545e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
546e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
547e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	/* Initialize PLL for 10G */
548e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	pll_cfg = (PLL_CFG_ENPLL | PLL_CFG_MPY_10X);
549e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
550e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
551e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			 ESR2_TI_PLL_CFG_L, pll_cfg & 0xffff);
552e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	if (err) {
553f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "NIU Port %d %s() mdio write to ESR2_TI_PLL_CFG_L failed\n",
554f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   np->port, __func__);
555e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		return err;
556e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
557e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
558e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	pll_sts = PLL_CFG_ENPLL;
559e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
560e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
561e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			 ESR2_TI_PLL_STS_L, pll_sts & 0xffff);
562e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	if (err) {
563f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "NIU Port %d %s() mdio write to ESR2_TI_PLL_STS_L failed\n",
564f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   np->port, __func__);
565e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		return err;
566e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
567e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
568e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	udelay(200);
569e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
570e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	/* Initialize all 4 lanes of the SERDES.  */
571e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	for (i = 0; i < 4; i++) {
572e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		err = esr2_set_tx_cfg(np, i, tx_cfg);
573e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		if (err)
574e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			return err;
575e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
576e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
577e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	for (i = 0; i < 4; i++) {
578e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		err = esr2_set_rx_cfg(np, i, rx_cfg);
579e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		if (err)
580e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			return err;
581e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
582e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
583e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	/* check if serdes is ready */
584e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
585e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	switch (np->port) {
586e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	case 0:
587e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		mask = ESR_INT_SIGNALS_P0_BITS;
588e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		val = (ESR_INT_SRDY0_P0 |
589e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		       ESR_INT_DET0_P0 |
590e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		       ESR_INT_XSRDY_P0 |
591e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		       ESR_INT_XDP_P0_CH3 |
592e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		       ESR_INT_XDP_P0_CH2 |
593e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		       ESR_INT_XDP_P0_CH1 |
594e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		       ESR_INT_XDP_P0_CH0);
595e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		break;
596e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
597e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	case 1:
598e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		mask = ESR_INT_SIGNALS_P1_BITS;
599e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		val = (ESR_INT_SRDY0_P1 |
600e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		       ESR_INT_DET0_P1 |
601e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		       ESR_INT_XSRDY_P1 |
602e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		       ESR_INT_XDP_P1_CH3 |
603e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		       ESR_INT_XDP_P1_CH2 |
604e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		       ESR_INT_XDP_P1_CH1 |
605e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		       ESR_INT_XDP_P1_CH0);
606e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		break;
607e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
608e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	default:
609e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		return -EINVAL;
610e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
611e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
612e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	while (max_retry--) {
613e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		sig = nr64(ESR_INT_SIGNALS);
614e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		if ((sig & mask) == val)
615e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			break;
616e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
617e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		mdelay(500);
618e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
619e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
620e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	if ((sig & mask) != val) {
621f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_info("NIU Port %u signal bits [%08x] are not [%08x] for 10G...trying 1G\n",
622f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			np->port, (int)(sig & mask), (int)val);
623e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
624e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		/* 10G failed, try initializing at 1G */
625e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		err = serdes_init_niu_1g_serdes(np);
626e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		if (!err) {
627e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			np->flags &= ~NIU_FLAGS_10G;
628e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			np->mac_xcvr = MAC_XCVR_PCS;
629e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		}  else {
630f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			netdev_err(np->dev, "Port %u 10G/1G SERDES Link Failed\n",
631f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				   np->port);
632e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			return -ENODEV;
633e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		}
634e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	}
635e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	return 0;
636e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera}
637e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
638a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int esr_read_rxtx_ctrl(struct niu *np, unsigned long chan, u32 *val)
639a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
640a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
641a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
642a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, ESR_RXTX_CTRL_L(chan));
643a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err >= 0) {
644a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		*val = (err & 0xffff);
645a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
646a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				ESR_RXTX_CTRL_H(chan));
647a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err >= 0)
648a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			*val |= ((err & 0xffff) << 16);
649a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = 0;
650a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
651a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
652a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
653a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
654a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int esr_read_glue0(struct niu *np, unsigned long chan, u32 *val)
655a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
656a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
657a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
658a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
659a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			ESR_GLUE_CTRL0_L(chan));
660a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err >= 0) {
661a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		*val = (err & 0xffff);
662a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
663a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				ESR_GLUE_CTRL0_H(chan));
664a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err >= 0) {
665a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			*val |= ((err & 0xffff) << 16);
666a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			err = 0;
667a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
668a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
669a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
670a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
671a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
672a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int esr_read_reset(struct niu *np, u32 *val)
673a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
674a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
675a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
676a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
677a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			ESR_RXTX_RESET_CTRL_L);
678a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err >= 0) {
679a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		*val = (err & 0xffff);
680a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
681a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				ESR_RXTX_RESET_CTRL_H);
682a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err >= 0) {
683a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			*val |= ((err & 0xffff) << 16);
684a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			err = 0;
685a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
686a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
687a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
688a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
689a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
690a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int esr_write_rxtx_ctrl(struct niu *np, unsigned long chan, u32 val)
691a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
692a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
693a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
694a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
695a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 ESR_RXTX_CTRL_L(chan), val & 0xffff);
696a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err)
697a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
698a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 ESR_RXTX_CTRL_H(chan), (val >> 16));
699a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
700a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
701a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
702a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int esr_write_glue0(struct niu *np, unsigned long chan, u32 val)
703a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
704a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
705a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
706a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
707a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			ESR_GLUE_CTRL0_L(chan), val & 0xffff);
708a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err)
709a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
710a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 ESR_GLUE_CTRL0_H(chan), (val >> 16));
711a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
712a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
713a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
714a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int esr_reset(struct niu *np)
715a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
716f166400bd4c92df72d997e0da8713fae90d56e57Ingo Molnar	u32 uninitialized_var(reset);
717a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
718a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
719a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
720a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 ESR_RXTX_RESET_CTRL_L, 0x0000);
721a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
722a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
723a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
724a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 ESR_RXTX_RESET_CTRL_H, 0xffff);
725a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
726a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
727a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	udelay(200);
728a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
729a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
730a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 ESR_RXTX_RESET_CTRL_L, 0xffff);
731a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
732a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
733a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	udelay(200);
734a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
735a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
736a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 ESR_RXTX_RESET_CTRL_H, 0x0000);
737a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
738a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
739a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	udelay(200);
740a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
741a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = esr_read_reset(np, &reset);
742a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
743a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
744a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (reset != 0) {
745f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "Port %u ESR_RESET did not clear [%08x]\n",
746f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   np->port, reset);
747a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
748a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
749a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
750a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
751a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
752a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
753a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int serdes_init_10g(struct niu *np)
754a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
755a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_link_config *lp = &np->link_config;
756a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long ctrl_reg, test_cfg_reg, i;
757a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 ctrl_val, test_cfg_val, sig, mask, val;
758a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
759a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
760a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	switch (np->port) {
761a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 0:
762a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ctrl_reg = ENET_SERDES_0_CTRL_CFG;
763a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		test_cfg_reg = ENET_SERDES_0_TEST_CFG;
764a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
765a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 1:
766a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ctrl_reg = ENET_SERDES_1_CTRL_CFG;
767a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		test_cfg_reg = ENET_SERDES_1_TEST_CFG;
768a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
769a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
770a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	default:
771a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
772a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
773a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	ctrl_val = (ENET_SERDES_CTRL_SDET_0 |
774a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    ENET_SERDES_CTRL_SDET_1 |
775a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    ENET_SERDES_CTRL_SDET_2 |
776a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    ENET_SERDES_CTRL_SDET_3 |
777a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    (0x5 << ENET_SERDES_CTRL_EMPH_0_SHIFT) |
778a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    (0x5 << ENET_SERDES_CTRL_EMPH_1_SHIFT) |
779a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    (0x5 << ENET_SERDES_CTRL_EMPH_2_SHIFT) |
780a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    (0x5 << ENET_SERDES_CTRL_EMPH_3_SHIFT) |
781a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    (0x1 << ENET_SERDES_CTRL_LADJ_0_SHIFT) |
782a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    (0x1 << ENET_SERDES_CTRL_LADJ_1_SHIFT) |
783a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    (0x1 << ENET_SERDES_CTRL_LADJ_2_SHIFT) |
784a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    (0x1 << ENET_SERDES_CTRL_LADJ_3_SHIFT));
785a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	test_cfg_val = 0;
786a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
787a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (lp->loopback_mode == LOOPBACK_PHY) {
788a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		test_cfg_val |= ((ENET_TEST_MD_PAD_LOOPBACK <<
789a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  ENET_SERDES_TEST_MD_0_SHIFT) |
790a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 (ENET_TEST_MD_PAD_LOOPBACK <<
791a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  ENET_SERDES_TEST_MD_1_SHIFT) |
792a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 (ENET_TEST_MD_PAD_LOOPBACK <<
793a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  ENET_SERDES_TEST_MD_2_SHIFT) |
794a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 (ENET_TEST_MD_PAD_LOOPBACK <<
795a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  ENET_SERDES_TEST_MD_3_SHIFT));
796a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
797a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
798a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ctrl_reg, ctrl_val);
799a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(test_cfg_reg, test_cfg_val);
800a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
801a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* Initialize all 4 lanes of the SERDES.  */
802a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < 4; i++) {
803a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u32 rxtx_ctrl, glue0;
804a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
805a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = esr_read_rxtx_ctrl(np, i, &rxtx_ctrl);
806a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
807a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
808a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = esr_read_glue0(np, i, &glue0);
809a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
810a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
811a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
812a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rxtx_ctrl &= ~(ESR_RXTX_CTRL_VMUXLO);
813a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rxtx_ctrl |= (ESR_RXTX_CTRL_ENSTRETCH |
814a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			      (2 << ESR_RXTX_CTRL_VMUXLO_SHIFT));
815a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
816a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		glue0 &= ~(ESR_GLUE_CTRL0_SRATE |
817a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			   ESR_GLUE_CTRL0_THCNT |
818a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			   ESR_GLUE_CTRL0_BLTIME);
819a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		glue0 |= (ESR_GLUE_CTRL0_RXLOSENAB |
820a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  (0xf << ESR_GLUE_CTRL0_SRATE_SHIFT) |
821a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  (0xff << ESR_GLUE_CTRL0_THCNT_SHIFT) |
822a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  (BLTIME_300_CYCLES <<
823a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			   ESR_GLUE_CTRL0_BLTIME_SHIFT));
824a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
825a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = esr_write_rxtx_ctrl(np, i, rxtx_ctrl);
826a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
827a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
828a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = esr_write_glue0(np, i, glue0);
829a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
830a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
831a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
832a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
833a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = esr_reset(np);
834a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
835a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
836a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
837a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	sig = nr64(ESR_INT_SIGNALS);
838a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	switch (np->port) {
839a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 0:
840a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mask = ESR_INT_SIGNALS_P0_BITS;
841a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val = (ESR_INT_SRDY0_P0 |
842a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       ESR_INT_DET0_P0 |
843a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       ESR_INT_XSRDY_P0 |
844a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       ESR_INT_XDP_P0_CH3 |
845a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       ESR_INT_XDP_P0_CH2 |
846a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       ESR_INT_XDP_P0_CH1 |
847a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       ESR_INT_XDP_P0_CH0);
848a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
849a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
850a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 1:
851a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mask = ESR_INT_SIGNALS_P1_BITS;
852a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val = (ESR_INT_SRDY0_P1 |
853a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       ESR_INT_DET0_P1 |
854a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       ESR_INT_XSRDY_P1 |
855a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       ESR_INT_XDP_P1_CH3 |
856a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       ESR_INT_XDP_P1_CH2 |
857a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       ESR_INT_XDP_P1_CH1 |
858a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       ESR_INT_XDP_P1_CH0);
859a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
860a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
861a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	default:
862a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
863a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
864a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
865a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if ((sig & mask) != val) {
866a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		if (np->flags & NIU_FLAGS_HOTPLUG_PHY) {
867a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT;
868a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			return 0;
869a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		}
870f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "Port %u signal bits [%08x] are not [%08x]\n",
871f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   np->port, (int)(sig & mask), (int)val);
872a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
873a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
874a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (np->flags & NIU_FLAGS_HOTPLUG_PHY)
875a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		np->flags |= NIU_FLAGS_HOTPLUG_PHY_PRESENT;
876a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
877a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
878a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
879a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int serdes_init_1g(struct niu *np)
880a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
881a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
882a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
883a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(ENET_SERDES_1_PLL_CFG);
884a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~ENET_SERDES_PLL_FBDIV2;
885a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	switch (np->port) {
886a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 0:
887a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= ENET_SERDES_PLL_HRATE0;
888a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
889a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 1:
890a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= ENET_SERDES_PLL_HRATE1;
891a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
892a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 2:
893a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= ENET_SERDES_PLL_HRATE2;
894a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
895a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 3:
896a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= ENET_SERDES_PLL_HRATE3;
897a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
898a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	default:
899a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
900a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
901a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ENET_SERDES_1_PLL_CFG, val);
902a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
903a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
904a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
905a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9065fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Workustatic int serdes_init_1g_serdes(struct niu *np)
9075fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku{
9085fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	struct niu_link_config *lp = &np->link_config;
9095fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	unsigned long ctrl_reg, test_cfg_reg, pll_cfg, i;
9105fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	u64 ctrl_val, test_cfg_val, sig, mask, val;
9115fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	int err;
9125fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	u64 reset_val, val_rd;
9135fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
9145fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	val = ENET_SERDES_PLL_HRATE0 | ENET_SERDES_PLL_HRATE1 |
9155fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		ENET_SERDES_PLL_HRATE2 | ENET_SERDES_PLL_HRATE3 |
9165fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		ENET_SERDES_PLL_FBDIV0;
9175fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	switch (np->port) {
9185fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	case 0:
9195fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		reset_val =  ENET_SERDES_RESET_0;
9205fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		ctrl_reg = ENET_SERDES_0_CTRL_CFG;
9215fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		test_cfg_reg = ENET_SERDES_0_TEST_CFG;
9225fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		pll_cfg = ENET_SERDES_0_PLL_CFG;
9235fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		break;
9245fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	case 1:
9255fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		reset_val =  ENET_SERDES_RESET_1;
9265fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		ctrl_reg = ENET_SERDES_1_CTRL_CFG;
9275fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		test_cfg_reg = ENET_SERDES_1_TEST_CFG;
9285fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		pll_cfg = ENET_SERDES_1_PLL_CFG;
9295fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		break;
9305fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
9315fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	default:
9325fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		return -EINVAL;
9335fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
9345fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	ctrl_val = (ENET_SERDES_CTRL_SDET_0 |
9355fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    ENET_SERDES_CTRL_SDET_1 |
9365fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    ENET_SERDES_CTRL_SDET_2 |
9375fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    ENET_SERDES_CTRL_SDET_3 |
9385fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x5 << ENET_SERDES_CTRL_EMPH_0_SHIFT) |
9395fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x5 << ENET_SERDES_CTRL_EMPH_1_SHIFT) |
9405fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x5 << ENET_SERDES_CTRL_EMPH_2_SHIFT) |
9415fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x5 << ENET_SERDES_CTRL_EMPH_3_SHIFT) |
9425fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x1 << ENET_SERDES_CTRL_LADJ_0_SHIFT) |
9435fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x1 << ENET_SERDES_CTRL_LADJ_1_SHIFT) |
9445fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x1 << ENET_SERDES_CTRL_LADJ_2_SHIFT) |
9455fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x1 << ENET_SERDES_CTRL_LADJ_3_SHIFT));
9465fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	test_cfg_val = 0;
9475fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
9485fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (lp->loopback_mode == LOOPBACK_PHY) {
9495fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		test_cfg_val |= ((ENET_TEST_MD_PAD_LOOPBACK <<
9505fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				  ENET_SERDES_TEST_MD_0_SHIFT) |
9515fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				 (ENET_TEST_MD_PAD_LOOPBACK <<
9525fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				  ENET_SERDES_TEST_MD_1_SHIFT) |
9535fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				 (ENET_TEST_MD_PAD_LOOPBACK <<
9545fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				  ENET_SERDES_TEST_MD_2_SHIFT) |
9555fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				 (ENET_TEST_MD_PAD_LOOPBACK <<
9565fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				  ENET_SERDES_TEST_MD_3_SHIFT));
9575fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
9585fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
9595fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	nw64(ENET_SERDES_RESET, reset_val);
9605fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	mdelay(20);
9615fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	val_rd = nr64(ENET_SERDES_RESET);
9625fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	val_rd &= ~reset_val;
9635fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	nw64(pll_cfg, val);
9645fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	nw64(ctrl_reg, ctrl_val);
9655fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	nw64(test_cfg_reg, test_cfg_val);
9665fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	nw64(ENET_SERDES_RESET, val_rd);
9675fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	mdelay(2000);
9685fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
9695fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	/* Initialize all 4 lanes of the SERDES.  */
9705fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	for (i = 0; i < 4; i++) {
9715fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		u32 rxtx_ctrl, glue0;
9725fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
9735fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = esr_read_rxtx_ctrl(np, i, &rxtx_ctrl);
9745fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (err)
9755fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			return err;
9765fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = esr_read_glue0(np, i, &glue0);
9775fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (err)
9785fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			return err;
9795fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
9805fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		rxtx_ctrl &= ~(ESR_RXTX_CTRL_VMUXLO);
9815fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		rxtx_ctrl |= (ESR_RXTX_CTRL_ENSTRETCH |
9825fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			      (2 << ESR_RXTX_CTRL_VMUXLO_SHIFT));
9835fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
9845fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		glue0 &= ~(ESR_GLUE_CTRL0_SRATE |
9855fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			   ESR_GLUE_CTRL0_THCNT |
9865fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			   ESR_GLUE_CTRL0_BLTIME);
9875fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		glue0 |= (ESR_GLUE_CTRL0_RXLOSENAB |
9885fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			  (0xf << ESR_GLUE_CTRL0_SRATE_SHIFT) |
9895fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			  (0xff << ESR_GLUE_CTRL0_THCNT_SHIFT) |
9905fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			  (BLTIME_300_CYCLES <<
9915fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			   ESR_GLUE_CTRL0_BLTIME_SHIFT));
9925fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
9935fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = esr_write_rxtx_ctrl(np, i, rxtx_ctrl);
9945fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (err)
9955fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			return err;
9965fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = esr_write_glue0(np, i, glue0);
9975fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (err)
9985fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			return err;
9995fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
10005fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10015fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10025fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	sig = nr64(ESR_INT_SIGNALS);
10035fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	switch (np->port) {
10045fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	case 0:
10055fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		val = (ESR_INT_SRDY0_P0 | ESR_INT_DET0_P0);
10065fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		mask = val;
10075fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		break;
10085fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10095fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	case 1:
10105fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		val = (ESR_INT_SRDY0_P1 | ESR_INT_DET0_P1);
10115fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		mask = val;
10125fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		break;
10135fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10145fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	default:
10155fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		return -EINVAL;
10165fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
10175fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10185fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if ((sig & mask) != val) {
1019f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "Port %u signal bits [%08x] are not [%08x]\n",
1020f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   np->port, (int)(sig & mask), (int)val);
10215fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		return -ENODEV;
10225fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
10235fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10245fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	return 0;
10255fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku}
10265fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10275fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Workustatic int link_status_1g_serdes(struct niu *np, int *link_up_p)
10285fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku{
10295fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	struct niu_link_config *lp = &np->link_config;
10305fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	int link_up;
10315fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	u64 val;
10325fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	u16 current_speed;
10335fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	unsigned long flags;
10345fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	u8 current_duplex;
10355fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10365fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	link_up = 0;
10375fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	current_speed = SPEED_INVALID;
10385fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	current_duplex = DUPLEX_INVALID;
10395fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10405fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	spin_lock_irqsave(&np->lock, flags);
10415fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10425fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	val = nr64_pcs(PCS_MII_STAT);
10435fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10445fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (val & PCS_MII_STAT_LINK_STATUS) {
10455fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		link_up = 1;
10465fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		current_speed = SPEED_1000;
10475fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		current_duplex = DUPLEX_FULL;
10485fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
10495fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10505fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	lp->active_speed = current_speed;
10515fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	lp->active_duplex = current_duplex;
10525fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	spin_unlock_irqrestore(&np->lock, flags);
10535fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10545fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	*link_up_p = link_up;
10555fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	return 0;
10565fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku}
10575fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10585fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Workustatic int link_status_10g_serdes(struct niu *np, int *link_up_p)
10595fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku{
10605fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	unsigned long flags;
10615fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	struct niu_link_config *lp = &np->link_config;
10625fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	int link_up = 0;
10635fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	int link_ok = 1;
10645fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	u64 val, val2;
10655fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	u16 current_speed;
10665fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	u8 current_duplex;
10675fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10685fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (!(np->flags & NIU_FLAGS_10G))
10695fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		return link_status_1g_serdes(np, link_up_p);
10705fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10715fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	current_speed = SPEED_INVALID;
10725fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	current_duplex = DUPLEX_INVALID;
10735fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	spin_lock_irqsave(&np->lock, flags);
10745fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10755fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	val = nr64_xpcs(XPCS_STATUS(0));
10765fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	val2 = nr64_mac(XMAC_INTER2);
10775fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (val2 & 0x01000000)
10785fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		link_ok = 0;
10795fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
10805fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if ((val & 0x1000ULL) && link_ok) {
10815fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		link_up = 1;
10825fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		current_speed = SPEED_10000;
10835fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		current_duplex = DUPLEX_FULL;
10845fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
10855fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	lp->active_speed = current_speed;
10865fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	lp->active_duplex = current_duplex;
10875fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	spin_unlock_irqrestore(&np->lock, flags);
10885fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	*link_up_p = link_up;
10895fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	return 0;
10905fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku}
10915fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
109238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranovstatic int link_status_mii(struct niu *np, int *link_up_p)
109338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov{
109438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	struct niu_link_config *lp = &np->link_config;
109538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	int err;
109638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	int bmsr, advert, ctrl1000, stat1000, lpa, bmcr, estatus;
109738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	int supported, advertising, active_speed, active_duplex;
109838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
109938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	err = mii_read(np, np->phy_addr, MII_BMCR);
110038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (unlikely(err < 0))
110138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		return err;
110238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	bmcr = err;
110338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
110438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	err = mii_read(np, np->phy_addr, MII_BMSR);
110538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (unlikely(err < 0))
110638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		return err;
110738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	bmsr = err;
110838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
110938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	err = mii_read(np, np->phy_addr, MII_ADVERTISE);
111038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (unlikely(err < 0))
111138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		return err;
111238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	advert = err;
111338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
111438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	err = mii_read(np, np->phy_addr, MII_LPA);
111538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (unlikely(err < 0))
111638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		return err;
111738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	lpa = err;
111838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
111938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (likely(bmsr & BMSR_ESTATEN)) {
112038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		err = mii_read(np, np->phy_addr, MII_ESTATUS);
112138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if (unlikely(err < 0))
112238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			return err;
112338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		estatus = err;
112438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
112538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		err = mii_read(np, np->phy_addr, MII_CTRL1000);
112638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if (unlikely(err < 0))
112738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			return err;
112838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		ctrl1000 = err;
112938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
113038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		err = mii_read(np, np->phy_addr, MII_STAT1000);
113138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if (unlikely(err < 0))
113238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			return err;
113338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		stat1000 = err;
113438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	} else
113538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		estatus = ctrl1000 = stat1000 = 0;
113638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
113738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	supported = 0;
113838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (bmsr & BMSR_ANEGCAPABLE)
113938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		supported |= SUPPORTED_Autoneg;
114038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (bmsr & BMSR_10HALF)
114138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		supported |= SUPPORTED_10baseT_Half;
114238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (bmsr & BMSR_10FULL)
114338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		supported |= SUPPORTED_10baseT_Full;
114438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (bmsr & BMSR_100HALF)
114538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		supported |= SUPPORTED_100baseT_Half;
114638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (bmsr & BMSR_100FULL)
114738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		supported |= SUPPORTED_100baseT_Full;
114838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (estatus & ESTATUS_1000_THALF)
114938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		supported |= SUPPORTED_1000baseT_Half;
115038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (estatus & ESTATUS_1000_TFULL)
115138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		supported |= SUPPORTED_1000baseT_Full;
115238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	lp->supported = supported;
115338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
115437f07023d30708b5da091fe6d6be9b60783c6d82Matt Carlson	advertising = mii_adv_to_ethtool_adv_t(advert);
115537f07023d30708b5da091fe6d6be9b60783c6d82Matt Carlson	advertising |= mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
115638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
115738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (bmcr & BMCR_ANENABLE) {
115838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		int neg, neg1000;
115938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
116038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		lp->active_autoneg = 1;
116138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		advertising |= ADVERTISED_Autoneg;
116238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
116338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		neg = advert & lpa;
116438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		neg1000 = (ctrl1000 << 2) & stat1000;
116538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
116638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if (neg1000 & (LPA_1000FULL | LPA_1000HALF))
116738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			active_speed = SPEED_1000;
116838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		else if (neg & LPA_100)
116938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			active_speed = SPEED_100;
117038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		else if (neg & (LPA_10HALF | LPA_10FULL))
117138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			active_speed = SPEED_10;
117238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		else
117338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			active_speed = SPEED_INVALID;
117438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
117538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if ((neg1000 & LPA_1000FULL) || (neg & LPA_DUPLEX))
117638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			active_duplex = DUPLEX_FULL;
117738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		else if (active_speed != SPEED_INVALID)
117838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			active_duplex = DUPLEX_HALF;
117938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		else
118038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			active_duplex = DUPLEX_INVALID;
118138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	} else {
118238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		lp->active_autoneg = 0;
118338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
118438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if ((bmcr & BMCR_SPEED1000) && !(bmcr & BMCR_SPEED100))
118538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			active_speed = SPEED_1000;
118638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		else if (bmcr & BMCR_SPEED100)
118738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			active_speed = SPEED_100;
118838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		else
118938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			active_speed = SPEED_10;
119038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
119138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if (bmcr & BMCR_FULLDPLX)
119238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			active_duplex = DUPLEX_FULL;
119338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		else
119438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			active_duplex = DUPLEX_HALF;
119538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	}
119638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
119738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	lp->active_advertising = advertising;
119838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	lp->active_speed = active_speed;
119938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	lp->active_duplex = active_duplex;
120038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	*link_up_p = !!(bmsr & BMSR_LSTATUS);
120138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
120238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	return 0;
120338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov}
120438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
12055fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Workustatic int link_status_1g_rgmii(struct niu *np, int *link_up_p)
12065fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku{
12075fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	struct niu_link_config *lp = &np->link_config;
12085fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	u16 current_speed, bmsr;
12095fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	unsigned long flags;
12105fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	u8 current_duplex;
12115fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	int err, link_up;
12125fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
12135fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	link_up = 0;
12145fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	current_speed = SPEED_INVALID;
12155fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	current_duplex = DUPLEX_INVALID;
12165fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
12175fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	spin_lock_irqsave(&np->lock, flags);
12185fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
12195fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	err = -EINVAL;
12205fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
12215fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	err = mii_read(np, np->phy_addr, MII_BMSR);
12225fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (err < 0)
12235fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		goto out;
12245fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
12255fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	bmsr = err;
12265fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (bmsr & BMSR_LSTATUS) {
1227f344c25dbab1a392ef7a7afc8ca061b3b7285423David S. Miller		u16 adv, lpa;
12285fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
12295fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = mii_read(np, np->phy_addr, MII_ADVERTISE);
12305fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (err < 0)
12315fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			goto out;
12325fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		adv = err;
12335fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
12345fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = mii_read(np, np->phy_addr, MII_LPA);
12355fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (err < 0)
12365fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			goto out;
12375fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		lpa = err;
12385fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
12395fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = mii_read(np, np->phy_addr, MII_ESTATUS);
12405fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (err < 0)
12415fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			goto out;
12425fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		link_up = 1;
12435fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		current_speed = SPEED_1000;
12445fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		current_duplex = DUPLEX_FULL;
12455fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
12465fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
12475fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	lp->active_speed = current_speed;
12485fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	lp->active_duplex = current_duplex;
12495fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	err = 0;
12505fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
12515fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Workuout:
12525fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	spin_unlock_irqrestore(&np->lock, flags);
12535fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
12545fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	*link_up_p = link_up;
12555fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	return err;
12565fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku}
12575fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
125838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranovstatic int link_status_1g(struct niu *np, int *link_up_p)
125938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov{
126038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	struct niu_link_config *lp = &np->link_config;
126138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	unsigned long flags;
126238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	int err;
126338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
126438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	spin_lock_irqsave(&np->lock, flags);
126538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
126638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	err = link_status_mii(np, link_up_p);
126738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	lp->supported |= SUPPORTED_TP;
126838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	lp->active_advertising |= ADVERTISED_TP;
126938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
127038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	spin_unlock_irqrestore(&np->lock, flags);
127138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	return err;
127238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov}
127338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
1274a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int bcm8704_reset(struct niu *np)
1275a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
1276a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err, limit;
1277a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1278a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->phy_addr,
1279a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			BCM8704_PHYXS_DEV_ADDR, MII_BMCR);
12809c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang	if (err < 0 || err == 0xffff)
1281a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1282a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err |= BMCR_RESET;
1283a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_write(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
1284a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 MII_BMCR, err);
1285a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
1286a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1287a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1288a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	limit = 1000;
1289a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (--limit >= 0) {
1290a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = mdio_read(np, np->phy_addr,
1291a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				BCM8704_PHYXS_DEV_ADDR, MII_BMCR);
1292a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err < 0)
1293a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
1294a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!(err & BMCR_RESET))
1295a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
1296a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
1297a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (limit < 0) {
1298f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "Port %u PHY will not reset (bmcr=%04x)\n",
1299f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   np->port, (err & 0xffff));
1300a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
1301a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
1302a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
1303a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
1304a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1305a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller/* When written, certain PHY registers need to be read back twice
1306a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller * in order for the bits to settle properly.
1307a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller */
1308a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int bcm8704_user_dev3_readback(struct niu *np, int reg)
1309a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
1310a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, reg);
1311a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
1312a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1313a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, reg);
1314a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
1315a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1316a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
1317a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
1318a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1319a5d6ab56daa439d681aab29955498486e452224dMatheos Workustatic int bcm8706_init_user_dev3(struct niu *np)
1320a5d6ab56daa439d681aab29955498486e452224dMatheos Worku{
1321a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	int err;
1322a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1323a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1324a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
1325a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			BCM8704_USER_OPT_DIGITAL_CTRL);
1326a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err < 0)
1327a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		return err;
1328a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err &= ~USER_ODIG_CTRL_GPIOS;
1329a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err |= (0x3 << USER_ODIG_CTRL_GPIOS_SHIFT);
1330a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err |=  USER_ODIG_CTRL_RESV2;
1331a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = mdio_write(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
1332a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			 BCM8704_USER_OPT_DIGITAL_CTRL, err);
1333a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err)
1334a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		return err;
1335a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1336a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	mdelay(1000);
1337a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1338a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	return 0;
1339a5d6ab56daa439d681aab29955498486e452224dMatheos Worku}
1340a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1341a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int bcm8704_init_user_dev3(struct niu *np)
1342a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
1343a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
1344a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1345a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_write(np, np->phy_addr,
1346a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 BCM8704_USER_DEV3_ADDR, BCM8704_USER_CONTROL,
1347a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 (USER_CONTROL_OPTXRST_LVL |
1348a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  USER_CONTROL_OPBIASFLT_LVL |
1349a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  USER_CONTROL_OBTMPFLT_LVL |
1350a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  USER_CONTROL_OPPRFLT_LVL |
1351a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  USER_CONTROL_OPTXFLT_LVL |
1352a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  USER_CONTROL_OPRXLOS_LVL |
1353a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  USER_CONTROL_OPRXFLT_LVL |
1354a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  USER_CONTROL_OPTXON_LVL |
1355a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  (0x3f << USER_CONTROL_RES1_SHIFT)));
1356a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
1357a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1358a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1359a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_write(np, np->phy_addr,
1360a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 BCM8704_USER_DEV3_ADDR, BCM8704_USER_PMD_TX_CONTROL,
1361a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 (USER_PMD_TX_CTL_XFP_CLKEN |
1362a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  (1 << USER_PMD_TX_CTL_TX_DAC_TXD_SH) |
1363a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  (2 << USER_PMD_TX_CTL_TX_DAC_TXCK_SH) |
1364a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  USER_PMD_TX_CTL_TSCK_LPWREN));
1365a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
1366a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1367a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1368a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = bcm8704_user_dev3_readback(np, BCM8704_USER_CONTROL);
1369a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
1370a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1371a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = bcm8704_user_dev3_readback(np, BCM8704_USER_PMD_TX_CONTROL);
1372a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
1373a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1374a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1375a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
1376a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			BCM8704_USER_OPT_DIGITAL_CTRL);
1377a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
1378a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1379a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err &= ~USER_ODIG_CTRL_GPIOS;
1380a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err |= (0x3 << USER_ODIG_CTRL_GPIOS_SHIFT);
1381a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_write(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
1382a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 BCM8704_USER_OPT_DIGITAL_CTRL, err);
1383a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
1384a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1385a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1386a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mdelay(1000);
1387a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1388a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
1389a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
1390a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1391b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindnerstatic int mrvl88x2011_act_led(struct niu *np, int val)
1392b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner{
1393b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	int	err;
1394b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1395b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err  = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR,
1396b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		MRVL88X2011_LED_8_TO_11_CTL);
1397b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (err < 0)
1398b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		return err;
1399b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1400b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err &= ~MRVL88X2011_LED(MRVL88X2011_LED_ACT,MRVL88X2011_LED_CTL_MASK);
1401b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err |=  MRVL88X2011_LED(MRVL88X2011_LED_ACT,val);
1402b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1403b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	return mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR,
1404b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			  MRVL88X2011_LED_8_TO_11_CTL, err);
1405b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner}
1406b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1407b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindnerstatic int mrvl88x2011_led_blink_rate(struct niu *np, int rate)
1408b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner{
1409b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	int	err;
1410b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1411b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR,
1412b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			MRVL88X2011_LED_BLINK_CTL);
1413b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (err >= 0) {
1414b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		err &= ~MRVL88X2011_LED_BLKRATE_MASK;
1415b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		err |= (rate << 4);
1416b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1417b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR,
1418b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner				 MRVL88X2011_LED_BLINK_CTL, err);
1419b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	}
1420b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1421b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	return err;
1422b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner}
1423b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1424b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindnerstatic int xcvr_init_10g_mrvl88x2011(struct niu *np)
1425b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner{
1426b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	int	err;
1427b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1428b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	/* Set LED functions */
1429b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err = mrvl88x2011_led_blink_rate(np, MRVL88X2011_LED_BLKRATE_134MS);
1430b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (err)
1431b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		return err;
1432b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1433b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	/* led activity */
1434b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err = mrvl88x2011_act_led(np, MRVL88X2011_LED_CTL_OFF);
1435b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (err)
1436b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		return err;
1437b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1438b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR,
1439b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			MRVL88X2011_GENERAL_CTL);
1440b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (err < 0)
1441b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		return err;
1442b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1443b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err |= MRVL88X2011_ENA_XFPREFCLK;
1444b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1445b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR,
1446b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			 MRVL88X2011_GENERAL_CTL, err);
1447b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (err < 0)
1448b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		return err;
1449b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1450b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
1451b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			MRVL88X2011_PMA_PMD_CTL_1);
1452b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (err < 0)
1453b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		return err;
1454b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1455b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (np->link_config.loopback_mode == LOOPBACK_MAC)
1456b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		err |= MRVL88X2011_LOOPBACK;
1457b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	else
1458b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		err &= ~MRVL88X2011_LOOPBACK;
1459b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1460b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
1461b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			 MRVL88X2011_PMA_PMD_CTL_1, err);
1462b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (err < 0)
1463b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		return err;
1464b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1465b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	/* Enable PMD  */
1466b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	return mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
1467b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			  MRVL88X2011_10G_PMD_TX_DIS, MRVL88X2011_ENA_PMDTX);
1468b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner}
1469b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1470a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1471a5d6ab56daa439d681aab29955498486e452224dMatheos Workustatic int xcvr_diag_bcm870x(struct niu *np)
1472a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
1473a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u16 analog_stat0, tx_alarm_status;
1474a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	int err = 0;
1475a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1476a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#if 1
1477a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
1478a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			MII_STAT1000);
1479a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
1480a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1481f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	pr_info("Port %u PMA_PMD(MII_STAT1000) [%04x]\n", np->port, err);
1482a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1483a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, 0x20);
1484a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
1485a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1486f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	pr_info("Port %u USER_DEV3(0x20) [%04x]\n", np->port, err);
1487a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1488a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
1489a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			MII_NWAYTEST);
1490a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
1491a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1492f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	pr_info("Port %u PHYXS(MII_NWAYTEST) [%04x]\n", np->port, err);
1493a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif
1494a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1495a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* XXX dig this out it might not be so useful XXX */
1496a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
1497a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			BCM8704_USER_ANALOG_STATUS0);
1498a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
1499a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1500a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
1501a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			BCM8704_USER_ANALOG_STATUS0);
1502a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
1503a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1504a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	analog_stat0 = err;
1505a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1506a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
1507a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			BCM8704_USER_TX_ALARM_STATUS);
1508a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
1509a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1510a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
1511a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			BCM8704_USER_TX_ALARM_STATUS);
1512a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
1513a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1514a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tx_alarm_status = err;
1515a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1516a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (analog_stat0 != 0x03fc) {
1517a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if ((analog_stat0 == 0x43bc) && (tx_alarm_status != 0)) {
1518f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			pr_info("Port %u cable not connected or bad cable\n",
1519f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				np->port);
1520a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		} else if (analog_stat0 == 0x639c) {
1521f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			pr_info("Port %u optical module is bad or missing\n",
1522f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				np->port);
1523a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
1524a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
1525a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1526a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
1527a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
1528a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1529a5d6ab56daa439d681aab29955498486e452224dMatheos Workustatic int xcvr_10g_set_lb_bcm870x(struct niu *np)
1530a5d6ab56daa439d681aab29955498486e452224dMatheos Worku{
1531a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	struct niu_link_config *lp = &np->link_config;
1532a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	int err;
1533a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1534a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
1535a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			MII_BMCR);
1536a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err < 0)
1537a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		return err;
1538a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1539a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err &= ~BMCR_LOOPBACK;
1540a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1541a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (lp->loopback_mode == LOOPBACK_MAC)
1542a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		err |= BMCR_LOOPBACK;
1543a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1544a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = mdio_write(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
1545a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			 MII_BMCR, err);
1546a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err)
1547a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		return err;
1548a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1549a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	return 0;
1550a5d6ab56daa439d681aab29955498486e452224dMatheos Worku}
1551a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1552a5d6ab56daa439d681aab29955498486e452224dMatheos Workustatic int xcvr_init_10g_bcm8706(struct niu *np)
1553a5d6ab56daa439d681aab29955498486e452224dMatheos Worku{
1554a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	int err = 0;
1555a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	u64 val;
1556a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1557a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if ((np->flags & NIU_FLAGS_HOTPLUG_PHY) &&
1558a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	    (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) == 0)
1559a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			return err;
1560a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1561a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	val = nr64_mac(XMAC_CONFIG);
1562a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	val &= ~XMAC_CONFIG_LED_POLARITY;
1563a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	val |= XMAC_CONFIG_FORCE_LED_ON;
1564a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	nw64_mac(XMAC_CONFIG, val);
1565a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1566a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	val = nr64(MIF_CONFIG);
1567a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	val |= MIF_CONFIG_INDIRECT_MODE;
1568a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	nw64(MIF_CONFIG, val);
1569a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1570a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = bcm8704_reset(np);
1571a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err)
1572a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		return err;
1573a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1574a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = xcvr_10g_set_lb_bcm870x(np);
1575a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err)
1576a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		return err;
1577a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1578a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = bcm8706_init_user_dev3(np);
1579a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err)
1580a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		return err;
1581a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1582a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = xcvr_diag_bcm870x(np);
1583a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err)
1584a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		return err;
1585a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1586a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	return 0;
1587a5d6ab56daa439d681aab29955498486e452224dMatheos Worku}
1588a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1589a5d6ab56daa439d681aab29955498486e452224dMatheos Workustatic int xcvr_init_10g_bcm8704(struct niu *np)
1590a5d6ab56daa439d681aab29955498486e452224dMatheos Worku{
1591a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	int err;
1592a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1593a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = bcm8704_reset(np);
1594a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err)
1595a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		return err;
1596a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1597a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = bcm8704_init_user_dev3(np);
1598a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err)
1599a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		return err;
1600a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1601a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = xcvr_10g_set_lb_bcm870x(np);
1602a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err)
1603a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		return err;
1604a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1605a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err =  xcvr_diag_bcm870x(np);
1606a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err)
1607a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		return err;
1608a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1609a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	return 0;
1610a5d6ab56daa439d681aab29955498486e452224dMatheos Worku}
1611a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1612b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindnerstatic int xcvr_init_10g(struct niu *np)
1613b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner{
1614b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	int phy_id, err;
1615b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	u64 val;
1616b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1617b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	val = nr64_mac(XMAC_CONFIG);
1618b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	val &= ~XMAC_CONFIG_LED_POLARITY;
1619b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	val |= XMAC_CONFIG_FORCE_LED_ON;
1620b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	nw64_mac(XMAC_CONFIG, val);
1621b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1622b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	/* XXX shared resource, lock parent XXX */
1623b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	val = nr64(MIF_CONFIG);
1624b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	val |= MIF_CONFIG_INDIRECT_MODE;
1625b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	nw64(MIF_CONFIG, val);
1626b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1627b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	phy_id = phy_decode(np->parent->port_phy, np->port);
1628b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	phy_id = np->parent->phy_probe_info.phy_id[phy_id][np->port];
1629b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1630b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	/* handle different phy types */
1631b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	switch (phy_id & NIU_PHY_ID_MASK) {
1632b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	case NIU_PHY_ID_MRVL88X2011:
1633b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		err = xcvr_init_10g_mrvl88x2011(np);
1634b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		break;
1635b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1636b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	default: /* bcom 8704 */
1637b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		err = xcvr_init_10g_bcm8704(np);
1638b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		break;
1639b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	}
1640b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1641f344c25dbab1a392ef7a7afc8ca061b3b7285423David S. Miller	return err;
1642b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner}
1643b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1644a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int mii_reset(struct niu *np)
1645a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
1646a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int limit, err;
1647a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1648a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mii_write(np, np->phy_addr, MII_BMCR, BMCR_RESET);
1649a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
1650a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1651a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1652a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	limit = 1000;
1653a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (--limit >= 0) {
1654a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		udelay(500);
1655a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = mii_read(np, np->phy_addr, MII_BMCR);
1656a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err < 0)
1657a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
1658a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!(err & BMCR_RESET))
1659a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
1660a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
1661a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (limit < 0) {
1662f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "Port %u MII would not reset, bmcr[%04x]\n",
1663f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   np->port, err);
1664a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
1665a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
1666a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1667a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
1668a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
1669a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
16705fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Workustatic int xcvr_init_1g_rgmii(struct niu *np)
16715fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku{
16725fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	int err;
16735fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	u64 val;
16745fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	u16 bmcr, bmsr, estat;
16755fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
16765fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	val = nr64(MIF_CONFIG);
16775fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	val &= ~MIF_CONFIG_INDIRECT_MODE;
16785fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	nw64(MIF_CONFIG, val);
16795fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
16805fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	err = mii_reset(np);
16815fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (err)
16825fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		return err;
16835fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
16845fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	err = mii_read(np, np->phy_addr, MII_BMSR);
16855fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (err < 0)
16865fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		return err;
16875fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	bmsr = err;
16885fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
16895fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	estat = 0;
16905fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (bmsr & BMSR_ESTATEN) {
16915fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = mii_read(np, np->phy_addr, MII_ESTATUS);
16925fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (err < 0)
16935fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			return err;
16945fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		estat = err;
16955fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
16965fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
16975fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	bmcr = 0;
16985fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	err = mii_write(np, np->phy_addr, MII_BMCR, bmcr);
16995fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (err)
17005fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		return err;
17015fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
17025fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (bmsr & BMSR_ESTATEN) {
17035fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		u16 ctrl1000 = 0;
17045fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
17055fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (estat & ESTATUS_1000_TFULL)
17065fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			ctrl1000 |= ADVERTISE_1000FULL;
17075fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = mii_write(np, np->phy_addr, MII_CTRL1000, ctrl1000);
17085fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (err)
17095fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			return err;
17105fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
17115fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
17125fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	bmcr = (BMCR_SPEED1000 | BMCR_FULLDPLX);
17135fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
17145fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	err = mii_write(np, np->phy_addr, MII_BMCR, bmcr);
17155fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (err)
17165fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		return err;
17175fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
17185fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	err = mii_read(np, np->phy_addr, MII_BMCR);
17195fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (err < 0)
17205fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		return err;
17215fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	bmcr = mii_read(np, np->phy_addr, MII_BMCR);
17225fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
17235fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	err = mii_read(np, np->phy_addr, MII_BMSR);
17245fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (err < 0)
17255fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		return err;
17265fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
17275fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	return 0;
17285fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku}
17295fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
1730a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int mii_init_common(struct niu *np)
1731a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
1732a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_link_config *lp = &np->link_config;
1733a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u16 bmcr, bmsr, adv, estat;
1734a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
1735a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1736a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mii_reset(np);
1737a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
1738a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1739a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1740a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mii_read(np, np->phy_addr, MII_BMSR);
1741a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
1742a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1743a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	bmsr = err;
1744a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1745a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	estat = 0;
1746a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (bmsr & BMSR_ESTATEN) {
1747a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = mii_read(np, np->phy_addr, MII_ESTATUS);
1748a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err < 0)
1749a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
1750a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		estat = err;
1751a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
1752a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1753a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	bmcr = 0;
1754a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mii_write(np, np->phy_addr, MII_BMCR, bmcr);
1755a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
1756a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1757a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1758a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (lp->loopback_mode == LOOPBACK_MAC) {
1759a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		bmcr |= BMCR_LOOPBACK;
1760a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (lp->active_speed == SPEED_1000)
1761a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			bmcr |= BMCR_SPEED1000;
1762a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (lp->active_duplex == DUPLEX_FULL)
1763a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			bmcr |= BMCR_FULLDPLX;
1764a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
1765a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1766a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (lp->loopback_mode == LOOPBACK_PHY) {
1767a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u16 aux;
1768a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1769a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		aux = (BCM5464R_AUX_CTL_EXT_LB |
1770a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       BCM5464R_AUX_CTL_WRITE_1);
1771a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = mii_write(np, np->phy_addr, BCM5464R_AUX_CTL, aux);
1772a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
1773a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
1774a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
1775a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
177638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (lp->autoneg) {
177738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		u16 ctrl1000;
177838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
177938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
178038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if ((bmsr & BMSR_10HALF) &&
178138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			(lp->advertising & ADVERTISED_10baseT_Half))
178238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			adv |= ADVERTISE_10HALF;
178338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if ((bmsr & BMSR_10FULL) &&
178438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			(lp->advertising & ADVERTISED_10baseT_Full))
178538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			adv |= ADVERTISE_10FULL;
178638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if ((bmsr & BMSR_100HALF) &&
178738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			(lp->advertising & ADVERTISED_100baseT_Half))
178838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			adv |= ADVERTISE_100HALF;
178938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if ((bmsr & BMSR_100FULL) &&
179038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			(lp->advertising & ADVERTISED_100baseT_Full))
179138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			adv |= ADVERTISE_100FULL;
179238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		err = mii_write(np, np->phy_addr, MII_ADVERTISE, adv);
1793a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
1794a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
179538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
179638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if (likely(bmsr & BMSR_ESTATEN)) {
179738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			ctrl1000 = 0;
179838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			if ((estat & ESTATUS_1000_THALF) &&
179938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov				(lp->advertising & ADVERTISED_1000baseT_Half))
180038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov				ctrl1000 |= ADVERTISE_1000HALF;
180138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			if ((estat & ESTATUS_1000_TFULL) &&
180238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov				(lp->advertising & ADVERTISED_1000baseT_Full))
180338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov				ctrl1000 |= ADVERTISE_1000FULL;
180438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			err = mii_write(np, np->phy_addr,
180538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov					MII_CTRL1000, ctrl1000);
180638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			if (err)
180738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov				return err;
180838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		}
180938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
181038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
181138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	} else {
181238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		/* !lp->autoneg */
181338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		int fulldpx;
181438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
181538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if (lp->duplex == DUPLEX_FULL) {
181638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			bmcr |= BMCR_FULLDPLX;
181738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			fulldpx = 1;
181838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		} else if (lp->duplex == DUPLEX_HALF)
181938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			fulldpx = 0;
182038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		else
182138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			return -EINVAL;
182238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
182338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if (lp->speed == SPEED_1000) {
182438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			/* if X-full requested while not supported, or
182538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			   X-half requested while not supported... */
182638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			if ((fulldpx && !(estat & ESTATUS_1000_TFULL)) ||
182738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov				(!fulldpx && !(estat & ESTATUS_1000_THALF)))
182838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov				return -EINVAL;
182938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			bmcr |= BMCR_SPEED1000;
183038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		} else if (lp->speed == SPEED_100) {
183138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			if ((fulldpx && !(bmsr & BMSR_100FULL)) ||
183238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov				(!fulldpx && !(bmsr & BMSR_100HALF)))
183338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov				return -EINVAL;
183438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			bmcr |= BMCR_SPEED100;
183538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		} else if (lp->speed == SPEED_10) {
183638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			if ((fulldpx && !(bmsr & BMSR_10FULL)) ||
183738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov				(!fulldpx && !(bmsr & BMSR_10HALF)))
183838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov				return -EINVAL;
183938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		} else
184038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			return -EINVAL;
1841a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
1842a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1843a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mii_write(np, np->phy_addr, MII_BMCR, bmcr);
1844a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
1845a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
1846a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
184738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov#if 0
1848a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mii_read(np, np->phy_addr, MII_BMCR);
1849a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
1850a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
185138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	bmcr = err;
185238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
1853a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mii_read(np, np->phy_addr, MII_BMSR);
1854a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
1855a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
185638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	bmsr = err;
185738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
1858f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	pr_info("Port %u after MII init bmcr[%04x] bmsr[%04x]\n",
1859a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->port, bmcr, bmsr);
1860a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif
1861a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1862a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
1863a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
1864a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1865a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int xcvr_init_1g(struct niu *np)
1866a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
1867a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
1868a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1869a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* XXX shared resource, lock parent XXX */
1870a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(MIF_CONFIG);
1871a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~MIF_CONFIG_INDIRECT_MODE;
1872a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(MIF_CONFIG, val);
1873a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1874a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return mii_init_common(np);
1875a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
1876a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1877a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_xcvr_init(struct niu *np)
1878a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
1879a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const struct niu_phy_ops *ops = np->phy_ops;
1880a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
1881a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1882a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = 0;
1883a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (ops->xcvr_init)
1884a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = ops->xcvr_init(np);
1885a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1886a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
1887a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
1888a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1889a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_serdes_init(struct niu *np)
1890a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
1891a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const struct niu_phy_ops *ops = np->phy_ops;
1892a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
1893a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1894a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = 0;
1895a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (ops->serdes_init)
1896a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = ops->serdes_init(np);
1897a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1898a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
1899a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
1900a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1901a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_init_xif(struct niu *);
19020c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindnerstatic void niu_handle_led(struct niu *, int status);
1903a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1904a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_link_status_common(struct niu *np, int link_up)
1905a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
1906a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_link_config *lp = &np->link_config;
1907a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct net_device *dev = np->dev;
1908a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long flags;
1909a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1910a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!netif_carrier_ok(dev) && link_up) {
1911f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netif_info(np, link, dev, "Link is up at %s, %s duplex\n",
1912f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   lp->active_speed == SPEED_10000 ? "10Gb/sec" :
1913f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   lp->active_speed == SPEED_1000 ? "1Gb/sec" :
1914f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   lp->active_speed == SPEED_100 ? "100Mbit/sec" :
1915f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   "10Mbit/sec",
1916f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   lp->active_duplex == DUPLEX_FULL ? "full" : "half");
1917a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1918a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		spin_lock_irqsave(&np->lock, flags);
1919a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_init_xif(np);
19200c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner		niu_handle_led(np, 1);
1921a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		spin_unlock_irqrestore(&np->lock, flags);
1922a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1923a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		netif_carrier_on(dev);
1924a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else if (netif_carrier_ok(dev) && !link_up) {
1925f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netif_warn(np, link, dev, "Link is down\n");
19260c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner		spin_lock_irqsave(&np->lock, flags);
19270c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner		niu_handle_led(np, 0);
19280c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner		spin_unlock_irqrestore(&np->lock, flags);
1929a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		netif_carrier_off(dev);
1930a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
1931a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1932a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
1933a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
1934a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1935b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindnerstatic int link_status_10g_mrvl(struct niu *np, int *link_up_p)
1936a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
1937b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	int err, link_up, pma_status, pcs_status;
1938a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1939a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	link_up = 0;
1940a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1941b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
1942b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			MRVL88X2011_10G_PMD_STATUS_2);
1943b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (err < 0)
1944b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		goto out;
1945a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1946b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	/* Check PMA/PMD Register: 1.0001.2 == 1 */
1947b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
1948b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			MRVL88X2011_PMA_PMD_STATUS_1);
1949b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (err < 0)
1950b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		goto out;
1951b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1952b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	pma_status = ((err & MRVL88X2011_LNK_STATUS_OK) ? 1 : 0);
1953b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1954b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner        /* Check PMC Register : 3.0001.2 == 1: read twice */
1955b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR,
1956b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			MRVL88X2011_PMA_PMD_STATUS_1);
1957b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (err < 0)
1958b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		goto out;
1959b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1960b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR,
1961b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			MRVL88X2011_PMA_PMD_STATUS_1);
1962b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (err < 0)
1963b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		goto out;
1964b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1965b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	pcs_status = ((err & MRVL88X2011_LNK_STATUS_OK) ? 1 : 0);
1966b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1967b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner        /* Check XGXS Register : 4.0018.[0-3,12] */
1968b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV4_ADDR,
1969b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			MRVL88X2011_10G_XGXS_LANE_STAT);
1970b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (err < 0)
1971a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out;
1972a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1973b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (err == (PHYXS_XGXS_LANE_STAT_ALINGED | PHYXS_XGXS_LANE_STAT_LANE3 |
1974b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		    PHYXS_XGXS_LANE_STAT_LANE2 | PHYXS_XGXS_LANE_STAT_LANE1 |
1975b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		    PHYXS_XGXS_LANE_STAT_LANE0 | PHYXS_XGXS_LANE_STAT_MAGIC |
1976b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		    0x800))
1977b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		link_up = (pma_status && pcs_status) ? 1 : 0;
1978b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1979b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	np->link_config.active_speed = SPEED_10000;
1980b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	np->link_config.active_duplex = DUPLEX_FULL;
1981b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	err = 0;
1982b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindnerout:
1983b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	mrvl88x2011_act_led(np, (link_up ?
1984b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner				 MRVL88X2011_LED_CTL_PCS_ACT :
1985b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner				 MRVL88X2011_LED_CTL_OFF));
1986b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1987b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	*link_up_p = link_up;
1988b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	return err;
1989b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner}
1990b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
1991a5d6ab56daa439d681aab29955498486e452224dMatheos Workustatic int link_status_10g_bcm8706(struct niu *np, int *link_up_p)
1992a5d6ab56daa439d681aab29955498486e452224dMatheos Worku{
1993a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	int err, link_up;
1994a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	link_up = 0;
1995a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
1996a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
1997a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			BCM8704_PMD_RCV_SIGDET);
19989c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang	if (err < 0 || err == 0xffff)
1999a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		goto out;
2000a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (!(err & PMD_RCV_SIGDET_GLOBAL)) {
2001a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		err = 0;
2002a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		goto out;
2003a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	}
2004a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2005a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
2006a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			BCM8704_PCS_10G_R_STATUS);
2007a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err < 0)
2008a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		goto out;
2009a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2010a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (!(err & PCS_10G_R_STATUS_BLK_LOCK)) {
2011a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		err = 0;
2012a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		goto out;
2013a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	}
2014a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2015a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
2016a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			BCM8704_PHYXS_XGXS_LANE_STAT);
2017a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err < 0)
2018a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		goto out;
2019a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (err != (PHYXS_XGXS_LANE_STAT_ALINGED |
2020a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		    PHYXS_XGXS_LANE_STAT_MAGIC |
2021a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		    PHYXS_XGXS_LANE_STAT_PATTEST |
2022a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		    PHYXS_XGXS_LANE_STAT_LANE3 |
2023a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		    PHYXS_XGXS_LANE_STAT_LANE2 |
2024a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		    PHYXS_XGXS_LANE_STAT_LANE1 |
2025a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		    PHYXS_XGXS_LANE_STAT_LANE0)) {
2026a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		err = 0;
2027a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		np->link_config.active_speed = SPEED_INVALID;
2028a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		np->link_config.active_duplex = DUPLEX_INVALID;
2029a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		goto out;
2030a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	}
2031a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2032a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	link_up = 1;
2033a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	np->link_config.active_speed = SPEED_10000;
2034a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	np->link_config.active_duplex = DUPLEX_FULL;
2035a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	err = 0;
2036a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2037a5d6ab56daa439d681aab29955498486e452224dMatheos Workuout:
2038a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	*link_up_p = link_up;
2039a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	return err;
2040a5d6ab56daa439d681aab29955498486e452224dMatheos Worku}
2041a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2042b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindnerstatic int link_status_10g_bcom(struct niu *np, int *link_up_p)
2043b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner{
2044b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	int err, link_up;
2045b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
2046b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	link_up = 0;
2047b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
2048a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
2049a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			BCM8704_PMD_RCV_SIGDET);
2050a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
2051a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out;
2052a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!(err & PMD_RCV_SIGDET_GLOBAL)) {
2053a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = 0;
2054a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out;
2055a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
2056a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2057a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
2058a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			BCM8704_PCS_10G_R_STATUS);
2059a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
2060a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out;
2061a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!(err & PCS_10G_R_STATUS_BLK_LOCK)) {
2062a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = 0;
2063a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out;
2064a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
2065a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2066a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
2067a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			BCM8704_PHYXS_XGXS_LANE_STAT);
2068a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
2069a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out;
2070a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2071a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err != (PHYXS_XGXS_LANE_STAT_ALINGED |
2072a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    PHYXS_XGXS_LANE_STAT_MAGIC |
2073a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    PHYXS_XGXS_LANE_STAT_LANE3 |
2074a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    PHYXS_XGXS_LANE_STAT_LANE2 |
2075a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    PHYXS_XGXS_LANE_STAT_LANE1 |
2076a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    PHYXS_XGXS_LANE_STAT_LANE0)) {
2077a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = 0;
2078a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out;
2079a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
2080a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2081a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	link_up = 1;
2082a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->link_config.active_speed = SPEED_10000;
2083a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->link_config.active_duplex = DUPLEX_FULL;
2084a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = 0;
2085a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2086a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerout:
2087b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	*link_up_p = link_up;
2088b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	return err;
2089b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner}
2090b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
2091b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindnerstatic int link_status_10g(struct niu *np, int *link_up_p)
2092b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner{
2093b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	unsigned long flags;
2094b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	int err = -EINVAL;
2095b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
2096b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	spin_lock_irqsave(&np->lock, flags);
2097b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
2098b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	if (np->link_config.loopback_mode == LOOPBACK_DISABLED) {
2099b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		int phy_id;
2100b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
2101b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		phy_id = phy_decode(np->parent->port_phy, np->port);
2102b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		phy_id = np->parent->phy_probe_info.phy_id[phy_id][np->port];
2103b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
2104b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		/* handle different phy types */
2105b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		switch (phy_id & NIU_PHY_ID_MASK) {
2106b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		case NIU_PHY_ID_MRVL88X2011:
2107b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			err = link_status_10g_mrvl(np, link_up_p);
2108b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			break;
2109b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
2110b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		default: /* bcom 8704 */
2111b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			err = link_status_10g_bcom(np, link_up_p);
2112b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner			break;
2113b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		}
2114b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner	}
2115b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner
2116a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_unlock_irqrestore(&np->lock, flags);
2117a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2118a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
2119a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2120a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2121a5d6ab56daa439d681aab29955498486e452224dMatheos Workustatic int niu_10g_phy_present(struct niu *np)
2122a5d6ab56daa439d681aab29955498486e452224dMatheos Worku{
2123a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	u64 sig, mask, val;
2124a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2125a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	sig = nr64(ESR_INT_SIGNALS);
2126a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	switch (np->port) {
2127a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	case 0:
2128a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		mask = ESR_INT_SIGNALS_P0_BITS;
2129a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		val = (ESR_INT_SRDY0_P0 |
2130a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		       ESR_INT_DET0_P0 |
2131a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		       ESR_INT_XSRDY_P0 |
2132a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		       ESR_INT_XDP_P0_CH3 |
2133a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		       ESR_INT_XDP_P0_CH2 |
2134a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		       ESR_INT_XDP_P0_CH1 |
2135a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		       ESR_INT_XDP_P0_CH0);
2136a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		break;
2137a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2138a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	case 1:
2139a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		mask = ESR_INT_SIGNALS_P1_BITS;
2140a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		val = (ESR_INT_SRDY0_P1 |
2141a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		       ESR_INT_DET0_P1 |
2142a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		       ESR_INT_XSRDY_P1 |
2143a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		       ESR_INT_XDP_P1_CH3 |
2144a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		       ESR_INT_XDP_P1_CH2 |
2145a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		       ESR_INT_XDP_P1_CH1 |
2146a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		       ESR_INT_XDP_P1_CH0);
2147a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		break;
2148a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2149a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	default:
2150a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		return 0;
2151a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	}
2152a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2153a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if ((sig & mask) != val)
2154a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		return 0;
2155a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	return 1;
2156a5d6ab56daa439d681aab29955498486e452224dMatheos Worku}
2157a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2158a5d6ab56daa439d681aab29955498486e452224dMatheos Workustatic int link_status_10g_hotplug(struct niu *np, int *link_up_p)
2159a5d6ab56daa439d681aab29955498486e452224dMatheos Worku{
2160a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	unsigned long flags;
2161a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	int err = 0;
2162a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	int phy_present;
2163a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	int phy_present_prev;
2164a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2165a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	spin_lock_irqsave(&np->lock, flags);
2166a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2167a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	if (np->link_config.loopback_mode == LOOPBACK_DISABLED) {
2168a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		phy_present_prev = (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) ?
2169a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			1 : 0;
2170a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		phy_present = niu_10g_phy_present(np);
2171a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		if (phy_present != phy_present_prev) {
2172a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			/* state change */
2173a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			if (phy_present) {
21749c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang				/* A NEM was just plugged in */
2175a5d6ab56daa439d681aab29955498486e452224dMatheos Worku				np->flags |= NIU_FLAGS_HOTPLUG_PHY_PRESENT;
2176a5d6ab56daa439d681aab29955498486e452224dMatheos Worku				if (np->phy_ops->xcvr_init)
2177a5d6ab56daa439d681aab29955498486e452224dMatheos Worku					err = np->phy_ops->xcvr_init(np);
2178a5d6ab56daa439d681aab29955498486e452224dMatheos Worku				if (err) {
21799c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang					err = mdio_read(np, np->phy_addr,
21809c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang						BCM8704_PHYXS_DEV_ADDR, MII_BMCR);
21819c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang					if (err == 0xffff) {
21829c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang						/* No mdio, back-to-back XAUI */
21839c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang						goto out;
21849c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang					}
2185a5d6ab56daa439d681aab29955498486e452224dMatheos Worku					/* debounce */
2186a5d6ab56daa439d681aab29955498486e452224dMatheos Worku					np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT;
2187a5d6ab56daa439d681aab29955498486e452224dMatheos Worku				}
2188a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			} else {
2189a5d6ab56daa439d681aab29955498486e452224dMatheos Worku				np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT;
2190a5d6ab56daa439d681aab29955498486e452224dMatheos Worku				*link_up_p = 0;
2191f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				netif_warn(np, link, np->dev,
2192f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches					   "Hotplug PHY Removed\n");
2193a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			}
2194a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		}
21959c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Changout:
21969c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang		if (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) {
2197a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			err = link_status_10g_bcm8706(np, link_up_p);
21989c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang			if (err == 0xffff) {
21999c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang				/* No mdio, back-to-back XAUI: it is C10NEM */
22009c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang				*link_up_p = 1;
22019c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang				np->link_config.active_speed = SPEED_10000;
22029c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang				np->link_config.active_duplex = DUPLEX_FULL;
22039c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang			}
22049c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang		}
2205a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	}
2206a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2207a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	spin_unlock_irqrestore(&np->lock, flags);
2208a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
22099c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang	return 0;
2210a5d6ab56daa439d681aab29955498486e452224dMatheos Worku}
2211a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
2212a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_link_status(struct niu *np, int *link_up_p)
2213a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2214a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const struct niu_phy_ops *ops = np->phy_ops;
2215a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
2216a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2217a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = 0;
2218a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (ops->link_status)
2219a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = ops->link_status(np, link_up_p);
2220a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2221a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
2222a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2223a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2224a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_timer(unsigned long __opaque)
2225a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2226a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = (struct niu *) __opaque;
2227a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long off;
2228a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err, link_up;
2229a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2230a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_link_status(np, &link_up);
2231a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err)
2232a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_link_status_common(np, link_up);
2233a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2234a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (netif_carrier_ok(np->dev))
2235a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		off = 5 * HZ;
2236a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
2237a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		off = 1 * HZ;
2238a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->timer.expires = jiffies + off;
2239a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2240a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	add_timer(&np->timer);
2241a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2242a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
22435fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Workustatic const struct niu_phy_ops phy_ops_10g_serdes = {
22445fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	.serdes_init		= serdes_init_10g_serdes,
22455fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	.link_status		= link_status_10g_serdes,
22465fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku};
22475fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
2248e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Beherastatic const struct niu_phy_ops phy_ops_10g_serdes_niu = {
2249e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	.serdes_init		= serdes_init_niu_10g_serdes,
2250e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	.link_status		= link_status_10g_serdes,
2251e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera};
2252e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
2253e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Beherastatic const struct niu_phy_ops phy_ops_1g_serdes_niu = {
2254e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	.serdes_init		= serdes_init_niu_1g_serdes,
2255e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	.link_status		= link_status_1g_serdes,
2256e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera};
2257e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
22585fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Workustatic const struct niu_phy_ops phy_ops_1g_rgmii = {
22595fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	.xcvr_init		= xcvr_init_1g_rgmii,
22605fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	.link_status		= link_status_1g_rgmii,
22615fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku};
22625fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
2263a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct niu_phy_ops phy_ops_10g_fiber_niu = {
2264e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	.serdes_init		= serdes_init_niu_10g_fiber,
2265a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.xcvr_init		= xcvr_init_10g,
2266a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.link_status		= link_status_10g,
2267a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
2268a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2269a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct niu_phy_ops phy_ops_10g_fiber = {
2270a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.serdes_init		= serdes_init_10g,
2271a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.xcvr_init		= xcvr_init_10g,
2272a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.link_status		= link_status_10g,
2273a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
2274a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2275a5d6ab56daa439d681aab29955498486e452224dMatheos Workustatic const struct niu_phy_ops phy_ops_10g_fiber_hotplug = {
2276a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	.serdes_init		= serdes_init_10g,
2277a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	.xcvr_init		= xcvr_init_10g_bcm8706,
2278a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	.link_status		= link_status_10g_hotplug,
2279a5d6ab56daa439d681aab29955498486e452224dMatheos Worku};
2280a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
22819c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Changstatic const struct niu_phy_ops phy_ops_niu_10g_hotplug = {
22829c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang	.serdes_init		= serdes_init_niu_10g_fiber,
22839c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang	.xcvr_init		= xcvr_init_10g_bcm8706,
22849c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang	.link_status		= link_status_10g_hotplug,
22859c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang};
22869c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang
2287a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct niu_phy_ops phy_ops_10g_copper = {
2288a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.serdes_init		= serdes_init_10g,
2289a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.link_status		= link_status_10g, /* XXX */
2290a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
2291a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2292a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct niu_phy_ops phy_ops_1g_fiber = {
2293a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.serdes_init		= serdes_init_1g,
2294a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.xcvr_init		= xcvr_init_1g,
2295a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.link_status		= link_status_1g,
2296a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
2297a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2298a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct niu_phy_ops phy_ops_1g_copper = {
2299a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.xcvr_init		= xcvr_init_1g,
2300a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.link_status		= link_status_1g,
2301a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
2302a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2303a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstruct niu_phy_template {
2304a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const struct niu_phy_ops	*ops;
2305a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u32				phy_addr_base;
2306a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
2307a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2308e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Beherastatic const struct niu_phy_template phy_template_niu_10g_fiber = {
2309a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.ops		= &phy_ops_10g_fiber_niu,
2310a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.phy_addr_base	= 16,
2311a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
2312a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2313e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Beherastatic const struct niu_phy_template phy_template_niu_10g_serdes = {
2314e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	.ops		= &phy_ops_10g_serdes_niu,
2315e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	.phy_addr_base	= 0,
2316e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera};
2317e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
2318e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Beherastatic const struct niu_phy_template phy_template_niu_1g_serdes = {
2319e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	.ops		= &phy_ops_1g_serdes_niu,
2320e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	.phy_addr_base	= 0,
2321e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera};
2322e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
2323a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct niu_phy_template phy_template_10g_fiber = {
2324a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.ops		= &phy_ops_10g_fiber,
2325a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.phy_addr_base	= 8,
2326a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
2327a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2328a5d6ab56daa439d681aab29955498486e452224dMatheos Workustatic const struct niu_phy_template phy_template_10g_fiber_hotplug = {
2329a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	.ops		= &phy_ops_10g_fiber_hotplug,
2330a5d6ab56daa439d681aab29955498486e452224dMatheos Worku	.phy_addr_base	= 8,
2331a5d6ab56daa439d681aab29955498486e452224dMatheos Worku};
2332a5d6ab56daa439d681aab29955498486e452224dMatheos Worku
23339c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Changstatic const struct niu_phy_template phy_template_niu_10g_hotplug = {
23349c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang	.ops		= &phy_ops_niu_10g_hotplug,
23359c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang	.phy_addr_base	= 8,
23369c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang};
23379c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang
2338a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct niu_phy_template phy_template_10g_copper = {
2339a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.ops		= &phy_ops_10g_copper,
2340a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.phy_addr_base	= 10,
2341a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
2342a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2343a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct niu_phy_template phy_template_1g_fiber = {
2344a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.ops		= &phy_ops_1g_fiber,
2345a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.phy_addr_base	= 0,
2346a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
2347a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2348a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct niu_phy_template phy_template_1g_copper = {
2349a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.ops		= &phy_ops_1g_copper,
2350a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.phy_addr_base	= 0,
2351a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
2352a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
23535fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Workustatic const struct niu_phy_template phy_template_1g_rgmii = {
23545fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	.ops		= &phy_ops_1g_rgmii,
23555fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	.phy_addr_base	= 0,
23565fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku};
23575fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
23585fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Workustatic const struct niu_phy_template phy_template_10g_serdes = {
23595fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	.ops		= &phy_ops_10g_serdes,
23605fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	.phy_addr_base	= 0,
23615fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku};
23625fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
23635fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Workustatic int niu_atca_port_num[4] = {
23645fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	0, 0,  11, 10
23655fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku};
23665fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
23675fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Workustatic int serdes_init_10g_serdes(struct niu *np)
23685fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku{
23695fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	struct niu_link_config *lp = &np->link_config;
23705fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	unsigned long ctrl_reg, test_cfg_reg, pll_cfg, i;
23715fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	u64 ctrl_val, test_cfg_val, sig, mask, val;
23725fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
23735fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	switch (np->port) {
23745fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	case 0:
23755fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		ctrl_reg = ENET_SERDES_0_CTRL_CFG;
23765fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		test_cfg_reg = ENET_SERDES_0_TEST_CFG;
23775fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		pll_cfg = ENET_SERDES_0_PLL_CFG;
23785fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		break;
23795fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	case 1:
23805fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		ctrl_reg = ENET_SERDES_1_CTRL_CFG;
23815fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		test_cfg_reg = ENET_SERDES_1_TEST_CFG;
23825fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		pll_cfg = ENET_SERDES_1_PLL_CFG;
23835fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		break;
23845fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
23855fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	default:
23865fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		return -EINVAL;
23875fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
23885fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	ctrl_val = (ENET_SERDES_CTRL_SDET_0 |
23895fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    ENET_SERDES_CTRL_SDET_1 |
23905fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    ENET_SERDES_CTRL_SDET_2 |
23915fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    ENET_SERDES_CTRL_SDET_3 |
23925fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x5 << ENET_SERDES_CTRL_EMPH_0_SHIFT) |
23935fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x5 << ENET_SERDES_CTRL_EMPH_1_SHIFT) |
23945fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x5 << ENET_SERDES_CTRL_EMPH_2_SHIFT) |
23955fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x5 << ENET_SERDES_CTRL_EMPH_3_SHIFT) |
23965fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x1 << ENET_SERDES_CTRL_LADJ_0_SHIFT) |
23975fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x1 << ENET_SERDES_CTRL_LADJ_1_SHIFT) |
23985fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x1 << ENET_SERDES_CTRL_LADJ_2_SHIFT) |
23995fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    (0x1 << ENET_SERDES_CTRL_LADJ_3_SHIFT));
24005fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	test_cfg_val = 0;
24015fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
24025fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (lp->loopback_mode == LOOPBACK_PHY) {
24035fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		test_cfg_val |= ((ENET_TEST_MD_PAD_LOOPBACK <<
24045fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				  ENET_SERDES_TEST_MD_0_SHIFT) |
24055fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				 (ENET_TEST_MD_PAD_LOOPBACK <<
24065fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				  ENET_SERDES_TEST_MD_1_SHIFT) |
24075fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				 (ENET_TEST_MD_PAD_LOOPBACK <<
24085fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				  ENET_SERDES_TEST_MD_2_SHIFT) |
24095fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				 (ENET_TEST_MD_PAD_LOOPBACK <<
24105fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				  ENET_SERDES_TEST_MD_3_SHIFT));
24115fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
24125fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
24135fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	esr_reset(np);
24145fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	nw64(pll_cfg, ENET_SERDES_PLL_FBDIV2);
24155fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	nw64(ctrl_reg, ctrl_val);
24165fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	nw64(test_cfg_reg, test_cfg_val);
24175fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
24185fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	/* Initialize all 4 lanes of the SERDES.  */
24195fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	for (i = 0; i < 4; i++) {
24205fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		u32 rxtx_ctrl, glue0;
24217c34eb897362a51133222ef4229628469333f4d9Hannes Eder		int err;
24225fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
24235fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = esr_read_rxtx_ctrl(np, i, &rxtx_ctrl);
24245fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (err)
24255fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			return err;
24265fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = esr_read_glue0(np, i, &glue0);
24275fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (err)
24285fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			return err;
24295fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
24305fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		rxtx_ctrl &= ~(ESR_RXTX_CTRL_VMUXLO);
24315fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		rxtx_ctrl |= (ESR_RXTX_CTRL_ENSTRETCH |
24325fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			      (2 << ESR_RXTX_CTRL_VMUXLO_SHIFT));
24335fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
24345fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		glue0 &= ~(ESR_GLUE_CTRL0_SRATE |
24355fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			   ESR_GLUE_CTRL0_THCNT |
24365fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			   ESR_GLUE_CTRL0_BLTIME);
24375fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		glue0 |= (ESR_GLUE_CTRL0_RXLOSENAB |
24385fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			  (0xf << ESR_GLUE_CTRL0_SRATE_SHIFT) |
24395fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			  (0xff << ESR_GLUE_CTRL0_THCNT_SHIFT) |
24405fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			  (BLTIME_300_CYCLES <<
24415fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			   ESR_GLUE_CTRL0_BLTIME_SHIFT));
24425fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
24435fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = esr_write_rxtx_ctrl(np, i, rxtx_ctrl);
24445fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (err)
24455fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			return err;
24465fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = esr_write_glue0(np, i, glue0);
24475fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (err)
24485fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			return err;
24495fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
24505fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
24515fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
24525fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	sig = nr64(ESR_INT_SIGNALS);
24535fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	switch (np->port) {
24545fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	case 0:
24555fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		mask = ESR_INT_SIGNALS_P0_BITS;
24565fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		val = (ESR_INT_SRDY0_P0 |
24575fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		       ESR_INT_DET0_P0 |
24585fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		       ESR_INT_XSRDY_P0 |
24595fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		       ESR_INT_XDP_P0_CH3 |
24605fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		       ESR_INT_XDP_P0_CH2 |
24615fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		       ESR_INT_XDP_P0_CH1 |
24625fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		       ESR_INT_XDP_P0_CH0);
24635fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		break;
24645fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
24655fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	case 1:
24665fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		mask = ESR_INT_SIGNALS_P1_BITS;
24675fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		val = (ESR_INT_SRDY0_P1 |
24685fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		       ESR_INT_DET0_P1 |
24695fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		       ESR_INT_XSRDY_P1 |
24705fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		       ESR_INT_XDP_P1_CH3 |
24715fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		       ESR_INT_XDP_P1_CH2 |
24725fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		       ESR_INT_XDP_P1_CH1 |
24735fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		       ESR_INT_XDP_P1_CH0);
24745fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		break;
24755fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
24765fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	default:
24775fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		return -EINVAL;
24785fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
24795fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
24805fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if ((sig & mask) != val) {
24815fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		int err;
24825fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = serdes_init_1g_serdes(np);
24835fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (!err) {
24845fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			np->flags &= ~NIU_FLAGS_10G;
24855fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			np->mac_xcvr = MAC_XCVR_PCS;
24865fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		}  else {
2487f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			netdev_err(np->dev, "Port %u 10G/1G SERDES Link Failed\n",
2488f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				   np->port);
24895fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			return -ENODEV;
24905fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		}
24915fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
24925fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
24935fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	return 0;
24945fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku}
24955fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
2496a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_determine_phy_disposition(struct niu *np)
2497a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2498a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent = np->parent;
2499a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u8 plat_type = parent->plat_type;
2500a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const struct niu_phy_template *tp;
2501a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u32 phy_addr_off = 0;
2502a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2503a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (plat_type == PLAT_TYPE_NIU) {
2504e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		switch (np->flags &
2505e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			(NIU_FLAGS_10G |
2506e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			 NIU_FLAGS_FIBER |
2507e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			 NIU_FLAGS_XCVR_SERDES)) {
2508e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		case NIU_FLAGS_10G | NIU_FLAGS_XCVR_SERDES:
2509e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			/* 10G Serdes */
2510e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			tp = &phy_template_niu_10g_serdes;
2511e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			break;
2512e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		case NIU_FLAGS_XCVR_SERDES:
2513e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			/* 1G Serdes */
2514e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			tp = &phy_template_niu_1g_serdes;
2515e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			break;
2516e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		case NIU_FLAGS_10G | NIU_FLAGS_FIBER:
2517e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			/* 10G Fiber */
2518e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		default:
25199c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang			if (np->flags & NIU_FLAGS_HOTPLUG_PHY) {
25209c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang				tp = &phy_template_niu_10g_hotplug;
25219c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang				if (np->port == 0)
25229c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang					phy_addr_off = 8;
25239c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang				if (np->port == 1)
25249c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang					phy_addr_off = 12;
25259c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang			} else {
25269c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang				tp = &phy_template_niu_10g_fiber;
25279c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang				phy_addr_off += np->port;
25289c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang			}
2529e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			break;
2530e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		}
2531a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
25325fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		switch (np->flags &
25335fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			(NIU_FLAGS_10G |
25345fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			 NIU_FLAGS_FIBER |
25355fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			 NIU_FLAGS_XCVR_SERDES)) {
2536a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		case 0:
2537a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			/* 1G copper */
2538a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			tp = &phy_template_1g_copper;
2539a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (plat_type == PLAT_TYPE_VF_P0)
2540a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				phy_addr_off = 10;
2541a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			else if (plat_type == PLAT_TYPE_VF_P1)
2542a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				phy_addr_off = 26;
2543a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2544a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			phy_addr_off += (np->port ^ 0x3);
2545a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
2546a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2547a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		case NIU_FLAGS_10G:
2548a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			/* 10G copper */
2549e0d8496a66de9eca13a88d93a5642db47e5a2b60Constantin Baranov			tp = &phy_template_10g_copper;
2550a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
2551a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2552a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		case NIU_FLAGS_FIBER:
2553a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			/* 1G fiber */
2554a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			tp = &phy_template_1g_fiber;
2555a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
2556a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2557a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		case NIU_FLAGS_10G | NIU_FLAGS_FIBER:
2558a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			/* 10G fiber */
2559a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			tp = &phy_template_10g_fiber;
2560a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (plat_type == PLAT_TYPE_VF_P0 ||
2561a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			    plat_type == PLAT_TYPE_VF_P1)
2562a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				phy_addr_off = 8;
2563a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			phy_addr_off += np->port;
2564a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			if (np->flags & NIU_FLAGS_HOTPLUG_PHY) {
2565a5d6ab56daa439d681aab29955498486e452224dMatheos Worku				tp = &phy_template_10g_fiber_hotplug;
2566a5d6ab56daa439d681aab29955498486e452224dMatheos Worku				if (np->port == 0)
2567a5d6ab56daa439d681aab29955498486e452224dMatheos Worku					phy_addr_off = 8;
2568a5d6ab56daa439d681aab29955498486e452224dMatheos Worku				if (np->port == 1)
2569a5d6ab56daa439d681aab29955498486e452224dMatheos Worku					phy_addr_off = 12;
2570a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			}
2571a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
2572a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
25735fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		case NIU_FLAGS_10G | NIU_FLAGS_XCVR_SERDES:
25745fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		case NIU_FLAGS_XCVR_SERDES | NIU_FLAGS_FIBER:
25755fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		case NIU_FLAGS_XCVR_SERDES:
25765fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			switch(np->port) {
25775fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			case 0:
25785fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			case 1:
25795fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				tp = &phy_template_10g_serdes;
25805fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				break;
25815fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			case 2:
25825fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			case 3:
25835fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				tp = &phy_template_1g_rgmii;
25845fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				break;
25855fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			default:
25865fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				return -EINVAL;
25875fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				break;
25885fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			}
25895fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			phy_addr_off = niu_atca_port_num[np->port];
25905fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			break;
25915fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
2592a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		default:
2593a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return -EINVAL;
2594a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
2595a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
2596a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2597a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->phy_ops = tp->ops;
2598a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->phy_addr = tp->phy_addr_base + phy_addr_off;
2599a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2600a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
2601a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2602a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2603a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_init_link(struct niu *np)
2604a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2605a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent = np->parent;
2606a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err, ignore;
2607a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2608a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (parent->plat_type == PLAT_TYPE_NIU) {
2609a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_xcvr_init(np);
2610a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
2611a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
2612a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		msleep(200);
2613a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
2614a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_serdes_init(np);
26159c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang	if (err && !(np->flags & NIU_FLAGS_HOTPLUG_PHY))
2616a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
2617a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	msleep(200);
2618a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_xcvr_init(np);
26199c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang	if (!err || (np->flags & NIU_FLAGS_HOTPLUG_PHY))
2620a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_link_status(np, &ignore);
2621a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
2622a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2623a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2624a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_set_primary_mac(struct niu *np, unsigned char *addr)
2625a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2626a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u16 reg0 = addr[4] << 8 | addr[5];
2627a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u16 reg1 = addr[2] << 8 | addr[3];
2628a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u16 reg2 = addr[0] << 8 | addr[1];
2629a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2630a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC) {
2631a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(XMAC_ADDR0, reg0);
2632a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(XMAC_ADDR1, reg1);
2633a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(XMAC_ADDR2, reg2);
2634a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
2635a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(BMAC_ADDR0, reg0);
2636a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(BMAC_ADDR1, reg1);
2637a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(BMAC_ADDR2, reg2);
2638a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
2639a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2640a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2641a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_num_alt_addr(struct niu *np)
2642a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2643a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC)
2644a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return XMAC_NUM_ALT_ADDR;
2645a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
2646a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return BMAC_NUM_ALT_ADDR;
2647a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2648a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2649a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_set_alt_mac(struct niu *np, int index, unsigned char *addr)
2650a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2651a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u16 reg0 = addr[4] << 8 | addr[5];
2652a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u16 reg1 = addr[2] << 8 | addr[3];
2653a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u16 reg2 = addr[0] << 8 | addr[1];
2654a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2655a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (index >= niu_num_alt_addr(np))
2656a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
2657a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2658a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC) {
2659a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(XMAC_ALT_ADDR0(index), reg0);
2660a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(XMAC_ALT_ADDR1(index), reg1);
2661a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(XMAC_ALT_ADDR2(index), reg2);
2662a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
2663a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(BMAC_ALT_ADDR0(index), reg0);
2664a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(BMAC_ALT_ADDR1(index), reg1);
2665a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(BMAC_ALT_ADDR2(index), reg2);
2666a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
2667a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2668a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
2669a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2670a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2671a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_enable_alt_mac(struct niu *np, int index, int on)
2672a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2673a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long reg;
2674a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val, mask;
2675a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2676a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (index >= niu_num_alt_addr(np))
2677a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
2678a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2679fa907895b7b776208a1406efe5ba7ffe0f49f507Matheos Worku	if (np->flags & NIU_FLAGS_XMAC) {
2680a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		reg = XMAC_ADDR_CMPEN;
2681fa907895b7b776208a1406efe5ba7ffe0f49f507Matheos Worku		mask = 1 << index;
2682fa907895b7b776208a1406efe5ba7ffe0f49f507Matheos Worku	} else {
2683a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		reg = BMAC_ADDR_CMPEN;
2684fa907895b7b776208a1406efe5ba7ffe0f49f507Matheos Worku		mask = 1 << (index + 1);
2685fa907895b7b776208a1406efe5ba7ffe0f49f507Matheos Worku	}
2686a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2687a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(reg);
2688a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on)
2689a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= mask;
2690a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
2691a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~mask;
2692a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(reg, val);
2693a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2694a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
2695a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2696a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2697a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __set_rdc_table_num_hw(struct niu *np, unsigned long reg,
2698a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				   int num, int mac_pref)
2699a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2700a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64_mac(reg);
2701a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~(HOST_INFO_MACRDCTBLN | HOST_INFO_MPR);
2702a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= num;
2703a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (mac_pref)
2704a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= HOST_INFO_MPR;
2705a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(reg, val);
2706a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2707a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2708a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __set_rdc_table_num(struct niu *np,
2709a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       int xmac_index, int bmac_index,
2710a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       int rdc_table_num, int mac_pref)
2711a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2712a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long reg;
2713a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2714a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (rdc_table_num & ~HOST_INFO_MACRDCTBLN)
2715a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
2716a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC)
2717a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		reg = XMAC_HOST_INFO(xmac_index);
2718a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
2719a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		reg = BMAC_HOST_INFO(bmac_index);
2720a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	__set_rdc_table_num_hw(np, reg, rdc_table_num, mac_pref);
2721a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
2722a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2723a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2724a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_set_primary_mac_rdc_table(struct niu *np, int table_num,
2725a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					 int mac_pref)
2726a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2727a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return __set_rdc_table_num(np, 17, 0, table_num, mac_pref);
2728a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2729a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2730a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_set_multicast_mac_rdc_table(struct niu *np, int table_num,
2731a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					   int mac_pref)
2732a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2733a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return __set_rdc_table_num(np, 16, 8, table_num, mac_pref);
2734a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2735a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2736a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_set_alt_mac_rdc_table(struct niu *np, int idx,
2737a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				     int table_num, int mac_pref)
2738a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2739a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (idx >= niu_num_alt_addr(np))
2740a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
2741a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return __set_rdc_table_num(np, idx, idx + 1, table_num, mac_pref);
2742a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2743a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2744a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic u64 vlan_entry_set_parity(u64 reg_val)
2745a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2746a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 port01_mask;
2747a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 port23_mask;
2748a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2749a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	port01_mask = 0x00ff;
2750a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	port23_mask = 0xff00;
2751a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2752a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (hweight64(reg_val & port01_mask) & 1)
2753a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		reg_val |= ENET_VLAN_TBL_PARITY0;
2754a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
2755a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		reg_val &= ~ENET_VLAN_TBL_PARITY0;
2756a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2757a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (hweight64(reg_val & port23_mask) & 1)
2758a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		reg_val |= ENET_VLAN_TBL_PARITY1;
2759a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
2760a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		reg_val &= ~ENET_VLAN_TBL_PARITY1;
2761a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2762a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return reg_val;
2763a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2764a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2765a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void vlan_tbl_write(struct niu *np, unsigned long index,
2766a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			   int port, int vpr, int rdc_table)
2767a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2768a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 reg_val = nr64(ENET_VLAN_TBL(index));
2769a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2770a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	reg_val &= ~((ENET_VLAN_TBL_VPR |
2771a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		      ENET_VLAN_TBL_VLANRDCTBLN) <<
2772a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		     ENET_VLAN_TBL_SHIFT(port));
2773a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (vpr)
2774a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		reg_val |= (ENET_VLAN_TBL_VPR <<
2775a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			    ENET_VLAN_TBL_SHIFT(port));
2776a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	reg_val |= (rdc_table << ENET_VLAN_TBL_SHIFT(port));
2777a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2778a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	reg_val = vlan_entry_set_parity(reg_val);
2779a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2780a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ENET_VLAN_TBL(index), reg_val);
2781a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2782a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2783a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void vlan_tbl_clear(struct niu *np)
2784a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2785a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
2786a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2787a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < ENET_VLAN_TBL_NUM_ENTRIES; i++)
2788a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64(ENET_VLAN_TBL(i), 0);
2789a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2790a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2791a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int tcam_wait_bit(struct niu *np, u64 bit)
2792a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2793a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int limit = 1000;
2794a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2795a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (--limit > 0) {
2796a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (nr64(TCAM_CTL) & bit)
2797a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
2798a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		udelay(1);
2799a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
2800d2a928e4bfc75170af641f073475fc974cf176c2roel kluin	if (limit <= 0)
2801a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
2802a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2803a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
2804a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2805a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2806a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int tcam_flush(struct niu *np, int index)
2807a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2808a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_KEY_0, 0x00);
2809a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_KEY_MASK_0, 0xff);
2810a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_WRITE | index));
2811a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2812a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return tcam_wait_bit(np, TCAM_CTL_STAT);
2813a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2814a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2815a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#if 0
2816a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int tcam_read(struct niu *np, int index,
2817a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		     u64 *key, u64 *mask)
2818a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2819a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
2820a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2821a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_READ | index));
2822a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = tcam_wait_bit(np, TCAM_CTL_STAT);
2823a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err) {
2824a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		key[0] = nr64(TCAM_KEY_0);
2825a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		key[1] = nr64(TCAM_KEY_1);
2826a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		key[2] = nr64(TCAM_KEY_2);
2827a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		key[3] = nr64(TCAM_KEY_3);
2828a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mask[0] = nr64(TCAM_KEY_MASK_0);
2829a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mask[1] = nr64(TCAM_KEY_MASK_1);
2830a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mask[2] = nr64(TCAM_KEY_MASK_2);
2831a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mask[3] = nr64(TCAM_KEY_MASK_3);
2832a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
2833a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
2834a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2835a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif
2836a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2837a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int tcam_write(struct niu *np, int index,
2838a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		      u64 *key, u64 *mask)
2839a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2840a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_KEY_0, key[0]);
2841a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_KEY_1, key[1]);
2842a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_KEY_2, key[2]);
2843a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_KEY_3, key[3]);
2844a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_KEY_MASK_0, mask[0]);
2845a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_KEY_MASK_1, mask[1]);
2846a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_KEY_MASK_2, mask[2]);
2847a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_KEY_MASK_3, mask[3]);
2848a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_WRITE | index));
2849a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2850a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return tcam_wait_bit(np, TCAM_CTL_STAT);
2851a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2852a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2853a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#if 0
2854a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int tcam_assoc_read(struct niu *np, int index, u64 *data)
2855a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2856a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
2857a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2858a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_CTL, (TCAM_CTL_RWC_RAM_READ | index));
2859a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = tcam_wait_bit(np, TCAM_CTL_STAT);
2860a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err)
2861a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		*data = nr64(TCAM_KEY_1);
2862a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2863a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
2864a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2865a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif
2866a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2867a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int tcam_assoc_write(struct niu *np, int index, u64 assoc_data)
2868a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2869a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_KEY_1, assoc_data);
2870a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_CTL, (TCAM_CTL_RWC_RAM_WRITE | index));
2871a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2872a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return tcam_wait_bit(np, TCAM_CTL_STAT);
2873a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2874a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2875a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void tcam_enable(struct niu *np, int on)
2876a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2877a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64(FFLP_CFG_1);
2878a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2879a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on)
2880a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~FFLP_CFG_1_TCAM_DIS;
2881a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
2882a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= FFLP_CFG_1_TCAM_DIS;
2883a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(FFLP_CFG_1, val);
2884a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2885a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2886a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void tcam_set_lat_and_ratio(struct niu *np, u64 latency, u64 ratio)
2887a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2888a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64(FFLP_CFG_1);
2889a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2890a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~(FFLP_CFG_1_FFLPINITDONE |
2891a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 FFLP_CFG_1_CAMLAT |
2892a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 FFLP_CFG_1_CAMRATIO);
2893a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (latency << FFLP_CFG_1_CAMLAT_SHIFT);
2894a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (ratio << FFLP_CFG_1_CAMRATIO_SHIFT);
2895a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(FFLP_CFG_1, val);
2896a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2897a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(FFLP_CFG_1);
2898a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= FFLP_CFG_1_FFLPINITDONE;
2899a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(FFLP_CFG_1, val);
2900a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2901a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2902a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int tcam_user_eth_class_enable(struct niu *np, unsigned long class,
2903a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				      int on)
2904a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2905a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long reg;
2906a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
2907a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2908a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (class < CLASS_CODE_ETHERTYPE1 ||
2909a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    class > CLASS_CODE_ETHERTYPE2)
2910a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
2911a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2912a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	reg = L2_CLS(class - CLASS_CODE_ETHERTYPE1);
2913a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(reg);
2914a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on)
2915a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= L2_CLS_VLD;
2916a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
2917a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~L2_CLS_VLD;
2918a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(reg, val);
2919a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2920a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
2921a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2922a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2923a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#if 0
2924a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int tcam_user_eth_class_set(struct niu *np, unsigned long class,
2925a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				   u64 ether_type)
2926a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2927a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long reg;
2928a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
2929a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2930a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (class < CLASS_CODE_ETHERTYPE1 ||
2931a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    class > CLASS_CODE_ETHERTYPE2 ||
2932a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    (ether_type & ~(u64)0xffff) != 0)
2933a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
2934a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2935a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	reg = L2_CLS(class - CLASS_CODE_ETHERTYPE1);
2936a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(reg);
2937a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~L2_CLS_ETYPE;
2938a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (ether_type << L2_CLS_ETYPE_SHIFT);
2939a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(reg, val);
2940a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2941a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
2942a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2943a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif
2944a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2945a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int tcam_user_ip_class_enable(struct niu *np, unsigned long class,
2946a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				     int on)
2947a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2948a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long reg;
2949a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
2950a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2951a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (class < CLASS_CODE_USER_PROG1 ||
2952a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    class > CLASS_CODE_USER_PROG4)
2953a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
2954a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2955a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	reg = L3_CLS(class - CLASS_CODE_USER_PROG1);
2956a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(reg);
2957a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on)
2958a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= L3_CLS_VALID;
2959a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
2960a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~L3_CLS_VALID;
2961a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(reg, val);
2962a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2963a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
2964a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2965a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2966a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int tcam_user_ip_class_set(struct niu *np, unsigned long class,
2967a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  int ipv6, u64 protocol_id,
2968a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  u64 tos_mask, u64 tos_val)
2969a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2970a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long reg;
2971a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
2972a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2973a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (class < CLASS_CODE_USER_PROG1 ||
2974a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    class > CLASS_CODE_USER_PROG4 ||
2975a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    (protocol_id & ~(u64)0xff) != 0 ||
2976a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    (tos_mask & ~(u64)0xff) != 0 ||
2977a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    (tos_val & ~(u64)0xff) != 0)
2978a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
2979a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2980a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	reg = L3_CLS(class - CLASS_CODE_USER_PROG1);
2981a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(reg);
2982a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~(L3_CLS_IPVER | L3_CLS_PID |
2983a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 L3_CLS_TOSMASK | L3_CLS_TOS);
2984a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (ipv6)
2985a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= L3_CLS_IPVER;
2986a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (protocol_id << L3_CLS_PID_SHIFT);
2987a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (tos_mask << L3_CLS_TOSMASK_SHIFT);
2988a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (tos_val << L3_CLS_TOS_SHIFT);
2989a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(reg, val);
2990a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2991a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
2992a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
2993a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2994a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int tcam_early_init(struct niu *np)
2995a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
2996a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long i;
2997a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
2998a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
2999a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tcam_enable(np, 0);
3000a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tcam_set_lat_and_ratio(np,
3001a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       DEFAULT_TCAM_LATENCY,
3002a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       DEFAULT_TCAM_ACCESS_RATIO);
3003a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = CLASS_CODE_ETHERTYPE1; i <= CLASS_CODE_ETHERTYPE2; i++) {
3004a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = tcam_user_eth_class_enable(np, i, 0);
3005a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
3006a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
3007a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3008a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_USER_PROG4; i++) {
3009a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = tcam_user_ip_class_enable(np, i, 0);
3010a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
3011a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
3012a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3013a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3014a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
3015a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3016a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3017a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int tcam_flush_all(struct niu *np)
3018a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3019a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long i;
3020a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3021a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->parent->tcam_num_entries; i++) {
3022a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int err = tcam_flush(np, i);
3023a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
3024a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
3025a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3026a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
3027a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3028a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3029a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic u64 hash_addr_regval(unsigned long index, unsigned long num_entries)
3030a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3031807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet	return (u64)index | (num_entries == 1 ? HASH_TBL_ADDR_AUTOINC : 0);
3032a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3033a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3034a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#if 0
3035a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int hash_read(struct niu *np, unsigned long partition,
3036a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		     unsigned long index, unsigned long num_entries,
3037a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		     u64 *data)
3038a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3039a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = hash_addr_regval(index, num_entries);
3040a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long i;
3041a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3042a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (partition >= FCRAM_NUM_PARTITIONS ||
3043a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    index + num_entries > FCRAM_SIZE)
3044a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
3045a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3046a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(HASH_TBL_ADDR(partition), val);
3047a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < num_entries; i++)
3048a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data[i] = nr64(HASH_TBL_DATA(partition));
3049a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3050a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
3051a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3052a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif
3053a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3054a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int hash_write(struct niu *np, unsigned long partition,
3055a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		      unsigned long index, unsigned long num_entries,
3056a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		      u64 *data)
3057a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3058a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = hash_addr_regval(index, num_entries);
3059a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long i;
3060a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3061a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (partition >= FCRAM_NUM_PARTITIONS ||
3062a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    index + (num_entries * 8) > FCRAM_SIZE)
3063a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
3064a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3065a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(HASH_TBL_ADDR(partition), val);
3066a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < num_entries; i++)
3067a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64(HASH_TBL_DATA(partition), data[i]);
3068a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3069a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
3070a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3071a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3072a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void fflp_reset(struct niu *np)
3073a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3074a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
3075a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3076a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(FFLP_CFG_1, FFLP_CFG_1_PIO_FIO_RST);
3077a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	udelay(10);
3078a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(FFLP_CFG_1, 0);
3079a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3080a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = FFLP_CFG_1_FCRAMOUTDR_NORMAL | FFLP_CFG_1_FFLPINITDONE;
3081a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(FFLP_CFG_1, val);
3082a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3083a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3084a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void fflp_set_timings(struct niu *np)
3085a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3086a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64(FFLP_CFG_1);
3087a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3088a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~FFLP_CFG_1_FFLPINITDONE;
3089a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (DEFAULT_FCRAMRATIO << FFLP_CFG_1_FCRAMRATIO_SHIFT);
3090a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(FFLP_CFG_1, val);
3091a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3092a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(FFLP_CFG_1);
3093a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= FFLP_CFG_1_FFLPINITDONE;
3094a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(FFLP_CFG_1, val);
3095a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3096a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(FCRAM_REF_TMR);
3097a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~(FCRAM_REF_TMR_MAX | FCRAM_REF_TMR_MIN);
3098a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (DEFAULT_FCRAM_REFRESH_MAX << FCRAM_REF_TMR_MAX_SHIFT);
3099a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (DEFAULT_FCRAM_REFRESH_MIN << FCRAM_REF_TMR_MIN_SHIFT);
3100a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(FCRAM_REF_TMR, val);
3101a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3102a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3103a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int fflp_set_partition(struct niu *np, u64 partition,
3104a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			      u64 mask, u64 base, int enable)
3105a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3106a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long reg;
3107a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
3108a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3109a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (partition >= FCRAM_NUM_PARTITIONS ||
3110a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    (mask & ~(u64)0x1f) != 0 ||
3111a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    (base & ~(u64)0x1f) != 0)
3112a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
3113a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3114a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	reg = FLW_PRT_SEL(partition);
3115a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3116a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(reg);
3117a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~(FLW_PRT_SEL_EXT | FLW_PRT_SEL_MASK | FLW_PRT_SEL_BASE);
3118a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (mask << FLW_PRT_SEL_MASK_SHIFT);
3119a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (base << FLW_PRT_SEL_BASE_SHIFT);
3120a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (enable)
3121a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= FLW_PRT_SEL_EXT;
3122a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(reg, val);
3123a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3124a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
3125a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3126a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3127a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int fflp_disable_all_partitions(struct niu *np)
3128a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3129a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long i;
3130a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3131a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < FCRAM_NUM_PARTITIONS; i++) {
3132a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int err = fflp_set_partition(np, 0, 0, 0, 0);
3133a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
3134a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
3135a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3136a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
3137a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3138a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3139a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void fflp_llcsnap_enable(struct niu *np, int on)
3140a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3141a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64(FFLP_CFG_1);
3142a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3143a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on)
3144a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= FFLP_CFG_1_LLCSNAP;
3145a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
3146a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~FFLP_CFG_1_LLCSNAP;
3147a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(FFLP_CFG_1, val);
3148a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3149a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3150a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void fflp_errors_enable(struct niu *np, int on)
3151a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3152a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64(FFLP_CFG_1);
3153a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3154a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on)
3155a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~FFLP_CFG_1_ERRORDIS;
3156a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
3157a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= FFLP_CFG_1_ERRORDIS;
3158a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(FFLP_CFG_1, val);
3159a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3160a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3161a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int fflp_hash_clear(struct niu *np)
3162a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3163a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct fcram_hash_ipv4 ent;
3164a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long i;
3165a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3166a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* IPV4 hash entry with valid bit clear, rest is don't care.  */
3167a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	memset(&ent, 0, sizeof(ent));
3168a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	ent.header = HASH_HEADER_EXT;
3169a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3170a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < FCRAM_SIZE; i += sizeof(ent)) {
3171a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int err = hash_write(np, 0, i, 1, (u64 *) &ent);
3172a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
3173a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
3174a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3175a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
3176a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3177a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3178a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int fflp_early_init(struct niu *np)
3179a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3180a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent;
3181a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long flags;
3182a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
3183a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3184a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_lock_parent(np, flags);
3185a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3186a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	parent = np->parent;
3187a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = 0;
3188a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!(parent->flags & PARENT_FLGS_CLS_HWINIT)) {
3189a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (np->parent->plat_type != PLAT_TYPE_NIU) {
3190a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			fflp_reset(np);
3191a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			fflp_set_timings(np);
3192a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			err = fflp_disable_all_partitions(np);
3193a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (err) {
3194f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				netif_printk(np, probe, KERN_DEBUG, np->dev,
3195f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches					     "fflp_disable_all_partitions failed, err=%d\n",
3196f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches					     err);
3197a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				goto out;
3198a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			}
3199a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
3200a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3201a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = tcam_early_init(np);
3202a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err) {
3203f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			netif_printk(np, probe, KERN_DEBUG, np->dev,
3204f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				     "tcam_early_init failed, err=%d\n", err);
3205a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			goto out;
3206a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
3207a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		fflp_llcsnap_enable(np, 1);
3208a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		fflp_errors_enable(np, 0);
3209a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64(H1POLY, 0);
3210a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64(H2POLY, 0);
3211a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3212a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = tcam_flush_all(np);
3213a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err) {
3214f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			netif_printk(np, probe, KERN_DEBUG, np->dev,
3215f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				     "tcam_flush_all failed, err=%d\n", err);
3216a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			goto out;
3217a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
3218a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (np->parent->plat_type != PLAT_TYPE_NIU) {
3219a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			err = fflp_hash_clear(np);
3220a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (err) {
3221f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				netif_printk(np, probe, KERN_DEBUG, np->dev,
3222f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches					     "fflp_hash_clear failed, err=%d\n",
3223f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches					     err);
3224a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				goto out;
3225a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			}
3226a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
3227a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3228a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		vlan_tbl_clear(np);
3229a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3230a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		parent->flags |= PARENT_FLGS_CLS_HWINIT;
3231a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3232a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerout:
3233a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_unlock_parent(np, flags);
3234a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
3235a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3236a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3237a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_set_flow_key(struct niu *np, unsigned long class_code, u64 key)
3238a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3239a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (class_code < CLASS_CODE_USER_PROG1 ||
3240a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    class_code > CLASS_CODE_SCTP_IPV6)
3241a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
3242a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3243a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(FLOW_KEY(class_code - CLASS_CODE_USER_PROG1), key);
3244a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
3245a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3246a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3247a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_set_tcam_key(struct niu *np, unsigned long class_code, u64 key)
3248a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3249a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (class_code < CLASS_CODE_USER_PROG1 ||
3250a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    class_code > CLASS_CODE_SCTP_IPV6)
3251a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
3252a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3253a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TCAM_KEY(class_code - CLASS_CODE_USER_PROG1), key);
3254a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
3255a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3256a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
32572d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera/* Entries for the ports are interleaved in the TCAM */
32582d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic u16 tcam_get_index(struct niu *np, u16 idx)
32592d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera{
32602d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	/* One entry reserved for IP fragment rule */
32612d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (idx >= (np->clas.tcam_sz - 1))
32622d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		idx = 0;
3263807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet	return np->clas.tcam_top + ((idx+1) * np->parent->num_ports);
32642d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera}
32652d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
32662d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic u16 tcam_get_size(struct niu *np)
32672d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera{
32682d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	/* One entry reserved for IP fragment rule */
32692d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	return np->clas.tcam_sz - 1;
32702d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera}
32712d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
32722d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic u16 tcam_get_valid_entry_cnt(struct niu *np)
32732d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera{
32742d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	/* One entry reserved for IP fragment rule */
32752d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	return np->clas.tcam_valid_entries - 1;
32762d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera}
32772d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
3278a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_rx_skb_append(struct sk_buff *skb, struct page *page,
3279e7e5a4033f765e2a37095cd0a73261c99840f77eEric Dumazet			      u32 offset, u32 size, u32 truesize)
3280a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3281e7e5a4033f765e2a37095cd0a73261c99840f77eEric Dumazet	skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, offset, size);
3282a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3283a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	skb->len += size;
3284a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	skb->data_len += size;
3285e7e5a4033f765e2a37095cd0a73261c99840f77eEric Dumazet	skb->truesize += truesize;
3286a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3287a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3288a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic unsigned int niu_hash_rxaddr(struct rx_ring_info *rp, u64 a)
3289a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3290a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	a >>= PAGE_SHIFT;
3291a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	a ^= (a >> ilog2(MAX_RBR_RING_SIZE));
3292a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3293807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet	return a & (MAX_RBR_RING_SIZE - 1);
3294a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3295a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3296a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic struct page *niu_find_rxpage(struct rx_ring_info *rp, u64 addr,
3297a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    struct page ***link)
3298a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3299a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned int h = niu_hash_rxaddr(rp, addr);
3300a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct page *p, **pp;
3301a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3302a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	addr &= PAGE_MASK;
3303a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pp = &rp->rxhash[h];
3304a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (; (p = *pp) != NULL; pp = (struct page **) &p->mapping) {
3305a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (p->index == addr) {
3306a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			*link = pp;
3307a038716957d3888a595014a660b1db1f28946f62David S. Miller			goto found;
3308a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
3309a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3310a038716957d3888a595014a660b1db1f28946f62David S. Miller	BUG();
3311a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3312a038716957d3888a595014a660b1db1f28946f62David S. Millerfound:
3313a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return p;
3314a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3315a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3316a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_hash_page(struct rx_ring_info *rp, struct page *page, u64 base)
3317a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3318a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned int h = niu_hash_rxaddr(rp, base);
3319a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3320a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	page->index = base;
3321a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	page->mapping = (struct address_space *) rp->rxhash[h];
3322a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rxhash[h] = page;
3323a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3324a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3325a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_rbr_add_page(struct niu *np, struct rx_ring_info *rp,
3326a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			    gfp_t mask, int start_index)
3327a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3328a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct page *page;
3329a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 addr;
3330a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
3331a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3332a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	page = alloc_page(mask);
3333a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!page)
3334a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENOMEM;
3335a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3336a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	addr = np->ops->map_page(np->device, page, 0,
3337a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 PAGE_SIZE, DMA_FROM_DEVICE);
3338a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3339a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_hash_page(rp, page, addr);
3340a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (rp->rbr_blocks_per_page > 1)
3341a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		atomic_add(rp->rbr_blocks_per_page - 1,
3342a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			   &compound_head(page)->_count);
3343a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3344a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < rp->rbr_blocks_per_page; i++) {
3345a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		__le32 *rbr = &rp->rbr[start_index + i];
3346a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3347a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		*rbr = cpu_to_le32(addr >> RBR_DESCR_ADDR_SHIFT);
3348a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		addr += rp->rbr_block_size;
3349a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3350a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3351a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
3352a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3353a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3354a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_rbr_refill(struct niu *np, struct rx_ring_info *rp, gfp_t mask)
3355a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3356a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int index = rp->rbr_index;
3357a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3358a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rbr_pending++;
3359a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if ((rp->rbr_pending % rp->rbr_blocks_per_page) == 0) {
3360a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int err = niu_rbr_add_page(np, rp, mask, index);
3361a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3362a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (unlikely(err)) {
3363a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			rp->rbr_pending--;
3364a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return;
3365a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
3366a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3367a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->rbr_index += rp->rbr_blocks_per_page;
3368a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		BUG_ON(rp->rbr_index > rp->rbr_table_size);
3369a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (rp->rbr_index == rp->rbr_table_size)
3370a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			rp->rbr_index = 0;
3371a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3372a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (rp->rbr_pending >= rp->rbr_kick_thresh) {
3373a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			nw64(RBR_KICK(rp->rx_channel), rp->rbr_pending);
3374a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			rp->rbr_pending = 0;
3375a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
3376a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3377a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3378a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3379a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_rx_pkt_ignore(struct niu *np, struct rx_ring_info *rp)
3380a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3381a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned int index = rp->rcr_index;
3382a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int num_rcr = 0;
3383a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3384a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rx_dropped++;
3385a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (1) {
3386a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct page *page, **link;
3387a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u64 addr, val;
3388a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u32 rcr_size;
3389a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3390a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		num_rcr++;
3391a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3392a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val = le64_to_cpup(&rp->rcr[index]);
3393a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		addr = (val & RCR_ENTRY_PKT_BUF_ADDR) <<
3394a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			RCR_ENTRY_PKT_BUF_ADDR_SHIFT;
3395a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		page = niu_find_rxpage(rp, addr, &link);
3396a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3397a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rcr_size = rp->rbr_sizes[(val & RCR_ENTRY_PKTBUFSZ) >>
3398a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					 RCR_ENTRY_PKTBUFSZ_SHIFT];
3399a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if ((page->index + PAGE_SIZE) - rcr_size == addr) {
3400a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			*link = (struct page *) page->mapping;
3401a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			np->ops->unmap_page(np->device, page->index,
3402a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					    PAGE_SIZE, DMA_FROM_DEVICE);
3403a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			page->index = 0;
3404a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			page->mapping = NULL;
3405a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			__free_page(page);
3406a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			rp->rbr_refill_pending++;
3407a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
3408a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3409a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		index = NEXT_RCR(rp, index);
3410a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!(val & RCR_ENTRY_MULTI))
3411a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
3412a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3413a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3414a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rcr_index = index;
3415a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3416a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return num_rcr;
3417a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3418a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
34194099e01224e2afcaeea439cd92db3e7cf6e0f84fDavid S. Millerstatic int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np,
34204099e01224e2afcaeea439cd92db3e7cf6e0f84fDavid S. Miller			      struct rx_ring_info *rp)
3421a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3422a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned int index = rp->rcr_index;
34233cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller	struct rx_pkt_hdr1 *rh;
3424a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct sk_buff *skb;
3425a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int len, num_rcr;
3426a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3427a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	skb = netdev_alloc_skb(np->dev, RX_SKB_ALLOC_SIZE);
3428a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (unlikely(!skb))
3429a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return niu_rx_pkt_ignore(np, rp);
3430a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3431a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	num_rcr = 0;
3432a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (1) {
3433a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct page *page, **link;
3434a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u32 rcr_size, append_size;
3435a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u64 addr, val, off;
3436a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3437a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		num_rcr++;
3438a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3439a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val = le64_to_cpup(&rp->rcr[index]);
3440a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3441a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		len = (val & RCR_ENTRY_L2_LEN) >>
3442a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			RCR_ENTRY_L2_LEN_SHIFT;
3443a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		len -= ETH_FCS_LEN;
3444a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3445a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		addr = (val & RCR_ENTRY_PKT_BUF_ADDR) <<
3446a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			RCR_ENTRY_PKT_BUF_ADDR_SHIFT;
3447a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		page = niu_find_rxpage(rp, addr, &link);
3448a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3449a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rcr_size = rp->rbr_sizes[(val & RCR_ENTRY_PKTBUFSZ) >>
3450a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					 RCR_ENTRY_PKTBUFSZ_SHIFT];
3451a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3452a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		off = addr & ~PAGE_MASK;
3453a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		append_size = rcr_size;
3454a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (num_rcr == 1) {
3455a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			int ptype;
3456a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3457a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			ptype = (val >> RCR_ENTRY_PKT_TYPE_SHIFT);
3458a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if ((ptype == RCR_PKT_TYPE_TCP ||
3459a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			     ptype == RCR_PKT_TYPE_UDP) &&
3460a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			    !(val & (RCR_ENTRY_NOPORT |
3461a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				     RCR_ENTRY_ERROR)))
3462a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				skb->ip_summed = CHECKSUM_UNNECESSARY;
3463a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			else
3464bc8acf2c8c3e43fcc192762a9f964b3e9a17748bEric Dumazet				skb_checksum_none_assert(skb);
34653cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller		} else if (!(val & RCR_ENTRY_MULTI))
3466a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			append_size = len - skb->len;
3467a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3468e7e5a4033f765e2a37095cd0a73261c99840f77eEric Dumazet		niu_rx_skb_append(skb, page, off, append_size, rcr_size);
3469a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if ((page->index + rp->rbr_block_size) - rcr_size == addr) {
3470a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			*link = (struct page *) page->mapping;
3471a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			np->ops->unmap_page(np->device, page->index,
3472a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					    PAGE_SIZE, DMA_FROM_DEVICE);
3473a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			page->index = 0;
3474a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			page->mapping = NULL;
3475a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			rp->rbr_refill_pending++;
3476a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		} else
3477a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			get_page(page);
3478a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3479a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		index = NEXT_RCR(rp, index);
3480a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!(val & RCR_ENTRY_MULTI))
3481a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
3482a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3483a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3484a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rcr_index = index;
3485a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
34863cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller	len += sizeof(*rh);
34873cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller	len = min_t(int, len, sizeof(*rh) + VLAN_ETH_HLEN);
34883cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller	__pskb_pull_tail(skb, len);
34893cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller
34903cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller	rh = (struct rx_pkt_hdr1 *) skb->data;
34913cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller	if (np->dev->features & NETIF_F_RXHASH)
34923cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller		skb->rxhash = ((u32)rh->hashval2_0 << 24 |
34933cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller			       (u32)rh->hashval2_1 << 16 |
34943cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller			       (u32)rh->hashval1_1 << 8 |
34953cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller			       (u32)rh->hashval1_2 << 0);
34963cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller	skb_pull(skb, sizeof(*rh));
3497a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3498a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rx_packets++;
3499a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rx_bytes += skb->len;
3500a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3501a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	skb->protocol = eth_type_trans(skb, np->dev);
35020c8dfc830aadd978e461dad66c33741b71c6a0beDavid S. Miller	skb_record_rx_queue(skb, rp->rx_channel);
35034099e01224e2afcaeea439cd92db3e7cf6e0f84fDavid S. Miller	napi_gro_receive(napi, skb);
3504a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3505a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return num_rcr;
3506a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3507a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3508a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_rbr_fill(struct niu *np, struct rx_ring_info *rp, gfp_t mask)
3509a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3510a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int blocks_per_page = rp->rbr_blocks_per_page;
3511a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err, index = rp->rbr_index;
3512a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3513a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = 0;
3514a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (index < (rp->rbr_table_size - blocks_per_page)) {
3515a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_rbr_add_page(np, rp, mask, index);
3516a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
3517a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
3518a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3519a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		index += blocks_per_page;
3520a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3521a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3522a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rbr_index = index;
3523a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
3524a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3525a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3526a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_rbr_free(struct niu *np, struct rx_ring_info *rp)
3527a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3528a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
3529a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3530a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < MAX_RBR_RING_SIZE; i++) {
3531a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct page *page;
3532a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3533a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		page = rp->rxhash[i];
3534a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		while (page) {
3535a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			struct page *next = (struct page *) page->mapping;
3536a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			u64 base = page->index;
3537a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3538a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			np->ops->unmap_page(np->device, base, PAGE_SIZE,
3539a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					    DMA_FROM_DEVICE);
3540a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			page->index = 0;
3541a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			page->mapping = NULL;
3542a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3543a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			__free_page(page);
3544a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3545a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			page = next;
3546a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
3547a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3548a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3549a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < rp->rbr_table_size; i++)
3550a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->rbr[i] = cpu_to_le32(0);
3551a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rbr_index = 0;
3552a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3553a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3554a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int release_tx_packet(struct niu *np, struct tx_ring_info *rp, int idx)
3555a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3556a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct tx_buff_info *tb = &rp->tx_buffs[idx];
3557a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct sk_buff *skb = tb->skb;
3558a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct tx_pkt_hdr *tp;
3559a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 tx_flags;
3560a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, len;
3561a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3562a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tp = (struct tx_pkt_hdr *) skb->data;
3563a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tx_flags = le64_to_cpup(&tp->flags);
3564a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3565a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->tx_packets++;
3566a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->tx_bytes += (((tx_flags & TXHDR_LEN) >> TXHDR_LEN_SHIFT) -
3567a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			 ((tx_flags & TXHDR_PAD) / 2));
3568a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3569a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	len = skb_headlen(skb);
3570a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->ops->unmap_single(np->device, tb->mapping,
3571a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			      len, DMA_TO_DEVICE);
3572a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3573a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (le64_to_cpu(rp->descr[idx]) & TX_DESC_MARK)
3574a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->mark_pending--;
3575a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3576a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tb->skb = NULL;
3577a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	do {
3578a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		idx = NEXT_TX(rp, idx);
3579a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		len -= MAX_TX_DESC_LEN;
3580a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} while (len > 0);
3581a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3582a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
3583a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		tb = &rp->tx_buffs[idx];
3584a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		BUG_ON(tb->skb != NULL);
3585a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->ops->unmap_page(np->device, tb->mapping,
35869e903e085262ffbf1fc44a17ac06058aca03524aEric Dumazet				    skb_frag_size(&skb_shinfo(skb)->frags[i]),
3587a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    DMA_TO_DEVICE);
3588a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		idx = NEXT_TX(rp, idx);
3589a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3590a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3591a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev_kfree_skb(skb);
3592a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3593a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return idx;
3594a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3595a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3596a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define NIU_TX_WAKEUP_THRESH(rp)		((rp)->pending / 4)
3597a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3598a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_tx_work(struct niu *np, struct tx_ring_info *rp)
3599a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3600b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller	struct netdev_queue *txq;
3601a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u16 pkt_cnt, tmp;
3602b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller	int cons, index;
3603a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 cs;
3604a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3605b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller	index = (rp - np->tx_rings);
3606b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller	txq = netdev_get_tx_queue(np->dev, index);
3607b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller
3608a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	cs = rp->tx_cs;
3609a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (unlikely(!(cs & (TX_CS_MK | TX_CS_MMK))))
3610a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out;
3611a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3612a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tmp = pkt_cnt = (cs & TX_CS_PKT_CNT) >> TX_CS_PKT_CNT_SHIFT;
3613a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pkt_cnt = (pkt_cnt - rp->last_pkt_cnt) &
3614a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		(TX_CS_PKT_CNT >> TX_CS_PKT_CNT_SHIFT);
3615a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3616a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->last_pkt_cnt = tmp;
3617a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3618a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	cons = rp->cons;
3619a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3620f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, tx_done, KERN_DEBUG, np->dev,
3621f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "%s() pkt_cnt[%u] cons[%d]\n", __func__, pkt_cnt, cons);
3622a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
362343d950abdab622bf97d0a0c233809f88a3eb6240David S. Miller	while (pkt_cnt--)
3624a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		cons = release_tx_packet(np, rp, cons);
3625a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3626a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->cons = cons;
3627a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	smp_mb();
3628a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3629a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerout:
3630b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller	if (unlikely(netif_tx_queue_stopped(txq) &&
3631a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		     (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)))) {
3632b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller		__netif_tx_lock(txq, smp_processor_id());
3633b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller		if (netif_tx_queue_stopped(txq) &&
3634a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)))
3635b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller			netif_tx_wake_queue(txq);
3636b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller		__netif_tx_unlock(txq);
3637a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3638a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3639a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3640b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouerstatic inline void niu_sync_rx_discard_stats(struct niu *np,
3641b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer					     struct rx_ring_info *rp,
3642b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer					     const int limit)
3643b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer{
3644b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	/* This elaborate scheme is needed for reading the RX discard
3645b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	 * counters, as they are only 16-bit and can overflow quickly,
3646b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	 * and because the overflow indication bit is not usable as
3647b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	 * the counter value does not wrap, but remains at max value
3648b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	 * 0xFFFF.
3649b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	 *
3650b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	 * In theory and in practice counters can be lost in between
3651b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	 * reading nr64() and clearing the counter nw64().  For this
3652b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	 * reason, the number of counter clearings nw64() is
3653b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	 * limited/reduced though the limit parameter.
3654b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	 */
3655b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	int rx_channel = rp->rx_channel;
3656b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	u32 misc, wred;
3657b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer
3658b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	/* RXMISC (Receive Miscellaneous Discard Count), covers the
3659b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	 * following discard events: IPP (Input Port Process),
3660b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	 * FFLP/TCAM, Full RCR (Receive Completion Ring) RBR (Receive
3661b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	 * Block Ring) prefetch buffer is empty.
3662b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	 */
3663b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	misc = nr64(RXMISC(rx_channel));
3664b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	if (unlikely((misc & RXMISC_COUNT) > limit)) {
3665b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer		nw64(RXMISC(rx_channel), 0);
3666b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer		rp->rx_errors += misc & RXMISC_COUNT;
3667b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer
3668b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer		if (unlikely(misc & RXMISC_OFLOW))
3669f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			dev_err(np->device, "rx-%d: Counter overflow RXMISC discard\n",
3670f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				rx_channel);
3671d231776fda4a1ed754298720c5fbc29eb34f130cJesper Dangaard Brouer
3672f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netif_printk(np, rx_err, KERN_DEBUG, np->dev,
3673f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			     "rx-%d: MISC drop=%u over=%u\n",
3674f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			     rx_channel, misc, misc-limit);
3675b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	}
3676b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer
3677b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	/* WRED (Weighted Random Early Discard) by hardware */
3678b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	wred = nr64(RED_DIS_CNT(rx_channel));
3679b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	if (unlikely((wred & RED_DIS_CNT_COUNT) > limit)) {
3680b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer		nw64(RED_DIS_CNT(rx_channel), 0);
3681b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer		rp->rx_dropped += wred & RED_DIS_CNT_COUNT;
3682b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer
3683b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer		if (unlikely(wred & RED_DIS_CNT_OFLOW))
3684f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			dev_err(np->device, "rx-%d: Counter overflow WRED discard\n", rx_channel);
3685d231776fda4a1ed754298720c5fbc29eb34f130cJesper Dangaard Brouer
3686f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netif_printk(np, rx_err, KERN_DEBUG, np->dev,
3687f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			     "rx-%d: WRED drop=%u over=%u\n",
3688f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			     rx_channel, wred, wred-limit);
3689b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer	}
3690b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer}
3691b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer
36924099e01224e2afcaeea439cd92db3e7cf6e0f84fDavid S. Millerstatic int niu_rx_work(struct napi_struct *napi, struct niu *np,
36934099e01224e2afcaeea439cd92db3e7cf6e0f84fDavid S. Miller		       struct rx_ring_info *rp, int budget)
3694a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3695a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int qlen, rcr_done = 0, work_done = 0;
3696a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct rxdma_mailbox *mbox = rp->mbox;
3697a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 stat;
3698a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3699a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#if 1
3700a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel));
3701a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	qlen = nr64(RCRSTAT_A(rp->rx_channel)) & RCRSTAT_A_QLEN;
3702a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#else
3703a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	stat = le64_to_cpup(&mbox->rx_dma_ctl_stat);
3704a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	qlen = (le64_to_cpup(&mbox->rcrstat_a) & RCRSTAT_A_QLEN);
3705a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif
3706a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mbox->rx_dma_ctl_stat = 0;
3707a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mbox->rcrstat_a = 0;
3708a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3709f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, rx_status, KERN_DEBUG, np->dev,
3710f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "%s(chan[%d]), stat[%llx] qlen=%d\n",
3711f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     __func__, rp->rx_channel, (unsigned long long)stat, qlen);
3712a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3713a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rcr_done = work_done = 0;
3714a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	qlen = min(qlen, budget);
3715a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (work_done < qlen) {
37164099e01224e2afcaeea439cd92db3e7cf6e0f84fDavid S. Miller		rcr_done += niu_process_rx_pkt(napi, np, rp);
3717a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		work_done++;
3718a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3719a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3720a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (rp->rbr_refill_pending >= rp->rbr_kick_thresh) {
3721a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		unsigned int i;
3722a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3723a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		for (i = 0; i < rp->rbr_refill_pending; i++)
3724a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			niu_rbr_refill(np, rp, GFP_ATOMIC);
3725a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->rbr_refill_pending = 0;
3726a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3727a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3728a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	stat = (RX_DMA_CTL_STAT_MEX |
3729a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		((u64)work_done << RX_DMA_CTL_STAT_PKTREAD_SHIFT) |
3730a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		((u64)rcr_done << RX_DMA_CTL_STAT_PTRREAD_SHIFT));
3731a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3732a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat);
3733a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3734e98def1f71fa0a6a37e12a56eb52ce5ed9e2e800Jesper Dangaard Brouer	/* Only sync discards stats when qlen indicate potential for drops */
3735e98def1f71fa0a6a37e12a56eb52ce5ed9e2e800Jesper Dangaard Brouer	if (qlen > 10)
3736e98def1f71fa0a6a37e12a56eb52ce5ed9e2e800Jesper Dangaard Brouer		niu_sync_rx_discard_stats(np, rp, 0x7FFF);
3737b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer
3738a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return work_done;
3739a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3740a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3741a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_poll_core(struct niu *np, struct niu_ldg *lp, int budget)
3742a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3743a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 v0 = lp->v0;
3744a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u32 tx_vec = (v0 >> 32);
3745a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u32 rx_vec = (v0 & 0xffffffff);
3746a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, work_done = 0;
3747a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3748f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, intr, KERN_DEBUG, np->dev,
3749f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "%s() v0[%016llx]\n", __func__, (unsigned long long)v0);
3750a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3751a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_tx_rings; i++) {
3752a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct tx_ring_info *rp = &np->tx_rings[i];
3753a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (tx_vec & (1 << rp->tx_channel))
3754a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			niu_tx_work(np, rp);
3755a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64(LD_IM0(LDN_TXDMA(rp->tx_channel)), 0);
3756a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3757a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3758a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_rx_rings; i++) {
3759a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct rx_ring_info *rp = &np->rx_rings[i];
3760a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3761a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (rx_vec & (1 << rp->rx_channel)) {
3762a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			int this_work_done;
3763a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
37644099e01224e2afcaeea439cd92db3e7cf6e0f84fDavid S. Miller			this_work_done = niu_rx_work(&lp->napi, np, rp,
3765a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller						     budget);
3766a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3767a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			budget -= this_work_done;
3768a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			work_done += this_work_done;
3769a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
3770a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64(LD_IM0(LDN_RXDMA(rp->rx_channel)), 0);
3771a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3772a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3773a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return work_done;
3774a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3775a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3776a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_poll(struct napi_struct *napi, int budget)
3777a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3778a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_ldg *lp = container_of(napi, struct niu_ldg, napi);
3779a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = lp->np;
3780a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int work_done;
3781a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3782a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	work_done = niu_poll_core(np, lp, budget);
3783a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3784a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (work_done < budget) {
3785288379f050284087578b77e04f040b57db3db3f8Ben Hutchings		napi_complete(napi);
3786a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_ldg_rearm(np, lp, 1);
3787a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3788a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return work_done;
3789a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3790a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3791a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_log_rxchan_errors(struct niu *np, struct rx_ring_info *rp,
3792a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  u64 stat)
3793a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3794f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netdev_err(np->dev, "RX channel %u errors ( ", rp->rx_channel);
3795a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3796a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & RX_DMA_CTL_STAT_RBR_TMOUT)
3797f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("RBR_TMOUT ");
3798a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & RX_DMA_CTL_STAT_RSP_CNT_ERR)
3799f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("RSP_CNT ");
3800a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & RX_DMA_CTL_STAT_BYTE_EN_BUS)
3801f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("BYTE_EN_BUS ");
3802a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & RX_DMA_CTL_STAT_RSP_DAT_ERR)
3803f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("RSP_DAT ");
3804a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & RX_DMA_CTL_STAT_RCR_ACK_ERR)
3805f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("RCR_ACK ");
3806a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & RX_DMA_CTL_STAT_RCR_SHA_PAR)
3807f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("RCR_SHA_PAR ");
3808a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & RX_DMA_CTL_STAT_RBR_PRE_PAR)
3809f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("RBR_PRE_PAR ");
3810a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & RX_DMA_CTL_STAT_CONFIG_ERR)
3811f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("CONFIG ");
3812a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & RX_DMA_CTL_STAT_RCRINCON)
3813f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("RCRINCON ");
3814a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & RX_DMA_CTL_STAT_RCRFULL)
3815f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("RCRFULL ");
3816a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & RX_DMA_CTL_STAT_RBRFULL)
3817f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("RBRFULL ");
3818a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & RX_DMA_CTL_STAT_RBRLOGPAGE)
3819f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("RBRLOGPAGE ");
3820a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & RX_DMA_CTL_STAT_CFIGLOGPAGE)
3821f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("CFIGLOGPAGE ");
3822a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & RX_DMA_CTL_STAT_DC_FIFO_ERR)
3823f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("DC_FIDO ");
3824a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3825f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	pr_cont(")\n");
3826a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3827a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3828a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_rx_error(struct niu *np, struct rx_ring_info *rp)
3829a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3830a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel));
3831a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err = 0;
3832a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3833a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3834a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & (RX_DMA_CTL_STAT_CHAN_FATAL |
3835a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    RX_DMA_CTL_STAT_PORT_FATAL))
3836a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = -EINVAL;
3837a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3838406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku	if (err) {
3839f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "RX channel %u error, stat[%llx]\n",
3840f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   rp->rx_channel,
3841f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   (unsigned long long) stat);
3842406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku
3843406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku		niu_log_rxchan_errors(np, rp, stat);
3844406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku	}
3845406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku
3846a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_DMA_CTL_STAT(rp->rx_channel),
3847a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	     stat & RX_DMA_CTL_WRITE_CLEAR_ERRS);
3848a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3849a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
3850a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3851a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3852a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_log_txchan_errors(struct niu *np, struct tx_ring_info *rp,
3853a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  u64 cs)
3854a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3855f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netdev_err(np->dev, "TX channel %u errors ( ", rp->tx_channel);
3856a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3857a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (cs & TX_CS_MBOX_ERR)
3858f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("MBOX ");
3859a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (cs & TX_CS_PKT_SIZE_ERR)
3860f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("PKT_SIZE ");
3861a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (cs & TX_CS_TX_RING_OFLOW)
3862f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("TX_RING_OFLOW ");
3863a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (cs & TX_CS_PREF_BUF_PAR_ERR)
3864f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("PREF_BUF_PAR ");
3865a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (cs & TX_CS_NACK_PREF)
3866f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("NACK_PREF ");
3867a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (cs & TX_CS_NACK_PKT_RD)
3868f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("NACK_PKT_RD ");
3869a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (cs & TX_CS_CONF_PART_ERR)
3870f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("CONF_PART ");
3871a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (cs & TX_CS_PKT_PRT_ERR)
3872f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("PKT_PTR ");
3873a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3874f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	pr_cont(")\n");
3875a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3876a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3877a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_tx_error(struct niu *np, struct tx_ring_info *rp)
3878a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3879a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 cs, logh, logl;
3880a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3881a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	cs = nr64(TX_CS(rp->tx_channel));
3882a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	logh = nr64(TX_RNG_ERR_LOGH(rp->tx_channel));
3883a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	logl = nr64(TX_RNG_ERR_LOGL(rp->tx_channel));
3884a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3885f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netdev_err(np->dev, "TX channel %u error, cs[%llx] logh[%llx] logl[%llx]\n",
3886f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		   rp->tx_channel,
3887f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		   (unsigned long long)cs,
3888f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		   (unsigned long long)logh,
3889f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		   (unsigned long long)logl);
3890a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3891a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_log_txchan_errors(np, rp, cs);
3892a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3893a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return -ENODEV;
3894a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3895a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3896a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_mif_interrupt(struct niu *np)
3897a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3898a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 mif_status = nr64(MIF_STATUS);
3899a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int phy_mdint = 0;
3900a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3901a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC) {
3902a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u64 xrxmac_stat = nr64_mac(XRXMAC_STATUS);
3903a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3904a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (xrxmac_stat & XRXMAC_STATUS_PHY_MDINT)
3905a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			phy_mdint = 1;
3906a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
3907a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3908f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netdev_err(np->dev, "MIF interrupt, stat[%llx] phy_mdint(%d)\n",
3909f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		   (unsigned long long)mif_status, phy_mdint);
3910a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3911a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return -ENODEV;
3912a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3913a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3914a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_xmac_interrupt(struct niu *np)
3915a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3916a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_xmac_stats *mp = &np->mac_stats.xmac;
3917a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
3918a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3919a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(XTXMAC_STATUS);
3920a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XTXMAC_STATUS_FRAME_CNT_EXP)
3921a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->tx_frames += TXMAC_FRM_CNT_COUNT;
3922a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XTXMAC_STATUS_BYTE_CNT_EXP)
3923a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->tx_bytes += TXMAC_BYTE_CNT_COUNT;
3924a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XTXMAC_STATUS_TXFIFO_XFR_ERR)
3925a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->tx_fifo_errors++;
3926a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XTXMAC_STATUS_TXMAC_OFLOW)
3927a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->tx_overflow_errors++;
3928a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XTXMAC_STATUS_MAX_PSIZE_ERR)
3929a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->tx_max_pkt_size_errors++;
3930a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XTXMAC_STATUS_TXMAC_UFLOW)
3931a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->tx_underflow_errors++;
3932a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3933a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(XRXMAC_STATUS);
3934a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_LCL_FLT_STATUS)
3935a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_local_faults++;
3936a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_RFLT_DET)
3937a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_remote_faults++;
3938a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_LFLT_CNT_EXP)
3939a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_link_faults += LINK_FAULT_CNT_COUNT;
3940a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_ALIGNERR_CNT_EXP)
3941a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_align_errors += RXMAC_ALIGN_ERR_CNT_COUNT;
3942a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_RXFRAG_CNT_EXP)
3943a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_frags += RXMAC_FRAG_CNT_COUNT;
3944a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_RXMULTF_CNT_EXP)
3945a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_mcasts += RXMAC_MC_FRM_CNT_COUNT;
3946a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP)
3947a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT;
3948a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP)
3949a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT;
3950a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_RXHIST1_CNT_EXP)
3951a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_hist_cnt1 += RXMAC_HIST_CNT1_COUNT;
3952a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_RXHIST2_CNT_EXP)
3953a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_hist_cnt2 += RXMAC_HIST_CNT2_COUNT;
3954a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_RXHIST3_CNT_EXP)
3955a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_hist_cnt3 += RXMAC_HIST_CNT3_COUNT;
3956a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_RXHIST4_CNT_EXP)
3957a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_hist_cnt4 += RXMAC_HIST_CNT4_COUNT;
3958a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_RXHIST5_CNT_EXP)
3959a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_hist_cnt5 += RXMAC_HIST_CNT5_COUNT;
3960a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_RXHIST6_CNT_EXP)
3961a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_hist_cnt6 += RXMAC_HIST_CNT6_COUNT;
3962a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_RXHIST7_CNT_EXP)
3963a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_hist_cnt7 += RXMAC_HIST_CNT7_COUNT;
3964176edd52366d59350717b0bf6865b1d7ece156ccJulia Lawall	if (val & XRXMAC_STATUS_RXOCTET_CNT_EXP)
3965a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_octets += RXMAC_BT_CNT_COUNT;
3966a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_CVIOLERR_CNT_EXP)
3967a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_code_violations += RXMAC_CD_VIO_CNT_COUNT;
3968a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_LENERR_CNT_EXP)
3969a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_len_errors += RXMAC_MPSZER_CNT_COUNT;
3970a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_CRCERR_CNT_EXP)
3971a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_crc_errors += RXMAC_CRC_ER_CNT_COUNT;
3972a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_RXUFLOW)
3973a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_underflows++;
3974a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XRXMAC_STATUS_RXOFLOW)
3975a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_overflows++;
3976a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3977a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(XMAC_FC_STAT);
3978a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XMAC_FC_STAT_TX_MAC_NPAUSE)
3979a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->pause_off_state++;
3980a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XMAC_FC_STAT_TX_MAC_PAUSE)
3981a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->pause_on_state++;
3982a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & XMAC_FC_STAT_RX_MAC_RPAUSE)
3983a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->pause_received++;
3984a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
3985a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3986a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_bmac_interrupt(struct niu *np)
3987a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
3988a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_bmac_stats *mp = &np->mac_stats.bmac;
3989a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
3990a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
3991a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(BTXMAC_STATUS);
3992a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & BTXMAC_STATUS_UNDERRUN)
3993a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->tx_underflow_errors++;
3994a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & BTXMAC_STATUS_MAX_PKT_ERR)
3995a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->tx_max_pkt_size_errors++;
3996a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & BTXMAC_STATUS_BYTE_CNT_EXP)
3997a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->tx_bytes += BTXMAC_BYTE_CNT_COUNT;
3998a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & BTXMAC_STATUS_FRAME_CNT_EXP)
3999a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->tx_frames += BTXMAC_FRM_CNT_COUNT;
4000a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4001a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(BRXMAC_STATUS);
4002a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & BRXMAC_STATUS_OVERFLOW)
4003a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_overflows++;
4004a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & BRXMAC_STATUS_FRAME_CNT_EXP)
4005a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_frames += BRXMAC_FRAME_CNT_COUNT;
4006a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & BRXMAC_STATUS_ALIGN_ERR_EXP)
4007a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_align_errors += BRXMAC_ALIGN_ERR_CNT_COUNT;
4008a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & BRXMAC_STATUS_CRC_ERR_EXP)
4009a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_crc_errors += BRXMAC_ALIGN_ERR_CNT_COUNT;
4010a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & BRXMAC_STATUS_LEN_ERR_EXP)
4011a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->rx_len_errors += BRXMAC_CODE_VIOL_ERR_CNT_COUNT;
4012a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4013a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(BMAC_CTRL_STATUS);
4014a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & BMAC_CTRL_STATUS_NOPAUSE)
4015a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->pause_off_state++;
4016a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & BMAC_CTRL_STATUS_PAUSE)
4017a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->pause_on_state++;
4018a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (val & BMAC_CTRL_STATUS_PAUSE_RECV)
4019a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mp->pause_received++;
4020a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4021a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4022a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_mac_interrupt(struct niu *np)
4023a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4024a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC)
4025a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_xmac_interrupt(np);
4026a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
4027a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_bmac_interrupt(np);
4028a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4029a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
4030a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4031a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4032a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_log_device_error(struct niu *np, u64 stat)
4033a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4034f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netdev_err(np->dev, "Core device errors ( ");
4035a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4036a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & SYS_ERR_MASK_META2)
4037f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("META2 ");
4038a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & SYS_ERR_MASK_META1)
4039f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("META1 ");
4040a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & SYS_ERR_MASK_PEU)
4041f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("PEU ");
4042a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & SYS_ERR_MASK_TXC)
4043f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("TXC ");
4044a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & SYS_ERR_MASK_RDMC)
4045f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("RDMC ");
4046a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & SYS_ERR_MASK_TDMC)
4047f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("TDMC ");
4048a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & SYS_ERR_MASK_ZCP)
4049f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("ZCP ");
4050a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & SYS_ERR_MASK_FFLP)
4051f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("FFLP ");
4052a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & SYS_ERR_MASK_IPP)
4053f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("IPP ");
4054a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & SYS_ERR_MASK_MAC)
4055f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("MAC ");
4056a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stat & SYS_ERR_MASK_SMX)
4057f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_cont("SMX ");
4058a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4059f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	pr_cont(")\n");
4060a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4061a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4062a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_device_error(struct niu *np)
4063a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4064a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 stat = nr64(SYS_ERR_STAT);
4065a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4066f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netdev_err(np->dev, "Core device error, stat[%llx]\n",
4067f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		   (unsigned long long)stat);
4068a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4069a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_log_device_error(np, stat);
4070a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4071a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return -ENODEV;
4072a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4073a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4074406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Workustatic int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp,
4075406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku			      u64 v0, u64 v1, u64 v2)
4076a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4077406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku
4078a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, err = 0;
4079a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4080406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku	lp->v0 = v0;
4081406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku	lp->v1 = v1;
4082406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku	lp->v2 = v2;
4083406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku
4084a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (v1 & 0x00000000ffffffffULL) {
4085a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u32 rx_vec = (v1 & 0xffffffff);
4086a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4087a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		for (i = 0; i < np->num_rx_rings; i++) {
4088a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			struct rx_ring_info *rp = &np->rx_rings[i];
4089a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4090a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (rx_vec & (1 << rp->rx_channel)) {
4091a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				int r = niu_rx_error(np, rp);
4092406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku				if (r) {
4093a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					err = r;
4094406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku				} else {
4095406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku					if (!v0)
4096406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku						nw64(RX_DMA_CTL_STAT(rp->rx_channel),
4097406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku						     RX_DMA_CTL_STAT_MEX);
4098406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku				}
4099a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			}
4100a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
4101a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4102a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (v1 & 0x7fffffff00000000ULL) {
4103a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u32 tx_vec = (v1 >> 32) & 0x7fffffff;
4104a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4105a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		for (i = 0; i < np->num_tx_rings; i++) {
4106a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			struct tx_ring_info *rp = &np->tx_rings[i];
4107a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4108a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (tx_vec & (1 << rp->tx_channel)) {
4109a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				int r = niu_tx_error(np, rp);
4110a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				if (r)
4111a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					err = r;
4112a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			}
4113a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
4114a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4115a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if ((v0 | v1) & 0x8000000000000000ULL) {
4116a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int r = niu_mif_interrupt(np);
4117a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (r)
4118a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			err = r;
4119a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4120a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (v2) {
4121a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (v2 & 0x01ef) {
4122a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			int r = niu_mac_interrupt(np);
4123a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (r)
4124a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				err = r;
4125a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
4126a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (v2 & 0x0210) {
4127a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			int r = niu_device_error(np);
4128a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (r)
4129a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				err = r;
4130a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
4131a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4132a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4133a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
4134a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_enable_interrupts(np, 0);
4135a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4136406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku	return err;
4137a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4138a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4139a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_rxchan_intr(struct niu *np, struct rx_ring_info *rp,
4140a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			    int ldn)
4141a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4142a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct rxdma_mailbox *mbox = rp->mbox;
4143a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 stat_write, stat = le64_to_cpup(&mbox->rx_dma_ctl_stat);
4144a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4145a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	stat_write = (RX_DMA_CTL_STAT_RCRTHRES |
4146a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		      RX_DMA_CTL_STAT_RCRTO);
4147a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat_write);
4148a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4149f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, intr, KERN_DEBUG, np->dev,
4150f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "%s() stat[%llx]\n", __func__, (unsigned long long)stat);
4151a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4152a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4153a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_txchan_intr(struct niu *np, struct tx_ring_info *rp,
4154a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			    int ldn)
4155a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4156a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->tx_cs = nr64(TX_CS(rp->tx_channel));
4157a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4158f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, intr, KERN_DEBUG, np->dev,
4159f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "%s() cs[%llx]\n", __func__, (unsigned long long)rp->tx_cs);
4160a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4161a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4162a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __niu_fastpath_interrupt(struct niu *np, int ldg, u64 v0)
4163a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4164a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent = np->parent;
4165a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u32 rx_vec, tx_vec;
4166a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
4167a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4168a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tx_vec = (v0 >> 32);
4169a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rx_vec = (v0 & 0xffffffff);
4170a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4171a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_rx_rings; i++) {
4172a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct rx_ring_info *rp = &np->rx_rings[i];
4173a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int ldn = LDN_RXDMA(rp->rx_channel);
4174a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4175a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (parent->ldg_map[ldn] != ldg)
4176a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			continue;
4177a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4178a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64(LD_IM0(ldn), LD_IM0_MASK);
4179a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (rx_vec & (1 << rp->rx_channel))
4180a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			niu_rxchan_intr(np, rp, ldn);
4181a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4182a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4183a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_tx_rings; i++) {
4184a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct tx_ring_info *rp = &np->tx_rings[i];
4185a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int ldn = LDN_TXDMA(rp->tx_channel);
4186a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4187a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (parent->ldg_map[ldn] != ldg)
4188a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			continue;
4189a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4190a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64(LD_IM0(ldn), LD_IM0_MASK);
4191a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (tx_vec & (1 << rp->tx_channel))
4192a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			niu_txchan_intr(np, rp, ldn);
4193a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4194a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4195a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4196a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_schedule_napi(struct niu *np, struct niu_ldg *lp,
4197a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			      u64 v0, u64 v1, u64 v2)
4198a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4199288379f050284087578b77e04f040b57db3db3f8Ben Hutchings	if (likely(napi_schedule_prep(&lp->napi))) {
4200a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		lp->v0 = v0;
4201a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		lp->v1 = v1;
4202a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		lp->v2 = v2;
4203a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		__niu_fastpath_interrupt(np, lp->ldg_num, v0);
4204288379f050284087578b77e04f040b57db3db3f8Ben Hutchings		__napi_schedule(&lp->napi);
4205a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4206a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4207a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4208a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic irqreturn_t niu_interrupt(int irq, void *dev_id)
4209a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4210a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_ldg *lp = dev_id;
4211a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = lp->np;
4212a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int ldg = lp->ldg_num;
4213a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long flags;
4214a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 v0, v1, v2;
4215a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4216a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (netif_msg_intr(np))
4217f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		printk(KERN_DEBUG KBUILD_MODNAME ": " "%s() ldg[%p](%d)",
4218f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		       __func__, lp, ldg);
4219a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4220a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_lock_irqsave(&np->lock, flags);
4221a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4222a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	v0 = nr64(LDSV0(ldg));
4223a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	v1 = nr64(LDSV1(ldg));
4224a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	v2 = nr64(LDSV2(ldg));
4225a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4226a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (netif_msg_intr(np))
422702b1bae5e1c0f810168037be0134685085e95e88David S. Miller		pr_cont(" v0[%llx] v1[%llx] v2[%llx]\n",
4228a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       (unsigned long long) v0,
4229a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       (unsigned long long) v1,
4230a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       (unsigned long long) v2);
4231a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4232a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (unlikely(!v0 && !v1 && !v2)) {
4233a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		spin_unlock_irqrestore(&np->lock, flags);
4234a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return IRQ_NONE;
4235a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4236a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4237a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (unlikely((v0 & ((u64)1 << LDN_MIF)) || v1 || v2)) {
4238406f353c857e4b2dbddb7cd20c67941d829b8b15Matheos Worku		int err = niu_slowpath_interrupt(np, lp, v0, v1, v2);
4239a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
4240a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			goto out;
4241a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4242a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (likely(v0 & ~((u64)1 << LDN_MIF)))
4243a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_schedule_napi(np, lp, v0, v1, v2);
4244a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
4245a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_ldg_rearm(np, lp, 1);
4246a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerout:
4247a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_unlock_irqrestore(&np->lock, flags);
4248a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4249a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return IRQ_HANDLED;
4250a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4251a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4252a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_free_rx_ring_info(struct niu *np, struct rx_ring_info *rp)
4253a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4254a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (rp->mbox) {
4255a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->ops->free_coherent(np->device,
4256a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				       sizeof(struct rxdma_mailbox),
4257a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				       rp->mbox, rp->mbox_dma);
4258a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->mbox = NULL;
4259a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4260a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (rp->rcr) {
4261a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->ops->free_coherent(np->device,
4262a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				       MAX_RCR_RING_SIZE * sizeof(__le64),
4263a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				       rp->rcr, rp->rcr_dma);
4264a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->rcr = NULL;
4265a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->rcr_table_size = 0;
4266a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->rcr_index = 0;
4267a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4268a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (rp->rbr) {
4269a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_rbr_free(np, rp);
4270a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4271a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->ops->free_coherent(np->device,
4272a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				       MAX_RBR_RING_SIZE * sizeof(__le32),
4273a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				       rp->rbr, rp->rbr_dma);
4274a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->rbr = NULL;
4275a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->rbr_table_size = 0;
4276a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->rbr_index = 0;
4277a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4278a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	kfree(rp->rxhash);
4279a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rxhash = NULL;
4280a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4281a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4282a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_free_tx_ring_info(struct niu *np, struct tx_ring_info *rp)
4283a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4284a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (rp->mbox) {
4285a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->ops->free_coherent(np->device,
4286a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				       sizeof(struct txdma_mailbox),
4287a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				       rp->mbox, rp->mbox_dma);
4288a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->mbox = NULL;
4289a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4290a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (rp->descr) {
4291a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int i;
4292a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4293a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		for (i = 0; i < MAX_TX_RING_SIZE; i++) {
4294a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (rp->tx_buffs[i].skb)
4295a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				(void) release_tx_packet(np, rp, i);
4296a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
4297a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4298a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->ops->free_coherent(np->device,
4299a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				       MAX_TX_RING_SIZE * sizeof(__le64),
4300a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				       rp->descr, rp->descr_dma);
4301a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->descr = NULL;
4302a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->pending = 0;
4303a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->prod = 0;
4304a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->cons = 0;
4305a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->wrap_bit = 0;
4306a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4307a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4308a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4309a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_free_channels(struct niu *np)
4310a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4311a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
4312a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4313a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->rx_rings) {
4314a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		for (i = 0; i < np->num_rx_rings; i++) {
4315a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			struct rx_ring_info *rp = &np->rx_rings[i];
4316a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4317a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			niu_free_rx_ring_info(np, rp);
4318a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
4319a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		kfree(np->rx_rings);
4320a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->rx_rings = NULL;
4321a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->num_rx_rings = 0;
4322a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4323a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4324a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->tx_rings) {
4325a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		for (i = 0; i < np->num_tx_rings; i++) {
4326a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			struct tx_ring_info *rp = &np->tx_rings[i];
4327a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4328a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			niu_free_tx_ring_info(np, rp);
4329a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
4330a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		kfree(np->tx_rings);
4331a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->tx_rings = NULL;
4332a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->num_tx_rings = 0;
4333a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4334a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4335a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4336a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_alloc_rx_ring_info(struct niu *np,
4337a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  struct rx_ring_info *rp)
4338a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4339a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	BUILD_BUG_ON(sizeof(struct rxdma_mailbox) != 64);
4340a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4341a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rxhash = kzalloc(MAX_RBR_RING_SIZE * sizeof(struct page *),
4342a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			     GFP_KERNEL);
4343a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!rp->rxhash)
4344a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENOMEM;
4345a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4346a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->mbox = np->ops->alloc_coherent(np->device,
4347a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					   sizeof(struct rxdma_mailbox),
4348a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					   &rp->mbox_dma, GFP_KERNEL);
4349a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!rp->mbox)
4350a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENOMEM;
4351a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if ((unsigned long)rp->mbox & (64UL - 1)) {
4352f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "Coherent alloc gives misaligned RXDMA mailbox %p\n",
4353f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   rp->mbox);
4354a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
4355a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4356a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4357a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rcr = np->ops->alloc_coherent(np->device,
4358a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					  MAX_RCR_RING_SIZE * sizeof(__le64),
4359a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					  &rp->rcr_dma, GFP_KERNEL);
4360a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!rp->rcr)
4361a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENOMEM;
4362a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if ((unsigned long)rp->rcr & (64UL - 1)) {
4363f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "Coherent alloc gives misaligned RXDMA RCR table %p\n",
4364f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   rp->rcr);
4365a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
4366a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4367a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rcr_table_size = MAX_RCR_RING_SIZE;
4368a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rcr_index = 0;
4369a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4370a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rbr = np->ops->alloc_coherent(np->device,
4371a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					  MAX_RBR_RING_SIZE * sizeof(__le32),
4372a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					  &rp->rbr_dma, GFP_KERNEL);
4373a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!rp->rbr)
4374a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENOMEM;
4375a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if ((unsigned long)rp->rbr & (64UL - 1)) {
4376f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "Coherent alloc gives misaligned RXDMA RBR table %p\n",
4377f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   rp->rbr);
4378a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
4379a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4380a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rbr_table_size = MAX_RBR_RING_SIZE;
4381a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rbr_index = 0;
4382a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rbr_pending = 0;
4383a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4384a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
4385a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4386a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4387a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_set_max_burst(struct niu *np, struct tx_ring_info *rp)
4388a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4389a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int mtu = np->dev->mtu;
4390a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4391a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* These values are recommended by the HW designers for fair
4392a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 * utilization of DRR amongst the rings.
4393a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 */
4394a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->max_burst = mtu + 32;
4395a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (rp->max_burst > 4096)
4396a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->max_burst = 4096;
4397a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4398a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4399a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_alloc_tx_ring_info(struct niu *np,
4400a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  struct tx_ring_info *rp)
4401a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4402a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	BUILD_BUG_ON(sizeof(struct txdma_mailbox) != 64);
4403a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4404a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->mbox = np->ops->alloc_coherent(np->device,
4405a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					   sizeof(struct txdma_mailbox),
4406a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					   &rp->mbox_dma, GFP_KERNEL);
4407a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!rp->mbox)
4408a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENOMEM;
4409a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if ((unsigned long)rp->mbox & (64UL - 1)) {
4410f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "Coherent alloc gives misaligned TXDMA mailbox %p\n",
4411f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   rp->mbox);
4412a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
4413a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4414a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4415a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->descr = np->ops->alloc_coherent(np->device,
4416a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					    MAX_TX_RING_SIZE * sizeof(__le64),
4417a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					    &rp->descr_dma, GFP_KERNEL);
4418a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!rp->descr)
4419a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENOMEM;
4420a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if ((unsigned long)rp->descr & (64UL - 1)) {
4421f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "Coherent alloc gives misaligned TXDMA descr table %p\n",
4422f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   rp->descr);
4423a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
4424a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4425a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4426a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->pending = MAX_TX_RING_SIZE;
4427a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->prod = 0;
4428a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->cons = 0;
4429a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->wrap_bit = 0;
4430a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4431a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* XXX make these configurable... XXX */
4432a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->mark_freq = rp->pending / 4;
4433a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4434a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_set_max_burst(np, rp);
4435a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4436a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
4437a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4438a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4439a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_size_rbr(struct niu *np, struct rx_ring_info *rp)
4440a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
444181429973cfff7745792c877dd083eec29724ec97Olof Johansson	u16 bss;
4442a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
444381429973cfff7745792c877dd083eec29724ec97Olof Johansson	bss = min(PAGE_SHIFT, 15);
4444a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
444581429973cfff7745792c877dd083eec29724ec97Olof Johansson	rp->rbr_block_size = 1 << bss;
444681429973cfff7745792c877dd083eec29724ec97Olof Johansson	rp->rbr_blocks_per_page = 1 << (PAGE_SHIFT-bss);
4447a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4448a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rbr_sizes[0] = 256;
4449a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rbr_sizes[1] = 1024;
4450a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->dev->mtu > ETH_DATA_LEN) {
4451a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		switch (PAGE_SIZE) {
4452a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		case 4 * 1024:
4453a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			rp->rbr_sizes[2] = 4096;
4454a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
4455a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4456a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		default:
4457a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			rp->rbr_sizes[2] = 8192;
4458a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
4459a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
4460a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
4461a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->rbr_sizes[2] = 2048;
4462a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4463a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->rbr_sizes[3] = rp->rbr_block_size;
4464a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4465a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4466a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_alloc_channels(struct niu *np)
4467a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4468a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent = np->parent;
4469a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int first_rx_channel, first_tx_channel;
44709690c636ac118b6662f28308bee817343d9932d8David S. Miller	int num_rx_rings, num_tx_rings;
44719690c636ac118b6662f28308bee817343d9932d8David S. Miller	struct rx_ring_info *rx_rings;
44729690c636ac118b6662f28308bee817343d9932d8David S. Miller	struct tx_ring_info *tx_rings;
4473a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, port, err;
4474a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4475a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	port = np->port;
4476a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	first_rx_channel = first_tx_channel = 0;
4477a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < port; i++) {
4478a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		first_rx_channel += parent->rxchan_per_port[i];
4479a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		first_tx_channel += parent->txchan_per_port[i];
4480a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4481a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
44829690c636ac118b6662f28308bee817343d9932d8David S. Miller	num_rx_rings = parent->rxchan_per_port[port];
44839690c636ac118b6662f28308bee817343d9932d8David S. Miller	num_tx_rings = parent->txchan_per_port[port];
4484a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
44859690c636ac118b6662f28308bee817343d9932d8David S. Miller	rx_rings = kcalloc(num_rx_rings, sizeof(struct rx_ring_info),
44869690c636ac118b6662f28308bee817343d9932d8David S. Miller			   GFP_KERNEL);
4487a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = -ENOMEM;
44889690c636ac118b6662f28308bee817343d9932d8David S. Miller	if (!rx_rings)
4489a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out_err;
4490a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
44919690c636ac118b6662f28308bee817343d9932d8David S. Miller	np->num_rx_rings = num_rx_rings;
44929690c636ac118b6662f28308bee817343d9932d8David S. Miller	smp_wmb();
44939690c636ac118b6662f28308bee817343d9932d8David S. Miller	np->rx_rings = rx_rings;
44949690c636ac118b6662f28308bee817343d9932d8David S. Miller
44959690c636ac118b6662f28308bee817343d9932d8David S. Miller	netif_set_real_num_rx_queues(np->dev, num_rx_rings);
44969690c636ac118b6662f28308bee817343d9932d8David S. Miller
4497a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_rx_rings; i++) {
4498a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct rx_ring_info *rp = &np->rx_rings[i];
4499a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4500a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->np = np;
4501a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->rx_channel = first_rx_channel + i;
4502a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4503a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_alloc_rx_ring_info(np, rp);
4504a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
4505a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			goto out_err;
4506a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4507a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_size_rbr(np, rp);
4508a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4509a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* XXX better defaults, configurable, etc... XXX */
4510a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->nonsyn_window = 64;
4511a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->nonsyn_threshold = rp->rcr_table_size - 64;
4512a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->syn_window = 64;
4513a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->syn_threshold = rp->rcr_table_size - 64;
4514a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->rcr_pkt_threshold = 16;
4515a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->rcr_timeout = 8;
4516a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->rbr_kick_thresh = RBR_REFILL_MIN;
4517a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (rp->rbr_kick_thresh < rp->rbr_blocks_per_page)
4518a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			rp->rbr_kick_thresh = rp->rbr_blocks_per_page;
4519a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4520a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_rbr_fill(np, rp, GFP_KERNEL);
4521a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
4522a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
4523a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4524a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
45259690c636ac118b6662f28308bee817343d9932d8David S. Miller	tx_rings = kcalloc(num_tx_rings, sizeof(struct tx_ring_info),
45269690c636ac118b6662f28308bee817343d9932d8David S. Miller			   GFP_KERNEL);
4527a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = -ENOMEM;
45289690c636ac118b6662f28308bee817343d9932d8David S. Miller	if (!tx_rings)
4529a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out_err;
4530a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
45319690c636ac118b6662f28308bee817343d9932d8David S. Miller	np->num_tx_rings = num_tx_rings;
45329690c636ac118b6662f28308bee817343d9932d8David S. Miller	smp_wmb();
45339690c636ac118b6662f28308bee817343d9932d8David S. Miller	np->tx_rings = tx_rings;
45349690c636ac118b6662f28308bee817343d9932d8David S. Miller
45359690c636ac118b6662f28308bee817343d9932d8David S. Miller	netif_set_real_num_tx_queues(np->dev, num_tx_rings);
45369690c636ac118b6662f28308bee817343d9932d8David S. Miller
4537a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_tx_rings; i++) {
4538a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct tx_ring_info *rp = &np->tx_rings[i];
4539a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4540a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->np = np;
4541a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->tx_channel = first_tx_channel + i;
4542a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4543a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_alloc_tx_ring_info(np, rp);
4544a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
4545a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			goto out_err;
4546a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4547a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4548a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
4549a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4550a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerout_err:
4551a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_free_channels(np);
4552a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
4553a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4554a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4555a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_tx_cs_sng_poll(struct niu *np, int channel)
4556a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4557a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int limit = 1000;
4558a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4559a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (--limit > 0) {
4560a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u64 val = nr64(TX_CS(channel));
4561a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (val & TX_CS_SNG_STATE)
4562a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return 0;
4563a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4564a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return -ENODEV;
4565a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4566a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4567a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_tx_channel_stop(struct niu *np, int channel)
4568a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4569a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64(TX_CS(channel));
4570a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4571a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= TX_CS_STOP_N_GO;
4572a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TX_CS(channel), val);
4573a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4574a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return niu_tx_cs_sng_poll(np, channel);
4575a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4576a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4577a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_tx_cs_reset_poll(struct niu *np, int channel)
4578a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4579a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int limit = 1000;
4580a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4581a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (--limit > 0) {
4582a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u64 val = nr64(TX_CS(channel));
4583a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!(val & TX_CS_RST))
4584a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return 0;
4585a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4586a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return -ENODEV;
4587a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4588a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4589a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_tx_channel_reset(struct niu *np, int channel)
4590a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4591a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64(TX_CS(channel));
4592a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
4593a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4594a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= TX_CS_RST;
4595a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TX_CS(channel), val);
4596a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4597a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_tx_cs_reset_poll(np, channel);
4598a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err)
4599a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64(TX_RING_KICK(channel), 0);
4600a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4601a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
4602a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4603a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4604a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_tx_channel_lpage_init(struct niu *np, int channel)
4605a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4606a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
4607a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4608a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TX_LOG_MASK1(channel), 0);
4609a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TX_LOG_VAL1(channel), 0);
4610a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TX_LOG_MASK2(channel), 0);
4611a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TX_LOG_VAL2(channel), 0);
4612a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TX_LOG_PAGE_RELO1(channel), 0);
4613a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TX_LOG_PAGE_RELO2(channel), 0);
4614a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TX_LOG_PAGE_HDL(channel), 0);
4615a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4616a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val  = (u64)np->port << TX_LOG_PAGE_VLD_FUNC_SHIFT;
4617a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (TX_LOG_PAGE_VLD_PAGE0 | TX_LOG_PAGE_VLD_PAGE1);
4618a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TX_LOG_PAGE_VLD(channel), val);
4619a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4620a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* XXX TXDMA 32bit mode? XXX */
4621a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4622a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
4623a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4624a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4625a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_txc_enable_port(struct niu *np, int on)
4626a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4627a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long flags;
4628a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val, mask;
4629a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4630a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_lock_parent(np, flags);
4631a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(TXC_CONTROL);
4632a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mask = (u64)1 << np->port;
4633a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on) {
4634a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= TXC_CONTROL_ENABLE | mask;
4635a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
4636a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~mask;
4637a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if ((val & ~TXC_CONTROL_ENABLE) == 0)
4638a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			val &= ~TXC_CONTROL_ENABLE;
4639a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4640a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TXC_CONTROL, val);
4641a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_unlock_parent(np, flags);
4642a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4643a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4644a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_txc_set_imask(struct niu *np, u64 imask)
4645a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4646a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long flags;
4647a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
4648a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4649a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_lock_parent(np, flags);
4650a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(TXC_INT_MASK);
4651a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~TXC_INT_MASK_VAL(np->port);
4652a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (imask << TXC_INT_MASK_VAL_SHIFT(np->port));
4653a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_unlock_parent(np, flags);
4654a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4655a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4656a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_txc_port_dma_enable(struct niu *np, int on)
4657a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4658a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = 0;
4659a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4660a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on) {
4661a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int i;
4662a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4663a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		for (i = 0; i < np->num_tx_rings; i++)
4664a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			val |= (1 << np->tx_rings[i].tx_channel);
4665a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4666a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TXC_PORT_DMA(np->port), val);
4667a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4668a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4669a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_init_one_tx_channel(struct niu *np, struct tx_ring_info *rp)
4670a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4671a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err, channel = rp->tx_channel;
4672a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val, ring_len;
4673a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4674a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_tx_channel_stop(np, channel);
4675a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
4676a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
4677a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4678a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_tx_channel_reset(np, channel);
4679a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
4680a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
4681a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4682a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_tx_channel_lpage_init(np, channel);
4683a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
4684a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
4685a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4686a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TXC_DMA_MAX(channel), rp->max_burst);
4687a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TX_ENT_MSK(channel), 0);
4688a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4689a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (rp->descr_dma & ~(TX_RNG_CFIG_STADDR_BASE |
4690a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			      TX_RNG_CFIG_STADDR)) {
4691f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "TX ring channel %d DMA addr (%llx) is not aligned\n",
4692f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   channel, (unsigned long long)rp->descr_dma);
4693a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
4694a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4695a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4696a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* The length field in TX_RNG_CFIG is measured in 64-byte
4697a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 * blocks.  rp->pending is the number of TX descriptors in
4698a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 * our ring, 8 bytes each, thus we divide by 8 bytes more
4699a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 * to get the proper value the chip wants.
4700a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 */
4701a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	ring_len = (rp->pending / 8);
4702a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4703a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = ((ring_len << TX_RNG_CFIG_LEN_SHIFT) |
4704a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	       rp->descr_dma);
4705a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TX_RNG_CFIG(channel), val);
4706a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4707a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (((rp->mbox_dma >> 32) & ~TXDMA_MBH_MBADDR) ||
4708a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    ((u32)rp->mbox_dma & ~TXDMA_MBL_MBADDR)) {
4709f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "TX ring channel %d MBOX addr (%llx) has invalid bits\n",
4710f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			    channel, (unsigned long long)rp->mbox_dma);
4711a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
4712a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4713a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TXDMA_MBH(channel), rp->mbox_dma >> 32);
4714a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TXDMA_MBL(channel), rp->mbox_dma & TXDMA_MBL_MBADDR);
4715a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4716a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TX_CS(channel), 0);
4717a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4718a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->last_pkt_cnt = 0;
4719a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4720a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
4721a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4722a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4723a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_init_rdc_groups(struct niu *np)
4724a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4725a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_rdc_tables *tp = &np->parent->rdc_group_cfg[np->port];
4726a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, first_table_num = tp->first_table_num;
4727a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4728a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < tp->num_tables; i++) {
4729a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct rdc_table *tbl = &tp->tables[i];
4730a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int this_table = first_table_num + i;
4731a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int slot;
4732a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4733a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		for (slot = 0; slot < NIU_RDC_TABLE_SLOTS; slot++)
4734a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			nw64(RDC_TBL(this_table, slot),
4735a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			     tbl->rxdma_channel[slot]);
4736a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4737a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4738a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(DEF_RDC(np->port), np->parent->rdc_default[np->port]);
4739a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4740a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4741a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_init_drr_weight(struct niu *np)
4742a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4743a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int type = phy_decode(np->parent->port_phy, np->port);
4744a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
4745a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4746a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	switch (type) {
4747a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case PORT_TYPE_10G:
4748a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val = PT_DRR_WEIGHT_DEFAULT_10G;
4749a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4750a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4751a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case PORT_TYPE_1G:
4752a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	default:
4753a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val = PT_DRR_WEIGHT_DEFAULT_1G;
4754a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4755a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4756a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(PT_DRR_WT(np->port), val);
4757a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4758a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4759a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_init_hostinfo(struct niu *np)
4760a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4761a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent = np->parent;
4762a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port];
4763a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, err, num_alt = niu_num_alt_addr(np);
4764a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int first_rdc_table = tp->first_table_num;
4765a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4766a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_set_primary_mac_rdc_table(np, first_rdc_table, 1);
4767a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
4768a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
4769a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4770a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1);
4771a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
4772a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
4773a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4774a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < num_alt; i++) {
4775a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_set_alt_mac_rdc_table(np, i, first_rdc_table, 1);
4776a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
4777a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
4778a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4779a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4780a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
4781a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4782a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4783a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_rx_channel_reset(struct niu *np, int channel)
4784a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4785a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return niu_set_and_wait_clear(np, RXDMA_CFIG1(channel),
4786a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				      RXDMA_CFIG1_RST, 1000, 10,
4787a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				      "RXDMA_CFIG1");
4788a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4789a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4790a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_rx_channel_lpage_init(struct niu *np, int channel)
4791a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4792a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
4793a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4794a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_LOG_MASK1(channel), 0);
4795a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_LOG_VAL1(channel), 0);
4796a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_LOG_MASK2(channel), 0);
4797a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_LOG_VAL2(channel), 0);
4798a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_LOG_PAGE_RELO1(channel), 0);
4799a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_LOG_PAGE_RELO2(channel), 0);
4800a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_LOG_PAGE_HDL(channel), 0);
4801a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4802a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val  = (u64)np->port << RX_LOG_PAGE_VLD_FUNC_SHIFT;
4803a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (RX_LOG_PAGE_VLD_PAGE0 | RX_LOG_PAGE_VLD_PAGE1);
4804a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_LOG_PAGE_VLD(channel), val);
4805a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4806a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
4807a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4808a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4809a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_rx_channel_wred_init(struct niu *np, struct rx_ring_info *rp)
4810a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4811a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
4812a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4813a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = (((u64)rp->nonsyn_window << RDC_RED_PARA_WIN_SHIFT) |
4814a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	       ((u64)rp->nonsyn_threshold << RDC_RED_PARA_THRE_SHIFT) |
4815a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	       ((u64)rp->syn_window << RDC_RED_PARA_WIN_SYN_SHIFT) |
4816a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	       ((u64)rp->syn_threshold << RDC_RED_PARA_THRE_SYN_SHIFT));
4817a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RDC_RED_PARA(rp->rx_channel), val);
4818a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4819a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4820a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_compute_rbr_cfig_b(struct rx_ring_info *rp, u64 *ret)
4821a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4822a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = 0;
4823a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4824efb6c736da8f9c455c22bcbf717dbcf1889d0325David S. Miller	*ret = 0;
4825a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	switch (rp->rbr_block_size) {
4826a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 4 * 1024:
4827a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BLKSIZE_4K << RBR_CFIG_B_BLKSIZE_SHIFT);
4828a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4829a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 8 * 1024:
4830a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BLKSIZE_8K << RBR_CFIG_B_BLKSIZE_SHIFT);
4831a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4832a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 16 * 1024:
4833a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BLKSIZE_16K << RBR_CFIG_B_BLKSIZE_SHIFT);
4834a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4835a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 32 * 1024:
4836a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BLKSIZE_32K << RBR_CFIG_B_BLKSIZE_SHIFT);
4837a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4838a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	default:
4839a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
4840a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4841a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= RBR_CFIG_B_VLD2;
4842a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	switch (rp->rbr_sizes[2]) {
4843a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 2 * 1024:
4844a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BUFSZ2_2K << RBR_CFIG_B_BUFSZ2_SHIFT);
4845a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4846a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 4 * 1024:
4847a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BUFSZ2_4K << RBR_CFIG_B_BUFSZ2_SHIFT);
4848a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4849a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 8 * 1024:
4850a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BUFSZ2_8K << RBR_CFIG_B_BUFSZ2_SHIFT);
4851a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4852a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 16 * 1024:
4853a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BUFSZ2_16K << RBR_CFIG_B_BUFSZ2_SHIFT);
4854a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4855a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4856a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	default:
4857a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
4858a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4859a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= RBR_CFIG_B_VLD1;
4860a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	switch (rp->rbr_sizes[1]) {
4861a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 1 * 1024:
4862a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BUFSZ1_1K << RBR_CFIG_B_BUFSZ1_SHIFT);
4863a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4864a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 2 * 1024:
4865a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BUFSZ1_2K << RBR_CFIG_B_BUFSZ1_SHIFT);
4866a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4867a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 4 * 1024:
4868a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BUFSZ1_4K << RBR_CFIG_B_BUFSZ1_SHIFT);
4869a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4870a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 8 * 1024:
4871a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BUFSZ1_8K << RBR_CFIG_B_BUFSZ1_SHIFT);
4872a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4873a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4874a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	default:
4875a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
4876a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4877a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= RBR_CFIG_B_VLD0;
4878a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	switch (rp->rbr_sizes[0]) {
4879a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 256:
4880a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BUFSZ0_256 << RBR_CFIG_B_BUFSZ0_SHIFT);
4881a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4882a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 512:
4883a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BUFSZ0_512 << RBR_CFIG_B_BUFSZ0_SHIFT);
4884a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4885a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 1 * 1024:
4886a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BUFSZ0_1K << RBR_CFIG_B_BUFSZ0_SHIFT);
4887a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4888a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 2 * 1024:
4889a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (RBR_BUFSZ0_2K << RBR_CFIG_B_BUFSZ0_SHIFT);
4890a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
4891a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4892a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	default:
4893a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
4894a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4895a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4896a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	*ret = val;
4897a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
4898a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4899a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4900a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_enable_rx_channel(struct niu *np, int channel, int on)
4901a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4902a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64(RXDMA_CFIG1(channel));
4903a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int limit;
4904a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4905a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on)
4906a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= RXDMA_CFIG1_EN;
4907a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
4908a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~RXDMA_CFIG1_EN;
4909a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RXDMA_CFIG1(channel), val);
4910a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4911a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	limit = 1000;
4912a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (--limit > 0) {
4913a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (nr64(RXDMA_CFIG1(channel)) & RXDMA_CFIG1_QST)
4914a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
4915a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		udelay(10);
4916a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
4917a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (limit <= 0)
4918a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
4919a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
4920a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4921a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4922a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_init_one_rx_channel(struct niu *np, struct rx_ring_info *rp)
4923a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4924a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err, channel = rp->rx_channel;
4925a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
4926a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4927a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_rx_channel_reset(np, channel);
4928a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
4929a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
4930a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4931a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_rx_channel_lpage_init(np, channel);
4932a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
4933a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
4934a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4935a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_rx_channel_wred_init(np, rp);
4936a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4937a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_DMA_ENT_MSK(channel), RX_DMA_ENT_MSK_RBR_EMPTY);
4938a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_DMA_CTL_STAT(channel),
4939a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	     (RX_DMA_CTL_STAT_MEX |
4940a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	      RX_DMA_CTL_STAT_RCRTHRES |
4941a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	      RX_DMA_CTL_STAT_RCRTO |
4942a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	      RX_DMA_CTL_STAT_RBR_EMPTY));
4943a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RXDMA_CFIG1(channel), rp->mbox_dma >> 32);
49443cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller	nw64(RXDMA_CFIG2(channel),
49453cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller	     ((rp->mbox_dma & RXDMA_CFIG2_MBADDR_L) |
49463cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller	      RXDMA_CFIG2_FULL_HDR));
4947a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RBR_CFIG_A(channel),
4948a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	     ((u64)rp->rbr_table_size << RBR_CFIG_A_LEN_SHIFT) |
4949a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	     (rp->rbr_dma & (RBR_CFIG_A_STADDR_BASE | RBR_CFIG_A_STADDR)));
4950a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_compute_rbr_cfig_b(rp, &val);
4951a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
4952a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
4953a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RBR_CFIG_B(channel), val);
4954a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RCRCFIG_A(channel),
4955a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	     ((u64)rp->rcr_table_size << RCRCFIG_A_LEN_SHIFT) |
4956a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	     (rp->rcr_dma & (RCRCFIG_A_STADDR_BASE | RCRCFIG_A_STADDR)));
4957a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RCRCFIG_B(channel),
4958a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	     ((u64)rp->rcr_pkt_threshold << RCRCFIG_B_PTHRES_SHIFT) |
4959a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	     RCRCFIG_B_ENTOUT |
4960a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	     ((u64)rp->rcr_timeout << RCRCFIG_B_TIMEOUT_SHIFT));
4961a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4962a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_enable_rx_channel(np, channel, 1);
4963a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
4964a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
4965a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4966a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RBR_KICK(channel), rp->rbr_index);
4967a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4968a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(RX_DMA_CTL_STAT(channel));
4969a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= RX_DMA_CTL_STAT_RBR_EMPTY;
4970a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_DMA_CTL_STAT(channel), val);
4971a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4972a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
4973a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
4974a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4975a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_init_rx_channels(struct niu *np)
4976a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
4977a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long flags;
4978a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 seed = jiffies_64;
4979a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err, i;
4980a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4981a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_lock_parent(np, flags);
4982a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_DMA_CK_DIV, np->parent->rxdma_clock_divider);
4983a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RED_RAN_INIT, RED_RAN_INIT_OPMODE | (seed & RED_RAN_INIT_VAL));
4984a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_unlock_parent(np, flags);
4985a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4986a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* XXX RXDMA 32bit mode? XXX */
4987a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4988a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_init_rdc_groups(np);
4989a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_init_drr_weight(np);
4990a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4991a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_init_hostinfo(np);
4992a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
4993a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
4994a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4995a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_rx_rings; i++) {
4996a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct rx_ring_info *rp = &np->rx_rings[i];
4997a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
4998a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_init_one_rx_channel(np, rp);
4999a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
5000a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
5001a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5002a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5003a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
5004a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5005a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5006a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_set_ip_frag_rule(struct niu *np)
5007a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5008a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent = np->parent;
5009a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_classifier *cp = &np->clas;
5010a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_tcam_entry *tp;
5011a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int index, err;
5012a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
50132d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	index = cp->tcam_top;
5014a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tp = &parent->tcam[index];
5015a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5016a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* Note that the noport bit is the same in both ipv4 and
5017a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 * ipv6 format TCAM entries.
5018a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 */
5019a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	memset(tp, 0, sizeof(*tp));
5020a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tp->key[1] = TCAM_V4KEY1_NOPORT;
5021a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tp->key_mask[1] = TCAM_V4KEY1_NOPORT;
5022a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tp->assoc_data = (TCAM_ASSOCDATA_TRES_USE_OFFSET |
5023a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  ((u64)0 << TCAM_ASSOCDATA_OFFSET_SHIFT));
5024a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = tcam_write(np, index, tp->key, tp->key_mask);
5025a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
5026a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
5027a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = tcam_assoc_write(np, index, tp->assoc_data);
5028a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
5029a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
50302d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp->valid = 1;
50312d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	cp->tcam_valid_entries++;
5032a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5033a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
5034a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5035a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5036a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_init_classifier_hw(struct niu *np)
5037a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5038a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent = np->parent;
5039a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_classifier *cp = &np->clas;
5040a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, err;
5041a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5042a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(H1POLY, cp->h1_init);
5043a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(H2POLY, cp->h2_init);
5044a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5045a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_init_hostinfo(np);
5046a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
5047a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
5048a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5049a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < ENET_VLAN_TBL_NUM_ENTRIES; i++) {
5050a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct niu_vlan_rdc *vp = &cp->vlan_mappings[i];
5051a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5052a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		vlan_tbl_write(np, i, np->port,
5053a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       vp->vlan_pref, vp->rdc_num);
5054a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5055a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5056a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < cp->num_alt_mac_mappings; i++) {
5057a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct niu_altmac_rdc *ap = &cp->alt_mac_mappings[i];
5058a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5059a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_set_alt_mac_rdc_table(np, ap->alt_mac_num,
5060a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller						ap->rdc_num, ap->mac_pref);
5061a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
5062a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
5063a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5064a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5065a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_SCTP_IPV6; i++) {
5066a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int index = i - CLASS_CODE_USER_PROG1;
5067a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5068a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_set_tcam_key(np, i, parent->tcam_key[index]);
5069a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
5070a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
5071a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_set_flow_key(np, i, parent->flow_key[index]);
5072a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
5073a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
5074a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5075a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5076a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_set_ip_frag_rule(np);
5077a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
5078a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
5079a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5080a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tcam_enable(np, 1);
5081a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5082a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
5083a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5084a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5085a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_zcp_write(struct niu *np, int index, u64 *data)
5086a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5087a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ZCP_RAM_DATA0, data[0]);
5088a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ZCP_RAM_DATA1, data[1]);
5089a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ZCP_RAM_DATA2, data[2]);
5090a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ZCP_RAM_DATA3, data[3]);
5091a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ZCP_RAM_DATA4, data[4]);
5092a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ZCP_RAM_BE, ZCP_RAM_BE_VAL);
5093a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ZCP_RAM_ACC,
5094a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	     (ZCP_RAM_ACC_WRITE |
5095a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	      (0 << ZCP_RAM_ACC_ZFCID_SHIFT) |
5096a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	      (ZCP_RAM_SEL_CFIFO(np->port) << ZCP_RAM_ACC_RAM_SEL_SHIFT)));
5097a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5098a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY,
5099a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				   1000, 100);
5100a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5101a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5102a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_zcp_read(struct niu *np, int index, u64 *data)
5103a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5104a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
5105a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5106a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY,
5107a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  1000, 100);
5108a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err) {
5109f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "ZCP read busy won't clear, ZCP_RAM_ACC[%llx]\n",
5110f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   (unsigned long long)nr64(ZCP_RAM_ACC));
5111a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
5112a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5113a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5114a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ZCP_RAM_ACC,
5115a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	     (ZCP_RAM_ACC_READ |
5116a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	      (0 << ZCP_RAM_ACC_ZFCID_SHIFT) |
5117a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	      (ZCP_RAM_SEL_CFIFO(np->port) << ZCP_RAM_ACC_RAM_SEL_SHIFT)));
5118a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5119a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY,
5120a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  1000, 100);
5121a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err) {
5122f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "ZCP read busy2 won't clear, ZCP_RAM_ACC[%llx]\n",
5123f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   (unsigned long long)nr64(ZCP_RAM_ACC));
5124a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
5125a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5126a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5127a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[0] = nr64(ZCP_RAM_DATA0);
5128a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[1] = nr64(ZCP_RAM_DATA1);
5129a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[2] = nr64(ZCP_RAM_DATA2);
5130a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[3] = nr64(ZCP_RAM_DATA3);
5131a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[4] = nr64(ZCP_RAM_DATA4);
5132a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5133a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
5134a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5135a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5136a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_zcp_cfifo_reset(struct niu *np)
5137a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5138a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64(RESET_CFIFO);
5139a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5140a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= RESET_CFIFO_RST(np->port);
5141a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RESET_CFIFO, val);
5142a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	udelay(10);
5143a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5144a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~RESET_CFIFO_RST(np->port);
5145a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RESET_CFIFO, val);
5146a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5147a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5148a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_init_zcp(struct niu *np)
5149a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5150a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 data[5], rbuf[5];
5151a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, max, err;
5152a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5153a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->parent->plat_type != PLAT_TYPE_NIU) {
5154a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (np->port == 0 || np->port == 1)
5155a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			max = ATLAS_P0_P1_CFIFO_ENTRIES;
5156a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		else
5157a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			max = ATLAS_P2_P3_CFIFO_ENTRIES;
5158a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else
5159a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		max = NIU_CFIFO_ENTRIES;
5160a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5161a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[0] = 0;
5162a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[1] = 0;
5163a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[2] = 0;
5164a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[3] = 0;
5165a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[4] = 0;
5166a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5167a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < max; i++) {
5168a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_zcp_write(np, i, data);
5169a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
5170a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
5171a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_zcp_read(np, i, rbuf);
5172a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
5173a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
5174a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5175a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5176a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_zcp_cfifo_reset(np);
5177a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(CFIFO_ECC(np->port), 0);
5178a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ZCP_INT_STAT, ZCP_INT_STAT_ALL);
5179a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	(void) nr64(ZCP_INT_STAT);
5180a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ZCP_INT_MASK, ZCP_INT_MASK_ALL);
5181a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5182a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
5183a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5184a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5185a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_ipp_write(struct niu *np, int index, u64 *data)
5186a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5187a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64_ipp(IPP_CFIG);
5188a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5189a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_ipp(IPP_CFIG, val | IPP_CFIG_DFIFO_PIO_W);
5190a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_ipp(IPP_DFIFO_WR_PTR, index);
5191a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_ipp(IPP_DFIFO_WR0, data[0]);
5192a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_ipp(IPP_DFIFO_WR1, data[1]);
5193a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_ipp(IPP_DFIFO_WR2, data[2]);
5194a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_ipp(IPP_DFIFO_WR3, data[3]);
5195a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_ipp(IPP_DFIFO_WR4, data[4]);
5196a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_ipp(IPP_CFIG, val & ~IPP_CFIG_DFIFO_PIO_W);
5197a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5198a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5199a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_ipp_read(struct niu *np, int index, u64 *data)
5200a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5201a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_ipp(IPP_DFIFO_RD_PTR, index);
5202a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[0] = nr64_ipp(IPP_DFIFO_RD0);
5203a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[1] = nr64_ipp(IPP_DFIFO_RD1);
5204a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[2] = nr64_ipp(IPP_DFIFO_RD2);
5205a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[3] = nr64_ipp(IPP_DFIFO_RD3);
5206a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[4] = nr64_ipp(IPP_DFIFO_RD4);
5207a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5208a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5209a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_ipp_reset(struct niu *np)
5210a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5211a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return niu_set_and_wait_clear_ipp(np, IPP_CFIG, IPP_CFIG_SOFT_RST,
5212a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					  1000, 100, "IPP_CFIG");
5213a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5214a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5215a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_init_ipp(struct niu *np)
5216a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5217a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 data[5], rbuf[5], val;
5218a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, max, err;
5219a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5220a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->parent->plat_type != PLAT_TYPE_NIU) {
5221a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (np->port == 0 || np->port == 1)
5222a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			max = ATLAS_P0_P1_DFIFO_ENTRIES;
5223a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		else
5224a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			max = ATLAS_P2_P3_DFIFO_ENTRIES;
5225a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else
5226a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		max = NIU_DFIFO_ENTRIES;
5227a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5228a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[0] = 0;
5229a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[1] = 0;
5230a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[2] = 0;
5231a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[3] = 0;
5232a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	data[4] = 0;
5233a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5234a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < max; i++) {
5235a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_ipp_write(np, i, data);
5236a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_ipp_read(np, i, rbuf);
5237a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5238a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5239a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	(void) nr64_ipp(IPP_INT_STAT);
5240a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	(void) nr64_ipp(IPP_INT_STAT);
5241a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5242a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_ipp_reset(np);
5243a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
5244a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
5245a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5246a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	(void) nr64_ipp(IPP_PKT_DIS);
5247a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	(void) nr64_ipp(IPP_BAD_CS_CNT);
5248a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	(void) nr64_ipp(IPP_ECC);
5249a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5250a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	(void) nr64_ipp(IPP_INT_STAT);
5251a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5252a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_ipp(IPP_MSK, ~IPP_MSK_ALL);
5253a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5254a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_ipp(IPP_CFIG);
5255a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~IPP_CFIG_IP_MAX_PKT;
5256a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (IPP_CFIG_IPP_ENABLE |
5257a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		IPP_CFIG_DFIFO_ECC_EN |
5258a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		IPP_CFIG_DROP_BAD_CRC |
5259a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		IPP_CFIG_CKSUM_EN |
5260a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		(0x1ffff << IPP_CFIG_IP_MAX_PKT_SHIFT));
5261a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_ipp(IPP_CFIG, val);
5262a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5263a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
5264a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5265a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
52660c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindnerstatic void niu_handle_led(struct niu *np, int status)
5267a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5268a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
5269a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(XMAC_CONFIG);
5270a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5271a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if ((np->flags & NIU_FLAGS_10G) != 0 &&
5272a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    (np->flags & NIU_FLAGS_FIBER) != 0) {
52730c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner		if (status) {
5274a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			val |= XMAC_CONFIG_LED_POLARITY;
5275a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			val &= ~XMAC_CONFIG_FORCE_LED_ON;
5276a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		} else {
5277a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			val |= XMAC_CONFIG_FORCE_LED_ON;
5278a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			val &= ~XMAC_CONFIG_LED_POLARITY;
5279a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
5280a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5281a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
52820c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner	nw64_mac(XMAC_CONFIG, val);
52830c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner}
52840c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner
52850c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindnerstatic void niu_init_xif_xmac(struct niu *np)
52860c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner{
52870c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner	struct niu_link_config *lp = &np->link_config;
52880c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner	u64 val;
52890c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner
52905fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (np->flags & NIU_FLAGS_XCVR_SERDES) {
52915fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		val = nr64(MIF_CONFIG);
52925fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		val |= MIF_CONFIG_ATCA_GE;
52935fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		nw64(MIF_CONFIG, val);
52945fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
52955fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
52960c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner	val = nr64_mac(XMAC_CONFIG);
5297a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~XMAC_CONFIG_SEL_POR_CLK_SRC;
5298a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5299a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= XMAC_CONFIG_TX_OUTPUT_EN;
5300a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5301a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (lp->loopback_mode == LOOPBACK_MAC) {
5302a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~XMAC_CONFIG_SEL_POR_CLK_SRC;
5303a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= XMAC_CONFIG_LOOPBACK;
5304a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
5305a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~XMAC_CONFIG_LOOPBACK;
5306a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5307a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5308a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_10G) {
5309a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~XMAC_CONFIG_LFS_DISABLE;
5310a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
5311a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= XMAC_CONFIG_LFS_DISABLE;
53125fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (!(np->flags & NIU_FLAGS_FIBER) &&
53135fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		    !(np->flags & NIU_FLAGS_XCVR_SERDES))
5314a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			val |= XMAC_CONFIG_1G_PCS_BYPASS;
5315a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		else
5316a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			val &= ~XMAC_CONFIG_1G_PCS_BYPASS;
5317a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5318a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5319a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~XMAC_CONFIG_10G_XPCS_BYPASS;
5320a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5321a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (lp->active_speed == SPEED_100)
5322a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= XMAC_CONFIG_SEL_CLK_25MHZ;
5323a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5324a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~XMAC_CONFIG_SEL_CLK_25MHZ;
5325a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5326a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XMAC_CONFIG, val);
5327a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5328a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(XMAC_CONFIG);
5329a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~XMAC_CONFIG_MODE_MASK;
5330a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_10G) {
5331a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= XMAC_CONFIG_MODE_XGMII;
5332a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
533338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		if (lp->active_speed == SPEED_1000)
5334a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			val |= XMAC_CONFIG_MODE_GMII;
533538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		else
533638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov			val |= XMAC_CONFIG_MODE_MII;
5337a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5338a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5339a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XMAC_CONFIG, val);
5340a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5341a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5342a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_init_xif_bmac(struct niu *np)
5343a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5344a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_link_config *lp = &np->link_config;
5345a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
5346a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5347a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = BMAC_XIF_CONFIG_TX_OUTPUT_EN;
5348a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5349a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (lp->loopback_mode == LOOPBACK_MAC)
5350a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= BMAC_XIF_CONFIG_MII_LOOPBACK;
5351a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5352a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~BMAC_XIF_CONFIG_MII_LOOPBACK;
5353a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5354a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (lp->active_speed == SPEED_1000)
5355a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= BMAC_XIF_CONFIG_GMII_MODE;
5356a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5357a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~BMAC_XIF_CONFIG_GMII_MODE;
5358a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5359a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~(BMAC_XIF_CONFIG_LINK_LED |
5360a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 BMAC_XIF_CONFIG_LED_POLARITY);
5361a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5362a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!(np->flags & NIU_FLAGS_10G) &&
5363a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    !(np->flags & NIU_FLAGS_FIBER) &&
5364a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    lp->active_speed == SPEED_100)
5365a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= BMAC_XIF_CONFIG_25MHZ_CLOCK;
5366a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5367a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~BMAC_XIF_CONFIG_25MHZ_CLOCK;
5368a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5369a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BMAC_XIF_CONFIG, val);
5370a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5371a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5372a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_init_xif(struct niu *np)
5373a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5374a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC)
5375a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_init_xif_xmac(np);
5376a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5377a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_init_xif_bmac(np);
5378a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5379a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5380a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_pcs_mii_reset(struct niu *np)
5381a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
53825fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	int limit = 1000;
5383a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64_pcs(PCS_MII_CTL);
5384a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= PCS_MII_CTL_RST;
5385a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_pcs(PCS_MII_CTL, val);
53865fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	while ((--limit >= 0) && (val & PCS_MII_CTL_RST)) {
53875fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		udelay(100);
53885fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		val = nr64_pcs(PCS_MII_CTL);
53895fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
5390a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5391a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5392a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_xpcs_reset(struct niu *np)
5393a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
53945fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	int limit = 1000;
5395a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64_xpcs(XPCS_CONTROL1);
5396a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= XPCS_CONTROL1_RESET;
5397a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_xpcs(XPCS_CONTROL1, val);
53985fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	while ((--limit >= 0) && (val & XPCS_CONTROL1_RESET)) {
53995fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		udelay(100);
54005fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		val = nr64_xpcs(XPCS_CONTROL1);
54015fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
5402a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5403a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5404a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_init_pcs(struct niu *np)
5405a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5406a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_link_config *lp = &np->link_config;
5407a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
5408a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
54095fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	switch (np->flags & (NIU_FLAGS_10G |
54105fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			     NIU_FLAGS_FIBER |
54115fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			     NIU_FLAGS_XCVR_SERDES)) {
5412a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case NIU_FLAGS_FIBER:
5413a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* 1G fiber */
5414a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_pcs(PCS_CONF, PCS_CONF_MASK | PCS_CONF_ENABLE);
5415a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_pcs(PCS_DPATH_MODE, 0);
5416a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_pcs_mii_reset(np);
5417a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
5418a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5419a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case NIU_FLAGS_10G:
5420a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case NIU_FLAGS_10G | NIU_FLAGS_FIBER:
54215fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	case NIU_FLAGS_10G | NIU_FLAGS_XCVR_SERDES:
54225fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		/* 10G SERDES */
5423a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!(np->flags & NIU_FLAGS_XMAC))
5424a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return -EINVAL;
5425a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5426a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* 10G copper or fiber */
5427a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val = nr64_mac(XMAC_CONFIG);
5428a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~XMAC_CONFIG_10G_XPCS_BYPASS;
5429a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(XMAC_CONFIG, val);
5430a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5431a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_xpcs_reset(np);
5432a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5433a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val = nr64_xpcs(XPCS_CONTROL1);
5434a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (lp->loopback_mode == LOOPBACK_PHY)
5435a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			val |= XPCS_CONTROL1_LOOPBACK;
5436a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		else
5437a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			val &= ~XPCS_CONTROL1_LOOPBACK;
5438a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_xpcs(XPCS_CONTROL1, val);
5439a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5440a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_xpcs(XPCS_DESKEW_ERR_CNT, 0);
5441a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		(void) nr64_xpcs(XPCS_SYMERR_CNT01);
5442a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		(void) nr64_xpcs(XPCS_SYMERR_CNT23);
5443a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
5444a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
54455fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
54465fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	case NIU_FLAGS_XCVR_SERDES:
54475fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		/* 1G SERDES */
54485fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		niu_pcs_mii_reset(np);
54495fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		nw64_pcs(PCS_CONF, PCS_CONF_MASK | PCS_CONF_ENABLE);
54505fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		nw64_pcs(PCS_DPATH_MODE, 0);
54515fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		break;
54525fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
5453a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 0:
5454a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* 1G copper */
54555fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	case NIU_FLAGS_XCVR_SERDES | NIU_FLAGS_FIBER:
54565fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		/* 1G RGMII FIBER */
5457a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_pcs(PCS_DPATH_MODE, PCS_DPATH_MODE_MII);
5458a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_pcs_mii_reset(np);
5459a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
5460a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5461a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	default:
5462a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
5463a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5464a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5465a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
5466a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5467a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5468a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_reset_tx_xmac(struct niu *np)
5469a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5470a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return niu_set_and_wait_clear_mac(np, XTXMAC_SW_RST,
5471a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					  (XTXMAC_SW_RST_REG_RS |
5472a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					   XTXMAC_SW_RST_SOFT_RST),
5473a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					  1000, 100, "XTXMAC_SW_RST");
5474a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5475a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5476a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_reset_tx_bmac(struct niu *np)
5477a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5478a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int limit;
5479a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5480a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BTXMAC_SW_RST, BTXMAC_SW_RST_RESET);
5481a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	limit = 1000;
5482a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (--limit >= 0) {
5483a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!(nr64_mac(BTXMAC_SW_RST) & BTXMAC_SW_RST_RESET))
5484a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
5485a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		udelay(100);
5486a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5487a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (limit < 0) {
5488f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(np->device, "Port %u TX BMAC would not reset, BTXMAC_SW_RST[%llx]\n",
5489a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			np->port,
5490a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			(unsigned long long) nr64_mac(BTXMAC_SW_RST));
5491a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
5492a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5493a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5494a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
5495a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5496a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5497a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_reset_tx_mac(struct niu *np)
5498a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5499a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC)
5500a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return niu_reset_tx_xmac(np);
5501a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5502a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return niu_reset_tx_bmac(np);
5503a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5504a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5505a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_init_tx_xmac(struct niu *np, u64 min, u64 max)
5506a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5507a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
5508a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5509a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(XMAC_MIN);
5510a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~(XMAC_MIN_TX_MIN_PKT_SIZE |
5511a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_MIN_RX_MIN_PKT_SIZE);
5512a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (min << XMAC_MIN_RX_MIN_PKT_SIZE_SHFT);
5513a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (min << XMAC_MIN_TX_MIN_PKT_SIZE_SHFT);
5514a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XMAC_MIN, val);
5515a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5516a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XMAC_MAX, max);
5517a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5518a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XTXMAC_STAT_MSK, ~(u64)0);
5519a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5520a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(XMAC_IPG);
5521a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_10G) {
5522a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~XMAC_IPG_IPG_XGMII;
5523a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (IPG_12_15_XGMII << XMAC_IPG_IPG_XGMII_SHIFT);
5524a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
5525a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~XMAC_IPG_IPG_MII_GMII;
5526a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= (IPG_12_MII_GMII << XMAC_IPG_IPG_MII_GMII_SHIFT);
5527a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5528a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XMAC_IPG, val);
5529a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5530a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(XMAC_CONFIG);
5531a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~(XMAC_CONFIG_ALWAYS_NO_CRC |
5532a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_STRETCH_MODE |
5533a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_VAR_MIN_IPG_EN |
5534a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_TX_ENABLE);
5535a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XMAC_CONFIG, val);
5536a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5537a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(TXMAC_FRM_CNT, 0);
5538a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(TXMAC_BYTE_CNT, 0);
5539a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5540a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5541a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_init_tx_bmac(struct niu *np, u64 min, u64 max)
5542a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5543a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
5544a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5545a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BMAC_MIN_FRAME, min);
5546a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BMAC_MAX_FRAME, max);
5547a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5548a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BTXMAC_STATUS_MASK, ~(u64)0);
5549a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BMAC_CTRL_TYPE, 0x8808);
5550a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BMAC_PREAMBLE_SIZE, 7);
5551a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5552a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(BTXMAC_CONFIG);
5553a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~(BTXMAC_CONFIG_FCS_DISABLE |
5554a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 BTXMAC_CONFIG_ENABLE);
5555a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BTXMAC_CONFIG, val);
5556a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5557a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5558a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_init_tx_mac(struct niu *np)
5559a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5560a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 min, max;
5561a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5562a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	min = 64;
5563a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->dev->mtu > ETH_DATA_LEN)
5564a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		max = 9216;
5565a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5566a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		max = 1522;
5567a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5568a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* The XMAC_MIN register only accepts values for TX min which
5569a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 * have the low 3 bits cleared.
5570a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 */
55718c87df457cb58fe75b9b893007917cf8095660a0Jan Beulich	BUG_ON(min & 0x7);
5572a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5573a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC)
5574a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_init_tx_xmac(np, min, max);
5575a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5576a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_init_tx_bmac(np, min, max);
5577a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5578a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5579a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_reset_rx_xmac(struct niu *np)
5580a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5581a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int limit;
5582a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5583a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XRXMAC_SW_RST,
5584a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XRXMAC_SW_RST_REG_RS | XRXMAC_SW_RST_SOFT_RST);
5585a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	limit = 1000;
5586a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (--limit >= 0) {
5587a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!(nr64_mac(XRXMAC_SW_RST) & (XRXMAC_SW_RST_REG_RS |
5588a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller						 XRXMAC_SW_RST_SOFT_RST)))
5589f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			break;
5590a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		udelay(100);
5591a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5592a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (limit < 0) {
5593f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(np->device, "Port %u RX XMAC would not reset, XRXMAC_SW_RST[%llx]\n",
5594a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			np->port,
5595a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			(unsigned long long) nr64_mac(XRXMAC_SW_RST));
5596a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
5597a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5598a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5599a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
5600a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5601a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5602a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_reset_rx_bmac(struct niu *np)
5603a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5604a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int limit;
5605a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5606a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BRXMAC_SW_RST, BRXMAC_SW_RST_RESET);
5607a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	limit = 1000;
5608a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (--limit >= 0) {
5609a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!(nr64_mac(BRXMAC_SW_RST) & BRXMAC_SW_RST_RESET))
5610a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
5611a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		udelay(100);
5612a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5613a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (limit < 0) {
5614f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(np->device, "Port %u RX BMAC would not reset, BRXMAC_SW_RST[%llx]\n",
5615a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			np->port,
5616a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			(unsigned long long) nr64_mac(BRXMAC_SW_RST));
5617a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
5618a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5619a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5620a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
5621a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5622a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5623a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_reset_rx_mac(struct niu *np)
5624a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5625a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC)
5626a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return niu_reset_rx_xmac(np);
5627a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5628a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return niu_reset_rx_bmac(np);
5629a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5630a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5631a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_init_rx_xmac(struct niu *np)
5632a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5633a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent = np->parent;
5634a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port];
5635a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int first_rdc_table = tp->first_table_num;
5636a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long i;
5637a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
5638a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5639a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XMAC_ADD_FILT0, 0);
5640a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XMAC_ADD_FILT1, 0);
5641a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XMAC_ADD_FILT2, 0);
5642a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XMAC_ADD_FILT12_MASK, 0);
5643a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XMAC_ADD_FILT00_MASK, 0);
5644a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < MAC_NUM_HASH; i++)
5645a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(XMAC_HASH_TBL(i), 0);
5646a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XRXMAC_STAT_MSK, ~(u64)0);
5647a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_set_primary_mac_rdc_table(np, first_rdc_table, 1);
5648a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1);
5649a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5650a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(XMAC_CONFIG);
5651a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~(XMAC_CONFIG_RX_MAC_ENABLE |
5652a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_PROMISCUOUS |
5653a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_PROMISC_GROUP |
5654a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_ERR_CHK_DIS |
5655a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_RX_CRC_CHK_DIS |
5656a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_RESERVED_MULTICAST |
5657a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_RX_CODEV_CHK_DIS |
5658a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_ADDR_FILTER_EN |
5659a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_RCV_PAUSE_ENABLE |
5660a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_STRIP_CRC |
5661a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_PASS_FLOW_CTRL |
5662a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_MAC2IPP_PKT_CNT_EN);
5663a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (XMAC_CONFIG_HASH_FILTER_EN);
5664a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XMAC_CONFIG, val);
5665a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5666a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(RXMAC_BT_CNT, 0);
5667a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(RXMAC_BC_FRM_CNT, 0);
5668a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(RXMAC_MC_FRM_CNT, 0);
5669a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(RXMAC_FRAG_CNT, 0);
5670a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(RXMAC_HIST_CNT1, 0);
5671a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(RXMAC_HIST_CNT2, 0);
5672a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(RXMAC_HIST_CNT3, 0);
5673a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(RXMAC_HIST_CNT4, 0);
5674a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(RXMAC_HIST_CNT5, 0);
5675a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(RXMAC_HIST_CNT6, 0);
5676a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(RXMAC_HIST_CNT7, 0);
5677a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(RXMAC_MPSZER_CNT, 0);
5678a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(RXMAC_CRC_ER_CNT, 0);
5679a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(RXMAC_CD_VIO_CNT, 0);
5680a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(LINK_FAULT_CNT, 0);
5681a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5682a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5683a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_init_rx_bmac(struct niu *np)
5684a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5685a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent = np->parent;
5686a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port];
5687a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int first_rdc_table = tp->first_table_num;
5688a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long i;
5689a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val;
5690a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5691a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BMAC_ADD_FILT0, 0);
5692a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BMAC_ADD_FILT1, 0);
5693a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BMAC_ADD_FILT2, 0);
5694a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BMAC_ADD_FILT12_MASK, 0);
5695a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BMAC_ADD_FILT00_MASK, 0);
5696a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < MAC_NUM_HASH; i++)
5697a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(BMAC_HASH_TBL(i), 0);
5698a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_set_primary_mac_rdc_table(np, first_rdc_table, 1);
5699a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1);
5700a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BRXMAC_STATUS_MASK, ~(u64)0);
5701a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5702a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(BRXMAC_CONFIG);
5703a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~(BRXMAC_CONFIG_ENABLE |
5704a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 BRXMAC_CONFIG_STRIP_PAD |
5705a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 BRXMAC_CONFIG_STRIP_FCS |
5706a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 BRXMAC_CONFIG_PROMISC |
5707a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 BRXMAC_CONFIG_PROMISC_GRP |
5708a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 BRXMAC_CONFIG_ADDR_FILT_EN |
5709a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 BRXMAC_CONFIG_DISCARD_DIS);
5710a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (BRXMAC_CONFIG_HASH_FILT_EN);
5711a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BRXMAC_CONFIG, val);
5712a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5713a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(BMAC_ADDR_CMPEN);
5714a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= BMAC_ADDR_CMPEN_EN0;
5715a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BMAC_ADDR_CMPEN, val);
5716a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5717a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5718a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_init_rx_mac(struct niu *np)
5719a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5720a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_set_primary_mac(np, np->dev->dev_addr);
5721a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5722a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC)
5723a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_init_rx_xmac(np);
5724a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5725a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_init_rx_bmac(np);
5726a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5727a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5728a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_enable_tx_xmac(struct niu *np, int on)
5729a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5730a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64_mac(XMAC_CONFIG);
5731a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5732a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on)
5733a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= XMAC_CONFIG_TX_ENABLE;
5734a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5735a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~XMAC_CONFIG_TX_ENABLE;
5736a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XMAC_CONFIG, val);
5737a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5738a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5739a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_enable_tx_bmac(struct niu *np, int on)
5740a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5741a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64_mac(BTXMAC_CONFIG);
5742a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5743a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on)
5744a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= BTXMAC_CONFIG_ENABLE;
5745a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5746a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~BTXMAC_CONFIG_ENABLE;
5747a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BTXMAC_CONFIG, val);
5748a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5749a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5750a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_enable_tx_mac(struct niu *np, int on)
5751a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5752a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC)
5753a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_enable_tx_xmac(np, on);
5754a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5755a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_enable_tx_bmac(np, on);
5756a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5757a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5758a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_enable_rx_xmac(struct niu *np, int on)
5759a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5760a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64_mac(XMAC_CONFIG);
5761a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5762a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~(XMAC_CONFIG_HASH_FILTER_EN |
5763a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 XMAC_CONFIG_PROMISCUOUS);
5764a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5765a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_MCAST)
5766a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= XMAC_CONFIG_HASH_FILTER_EN;
5767a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_PROMISC)
5768a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= XMAC_CONFIG_PROMISCUOUS;
5769a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5770a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on)
5771a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= XMAC_CONFIG_RX_MAC_ENABLE;
5772a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5773a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~XMAC_CONFIG_RX_MAC_ENABLE;
5774a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(XMAC_CONFIG, val);
5775a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5776a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5777a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_enable_rx_bmac(struct niu *np, int on)
5778a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5779a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val = nr64_mac(BRXMAC_CONFIG);
5780a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5781a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~(BRXMAC_CONFIG_HASH_FILT_EN |
5782a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 BRXMAC_CONFIG_PROMISC);
5783a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5784a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_MCAST)
5785a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= BRXMAC_CONFIG_HASH_FILT_EN;
5786a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_PROMISC)
5787a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= BRXMAC_CONFIG_PROMISC;
5788a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5789a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on)
5790a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= BRXMAC_CONFIG_ENABLE;
5791a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5792a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~BRXMAC_CONFIG_ENABLE;
5793a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(BRXMAC_CONFIG, val);
5794a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5795a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5796a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_enable_rx_mac(struct niu *np, int on)
5797a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5798a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC)
5799a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_enable_rx_xmac(np, on);
5800a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
5801a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_enable_rx_bmac(np, on);
5802a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5803a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5804a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_init_mac(struct niu *np)
5805a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5806a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
5807a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5808a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_init_xif(np);
5809a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_init_pcs(np);
5810a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
5811a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
5812a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5813a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_reset_tx_mac(np);
5814a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
5815a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
5816a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_init_tx_mac(np);
5817a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_reset_rx_mac(np);
5818a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
5819a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
5820a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_init_rx_mac(np);
5821a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5822a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* This looks hookey but the RX MAC reset we just did will
5823a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 * undo some of the state we setup in niu_init_tx_mac() so we
5824a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 * have to call it again.  In particular, the RX MAC reset will
5825a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 * set the XMAC_MAX register back to it's default value.
5826a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 */
5827a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_init_tx_mac(np);
5828a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_enable_tx_mac(np, 1);
5829a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5830a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_enable_rx_mac(np, 1);
5831a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5832a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
5833a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5834a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5835a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_stop_one_tx_channel(struct niu *np, struct tx_ring_info *rp)
5836a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5837a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	(void) niu_tx_channel_stop(np, rp->tx_channel);
5838a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5839a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5840a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_stop_tx_channels(struct niu *np)
5841a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5842a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
5843a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5844a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_tx_rings; i++) {
5845a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct tx_ring_info *rp = &np->tx_rings[i];
5846a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5847a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_stop_one_tx_channel(np, rp);
5848a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5849a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5850a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5851a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_reset_one_tx_channel(struct niu *np, struct tx_ring_info *rp)
5852a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5853a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	(void) niu_tx_channel_reset(np, rp->tx_channel);
5854a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5855a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5856a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_reset_tx_channels(struct niu *np)
5857a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5858a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
5859a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5860a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_tx_rings; i++) {
5861a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct tx_ring_info *rp = &np->tx_rings[i];
5862a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5863a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_reset_one_tx_channel(np, rp);
5864a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5865a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5866a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5867a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_stop_one_rx_channel(struct niu *np, struct rx_ring_info *rp)
5868a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5869a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	(void) niu_enable_rx_channel(np, rp->rx_channel, 0);
5870a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5871a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5872a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_stop_rx_channels(struct niu *np)
5873a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5874a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
5875a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5876a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_rx_rings; i++) {
5877a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct rx_ring_info *rp = &np->rx_rings[i];
5878a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5879a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_stop_one_rx_channel(np, rp);
5880a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5881a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5882a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5883a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_reset_one_rx_channel(struct niu *np, struct rx_ring_info *rp)
5884a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5885a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int channel = rp->rx_channel;
5886a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5887a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	(void) niu_rx_channel_reset(np, channel);
5888a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_DMA_ENT_MSK(channel), RX_DMA_ENT_MSK_ALL);
5889a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(RX_DMA_CTL_STAT(channel), 0);
5890a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	(void) niu_enable_rx_channel(np, channel, 0);
5891a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5892a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5893a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_reset_rx_channels(struct niu *np)
5894a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5895a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
5896a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5897a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_rx_rings; i++) {
5898a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct rx_ring_info *rp = &np->rx_rings[i];
5899a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5900a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_reset_one_rx_channel(np, rp);
5901a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5902a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5903a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5904a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_disable_ipp(struct niu *np)
5905a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5906a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 rd, wr, val;
5907a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int limit;
5908a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5909a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rd = nr64_ipp(IPP_DFIFO_RD_PTR);
5910a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	wr = nr64_ipp(IPP_DFIFO_WR_PTR);
5911a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	limit = 100;
5912a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (--limit >= 0 && (rd != wr)) {
5913a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rd = nr64_ipp(IPP_DFIFO_RD_PTR);
5914a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		wr = nr64_ipp(IPP_DFIFO_WR_PTR);
5915a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5916a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (limit < 0 &&
5917a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    (rd != 0 && wr != 1)) {
5918f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(np->dev, "IPP would not quiesce, rd_ptr[%llx] wr_ptr[%llx]\n",
5919f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   (unsigned long long)nr64_ipp(IPP_DFIFO_RD_PTR),
5920f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   (unsigned long long)nr64_ipp(IPP_DFIFO_WR_PTR));
5921a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5922a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5923a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_ipp(IPP_CFIG);
5924a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val &= ~(IPP_CFIG_IPP_ENABLE |
5925a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 IPP_CFIG_DFIFO_ECC_EN |
5926a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 IPP_CFIG_DROP_BAD_CRC |
5927a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 IPP_CFIG_CKSUM_EN);
5928a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_ipp(IPP_CFIG, val);
5929a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5930a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	(void) niu_ipp_reset(np);
5931a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5932a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5933a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_init_hw(struct niu *np)
5934a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5935a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, err;
5936a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5937f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize TXC\n");
5938a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_txc_enable_port(np, 1);
5939a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_txc_port_dma_enable(np, 1);
5940a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_txc_set_imask(np, 0);
5941a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5942f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize TX channels\n");
5943a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_tx_rings; i++) {
5944a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct tx_ring_info *rp = &np->tx_rings[i];
5945a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5946a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_init_one_tx_channel(np, rp);
5947a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
5948a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
5949a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
5950a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5951f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize RX channels\n");
5952a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_init_rx_channels(np);
5953a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
5954a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out_uninit_tx_channels;
5955a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5956f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize classifier\n");
5957a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_init_classifier_hw(np);
5958a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
5959a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out_uninit_rx_channels;
5960a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5961f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize ZCP\n");
5962a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_init_zcp(np);
5963a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
5964a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out_uninit_rx_channels;
5965a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5966f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize IPP\n");
5967a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_init_ipp(np);
5968a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
5969a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out_uninit_rx_channels;
5970a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5971f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize MAC\n");
5972a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_init_mac(np);
5973a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
5974a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out_uninit_ipp;
5975a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5976a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
5977a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5978a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerout_uninit_ipp:
5979f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifup, KERN_DEBUG, np->dev, "Uninit IPP\n");
5980a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_disable_ipp(np);
5981a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5982a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerout_uninit_rx_channels:
5983f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifup, KERN_DEBUG, np->dev, "Uninit RX channels\n");
5984a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_stop_rx_channels(np);
5985a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_reset_rx_channels(np);
5986a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5987a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerout_uninit_tx_channels:
5988f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifup, KERN_DEBUG, np->dev, "Uninit TX channels\n");
5989a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_stop_tx_channels(np);
5990a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_reset_tx_channels(np);
5991a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5992a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
5993a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
5994a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
5995a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_stop_hw(struct niu *np)
5996a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
5997f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Disable interrupts\n");
5998a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_enable_interrupts(np, 0);
5999a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6000f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Disable RX MAC\n");
6001a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_enable_rx_mac(np, 0);
6002a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6003f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Disable IPP\n");
6004a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_disable_ipp(np);
6005a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6006f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Stop TX channels\n");
6007a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_stop_tx_channels(np);
6008a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6009f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Stop RX channels\n");
6010a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_stop_rx_channels(np);
6011a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6012f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Reset TX channels\n");
6013a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_reset_tx_channels(np);
6014a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6015f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Reset RX channels\n");
6016a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_reset_rx_channels(np);
6017a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6018a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
601970340d728f4f4cb49da00a11b10ded492260caa5Robert Olssonstatic void niu_set_irq_name(struct niu *np)
602070340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson{
602170340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson	int port = np->port;
602270340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson	int i, j = 1;
602370340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson
602470340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson	sprintf(np->irq_name[0], "%s:MAC", np->dev->name);
602570340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson
602670340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson	if (port == 0) {
602770340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson		sprintf(np->irq_name[1], "%s:MIF", np->dev->name);
602870340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson		sprintf(np->irq_name[2], "%s:SYSERR", np->dev->name);
602970340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson		j = 3;
603070340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson	}
603170340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson
603270340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson	for (i = 0; i < np->num_ldg - j; i++) {
603370340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson		if (i < np->num_rx_rings)
603470340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson			sprintf(np->irq_name[i+j], "%s-rx-%d",
603570340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson				np->dev->name, i);
603670340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson		else if (i < np->num_tx_rings + np->num_rx_rings)
603770340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson			sprintf(np->irq_name[i+j], "%s-tx-%d", np->dev->name,
603870340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson				i - np->num_rx_rings);
603970340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson	}
604070340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson}
604170340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson
6042a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_request_irq(struct niu *np)
6043a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6044a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, j, err;
6045a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
604670340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson	niu_set_irq_name(np);
604770340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson
6048a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = 0;
6049a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_ldg; i++) {
6050a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct niu_ldg *lp = &np->ldg[i];
6051a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6052ab392d2d6d4e2e50502985eead545b44ee58802cJavier Martinez Canillas		err = request_irq(lp->irq, niu_interrupt, IRQF_SHARED,
605370340d728f4f4cb49da00a11b10ded492260caa5Robert Olsson				  np->irq_name[i], lp);
6054a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
6055a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			goto out_free_irqs;
6056a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6057a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6058a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6059a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
6060a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6061a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerout_free_irqs:
6062a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (j = 0; j < i; j++) {
6063a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct niu_ldg *lp = &np->ldg[j];
6064a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6065a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		free_irq(lp->irq, lp);
6066a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6067a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
6068a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6069a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6070a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_free_irq(struct niu *np)
6071a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6072a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
6073a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6074a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_ldg; i++) {
6075a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct niu_ldg *lp = &np->ldg[i];
6076a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6077a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		free_irq(lp->irq, lp);
6078a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6079a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6080a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6081a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_enable_napi(struct niu *np)
6082a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6083a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
6084a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6085a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_ldg; i++)
6086a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		napi_enable(&np->ldg[i].napi);
6087a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6088a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6089a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_disable_napi(struct niu *np)
6090a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6091a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
6092a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6093a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_ldg; i++)
6094a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		napi_disable(&np->ldg[i].napi);
6095a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6096a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6097a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_open(struct net_device *dev)
6098a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6099a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
6100a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
6101a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6102a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	netif_carrier_off(dev);
6103a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6104a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_alloc_channels(np);
6105a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
6106a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out_err;
6107a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6108a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_enable_interrupts(np, 0);
6109a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
6110a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out_free_channels;
6111a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6112a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_request_irq(np);
6113a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
6114a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out_free_channels;
6115a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6116a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_enable_napi(np);
6117a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6118a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_lock_irq(&np->lock);
6119a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6120a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_init_hw(np);
6121a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err) {
6122a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		init_timer(&np->timer);
6123a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->timer.expires = jiffies + HZ;
6124a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->timer.data = (unsigned long) np;
6125a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->timer.function = niu_timer;
6126a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6127a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_enable_interrupts(np, 1);
6128a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
6129a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			niu_stop_hw(np);
6130a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6131a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6132a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_unlock_irq(&np->lock);
6133a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6134a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err) {
6135a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_disable_napi(np);
6136a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto out_free_irq;
6137a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6138a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6139b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller	netif_tx_start_all_queues(dev);
6140a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6141a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
6142a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		netif_carrier_on(dev);
6143a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6144a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	add_timer(&np->timer);
6145a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6146a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
6147a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6148a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerout_free_irq:
6149a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_free_irq(np);
6150a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6151a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerout_free_channels:
6152a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_free_channels(np);
6153a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6154a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerout_err:
6155a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
6156a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6157a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6158a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_full_shutdown(struct niu *np, struct net_device *dev)
6159a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6160a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	cancel_work_sync(&np->reset_task);
6161a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6162a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_disable_napi(np);
6163b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller	netif_tx_stop_all_queues(dev);
6164a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6165a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	del_timer_sync(&np->timer);
6166a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6167a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_lock_irq(&np->lock);
6168a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6169a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_stop_hw(np);
6170a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6171a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_unlock_irq(&np->lock);
6172a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6173a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6174a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_close(struct net_device *dev)
6175a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6176a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
6177a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6178a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_full_shutdown(np, dev);
6179a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6180a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_free_irq(np);
6181a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6182a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_free_channels(np);
6183a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
61840c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner	niu_handle_led(np, 0);
61850c3b091b9a7a5184011e75afa7f0206d288ddb06Mirko Lindner
6186a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
6187a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6188a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6189a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_sync_xmac_stats(struct niu *np)
6190a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6191a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_xmac_stats *mp = &np->mac_stats.xmac;
6192a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6193a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->tx_frames += nr64_mac(TXMAC_FRM_CNT);
6194a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->tx_bytes += nr64_mac(TXMAC_BYTE_CNT);
6195a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6196a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_link_faults += nr64_mac(LINK_FAULT_CNT);
6197a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_align_errors += nr64_mac(RXMAC_ALIGN_ERR_CNT);
6198a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_frags += nr64_mac(RXMAC_FRAG_CNT);
6199a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_mcasts += nr64_mac(RXMAC_MC_FRM_CNT);
6200a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_bcasts += nr64_mac(RXMAC_BC_FRM_CNT);
6201a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_hist_cnt1 += nr64_mac(RXMAC_HIST_CNT1);
6202a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_hist_cnt2 += nr64_mac(RXMAC_HIST_CNT2);
6203a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_hist_cnt3 += nr64_mac(RXMAC_HIST_CNT3);
6204a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_hist_cnt4 += nr64_mac(RXMAC_HIST_CNT4);
6205a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_hist_cnt5 += nr64_mac(RXMAC_HIST_CNT5);
6206a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_hist_cnt6 += nr64_mac(RXMAC_HIST_CNT6);
6207a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_hist_cnt7 += nr64_mac(RXMAC_HIST_CNT7);
6208a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_octets += nr64_mac(RXMAC_BT_CNT);
6209a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_code_violations += nr64_mac(RXMAC_CD_VIO_CNT);
6210a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_len_errors += nr64_mac(RXMAC_MPSZER_CNT);
6211a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_crc_errors += nr64_mac(RXMAC_CRC_ER_CNT);
6212a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6213a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6214a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_sync_bmac_stats(struct niu *np)
6215a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6216a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_bmac_stats *mp = &np->mac_stats.bmac;
6217a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6218a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->tx_bytes += nr64_mac(BTXMAC_BYTE_CNT);
6219a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->tx_frames += nr64_mac(BTXMAC_FRM_CNT);
6220a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6221a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_frames += nr64_mac(BRXMAC_FRAME_CNT);
6222a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_align_errors += nr64_mac(BRXMAC_ALIGN_ERR_CNT);
6223a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_crc_errors += nr64_mac(BRXMAC_ALIGN_ERR_CNT);
6224a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mp->rx_len_errors += nr64_mac(BRXMAC_CODE_VIOL_ERR_CNT);
6225a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6226a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6227a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_sync_mac_stats(struct niu *np)
6228a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6229a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC)
6230a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_sync_xmac_stats(np);
6231a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
6232a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_sync_bmac_stats(np);
6233a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6234a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
62351a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemmingerstatic void niu_get_rx_stats(struct niu *np,
62361a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger			     struct rtnl_link_stats64 *stats)
6237a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
62381a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger	u64 pkts, dropped, errors, bytes;
62399690c636ac118b6662f28308bee817343d9932d8David S. Miller	struct rx_ring_info *rx_rings;
6240a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
6241a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6242a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pkts = dropped = errors = bytes = 0;
62439690c636ac118b6662f28308bee817343d9932d8David S. Miller
62449690c636ac118b6662f28308bee817343d9932d8David S. Miller	rx_rings = ACCESS_ONCE(np->rx_rings);
62459690c636ac118b6662f28308bee817343d9932d8David S. Miller	if (!rx_rings)
62469690c636ac118b6662f28308bee817343d9932d8David S. Miller		goto no_rings;
62479690c636ac118b6662f28308bee817343d9932d8David S. Miller
6248a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_rx_rings; i++) {
62499690c636ac118b6662f28308bee817343d9932d8David S. Miller		struct rx_ring_info *rp = &rx_rings[i];
6250a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6251b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer		niu_sync_rx_discard_stats(np, rp, 0);
6252b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer
6253a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		pkts += rp->rx_packets;
6254a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		bytes += rp->rx_bytes;
6255a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		dropped += rp->rx_dropped;
6256a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		errors += rp->rx_errors;
6257a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
62589690c636ac118b6662f28308bee817343d9932d8David S. Miller
62599690c636ac118b6662f28308bee817343d9932d8David S. Millerno_rings:
62601a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger	stats->rx_packets = pkts;
62611a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger	stats->rx_bytes = bytes;
62621a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger	stats->rx_dropped = dropped;
62631a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger	stats->rx_errors = errors;
6264a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6265a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
62661a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemmingerstatic void niu_get_tx_stats(struct niu *np,
62671a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger			     struct rtnl_link_stats64 *stats)
6268a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
62691a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger	u64 pkts, errors, bytes;
62709690c636ac118b6662f28308bee817343d9932d8David S. Miller	struct tx_ring_info *tx_rings;
6271a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
6272a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6273a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pkts = errors = bytes = 0;
62749690c636ac118b6662f28308bee817343d9932d8David S. Miller
62759690c636ac118b6662f28308bee817343d9932d8David S. Miller	tx_rings = ACCESS_ONCE(np->tx_rings);
62769690c636ac118b6662f28308bee817343d9932d8David S. Miller	if (!tx_rings)
62779690c636ac118b6662f28308bee817343d9932d8David S. Miller		goto no_rings;
62789690c636ac118b6662f28308bee817343d9932d8David S. Miller
6279a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_tx_rings; i++) {
62809690c636ac118b6662f28308bee817343d9932d8David S. Miller		struct tx_ring_info *rp = &tx_rings[i];
6281a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6282a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		pkts += rp->tx_packets;
6283a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		bytes += rp->tx_bytes;
6284a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		errors += rp->tx_errors;
6285a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
62869690c636ac118b6662f28308bee817343d9932d8David S. Miller
62879690c636ac118b6662f28308bee817343d9932d8David S. Millerno_rings:
62881a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger	stats->tx_packets = pkts;
62891a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger	stats->tx_bytes = bytes;
62901a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger	stats->tx_errors = errors;
6291a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6292a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
62931a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemmingerstatic struct rtnl_link_stats64 *niu_get_stats(struct net_device *dev,
62941a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger					       struct rtnl_link_stats64 *stats)
6295a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6296a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
6297a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
62989690c636ac118b6662f28308bee817343d9932d8David S. Miller	if (netif_running(dev)) {
62991a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger		niu_get_rx_stats(np, stats);
63001a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger		niu_get_tx_stats(np, stats);
63019690c636ac118b6662f28308bee817343d9932d8David S. Miller	}
63021a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger
63031a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger	return stats;
6304a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6305a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6306a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_load_hash_xmac(struct niu *np, u16 *hash)
6307a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6308a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
6309a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6310a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < 16; i++)
6311a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(XMAC_HASH_TBL(i), hash[i]);
6312a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6313a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6314a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_load_hash_bmac(struct niu *np, u16 *hash)
6315a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6316a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
6317a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6318a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < 16; i++)
6319a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(BMAC_HASH_TBL(i), hash[i]);
6320a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6321a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6322a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_load_hash(struct niu *np, u16 *hash)
6323a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6324a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC)
6325a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_load_hash_xmac(np, hash);
6326a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
6327a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_load_hash_bmac(np, hash);
6328a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6329a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6330a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_set_rx_mode(struct net_device *dev)
6331a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6332a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
6333a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, alt_cnt, err;
6334ccffad25b5136958d4769ed6de5e87992dd9c65cJiri Pirko	struct netdev_hw_addr *ha;
6335a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long flags;
6336a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u16 hash[16] = { 0, };
6337a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6338a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_lock_irqsave(&np->lock, flags);
6339a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_enable_rx_mac(np, 0);
6340a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6341a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->flags &= ~(NIU_FLAGS_MCAST | NIU_FLAGS_PROMISC);
6342a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (dev->flags & IFF_PROMISC)
6343a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags |= NIU_FLAGS_PROMISC;
63444cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko	if ((dev->flags & IFF_ALLMULTI) || (!netdev_mc_empty(dev)))
6345a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags |= NIU_FLAGS_MCAST;
6346a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
634732e7bfc41110bc8f29ec0f293c3bcee6645fef34Jiri Pirko	alt_cnt = netdev_uc_count(dev);
6348a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (alt_cnt > niu_num_alt_addr(np)) {
6349a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		alt_cnt = 0;
6350a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags |= NIU_FLAGS_PROMISC;
6351a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6352a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6353a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (alt_cnt) {
6354a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int index = 0;
6355a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
635632e7bfc41110bc8f29ec0f293c3bcee6645fef34Jiri Pirko		netdev_for_each_uc_addr(ha, dev) {
6357ccffad25b5136958d4769ed6de5e87992dd9c65cJiri Pirko			err = niu_set_alt_mac(np, index, ha->addr);
6358a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (err)
6359f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				netdev_warn(dev, "Error %d adding alt mac %d\n",
6360f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches					    err, index);
6361a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			err = niu_enable_alt_mac(np, index, 1);
6362a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (err)
6363f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				netdev_warn(dev, "Error %d enabling alt mac %d\n",
6364f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches					    err, index);
6365a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6366a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			index++;
6367a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
6368a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
63693b5bcedeeb755b6e813537fcf4c32f010b490aefMatheos Worku		int alt_start;
63703b5bcedeeb755b6e813537fcf4c32f010b490aefMatheos Worku		if (np->flags & NIU_FLAGS_XMAC)
63713b5bcedeeb755b6e813537fcf4c32f010b490aefMatheos Worku			alt_start = 0;
63723b5bcedeeb755b6e813537fcf4c32f010b490aefMatheos Worku		else
63733b5bcedeeb755b6e813537fcf4c32f010b490aefMatheos Worku			alt_start = 1;
63743b5bcedeeb755b6e813537fcf4c32f010b490aefMatheos Worku		for (i = alt_start; i < niu_num_alt_addr(np); i++) {
6375a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			err = niu_enable_alt_mac(np, i, 0);
6376a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (err)
6377f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				netdev_warn(dev, "Error %d disabling alt mac %d\n",
6378f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches					    err, i);
6379a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
6380a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6381a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (dev->flags & IFF_ALLMULTI) {
6382a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		for (i = 0; i < 16; i++)
6383a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			hash[i] = 0xffff;
63844cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko	} else if (!netdev_mc_empty(dev)) {
638522bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko		netdev_for_each_mc_addr(ha, dev) {
638622bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko			u32 crc = ether_crc_le(ETH_ALEN, ha->addr);
6387a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6388a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			crc >>= 24;
6389a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			hash[crc >> 4] |= (1 << (15 - (crc & 0xf)));
6390a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
6391a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6392a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6393a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_MCAST)
6394a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_load_hash(np, hash);
6395a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6396a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_enable_rx_mac(np, 1);
6397a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_unlock_irqrestore(&np->lock, flags);
6398a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6399a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6400a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_set_mac_addr(struct net_device *dev, void *p)
6401a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6402a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
6403a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct sockaddr *addr = p;
6404a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long flags;
6405a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6406a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!is_valid_ether_addr(addr->sa_data))
6407504f9b5a6bb5336ad434438d0cdd61a16db80129Danny Kukawka		return -EADDRNOTAVAIL;
6408a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6409a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
6410a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6411a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!netif_running(dev))
6412a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return 0;
6413a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6414a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_lock_irqsave(&np->lock, flags);
6415a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_enable_rx_mac(np, 0);
6416a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_set_primary_mac(np, dev->dev_addr);
6417a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_enable_rx_mac(np, 1);
6418a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_unlock_irqrestore(&np->lock, flags);
6419a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6420a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
6421a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6422a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6423a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
6424a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6425a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return -EOPNOTSUPP;
6426a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6427a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6428a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_netif_stop(struct niu *np)
6429a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6430a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->dev->trans_start = jiffies;	/* prevent tx timeout */
6431a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6432a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_disable_napi(np);
6433a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6434a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	netif_tx_disable(np->dev);
6435a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6436a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6437a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_netif_start(struct niu *np)
6438a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6439a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* NOTE: unconditional netif_wake_queue is only appropriate
6440a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 * so long as all callers are assured to have free tx slots
6441a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 * (such as after niu_init_hw).
6442a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 */
6443b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller	netif_tx_wake_all_queues(np->dev);
6444a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6445a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_enable_napi(np);
6446a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6447a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_enable_interrupts(np, 1);
6448a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6449a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6450cff502a38394fd33693f6233e03fca363dfa956dSantwona Beherastatic void niu_reset_buffers(struct niu *np)
6451cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera{
6452cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera	int i, j, k, err;
6453cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera
6454cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera	if (np->rx_rings) {
6455cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera		for (i = 0; i < np->num_rx_rings; i++) {
6456cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			struct rx_ring_info *rp = &np->rx_rings[i];
6457cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera
6458cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			for (j = 0, k = 0; j < MAX_RBR_RING_SIZE; j++) {
6459cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera				struct page *page;
6460cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera
6461cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera				page = rp->rxhash[j];
6462cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera				while (page) {
6463cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera					struct page *next =
6464cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera						(struct page *) page->mapping;
6465cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera					u64 base = page->index;
6466cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera					base = base >> RBR_DESCR_ADDR_SHIFT;
6467cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera					rp->rbr[k++] = cpu_to_le32(base);
6468cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera					page = next;
6469cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera				}
6470cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			}
6471cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			for (; k < MAX_RBR_RING_SIZE; k++) {
6472cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera				err = niu_rbr_add_page(np, rp, GFP_ATOMIC, k);
6473cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera				if (unlikely(err))
6474cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera					break;
6475cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			}
6476cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera
6477cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			rp->rbr_index = rp->rbr_table_size - 1;
6478cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			rp->rcr_index = 0;
6479cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			rp->rbr_pending = 0;
6480cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			rp->rbr_refill_pending = 0;
6481cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera		}
6482cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera	}
6483cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera	if (np->tx_rings) {
6484cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera		for (i = 0; i < np->num_tx_rings; i++) {
6485cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			struct tx_ring_info *rp = &np->tx_rings[i];
6486cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera
6487cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			for (j = 0; j < MAX_TX_RING_SIZE; j++) {
6488cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera				if (rp->tx_buffs[j].skb)
6489cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera					(void) release_tx_packet(np, rp, j);
6490cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			}
6491cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera
6492cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			rp->pending = MAX_TX_RING_SIZE;
6493cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			rp->prod = 0;
6494cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			rp->cons = 0;
6495cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera			rp->wrap_bit = 0;
6496cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera		}
6497cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera	}
6498cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera}
6499cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera
6500a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_reset_task(struct work_struct *work)
6501a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6502a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = container_of(work, struct niu, reset_task);
6503a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long flags;
6504a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
6505a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6506a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_lock_irqsave(&np->lock, flags);
6507a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!netif_running(np->dev)) {
6508a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		spin_unlock_irqrestore(&np->lock, flags);
6509a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return;
6510a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6511a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6512a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_unlock_irqrestore(&np->lock, flags);
6513a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6514a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	del_timer_sync(&np->timer);
6515a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6516a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_netif_stop(np);
6517a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6518a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_lock_irqsave(&np->lock, flags);
6519a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6520a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_stop_hw(np);
6521a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6522cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera	spin_unlock_irqrestore(&np->lock, flags);
6523cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera
6524cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera	niu_reset_buffers(np);
6525cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera
6526cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera	spin_lock_irqsave(&np->lock, flags);
6527cff502a38394fd33693f6233e03fca363dfa956dSantwona Behera
6528a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_init_hw(np);
6529a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err) {
6530a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->timer.expires = jiffies + HZ;
6531a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		add_timer(&np->timer);
6532a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_netif_start(np);
6533a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6534a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6535a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_unlock_irqrestore(&np->lock, flags);
6536a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6537a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6538a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_tx_timeout(struct net_device *dev)
6539a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6540a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
6541a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6542f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	dev_err(np->device, "%s: Transmit timed out, resetting\n",
6543a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		dev->name);
6544a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6545a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	schedule_work(&np->reset_task);
6546a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6547a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6548a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_set_txd(struct tx_ring_info *rp, int index,
6549a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			u64 mapping, u64 len, u64 mark,
6550a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			u64 n_frags)
6551a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6552a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	__le64 *desc = &rp->descr[index];
6553a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6554a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	*desc = cpu_to_le64(mark |
6555a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			    (n_frags << TX_DESC_NUM_PTR_SHIFT) |
6556a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			    (len << TX_DESC_TR_LEN_SHIFT) |
6557a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			    (mapping & TX_DESC_SAD));
6558a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6559a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6560a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic u64 niu_compute_tx_flags(struct sk_buff *skb, struct ethhdr *ehdr,
6561a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				u64 pad_bytes, u64 len)
6562a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6563a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u16 eth_proto, eth_proto_inner;
6564a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 csum_bits, l3off, ihl, ret;
6565a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u8 ip_proto;
6566a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int ipv6;
6567a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6568a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	eth_proto = be16_to_cpu(ehdr->h_proto);
6569a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	eth_proto_inner = eth_proto;
6570a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (eth_proto == ETH_P_8021Q) {
6571a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct vlan_ethhdr *vp = (struct vlan_ethhdr *) ehdr;
6572a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		__be16 val = vp->h_vlan_encapsulated_proto;
6573a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6574a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		eth_proto_inner = be16_to_cpu(val);
6575a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6576a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6577a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	ipv6 = ihl = 0;
6578a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	switch (skb->protocol) {
657909640e6365c679b5642b1c41b6d7078f51689ddfHarvey Harrison	case cpu_to_be16(ETH_P_IP):
6580a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ip_proto = ip_hdr(skb)->protocol;
6581a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ihl = ip_hdr(skb)->ihl;
6582a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
658309640e6365c679b5642b1c41b6d7078f51689ddfHarvey Harrison	case cpu_to_be16(ETH_P_IPV6):
6584a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ip_proto = ipv6_hdr(skb)->nexthdr;
6585a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ihl = (40 >> 2);
6586a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ipv6 = 1;
6587a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
6588a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	default:
6589a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ip_proto = ihl = 0;
6590a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
6591a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6592a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6593a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	csum_bits = TXHDR_CSUM_NONE;
6594a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (skb->ip_summed == CHECKSUM_PARTIAL) {
6595a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u64 start, stuff;
6596a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6597a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		csum_bits = (ip_proto == IPPROTO_TCP ?
6598a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			     TXHDR_CSUM_TCP :
6599a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			     (ip_proto == IPPROTO_UDP ?
6600a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			      TXHDR_CSUM_UDP : TXHDR_CSUM_SCTP));
6601a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
66020d0b16727f24f8258eeb33818347ca0f4557f982Michał Mirosław		start = skb_checksum_start_offset(skb) -
6603a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			(pad_bytes + sizeof(struct tx_pkt_hdr));
6604a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		stuff = start + skb->csum_offset;
6605a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6606a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		csum_bits |= (start / 2) << TXHDR_L4START_SHIFT;
6607a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		csum_bits |= (stuff / 2) << TXHDR_L4STUFF_SHIFT;
6608a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6609a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6610a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	l3off = skb_network_offset(skb) -
6611a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		(pad_bytes + sizeof(struct tx_pkt_hdr));
6612a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6613a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	ret = (((pad_bytes / 2) << TXHDR_PAD_SHIFT) |
6614a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	       (len << TXHDR_LEN_SHIFT) |
6615a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	       ((l3off / 2) << TXHDR_L3START_SHIFT) |
6616a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	       (ihl << TXHDR_IHL_SHIFT) |
6617a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	       ((eth_proto_inner < 1536) ? TXHDR_LLC : 0) |
6618a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	       ((eth_proto == ETH_P_8021Q) ? TXHDR_VLAN : 0) |
6619a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	       (ipv6 ? TXHDR_IP_VER : 0) |
6620a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	       csum_bits);
6621a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6622a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return ret;
6623a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6624a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
662561357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t niu_start_xmit(struct sk_buff *skb,
662661357325f377889a1daffa14962d705dc814dd0eStephen Hemminger				  struct net_device *dev)
6627a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6628a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
6629a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long align, headroom;
6630b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller	struct netdev_queue *txq;
6631a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct tx_ring_info *rp;
6632a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct tx_pkt_hdr *tp;
6633a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned int len, nfg;
6634a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct ethhdr *ehdr;
6635a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int prod, i, tlen;
6636a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 mapping, mrk;
6637a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6638b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller	i = skb_get_queue_mapping(skb);
6639b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller	rp = &np->tx_rings[i];
6640b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller	txq = netdev_get_tx_queue(dev, i);
6641a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6642a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (niu_tx_avail(rp) <= (skb_shinfo(skb)->nr_frags + 1)) {
6643b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller		netif_tx_stop_queue(txq);
6644f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(np->device, "%s: BUG! Tx ring full when queue awake!\n", dev->name);
6645a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->tx_errors++;
6646a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return NETDEV_TX_BUSY;
6647a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6648a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6649a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (skb->len < ETH_ZLEN) {
6650a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		unsigned int pad_bytes = ETH_ZLEN - skb->len;
6651a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6652a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (skb_pad(skb, pad_bytes))
6653a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			goto out;
6654a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		skb_put(skb, pad_bytes);
6655a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6656a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6657a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	len = sizeof(struct tx_pkt_hdr) + 15;
6658a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (skb_headroom(skb) < len) {
6659a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct sk_buff *skb_new;
6660a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6661a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		skb_new = skb_realloc_headroom(skb, len);
6662a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!skb_new) {
6663a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			rp->tx_errors++;
6664a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			goto out_drop;
6665a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
6666a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		kfree_skb(skb);
6667a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		skb = skb_new;
66683ebebccf89b1b6e4fec4de05b245d6c459f27ce8David S. Miller	} else
66693ebebccf89b1b6e4fec4de05b245d6c459f27ce8David S. Miller		skb_orphan(skb);
6670a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6671a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	align = ((unsigned long) skb->data & (16 - 1));
6672a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	headroom = align + sizeof(struct tx_pkt_hdr);
6673a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6674a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	ehdr = (struct ethhdr *) skb->data;
6675a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tp = (struct tx_pkt_hdr *) skb_push(skb, headroom);
6676a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6677a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	len = skb->len - sizeof(struct tx_pkt_hdr);
6678a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tp->flags = cpu_to_le64(niu_compute_tx_flags(skb, ehdr, align, len));
6679a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tp->resv = 0;
6680a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6681a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	len = skb_headlen(skb);
6682a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mapping = np->ops->map_single(np->device, skb->data,
6683a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				      len, DMA_TO_DEVICE);
6684a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6685a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	prod = rp->prod;
6686a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6687a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->tx_buffs[prod].skb = skb;
6688a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->tx_buffs[prod].mapping = mapping;
6689a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6690a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mrk = TX_DESC_SOP;
6691a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (++rp->mark_counter == rp->mark_freq) {
6692a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->mark_counter = 0;
6693a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mrk |= TX_DESC_MARK;
6694a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->mark_pending++;
6695a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6696a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6697a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tlen = len;
6698a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nfg = skb_shinfo(skb)->nr_frags;
6699a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (tlen > 0) {
6700a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		tlen -= MAX_TX_DESC_LEN;
6701a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nfg++;
6702a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6703a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6704a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (len > 0) {
6705a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		unsigned int this_len = len;
6706a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6707a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (this_len > MAX_TX_DESC_LEN)
6708a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			this_len = MAX_TX_DESC_LEN;
6709a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6710a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_set_txd(rp, prod, mapping, this_len, mrk, nfg);
6711a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mrk = nfg = 0;
6712a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6713a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		prod = NEXT_TX(rp, prod);
6714a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		mapping += this_len;
6715a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		len -= this_len;
6716a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6717a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6718a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i <  skb_shinfo(skb)->nr_frags; i++) {
67199e903e085262ffbf1fc44a17ac06058aca03524aEric Dumazet		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
6720a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
67219e903e085262ffbf1fc44a17ac06058aca03524aEric Dumazet		len = skb_frag_size(frag);
6722134b413ca3a1055608495bbb60caeb754a073766Ian Campbell		mapping = np->ops->map_page(np->device, skb_frag_page(frag),
6723a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					    frag->page_offset, len,
6724a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					    DMA_TO_DEVICE);
6725a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6726a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->tx_buffs[prod].skb = NULL;
6727a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->tx_buffs[prod].mapping = mapping;
6728a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6729a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_set_txd(rp, prod, mapping, len, 0, 0);
6730a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6731a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		prod = NEXT_TX(rp, prod);
6732a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6733a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6734a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (prod < rp->prod)
6735a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rp->wrap_bit ^= TX_RING_KICK_WRAP;
6736a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->prod = prod;
6737a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6738a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(TX_RING_KICK(rp->tx_channel), rp->wrap_bit | (prod << 3));
6739a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6740a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (unlikely(niu_tx_avail(rp) <= (MAX_SKB_FRAGS + 1))) {
6741b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller		netif_tx_stop_queue(txq);
6742a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp))
6743b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller			netif_tx_wake_queue(txq);
6744a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6745a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6746a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerout:
6747a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return NETDEV_TX_OK;
6748a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6749a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerout_drop:
6750a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rp->tx_errors++;
6751a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	kfree_skb(skb);
6752a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	goto out;
6753a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6754a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6755a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_change_mtu(struct net_device *dev, int new_mtu)
6756a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6757a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
6758a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err, orig_jumbo, new_jumbo;
6759a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6760a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (new_mtu < 68 || new_mtu > NIU_MAX_MTU)
6761a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
6762a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6763a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	orig_jumbo = (dev->mtu > ETH_DATA_LEN);
6764a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	new_jumbo = (new_mtu > ETH_DATA_LEN);
6765a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6766a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev->mtu = new_mtu;
6767a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6768a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!netif_running(dev) ||
6769a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    (orig_jumbo == new_jumbo))
6770a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return 0;
6771a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6772a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_full_shutdown(np, dev);
6773a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6774a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_free_channels(np);
6775a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6776a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_enable_napi(np);
6777a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6778a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_alloc_channels(np);
6779a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
6780a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
6781a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6782a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_lock_irq(&np->lock);
6783a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6784a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_init_hw(np);
6785a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err) {
6786a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		init_timer(&np->timer);
6787a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->timer.expires = jiffies + HZ;
6788a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->timer.data = (unsigned long) np;
6789a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->timer.function = niu_timer;
6790a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6791a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_enable_interrupts(np, 1);
6792a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
6793a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			niu_stop_hw(np);
6794a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6795a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6796a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_unlock_irq(&np->lock);
6797a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6798a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err) {
6799b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller		netif_tx_start_all_queues(dev);
6800a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
6801a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			netif_carrier_on(dev);
6802a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6803a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		add_timer(&np->timer);
6804a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6805a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6806a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
6807a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6808a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6809a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_get_drvinfo(struct net_device *dev,
6810a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			    struct ethtool_drvinfo *info)
6811a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6812a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
6813a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_vpd *vpd = &np->vpd;
6814a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
681523020ab35364f2c91133b099c2b1f7458e29aa96Rick Jones	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
681623020ab35364f2c91133b099c2b1f7458e29aa96Rick Jones	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
681723020ab35364f2c91133b099c2b1f7458e29aa96Rick Jones	snprintf(info->fw_version, sizeof(info->fw_version), "%d.%d",
6818a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		vpd->fcode_major, vpd->fcode_minor);
6819a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->parent->plat_type != PLAT_TYPE_NIU)
682023020ab35364f2c91133b099c2b1f7458e29aa96Rick Jones		strlcpy(info->bus_info, pci_name(np->pdev),
682123020ab35364f2c91133b099c2b1f7458e29aa96Rick Jones			sizeof(info->bus_info));
6822a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6823a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6824a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6825a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6826a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
6827a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_link_config *lp;
6828a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6829a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	lp = &np->link_config;
6830a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6831a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	memset(cmd, 0, sizeof(*cmd));
6832a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	cmd->phy_address = np->phy_addr;
6833a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	cmd->supported = lp->supported;
683438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	cmd->advertising = lp->active_advertising;
683538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	cmd->autoneg = lp->active_autoneg;
6836707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny	ethtool_cmd_speed_set(cmd, lp->active_speed);
6837a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	cmd->duplex = lp->active_duplex;
683838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	cmd->port = (np->flags & NIU_FLAGS_FIBER) ? PORT_FIBRE : PORT_TP;
683938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	cmd->transceiver = (np->flags & NIU_FLAGS_XCVR_SERDES) ?
684038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		XCVR_EXTERNAL : XCVR_INTERNAL;
6841a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6842a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
6843a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6844a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6845a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6846a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
684738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	struct niu *np = netdev_priv(dev);
684838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	struct niu_link_config *lp = &np->link_config;
684938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
685038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	lp->advertising = cmd->advertising;
685125db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny	lp->speed = ethtool_cmd_speed(cmd);
685238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	lp->duplex = cmd->duplex;
685338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	lp->autoneg = cmd->autoneg;
685438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	return niu_init_link(np);
6855a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6856a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6857a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic u32 niu_get_msglevel(struct net_device *dev)
6858a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6859a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
6860a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return np->msg_enable;
6861a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6862a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6863a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_set_msglevel(struct net_device *dev, u32 value)
6864a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6865a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
6866a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->msg_enable = value;
6867a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6868a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
686938bb045d493cc166920834087acd934dedc1b5d5Constantin Baranovstatic int niu_nway_reset(struct net_device *dev)
687038bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov{
687138bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	struct niu *np = netdev_priv(dev);
687238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
687338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	if (np->link_config.autoneg)
687438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov		return niu_init_link(np);
687538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
687638bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	return 0;
687738bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov}
687838bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov
6879a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_get_eeprom_len(struct net_device *dev)
6880a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6881a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
6882a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6883a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return np->eeprom_len;
6884a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6885a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6886a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_get_eeprom(struct net_device *dev,
6887a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			  struct ethtool_eeprom *eeprom, u8 *data)
6888a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
6889a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
6890a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u32 offset, len, val;
6891a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6892a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	offset = eeprom->offset;
6893a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	len = eeprom->len;
6894a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6895a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (offset + len < offset)
6896a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
6897a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (offset >= np->eeprom_len)
6898a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
6899a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (offset + len > np->eeprom_len)
6900a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		len = eeprom->len = np->eeprom_len - offset;
6901a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6902a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (offset & 3) {
6903a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u32 b_offset, b_count;
6904a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6905a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		b_offset = offset & 3;
6906a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		b_count = 4 - b_offset;
6907a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (b_count > len)
6908a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			b_count = len;
6909a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
6910a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val = nr64(ESPC_NCR((offset - b_offset) / 4));
6911a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		memcpy(data, ((char *)&val) + b_offset, b_count);
6912a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data += b_count;
6913a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		len -= b_count;
6914a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		offset += b_count;
6915a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6916a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (len >= 4) {
6917a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val = nr64(ESPC_NCR(offset / 4));
6918a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		memcpy(data, &val, 4);
6919a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data += 4;
6920a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		len -= 4;
6921a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		offset += 4;
6922a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6923a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (len) {
6924a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val = nr64(ESPC_NCR(offset / 4));
6925a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		memcpy(data, &val, len);
6926a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
6927a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
6928a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
6929a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
69302d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic void niu_ethflow_to_l3proto(int flow_type, u8 *pid)
69312d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera{
69322d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	switch (flow_type) {
69332d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case TCP_V4_FLOW:
69342d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case TCP_V6_FLOW:
69352d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*pid = IPPROTO_TCP;
69362d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69372d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case UDP_V4_FLOW:
69382d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case UDP_V6_FLOW:
69392d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*pid = IPPROTO_UDP;
69402d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69412d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case SCTP_V4_FLOW:
69422d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case SCTP_V6_FLOW:
69432d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*pid = IPPROTO_SCTP;
69442d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69452d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case AH_V4_FLOW:
69462d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case AH_V6_FLOW:
69472d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*pid = IPPROTO_AH;
69482d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69492d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ESP_V4_FLOW:
69502d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ESP_V6_FLOW:
69512d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*pid = IPPROTO_ESP;
69522d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69532d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	default:
69542d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*pid = 0;
69552d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69562d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
69572d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera}
69582d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
69592d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic int niu_class_to_ethflow(u64 class, int *flow_type)
69602d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera{
69612d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	switch (class) {
69622d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case CLASS_CODE_TCP_IPV4:
69632d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*flow_type = TCP_V4_FLOW;
69642d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69652d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case CLASS_CODE_UDP_IPV4:
69662d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*flow_type = UDP_V4_FLOW;
69672d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69682d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case CLASS_CODE_AH_ESP_IPV4:
69692d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*flow_type = AH_V4_FLOW;
69702d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69712d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case CLASS_CODE_SCTP_IPV4:
69722d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*flow_type = SCTP_V4_FLOW;
69732d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69742d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case CLASS_CODE_TCP_IPV6:
69752d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*flow_type = TCP_V6_FLOW;
69762d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69772d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case CLASS_CODE_UDP_IPV6:
69782d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*flow_type = UDP_V6_FLOW;
69792d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69802d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case CLASS_CODE_AH_ESP_IPV6:
69812d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*flow_type = AH_V6_FLOW;
69822d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69832d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case CLASS_CODE_SCTP_IPV6:
69842d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*flow_type = SCTP_V6_FLOW;
69852d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69862d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case CLASS_CODE_USER_PROG1:
69872d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case CLASS_CODE_USER_PROG2:
69882d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case CLASS_CODE_USER_PROG3:
69892d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case CLASS_CODE_USER_PROG4:
69902d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		*flow_type = IP_USER_FLOW;
69912d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
69922d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	default:
69932d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		return 0;
69942d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
69952d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
69962d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	return 1;
69972d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera}
69982d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
6999b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Beherastatic int niu_ethflow_to_class(int flow_type, u64 *class)
7000b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera{
7001b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	switch (flow_type) {
7002b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	case TCP_V4_FLOW:
7003b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		*class = CLASS_CODE_TCP_IPV4;
7004b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		break;
7005b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	case UDP_V4_FLOW:
7006b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		*class = CLASS_CODE_UDP_IPV4;
7007b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		break;
7008c44d79950b2daa1025e62eede73e4e4a274d1ef3Ben Hutchings	case AH_ESP_V4_FLOW:
70092d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case AH_V4_FLOW:
70102d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ESP_V4_FLOW:
7011b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		*class = CLASS_CODE_AH_ESP_IPV4;
7012b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		break;
7013b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	case SCTP_V4_FLOW:
7014b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		*class = CLASS_CODE_SCTP_IPV4;
7015b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		break;
7016b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	case TCP_V6_FLOW:
7017b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		*class = CLASS_CODE_TCP_IPV6;
7018b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		break;
7019b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	case UDP_V6_FLOW:
7020b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		*class = CLASS_CODE_UDP_IPV6;
7021b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		break;
7022c44d79950b2daa1025e62eede73e4e4a274d1ef3Ben Hutchings	case AH_ESP_V6_FLOW:
70232d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case AH_V6_FLOW:
70242d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ESP_V6_FLOW:
7025b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		*class = CLASS_CODE_AH_ESP_IPV6;
7026b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		break;
7027b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	case SCTP_V6_FLOW:
7028b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		*class = CLASS_CODE_SCTP_IPV6;
7029b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		break;
7030b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	default:
703138c080ffa9c1b840390832b42ce8621464ab9f97Andreas Schwab		return 0;
7032b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	}
7033b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
7034b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	return 1;
7035b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera}
7036b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
7037b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Beherastatic u64 niu_flowkey_to_ethflow(u64 flow_key)
7038b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera{
7039b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	u64 ethflow = 0;
7040b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
7041b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (flow_key & FLOW_KEY_L2DA)
7042b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		ethflow |= RXH_L2DA;
7043b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (flow_key & FLOW_KEY_VLAN)
7044b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		ethflow |= RXH_VLAN;
7045b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (flow_key & FLOW_KEY_IPSA)
7046b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		ethflow |= RXH_IP_SRC;
7047b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (flow_key & FLOW_KEY_IPDA)
7048b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		ethflow |= RXH_IP_DST;
7049b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (flow_key & FLOW_KEY_PROTO)
7050b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		ethflow |= RXH_L3_PROTO;
7051b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (flow_key & (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_0_SHIFT))
7052b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		ethflow |= RXH_L4_B_0_1;
7053b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (flow_key & (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_1_SHIFT))
7054b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		ethflow |= RXH_L4_B_2_3;
7055b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
7056b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	return ethflow;
7057b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
7058b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera}
7059b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
7060b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Beherastatic int niu_ethflow_to_flowkey(u64 ethflow, u64 *flow_key)
7061b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera{
7062b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	u64 key = 0;
7063b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
7064b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (ethflow & RXH_L2DA)
7065b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		key |= FLOW_KEY_L2DA;
7066b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (ethflow & RXH_VLAN)
7067b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		key |= FLOW_KEY_VLAN;
7068b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (ethflow & RXH_IP_SRC)
7069b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		key |= FLOW_KEY_IPSA;
7070b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (ethflow & RXH_IP_DST)
7071b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		key |= FLOW_KEY_IPDA;
7072b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (ethflow & RXH_L3_PROTO)
7073b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		key |= FLOW_KEY_PROTO;
7074b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (ethflow & RXH_L4_B_0_1)
7075b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		key |= (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_0_SHIFT);
7076b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (ethflow & RXH_L4_B_2_3)
7077b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		key |= (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_1_SHIFT);
7078b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
7079b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	*flow_key = key;
7080b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
7081b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	return 1;
7082b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
7083b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera}
7084b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
70852d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic int niu_get_hash_opts(struct niu *np, struct ethtool_rxnfc *nfc)
7086b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera{
7087b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	u64 class;
7088b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
70892d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	nfc->data = 0;
7090b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
70912d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (!niu_ethflow_to_class(nfc->flow_type, &class))
7092b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		return -EINVAL;
7093b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
7094b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] &
7095b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	    TCAM_KEY_DISC)
70962d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		nfc->data = RXH_DISCARD;
7097b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	else
70982d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		nfc->data = niu_flowkey_to_ethflow(np->parent->flow_key[class -
7099b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera						      CLASS_CODE_USER_PROG1]);
7100b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	return 0;
7101b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera}
7102b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
71032d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic void niu_get_ip4fs_from_tcam_key(struct niu_tcam_entry *tp,
71042d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					struct ethtool_rx_flow_spec *fsp)
71052d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera{
7106ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison	u32 tmp;
7107ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison	u16 prt;
71082d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
7109ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison	tmp = (tp->key[3] & TCAM_V4KEY3_SADDR) >> TCAM_V4KEY3_SADDR_SHIFT;
7110ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison	fsp->h_u.tcp_ip4_spec.ip4src = cpu_to_be32(tmp);
7111ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison
7112ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison	tmp = (tp->key[3] & TCAM_V4KEY3_DADDR) >> TCAM_V4KEY3_DADDR_SHIFT;
7113ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison	fsp->h_u.tcp_ip4_spec.ip4dst = cpu_to_be32(tmp);
7114ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison
7115ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison	tmp = (tp->key_mask[3] & TCAM_V4KEY3_SADDR) >> TCAM_V4KEY3_SADDR_SHIFT;
7116ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison	fsp->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(tmp);
7117ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison
7118ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison	tmp = (tp->key_mask[3] & TCAM_V4KEY3_DADDR) >> TCAM_V4KEY3_DADDR_SHIFT;
7119ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison	fsp->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(tmp);
71202d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
71212d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	fsp->h_u.tcp_ip4_spec.tos = (tp->key[2] & TCAM_V4KEY2_TOS) >>
71222d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		TCAM_V4KEY2_TOS_SHIFT;
71232d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	fsp->m_u.tcp_ip4_spec.tos = (tp->key_mask[2] & TCAM_V4KEY2_TOS) >>
71242d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		TCAM_V4KEY2_TOS_SHIFT;
71252d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
71262d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	switch (fsp->flow_type) {
71272d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case TCP_V4_FLOW:
71282d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case UDP_V4_FLOW:
71292d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case SCTP_V4_FLOW:
7130ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		prt = ((tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
7131ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison			TCAM_V4KEY2_PORT_SPI_SHIFT) >> 16;
7132ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		fsp->h_u.tcp_ip4_spec.psrc = cpu_to_be16(prt);
7133ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison
7134ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		prt = ((tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
7135ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison			TCAM_V4KEY2_PORT_SPI_SHIFT) & 0xffff;
7136ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		fsp->h_u.tcp_ip4_spec.pdst = cpu_to_be16(prt);
71372d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
7138ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		prt = ((tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
7139ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison			TCAM_V4KEY2_PORT_SPI_SHIFT) >> 16;
7140ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		fsp->m_u.tcp_ip4_spec.psrc = cpu_to_be16(prt);
7141ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison
7142ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		prt = ((tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
7143ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison			 TCAM_V4KEY2_PORT_SPI_SHIFT) & 0xffff;
7144ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		fsp->m_u.tcp_ip4_spec.pdst = cpu_to_be16(prt);
71452d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
71462d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case AH_V4_FLOW:
71472d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ESP_V4_FLOW:
7148ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		tmp = (tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
71492d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			TCAM_V4KEY2_PORT_SPI_SHIFT;
7150ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		fsp->h_u.ah_ip4_spec.spi = cpu_to_be32(tmp);
71512d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
7152ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		tmp = (tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
7153ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison			TCAM_V4KEY2_PORT_SPI_SHIFT;
7154ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		fsp->m_u.ah_ip4_spec.spi = cpu_to_be32(tmp);
71552d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
71562d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case IP_USER_FLOW:
7157ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		tmp = (tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
71582d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			TCAM_V4KEY2_PORT_SPI_SHIFT;
7159ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		fsp->h_u.usr_ip4_spec.l4_4_bytes = cpu_to_be32(tmp);
71602d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
7161ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		tmp = (tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
7162ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison			TCAM_V4KEY2_PORT_SPI_SHIFT;
7163ed440e82fee9652715a8145ffee8f56396017d9aHarvey Harrison		fsp->m_u.usr_ip4_spec.l4_4_bytes = cpu_to_be32(tmp);
71642d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
71652d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		fsp->h_u.usr_ip4_spec.proto =
71662d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			(tp->key[2] & TCAM_V4KEY2_PROTO) >>
71672d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			TCAM_V4KEY2_PROTO_SHIFT;
71682d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		fsp->m_u.usr_ip4_spec.proto =
71692d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			(tp->key_mask[2] & TCAM_V4KEY2_PROTO) >>
71702d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			TCAM_V4KEY2_PROTO_SHIFT;
71712d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
71722d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
71732d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
71742d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	default:
71752d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
71762d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
71772d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera}
71782d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
71792d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic int niu_get_ethtool_tcam_entry(struct niu *np,
71802d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				      struct ethtool_rxnfc *nfc)
71812d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera{
71822d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	struct niu_parent *parent = np->parent;
71832d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	struct niu_tcam_entry *tp;
71842d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	struct ethtool_rx_flow_spec *fsp = &nfc->fs;
71852d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	u16 idx;
71862d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	u64 class;
71872d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	int ret = 0;
71882d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
71892d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	idx = tcam_get_index(np, (u16)nfc->fs.location);
71902d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
71912d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp = &parent->tcam[idx];
71922d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (!tp->valid) {
7193f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_info(np->dev, "niu%d: entry [%d] invalid for idx[%d]\n",
7194f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			    parent->index, (u16)nfc->fs.location, idx);
71952d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		return -EINVAL;
71962d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
71972d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
71982d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	/* fill the flow spec entry */
71992d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	class = (tp->key[0] & TCAM_V4KEY0_CLASS_CODE) >>
72002d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		TCAM_V4KEY0_CLASS_CODE_SHIFT;
72012d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	ret = niu_class_to_ethflow(class, &fsp->flow_type);
72022d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
72032d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (ret < 0) {
7204f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_info(np->dev, "niu%d: niu_class_to_ethflow failed\n",
7205f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			    parent->index);
72062d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		ret = -EINVAL;
72072d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		goto out;
72082d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
72092d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
72102d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (fsp->flow_type == AH_V4_FLOW || fsp->flow_type == AH_V6_FLOW) {
72112d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		u32 proto = (tp->key[2] & TCAM_V4KEY2_PROTO) >>
72122d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			TCAM_V4KEY2_PROTO_SHIFT;
72132d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		if (proto == IPPROTO_ESP) {
72142d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			if (fsp->flow_type == AH_V4_FLOW)
72152d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				fsp->flow_type = ESP_V4_FLOW;
72162d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			else
72172d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				fsp->flow_type = ESP_V6_FLOW;
72182d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		}
72192d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
72202d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
72212d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	switch (fsp->flow_type) {
72222d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case TCP_V4_FLOW:
72232d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case UDP_V4_FLOW:
72242d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case SCTP_V4_FLOW:
72252d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case AH_V4_FLOW:
72262d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ESP_V4_FLOW:
72272d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		niu_get_ip4fs_from_tcam_key(tp, fsp);
72282d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
72292d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case TCP_V6_FLOW:
72302d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case UDP_V6_FLOW:
72312d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case SCTP_V6_FLOW:
72322d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case AH_V6_FLOW:
72332d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ESP_V6_FLOW:
72342d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		/* Not yet implemented */
72352d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		ret = -EINVAL;
72362d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
72372d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case IP_USER_FLOW:
72382d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		niu_get_ip4fs_from_tcam_key(tp, fsp);
72392d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
72402d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	default:
72412d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		ret = -EINVAL;
72422d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
72432d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
72442d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
72452d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (ret < 0)
72462d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		goto out;
72472d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
72482d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (tp->assoc_data & TCAM_ASSOCDATA_DISC)
72492d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		fsp->ring_cookie = RX_CLS_FLOW_DISC;
72502d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	else
72512d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		fsp->ring_cookie = (tp->assoc_data & TCAM_ASSOCDATA_OFFSET) >>
72522d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			TCAM_ASSOCDATA_OFFSET_SHIFT;
72532d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
72542d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	/* put the tcam size here */
72552d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	nfc->data = tcam_get_size(np);
72562d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beheraout:
72572d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	return ret;
72582d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera}
72592d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
72602d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic int niu_get_ethtool_tcam_all(struct niu *np,
72612d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				    struct ethtool_rxnfc *nfc,
72622d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				    u32 *rule_locs)
72632d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera{
72642d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	struct niu_parent *parent = np->parent;
72652d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	struct niu_tcam_entry *tp;
72662d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	int i, idx, cnt;
72672d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	unsigned long flags;
7268ee9c5cfad29c8a13199962614b9b16f1c4137ac9Ben Hutchings	int ret = 0;
72692d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
72702d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	/* put the tcam size here */
72712d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	nfc->data = tcam_get_size(np);
72722d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
72732d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	niu_lock_parent(np, flags);
72742d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	for (cnt = 0, i = 0; i < nfc->data; i++) {
72752d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		idx = tcam_get_index(np, i);
72762d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		tp = &parent->tcam[idx];
72772d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		if (!tp->valid)
72782d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			continue;
7279ee9c5cfad29c8a13199962614b9b16f1c4137ac9Ben Hutchings		if (cnt == nfc->rule_cnt) {
7280ee9c5cfad29c8a13199962614b9b16f1c4137ac9Ben Hutchings			ret = -EMSGSIZE;
7281ee9c5cfad29c8a13199962614b9b16f1c4137ac9Ben Hutchings			break;
7282ee9c5cfad29c8a13199962614b9b16f1c4137ac9Ben Hutchings		}
72832d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		rule_locs[cnt] = i;
72842d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		cnt++;
72852d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
72862d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	niu_unlock_parent(np, flags);
72872d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
7288473e64ee4603671efa1e0785418e56e9ffdfc47bBen Hutchings	nfc->rule_cnt = cnt;
7289473e64ee4603671efa1e0785418e56e9ffdfc47bBen Hutchings
7290ee9c5cfad29c8a13199962614b9b16f1c4137ac9Ben Hutchings	return ret;
72912d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera}
72922d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
72932d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic int niu_get_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
7294815c7db5c809ea3d5735de3131ecdf758b0e14ffBen Hutchings		       u32 *rule_locs)
7295b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera{
7296b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	struct niu *np = netdev_priv(dev);
72972d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	int ret = 0;
72982d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
72992d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	switch (cmd->cmd) {
73002d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ETHTOOL_GRXFH:
73012d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		ret = niu_get_hash_opts(np, cmd);
73022d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
73032d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ETHTOOL_GRXRINGS:
73042d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		cmd->data = np->num_rx_rings;
73052d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
73062d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ETHTOOL_GRXCLSRLCNT:
73072d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		cmd->rule_cnt = tcam_get_valid_entry_cnt(np);
73082d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
73092d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ETHTOOL_GRXCLSRULE:
73102d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		ret = niu_get_ethtool_tcam_entry(np, cmd);
73112d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
73122d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ETHTOOL_GRXCLSRLALL:
7313815c7db5c809ea3d5735de3131ecdf758b0e14ffBen Hutchings		ret = niu_get_ethtool_tcam_all(np, cmd, rule_locs);
73142d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
73152d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	default:
73162d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		ret = -EINVAL;
73172d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
73182d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
73192d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
73202d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	return ret;
73212d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera}
73222d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
73232d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic int niu_set_hash_opts(struct niu *np, struct ethtool_rxnfc *nfc)
73242d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera{
7325b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	u64 class;
7326b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	u64 flow_key = 0;
7327b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	unsigned long flags;
7328b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
73292d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (!niu_ethflow_to_class(nfc->flow_type, &class))
7330b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		return -EINVAL;
7331b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
7332b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	if (class < CLASS_CODE_USER_PROG1 ||
7333b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	    class > CLASS_CODE_SCTP_IPV6)
7334b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		return -EINVAL;
7335b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
73362d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (nfc->data & RXH_DISCARD) {
7337b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		niu_lock_parent(np, flags);
7338b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		flow_key = np->parent->tcam_key[class -
7339b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera					       CLASS_CODE_USER_PROG1];
7340b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		flow_key |= TCAM_KEY_DISC;
7341b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		nw64(TCAM_KEY(class - CLASS_CODE_USER_PROG1), flow_key);
7342b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] = flow_key;
7343b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		niu_unlock_parent(np, flags);
7344b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		return 0;
7345b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	} else {
7346b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		/* Discard was set before, but is not set now */
7347b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] &
7348b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		    TCAM_KEY_DISC) {
7349b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera			niu_lock_parent(np, flags);
7350b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera			flow_key = np->parent->tcam_key[class -
7351b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera					       CLASS_CODE_USER_PROG1];
7352b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera			flow_key &= ~TCAM_KEY_DISC;
7353b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera			nw64(TCAM_KEY(class - CLASS_CODE_USER_PROG1),
7354b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera			     flow_key);
7355b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera			np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] =
7356b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera				flow_key;
7357b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera			niu_unlock_parent(np, flags);
7358b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		}
7359b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	}
7360b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
73612d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (!niu_ethflow_to_flowkey(nfc->data, &flow_key))
7362b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera		return -EINVAL;
7363b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
7364b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	niu_lock_parent(np, flags);
7365b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	nw64(FLOW_KEY(class - CLASS_CODE_USER_PROG1), flow_key);
7366b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	np->parent->flow_key[class - CLASS_CODE_USER_PROG1] = flow_key;
7367b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	niu_unlock_parent(np, flags);
7368b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
7369b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera	return 0;
7370b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera}
7371b4653e99450693b75a3c6c8ff4f070164f12815eSantwona Behera
73722d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic void niu_get_tcamkey_from_ip4fs(struct ethtool_rx_flow_spec *fsp,
73732d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				       struct niu_tcam_entry *tp,
73742d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				       int l2_rdc_tab, u64 class)
73752d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera{
73762d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	u8 pid = 0;
73772d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	u32 sip, dip, sipm, dipm, spi, spim;
73782d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	u16 sport, dport, spm, dpm;
73792d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
73802d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	sip = be32_to_cpu(fsp->h_u.tcp_ip4_spec.ip4src);
73812d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	sipm = be32_to_cpu(fsp->m_u.tcp_ip4_spec.ip4src);
73822d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	dip = be32_to_cpu(fsp->h_u.tcp_ip4_spec.ip4dst);
73832d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	dipm = be32_to_cpu(fsp->m_u.tcp_ip4_spec.ip4dst);
73842d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
73852d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp->key[0] = class << TCAM_V4KEY0_CLASS_CODE_SHIFT;
73862d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp->key_mask[0] = TCAM_V4KEY0_CLASS_CODE;
73872d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp->key[1] = (u64)l2_rdc_tab << TCAM_V4KEY1_L2RDCNUM_SHIFT;
73882d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp->key_mask[1] = TCAM_V4KEY1_L2RDCNUM;
73892d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
73902d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp->key[3] = (u64)sip << TCAM_V4KEY3_SADDR_SHIFT;
73912d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp->key[3] |= dip;
73922d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
73932d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp->key_mask[3] = (u64)sipm << TCAM_V4KEY3_SADDR_SHIFT;
73942d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp->key_mask[3] |= dipm;
73952d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
73962d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp->key[2] |= ((u64)fsp->h_u.tcp_ip4_spec.tos <<
73972d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		       TCAM_V4KEY2_TOS_SHIFT);
73982d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp->key_mask[2] |= ((u64)fsp->m_u.tcp_ip4_spec.tos <<
73992d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			    TCAM_V4KEY2_TOS_SHIFT);
74002d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	switch (fsp->flow_type) {
74012d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case TCP_V4_FLOW:
74022d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case UDP_V4_FLOW:
74032d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case SCTP_V4_FLOW:
74042d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		sport = be16_to_cpu(fsp->h_u.tcp_ip4_spec.psrc);
74052d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		spm = be16_to_cpu(fsp->m_u.tcp_ip4_spec.psrc);
74062d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		dport = be16_to_cpu(fsp->h_u.tcp_ip4_spec.pdst);
74072d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		dpm = be16_to_cpu(fsp->m_u.tcp_ip4_spec.pdst);
74082d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
74092d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		tp->key[2] |= (((u64)sport << 16) | dport);
74102d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		tp->key_mask[2] |= (((u64)spm << 16) | dpm);
74112d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		niu_ethflow_to_l3proto(fsp->flow_type, &pid);
74122d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
74132d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case AH_V4_FLOW:
74142d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ESP_V4_FLOW:
74152d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		spi = be32_to_cpu(fsp->h_u.ah_ip4_spec.spi);
74162d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		spim = be32_to_cpu(fsp->m_u.ah_ip4_spec.spi);
74172d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
74182d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		tp->key[2] |= spi;
74192d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		tp->key_mask[2] |= spim;
74202d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		niu_ethflow_to_l3proto(fsp->flow_type, &pid);
74212d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
74222d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case IP_USER_FLOW:
74232d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		spi = be32_to_cpu(fsp->h_u.usr_ip4_spec.l4_4_bytes);
74242d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		spim = be32_to_cpu(fsp->m_u.usr_ip4_spec.l4_4_bytes);
74252d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
74262d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		tp->key[2] |= spi;
74272d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		tp->key_mask[2] |= spim;
74282d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		pid = fsp->h_u.usr_ip4_spec.proto;
74292d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
74302d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	default:
74312d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
74322d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
74332d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
74342d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp->key[2] |= ((u64)pid << TCAM_V4KEY2_PROTO_SHIFT);
74352d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (pid) {
74362d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		tp->key_mask[2] |= TCAM_V4KEY2_PROTO;
74372d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
74382d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera}
74392d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
74402d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic int niu_add_ethtool_tcam_entry(struct niu *np,
74412d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				      struct ethtool_rxnfc *nfc)
74422d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera{
74432d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	struct niu_parent *parent = np->parent;
74442d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	struct niu_tcam_entry *tp;
74452d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	struct ethtool_rx_flow_spec *fsp = &nfc->fs;
74462d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	struct niu_rdc_tables *rdc_table = &parent->rdc_group_cfg[np->port];
74472d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	int l2_rdc_table = rdc_table->first_table_num;
74482d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	u16 idx;
74492d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	u64 class;
74502d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	unsigned long flags;
74512d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	int err, ret;
74522d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
74532d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	ret = 0;
74542d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
74552d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	idx = nfc->fs.location;
74562d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (idx >= tcam_get_size(np))
74572d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		return -EINVAL;
74582d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
74592d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (fsp->flow_type == IP_USER_FLOW) {
74602d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		int i;
74612d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		int add_usr_cls = 0;
74622d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		struct ethtool_usrip4_spec *uspec = &fsp->h_u.usr_ip4_spec;
74632d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		struct ethtool_usrip4_spec *umask = &fsp->m_u.usr_ip4_spec;
74642d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
7465e0de7c93b950b9e784894efc4b529c6958cb747aBen Hutchings		if (uspec->ip_ver != ETH_RX_NFC_IP4)
7466e0de7c93b950b9e784894efc4b529c6958cb747aBen Hutchings			return -EINVAL;
7467e0de7c93b950b9e784894efc4b529c6958cb747aBen Hutchings
74682d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		niu_lock_parent(np, flags);
74692d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
74702d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		for (i = 0; i < NIU_L3_PROG_CLS; i++) {
74712d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			if (parent->l3_cls[i]) {
74722d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				if (uspec->proto == parent->l3_cls_pid[i]) {
74732d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					class = parent->l3_cls[i];
74742d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					parent->l3_cls_refcnt[i]++;
74752d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					add_usr_cls = 1;
74762d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					break;
74772d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				}
74782d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			} else {
74792d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				/* Program new user IP class */
74802d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				switch (i) {
74812d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				case 0:
74822d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					class = CLASS_CODE_USER_PROG1;
74832d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					break;
74842d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				case 1:
74852d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					class = CLASS_CODE_USER_PROG2;
74862d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					break;
74872d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				case 2:
74882d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					class = CLASS_CODE_USER_PROG3;
74892d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					break;
74902d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				case 3:
74912d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					class = CLASS_CODE_USER_PROG4;
74922d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					break;
74932d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				default:
74942d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					break;
74952d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				}
7496e0de7c93b950b9e784894efc4b529c6958cb747aBen Hutchings				ret = tcam_user_ip_class_set(np, class, 0,
74972d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera							     uspec->proto,
74982d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera							     uspec->tos,
74992d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera							     umask->tos);
75002d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				if (ret)
75012d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					goto out;
75022d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
75032d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				ret = tcam_user_ip_class_enable(np, class, 1);
75042d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				if (ret)
75052d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					goto out;
75062d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				parent->l3_cls[i] = class;
75072d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				parent->l3_cls_pid[i] = uspec->proto;
75082d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				parent->l3_cls_refcnt[i]++;
75092d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				add_usr_cls = 1;
75102d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				break;
75112d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			}
75122d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		}
75132d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		if (!add_usr_cls) {
7514f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			netdev_info(np->dev, "niu%d: %s(): Could not find/insert class for pid %d\n",
7515f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				    parent->index, __func__, uspec->proto);
75162d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			ret = -EINVAL;
75172d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			goto out;
75182d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		}
75192d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		niu_unlock_parent(np, flags);
75202d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	} else {
75212d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		if (!niu_ethflow_to_class(fsp->flow_type, &class)) {
75222d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			return -EINVAL;
75232d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		}
75242d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
75252d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
75262d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	niu_lock_parent(np, flags);
75272d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
75282d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	idx = tcam_get_index(np, idx);
75292d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp = &parent->tcam[idx];
75302d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
75312d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	memset(tp, 0, sizeof(*tp));
75322d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
75332d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	/* fill in the tcam key and mask */
75342d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	switch (fsp->flow_type) {
75352d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case TCP_V4_FLOW:
75362d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case UDP_V4_FLOW:
75372d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case SCTP_V4_FLOW:
75382d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case AH_V4_FLOW:
75392d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ESP_V4_FLOW:
75402d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		niu_get_tcamkey_from_ip4fs(fsp, tp, l2_rdc_table, class);
75412d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
75422d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case TCP_V6_FLOW:
75432d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case UDP_V6_FLOW:
75442d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case SCTP_V6_FLOW:
75452d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case AH_V6_FLOW:
75462d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ESP_V6_FLOW:
75472d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		/* Not yet implemented */
7548f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_info(np->dev, "niu%d: In %s(): flow %d for IPv6 not implemented\n",
7549f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			    parent->index, __func__, fsp->flow_type);
75502d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		ret = -EINVAL;
75512d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		goto out;
75522d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case IP_USER_FLOW:
7553e0de7c93b950b9e784894efc4b529c6958cb747aBen Hutchings		niu_get_tcamkey_from_ip4fs(fsp, tp, l2_rdc_table, class);
75542d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
75552d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	default:
7556f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_info(np->dev, "niu%d: In %s(): Unknown flow type %d\n",
7557f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			    parent->index, __func__, fsp->flow_type);
75582d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		ret = -EINVAL;
75592d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		goto out;
75602d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
75612d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
75622d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	/* fill in the assoc data */
75632d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {
75642d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		tp->assoc_data = TCAM_ASSOCDATA_DISC;
75652d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	} else {
75662d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		if (fsp->ring_cookie >= np->num_rx_rings) {
7567f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			netdev_info(np->dev, "niu%d: In %s(): Invalid RX ring %lld\n",
7568f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				    parent->index, __func__,
7569f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				    (long long)fsp->ring_cookie);
75702d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			ret = -EINVAL;
75712d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			goto out;
75722d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		}
75732d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		tp->assoc_data = (TCAM_ASSOCDATA_TRES_USE_OFFSET |
75742d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				  (fsp->ring_cookie <<
75752d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				   TCAM_ASSOCDATA_OFFSET_SHIFT));
75762d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
75772d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
75782d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	err = tcam_write(np, idx, tp->key, tp->key_mask);
75792d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (err) {
75802d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		ret = -EINVAL;
75812d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		goto out;
75822d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
75832d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	err = tcam_assoc_write(np, idx, tp->assoc_data);
75842d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (err) {
75852d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		ret = -EINVAL;
75862d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		goto out;
75872d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
75882d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
75892d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	/* validate the entry */
75902d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp->valid = 1;
75912d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	np->clas.tcam_valid_entries++;
75922d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beheraout:
75932d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	niu_unlock_parent(np, flags);
75942d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
75952d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	return ret;
75962d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera}
75972d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
75982d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic int niu_del_ethtool_tcam_entry(struct niu *np, u32 loc)
75992d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera{
76002d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	struct niu_parent *parent = np->parent;
76012d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	struct niu_tcam_entry *tp;
76022d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	u16 idx;
76032d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	unsigned long flags;
76042d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	u64 class;
76052d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	int ret = 0;
76062d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
76072d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (loc >= tcam_get_size(np))
76082d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		return -EINVAL;
76092d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
76102d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	niu_lock_parent(np, flags);
76112d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
76122d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	idx = tcam_get_index(np, loc);
76132d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp = &parent->tcam[idx];
76142d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
76152d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	/* if the entry is of a user defined class, then update*/
76162d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	class = (tp->key[0] & TCAM_V4KEY0_CLASS_CODE) >>
76172d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		TCAM_V4KEY0_CLASS_CODE_SHIFT;
76182d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
76192d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (class >= CLASS_CODE_USER_PROG1 && class <= CLASS_CODE_USER_PROG4) {
76202d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		int i;
76212d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		for (i = 0; i < NIU_L3_PROG_CLS; i++) {
76222d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			if (parent->l3_cls[i] == class) {
76232d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				parent->l3_cls_refcnt[i]--;
76242d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				if (!parent->l3_cls_refcnt[i]) {
76252d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					/* disable class */
76262d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					ret = tcam_user_ip_class_enable(np,
76272d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera									class,
76282d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera									0);
76292d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					if (ret)
76302d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera						goto out;
76312d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					parent->l3_cls[i] = 0;
76322d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera					parent->l3_cls_pid[i] = 0;
76332d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				}
76342d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera				break;
76352d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			}
76362d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		}
76372d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		if (i == NIU_L3_PROG_CLS) {
7638f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			netdev_info(np->dev, "niu%d: In %s(): Usr class 0x%llx not found\n",
7639f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				    parent->index, __func__,
7640f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				    (unsigned long long)class);
76412d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			ret = -EINVAL;
76422d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera			goto out;
76432d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		}
76442d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
76452d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
76462d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	ret = tcam_flush(np, idx);
76472d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	if (ret)
76482d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		goto out;
76492d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
76502d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	/* invalidate the entry */
76512d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	tp->valid = 0;
76522d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	np->clas.tcam_valid_entries--;
76532d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beheraout:
76542d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	niu_unlock_parent(np, flags);
76552d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
76562d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	return ret;
76572d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera}
76582d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
76592d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Beherastatic int niu_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
76602d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera{
76612d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	struct niu *np = netdev_priv(dev);
76622d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	int ret = 0;
76632d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
76642d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	switch (cmd->cmd) {
76652d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ETHTOOL_SRXFH:
76662d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		ret = niu_set_hash_opts(np, cmd);
76672d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
76682d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ETHTOOL_SRXCLSRLINS:
76692d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		ret = niu_add_ethtool_tcam_entry(np, cmd);
76702d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
76712d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	case ETHTOOL_SRXCLSRLDEL:
76722d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		ret = niu_del_ethtool_tcam_entry(np, cmd->fs.location);
76732d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
76742d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	default:
76752d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		ret = -EINVAL;
76762d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera		break;
76772d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	}
76782d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
76792d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	return ret;
76802d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera}
76812d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera
7682a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct {
7683a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const char string[ETH_GSTRING_LEN];
7684a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller} niu_xmac_stat_keys[] = {
7685a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "tx_frames" },
7686a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "tx_bytes" },
7687a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "tx_fifo_errors" },
7688a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "tx_overflow_errors" },
7689a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "tx_max_pkt_size_errors" },
7690a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "tx_underflow_errors" },
7691a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_local_faults" },
7692a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_remote_faults" },
7693a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_link_faults" },
7694a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_align_errors" },
7695a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_frags" },
7696a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_mcasts" },
7697a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_bcasts" },
7698a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_hist_cnt1" },
7699a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_hist_cnt2" },
7700a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_hist_cnt3" },
7701a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_hist_cnt4" },
7702a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_hist_cnt5" },
7703a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_hist_cnt6" },
7704a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_hist_cnt7" },
7705a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_octets" },
7706a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_code_violations" },
7707a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_len_errors" },
7708a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_crc_errors" },
7709a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_underflows" },
7710a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_overflows" },
7711a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "pause_off_state" },
7712a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "pause_on_state" },
7713a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "pause_received" },
7714a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
7715a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7716a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define NUM_XMAC_STAT_KEYS	ARRAY_SIZE(niu_xmac_stat_keys)
7717a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7718a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct {
7719a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const char string[ETH_GSTRING_LEN];
7720a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller} niu_bmac_stat_keys[] = {
7721a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "tx_underflow_errors" },
7722a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "tx_max_pkt_size_errors" },
7723a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "tx_bytes" },
7724a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "tx_frames" },
7725a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_overflows" },
7726a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_frames" },
7727a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_align_errors" },
7728a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_crc_errors" },
7729a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_len_errors" },
7730a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "pause_off_state" },
7731a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "pause_on_state" },
7732a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "pause_received" },
7733a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
7734a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7735a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define NUM_BMAC_STAT_KEYS	ARRAY_SIZE(niu_bmac_stat_keys)
7736a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7737a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct {
7738a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const char string[ETH_GSTRING_LEN];
7739a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller} niu_rxchan_stat_keys[] = {
7740a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_channel" },
7741a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_packets" },
7742a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_bytes" },
7743a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_dropped" },
7744a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "rx_errors" },
7745a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
7746a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7747a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define NUM_RXCHAN_STAT_KEYS	ARRAY_SIZE(niu_rxchan_stat_keys)
7748a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7749a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct {
7750a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const char string[ETH_GSTRING_LEN];
7751a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller} niu_txchan_stat_keys[] = {
7752a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "tx_channel" },
7753a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "tx_packets" },
7754a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "tx_bytes" },
7755a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{ "tx_errors" },
7756a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
7757a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7758a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define NUM_TXCHAN_STAT_KEYS	ARRAY_SIZE(niu_txchan_stat_keys)
7759a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7760a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_get_strings(struct net_device *dev, u32 stringset, u8 *data)
7761a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
7762a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
7763a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
7764a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7765a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (stringset != ETH_SS_STATS)
7766a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return;
7767a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7768a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC) {
7769a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		memcpy(data, niu_xmac_stat_keys,
7770a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       sizeof(niu_xmac_stat_keys));
7771a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data += sizeof(niu_xmac_stat_keys);
7772a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
7773a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		memcpy(data, niu_bmac_stat_keys,
7774a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       sizeof(niu_bmac_stat_keys));
7775a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data += sizeof(niu_bmac_stat_keys);
7776a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
7777a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_rx_rings; i++) {
7778a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		memcpy(data, niu_rxchan_stat_keys,
7779a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       sizeof(niu_rxchan_stat_keys));
7780a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data += sizeof(niu_rxchan_stat_keys);
7781a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
7782a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_tx_rings; i++) {
7783a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		memcpy(data, niu_txchan_stat_keys,
7784a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       sizeof(niu_txchan_stat_keys));
7785a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data += sizeof(niu_txchan_stat_keys);
7786a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
7787a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
7788a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
778915f0a394c6573f4cb65a13095288ab9b9f8135f9Ben Hutchingsstatic int niu_get_sset_count(struct net_device *dev, int stringset)
7790a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
7791a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
7792a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
779315f0a394c6573f4cb65a13095288ab9b9f8135f9Ben Hutchings	if (stringset != ETH_SS_STATS)
779415f0a394c6573f4cb65a13095288ab9b9f8135f9Ben Hutchings		return -EINVAL;
779515f0a394c6573f4cb65a13095288ab9b9f8135f9Ben Hutchings
7796807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet	return (np->flags & NIU_FLAGS_XMAC ?
7797a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 NUM_XMAC_STAT_KEYS :
7798a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 NUM_BMAC_STAT_KEYS) +
7799a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		(np->num_rx_rings * NUM_RXCHAN_STAT_KEYS) +
7800807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet		(np->num_tx_rings * NUM_TXCHAN_STAT_KEYS);
7801a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
7802a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7803a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_get_ethtool_stats(struct net_device *dev,
7804a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  struct ethtool_stats *stats, u64 *data)
7805a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
7806a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
7807a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
7808a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7809a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_sync_mac_stats(np);
7810a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC) {
7811a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		memcpy(data, &np->mac_stats.xmac,
7812a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       sizeof(struct niu_xmac_stats));
7813a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data += (sizeof(struct niu_xmac_stats) / sizeof(u64));
7814a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
7815a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		memcpy(data, &np->mac_stats.bmac,
7816a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       sizeof(struct niu_bmac_stats));
7817a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data += (sizeof(struct niu_bmac_stats) / sizeof(u64));
7818a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
7819a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_rx_rings; i++) {
7820a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct rx_ring_info *rp = &np->rx_rings[i];
7821a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7822b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer		niu_sync_rx_discard_stats(np, rp, 0);
7823b8a606b871d37e03b92be1bd3deedeee97ea4f13Jesper Dangaard Brouer
7824a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data[0] = rp->rx_channel;
7825a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data[1] = rp->rx_packets;
7826a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data[2] = rp->rx_bytes;
7827a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data[3] = rp->rx_dropped;
7828a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data[4] = rp->rx_errors;
7829a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data += 5;
7830a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
7831a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_tx_rings; i++) {
7832a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct tx_ring_info *rp = &np->tx_rings[i];
7833a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7834a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data[0] = rp->tx_channel;
7835a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data[1] = rp->tx_packets;
7836a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data[2] = rp->tx_bytes;
7837a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data[3] = rp->tx_errors;
7838a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		data += 4;
7839a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
7840a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
7841a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7842a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic u64 niu_led_state_save(struct niu *np)
7843a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
7844a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC)
7845a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return nr64_mac(XMAC_CONFIG);
7846a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
7847a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return nr64_mac(BMAC_XIF_CONFIG);
7848a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
7849a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7850a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_led_state_restore(struct niu *np, u64 val)
7851a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
7852a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC)
7853a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(XMAC_CONFIG, val);
7854a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
7855a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64_mac(BMAC_XIF_CONFIG, val);
7856a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
7857a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7858a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_force_led(struct niu *np, int on)
7859a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
7860a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val, reg, bit;
7861a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7862a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_XMAC) {
7863a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		reg = XMAC_CONFIG;
7864a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		bit = XMAC_CONFIG_FORCE_LED_ON;
7865a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
7866a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		reg = BMAC_XIF_CONFIG;
7867a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		bit = BMAC_XIF_CONFIG_LINK_LED;
7868a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
7869a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7870a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64_mac(reg);
7871a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (on)
7872a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val |= bit;
7873a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
7874a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val &= ~bit;
7875a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64_mac(reg, val);
7876a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
7877a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
78787bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemmingerstatic int niu_set_phys_id(struct net_device *dev,
78797bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemminger			   enum ethtool_phys_id_state state)
78807bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemminger
7881a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
7882a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
7883a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7884a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!netif_running(dev))
7885a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EAGAIN;
7886a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
78877bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemminger	switch (state) {
78887bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemminger	case ETHTOOL_ID_ACTIVE:
78897bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemminger		np->orig_led_state = niu_led_state_save(np);
7890fce55922f5299a04c0a56b170a141fab34f13465Allan, Bruce W		return 1;	/* cycle on/off once per second */
7891a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
78927bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemminger	case ETHTOOL_ID_ON:
78937bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemminger		niu_force_led(np, 1);
78947bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemminger		break;
7895a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
78967bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemminger	case ETHTOOL_ID_OFF:
78977bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemminger		niu_force_led(np, 0);
78987bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemminger		break;
7899a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
79007bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemminger	case ETHTOOL_ID_INACTIVE:
79017bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemminger		niu_led_state_restore(np, np->orig_led_state);
7902a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
7903a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7904a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
7905a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
7906a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7907a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct ethtool_ops niu_ethtool_ops = {
7908a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.get_drvinfo		= niu_get_drvinfo,
7909a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.get_link		= ethtool_op_get_link,
7910a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.get_msglevel		= niu_get_msglevel,
7911a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.set_msglevel		= niu_set_msglevel,
791238bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	.nway_reset		= niu_nway_reset,
7913a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.get_eeprom_len		= niu_get_eeprom_len,
7914a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.get_eeprom		= niu_get_eeprom,
7915a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.get_settings		= niu_get_settings,
7916a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.set_settings		= niu_set_settings,
7917a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.get_strings		= niu_get_strings,
791815f0a394c6573f4cb65a13095288ab9b9f8135f9Ben Hutchings	.get_sset_count		= niu_get_sset_count,
7919a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.get_ethtool_stats	= niu_get_ethtool_stats,
79207bc93714042418cbc4ca89c51d3ab448ea3ef2festephen hemminger	.set_phys_id		= niu_set_phys_id,
79212d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	.get_rxnfc		= niu_get_nfc,
79222d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	.set_rxnfc		= niu_set_nfc,
7923a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
7924a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7925a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent,
7926a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			      int ldg, int ldn)
7927a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
7928a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (ldg < NIU_LDG_MIN || ldg > NIU_LDG_MAX)
7929a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
7930a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (ldn < 0 || ldn > LDN_MAX)
7931a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
7932a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7933a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	parent->ldg_map[ldn] = ldg;
7934a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7935a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->parent->plat_type == PLAT_TYPE_NIU) {
7936a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* On N2 NIU, the ldn-->ldg assignments are setup and fixed by
7937a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 * the firmware, and we're not supposed to change them.
7938a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 * Validate the mapping, because if it's wrong we probably
7939a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 * won't get any interrupts and that's painful to debug.
7940a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 */
7941a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (nr64(LDG_NUM(ldn)) != ldg) {
7942f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			dev_err(np->device, "Port %u, mis-matched LDG assignment for ldn %d, should be %d is %llu\n",
7943a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				np->port, ldn, ldg,
7944a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				(unsigned long long) nr64(LDG_NUM(ldn)));
7945a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return -EINVAL;
7946a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
7947a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else
7948a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64(LDG_NUM(ldn), ldg);
7949a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7950a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
7951a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
7952a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7953a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_set_ldg_timer_res(struct niu *np, int res)
7954a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
7955a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (res < 0 || res > LDG_TIMER_RES_VAL)
7956a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
7957a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7958a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7959a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(LDG_TIMER_RES, res);
7960a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7961a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
7962a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
7963a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7964a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_set_ldg_sid(struct niu *np, int ldg, int func, int vector)
7965a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
7966a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if ((ldg < NIU_LDG_MIN || ldg > NIU_LDG_MAX) ||
7967a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    (func < 0 || func > 3) ||
7968a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    (vector < 0 || vector > 0x1f))
7969a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
7970a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7971a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(SID(ldg), (func << SID_FUNC_SHIFT) | vector);
7972a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7973a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
7974a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
7975a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7976a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_pci_eeprom_read(struct niu *np, u32 addr)
7977a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
7978a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 frame, frame_base = (ESPC_PIO_STAT_READ_START |
7979a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 (addr << ESPC_PIO_STAT_ADDR_SHIFT));
7980a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int limit;
7981a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7982a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (addr > (ESPC_PIO_STAT_ADDR >> ESPC_PIO_STAT_ADDR_SHIFT))
7983a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
7984a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
7985a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	frame = frame_base;
7986a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ESPC_PIO_STAT, frame);
7987a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	limit = 64;
7988a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	do {
7989a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		udelay(5);
7990a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		frame = nr64(ESPC_PIO_STAT);
7991a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (frame & ESPC_PIO_STAT_READ_END)
7992a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
7993a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} while (limit--);
7994a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!(frame & ESPC_PIO_STAT_READ_END)) {
7995f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(np->device, "EEPROM read timeout frame[%llx]\n",
7996a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			(unsigned long long) frame);
7997a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
7998a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
7999a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8000a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	frame = frame_base;
8001a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	nw64(ESPC_PIO_STAT, frame);
8002a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	limit = 64;
8003a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	do {
8004a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		udelay(5);
8005a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		frame = nr64(ESPC_PIO_STAT);
8006a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (frame & ESPC_PIO_STAT_READ_END)
8007a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
8008a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} while (limit--);
8009a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!(frame & ESPC_PIO_STAT_READ_END)) {
8010f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(np->device, "EEPROM read timeout frame[%llx]\n",
8011a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			(unsigned long long) frame);
8012a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
8013a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8014a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8015a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	frame = nr64(ESPC_PIO_STAT);
8016a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return (frame & ESPC_PIO_STAT_DATA) >> ESPC_PIO_STAT_DATA_SHIFT;
8017a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8018a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8019a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_pci_eeprom_read16(struct niu *np, u32 off)
8020a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8021a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err = niu_pci_eeprom_read(np, off);
8022a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u16 val;
8023a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8024a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
8025a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
8026a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = (err << 8);
8027a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_pci_eeprom_read(np, off + 1);
8028a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
8029a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
8030a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (err & 0xff);
8031a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8032a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return val;
8033a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8034a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8035a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_pci_eeprom_read16_swp(struct niu *np, u32 off)
8036a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8037a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err = niu_pci_eeprom_read(np, off);
8038a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u16 val;
8039a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8040a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
8041a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
8042a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8043a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = (err & 0xff);
8044a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_pci_eeprom_read(np, off + 1);
8045a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
8046a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
8047a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8048a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val |= (err & 0xff) << 8;
8049a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8050a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return val;
8051a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8052a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8053a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_pci_vpd_get_propname(struct niu *np,
8054a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					      u32 off,
8055a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					      char *namebuf,
8056a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					      int namebuf_len)
8057a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8058a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
8059a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8060a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < namebuf_len; i++) {
8061a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int err = niu_pci_eeprom_read(np, off + i);
8062a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err < 0)
8063a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
8064a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		*namebuf++ = err;
8065a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!err)
8066a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
8067a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8068a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (i >= namebuf_len)
8069a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
8070a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8071a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return i + 1;
8072a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8073a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8074a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __devinit niu_vpd_parse_version(struct niu *np)
8075a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8076a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_vpd *vpd = &np->vpd;
8077a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int len = strlen(vpd->version) + 1;
8078a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const char *s = vpd->version;
8079a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
8080a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8081a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < len - 5; i++) {
80829ea2bdab11da97b2ac6f87d79976d25fa6d27295Joe Perches		if (!strncmp(s + i, "FCode ", 6))
8083a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
8084a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8085a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (i >= len - 5)
8086a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return;
8087a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8088a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	s += i + 5;
8089a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	sscanf(s, "%d.%d", &vpd->fcode_major, &vpd->fcode_minor);
8090a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8091f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, probe, KERN_DEBUG, np->dev,
8092f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "VPD_SCAN: FCODE major(%d) minor(%d)\n",
8093f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     vpd->fcode_major, vpd->fcode_minor);
8094a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (vpd->fcode_major > NIU_VPD_MIN_MAJOR ||
8095a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    (vpd->fcode_major == NIU_VPD_MIN_MAJOR &&
8096a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	     vpd->fcode_minor >= NIU_VPD_MIN_MINOR))
8097a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags |= NIU_FLAGS_VPD_VALID;
8098a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8099a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8100a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller/* ESPC_PIO_EN_ENABLE must be set */
8101a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_pci_vpd_scan_props(struct niu *np,
8102a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					    u32 start, u32 end)
8103a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8104a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned int found_mask = 0;
8105a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define FOUND_MASK_MODEL	0x00000001
8106a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define FOUND_MASK_BMODEL	0x00000002
8107a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define FOUND_MASK_VERS		0x00000004
8108a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define FOUND_MASK_MAC		0x00000008
8109a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define FOUND_MASK_NMAC		0x00000010
8110a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define FOUND_MASK_PHY		0x00000020
8111a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#define FOUND_MASK_ALL		0x0000003f
8112a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8113f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, probe, KERN_DEBUG, np->dev,
8114f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "VPD_SCAN: start[%x] end[%x]\n", start, end);
8115a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (start < end) {
8116f344c25dbab1a392ef7a7afc8ca061b3b7285423David S. Miller		int len, err, prop_len;
8117a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		char namebuf[64];
8118a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u8 *prop_buf;
8119a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int max_len;
8120a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8121a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (found_mask == FOUND_MASK_ALL) {
8122a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			niu_vpd_parse_version(np);
8123a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return 1;
8124a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
8125a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8126a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_pci_eeprom_read(np, start + 2);
8127a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err < 0)
8128a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
8129a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		len = err;
8130a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		start += 3;
8131a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8132a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		prop_len = niu_pci_eeprom_read(np, start + 4);
8133a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_pci_vpd_get_propname(np, start + 5, namebuf, 64);
8134a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err < 0)
8135a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
8136a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8137a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		prop_buf = NULL;
8138a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		max_len = 0;
8139a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!strcmp(namebuf, "model")) {
8140a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			prop_buf = np->vpd.model;
8141a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			max_len = NIU_VPD_MODEL_MAX;
8142a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			found_mask |= FOUND_MASK_MODEL;
8143a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		} else if (!strcmp(namebuf, "board-model")) {
8144a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			prop_buf = np->vpd.board_model;
8145a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			max_len = NIU_VPD_BD_MODEL_MAX;
8146a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			found_mask |= FOUND_MASK_BMODEL;
8147a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		} else if (!strcmp(namebuf, "version")) {
8148a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			prop_buf = np->vpd.version;
8149a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			max_len = NIU_VPD_VERSION_MAX;
8150a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			found_mask |= FOUND_MASK_VERS;
8151a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		} else if (!strcmp(namebuf, "local-mac-address")) {
8152a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			prop_buf = np->vpd.local_mac;
8153a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			max_len = ETH_ALEN;
8154a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			found_mask |= FOUND_MASK_MAC;
8155a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		} else if (!strcmp(namebuf, "num-mac-addresses")) {
8156a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			prop_buf = &np->vpd.mac_num;
8157a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			max_len = 1;
8158a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			found_mask |= FOUND_MASK_NMAC;
8159a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		} else if (!strcmp(namebuf, "phy-type")) {
8160a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			prop_buf = np->vpd.phy_type;
8161a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			max_len = NIU_VPD_PHY_TYPE_MAX;
8162a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			found_mask |= FOUND_MASK_PHY;
8163a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
8164a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8165a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (max_len && prop_len > max_len) {
8166f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			dev_err(np->device, "Property '%s' length (%d) is too long\n", namebuf, prop_len);
8167a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return -EINVAL;
8168a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
8169a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8170a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (prop_buf) {
8171a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			u32 off = start + 5 + err;
8172a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			int i;
8173a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8174f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			netif_printk(np, probe, KERN_DEBUG, np->dev,
8175f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				     "VPD_SCAN: Reading in property [%s] len[%d]\n",
8176f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				     namebuf, prop_len);
8177a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			for (i = 0; i < prop_len; i++)
8178a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				*prop_buf++ = niu_pci_eeprom_read(np, off + i);
8179a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
8180a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8181a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		start += len;
8182a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8183a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8184a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
8185a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8186a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8187a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller/* ESPC_PIO_EN_ENABLE must be set */
8188a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __devinit niu_pci_vpd_fetch(struct niu *np, u32 start)
8189a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8190a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u32 offset;
8191a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
8192a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8193a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_pci_eeprom_read16_swp(np, start + 1);
8194a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0)
8195a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return;
8196a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8197a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	offset = err + 3;
8198a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8199a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (start + offset < ESPC_EEPROM_SIZE) {
8200a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u32 here = start + offset;
8201a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u32 end;
8202a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8203a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_pci_eeprom_read(np, here);
8204a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err != 0x90)
8205a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return;
8206a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8207a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_pci_eeprom_read16_swp(np, here + 1);
8208a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err < 0)
8209a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return;
8210a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8211a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		here = start + offset + 3;
8212a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		end = start + offset + err;
8213a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8214a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		offset += err;
8215a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8216a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_pci_vpd_scan_props(np, here, end);
8217a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err < 0 || err == 1)
8218a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return;
8219a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8220a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8221a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8222a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller/* ESPC_PIO_EN_ENABLE must be set */
8223a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic u32 __devinit niu_pci_vpd_offset(struct niu *np)
8224a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8225a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u32 start = 0, end = ESPC_EEPROM_SIZE, ret;
8226a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
8227a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8228a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	while (start < end) {
8229a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ret = start;
8230a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8231a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* ROM header signature?  */
8232a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_pci_eeprom_read16(np, start +  0);
8233a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err != 0x55aa)
8234a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return 0;
8235a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8236a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* Apply offset to PCI data structure.  */
8237a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_pci_eeprom_read16(np, start + 23);
8238a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err < 0)
8239a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return 0;
8240a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		start += err;
8241a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8242a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* Check for "PCIR" signature.  */
8243a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_pci_eeprom_read16(np, start +  0);
8244a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err != 0x5043)
8245a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return 0;
8246a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_pci_eeprom_read16(np, start +  2);
8247a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err != 0x4952)
8248a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return 0;
8249a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8250a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* Check for OBP image type.  */
8251a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_pci_eeprom_read(np, start + 20);
8252a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err < 0)
8253a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return 0;
8254a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err != 0x01) {
8255a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			err = niu_pci_eeprom_read(np, ret + 2);
8256a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (err < 0)
8257a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				return 0;
8258a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8259a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			start = ret + (err * 512);
8260a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			continue;
8261a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
8262a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8263a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_pci_eeprom_read16_swp(np, start + 8);
8264a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err < 0)
8265a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
8266a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ret += err;
8267a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8268a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_pci_eeprom_read(np, ret + 0);
8269a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err != 0x82)
8270a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return 0;
8271a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8272a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return ret;
8273a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8274a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8275a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
8276a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8277a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8278a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_phy_type_prop_decode(struct niu *np,
8279a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					      const char *phy_prop)
8280a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8281a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!strcmp(phy_prop, "mif")) {
8282a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* 1G copper, MII */
8283a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags &= ~(NIU_FLAGS_FIBER |
8284a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       NIU_FLAGS_10G);
8285a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->mac_xcvr = MAC_XCVR_MII;
8286a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else if (!strcmp(phy_prop, "xgf")) {
8287a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* 10G fiber, XPCS */
8288a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags |= (NIU_FLAGS_10G |
8289a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			      NIU_FLAGS_FIBER);
8290a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->mac_xcvr = MAC_XCVR_XPCS;
8291a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else if (!strcmp(phy_prop, "pcs")) {
8292a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* 1G fiber, PCS */
8293a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags &= ~NIU_FLAGS_10G;
8294a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags |= NIU_FLAGS_FIBER;
8295a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->mac_xcvr = MAC_XCVR_PCS;
8296a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else if (!strcmp(phy_prop, "xgc")) {
8297a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* 10G copper, XPCS */
8298a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags |= NIU_FLAGS_10G;
8299a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags &= ~NIU_FLAGS_FIBER;
8300a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->mac_xcvr = MAC_XCVR_XPCS;
8301e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	} else if (!strcmp(phy_prop, "xgsd") || !strcmp(phy_prop, "gsd")) {
8302e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		/* 10G Serdes or 1G Serdes, default to 10G */
8303e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		np->flags |= NIU_FLAGS_10G;
8304e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		np->flags &= ~NIU_FLAGS_FIBER;
8305e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		np->flags |= NIU_FLAGS_XCVR_SERDES;
8306e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		np->mac_xcvr = MAC_XCVR_XPCS;
8307a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
8308a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
8309a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8310a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
8311a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8312a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
83137f7c4072ea552f97a0898331322f71986a97299cMatheos Workustatic int niu_pci_vpd_get_nports(struct niu *np)
83147f7c4072ea552f97a0898331322f71986a97299cMatheos Worku{
83157f7c4072ea552f97a0898331322f71986a97299cMatheos Worku	int ports = 0;
83167f7c4072ea552f97a0898331322f71986a97299cMatheos Worku
8317f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	if ((!strcmp(np->vpd.model, NIU_QGC_LP_MDL_STR)) ||
8318f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	    (!strcmp(np->vpd.model, NIU_QGC_PEM_MDL_STR)) ||
8319f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	    (!strcmp(np->vpd.model, NIU_MARAMBA_MDL_STR)) ||
8320f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	    (!strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) ||
8321f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	    (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR))) {
83227f7c4072ea552f97a0898331322f71986a97299cMatheos Worku		ports = 4;
8323f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	} else if ((!strcmp(np->vpd.model, NIU_2XGF_LP_MDL_STR)) ||
8324f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku		   (!strcmp(np->vpd.model, NIU_2XGF_PEM_MDL_STR)) ||
8325f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku		   (!strcmp(np->vpd.model, NIU_FOXXY_MDL_STR)) ||
8326f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku		   (!strcmp(np->vpd.model, NIU_2XGF_MRVL_MDL_STR))) {
83277f7c4072ea552f97a0898331322f71986a97299cMatheos Worku		ports = 2;
83287f7c4072ea552f97a0898331322f71986a97299cMatheos Worku	}
83297f7c4072ea552f97a0898331322f71986a97299cMatheos Worku
83307f7c4072ea552f97a0898331322f71986a97299cMatheos Worku	return ports;
83317f7c4072ea552f97a0898331322f71986a97299cMatheos Worku}
83327f7c4072ea552f97a0898331322f71986a97299cMatheos Worku
8333a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __devinit niu_pci_vpd_validate(struct niu *np)
8334a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8335a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct net_device *dev = np->dev;
8336a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_vpd *vpd = &np->vpd;
8337a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u8 val8;
8338a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8339a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!is_valid_ether_addr(&vpd->local_mac[0])) {
8340f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(np->device, "VPD MAC invalid, falling back to SPROM\n");
8341a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8342a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags &= ~NIU_FLAGS_VPD_VALID;
8343a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return;
8344a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8345a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8346f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	if (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR) ||
8347f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	    !strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) {
83485fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		np->flags |= NIU_FLAGS_10G;
83495fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		np->flags &= ~NIU_FLAGS_FIBER;
83505fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		np->flags |= NIU_FLAGS_XCVR_SERDES;
83515fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		np->mac_xcvr = MAC_XCVR_PCS;
83525fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (np->port > 1) {
83535fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			np->flags |= NIU_FLAGS_FIBER;
83545fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			np->flags &= ~NIU_FLAGS_10G;
83555fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		}
83565fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (np->flags & NIU_FLAGS_10G)
8357f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			np->mac_xcvr = MAC_XCVR_XPCS;
8358f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	} else if (!strcmp(np->vpd.model, NIU_FOXXY_MDL_STR)) {
8359a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		np->flags |= (NIU_FLAGS_10G | NIU_FLAGS_FIBER |
8360a5d6ab56daa439d681aab29955498486e452224dMatheos Worku			      NIU_FLAGS_HOTPLUG_PHY);
83615fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	} else if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
8362f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(np->device, "Illegal phy string [%s]\n",
8363a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			np->vpd.phy_type);
8364f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(np->device, "Falling back to SPROM\n");
8365a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags &= ~NIU_FLAGS_VPD_VALID;
8366a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return;
8367a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8368a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8369a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	memcpy(dev->perm_addr, vpd->local_mac, ETH_ALEN);
8370a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8371a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val8 = dev->perm_addr[5];
8372a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev->perm_addr[5] += np->port;
8373a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (dev->perm_addr[5] < val8)
8374a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		dev->perm_addr[4]++;
8375a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8376a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
8377a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8378a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8379a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_pci_probe_sprom(struct niu *np)
8380a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8381a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct net_device *dev = np->dev;
8382a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int len, i;
8383a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 val, sum;
8384a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u8 val8;
8385a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8386a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = (nr64(ESPC_VER_IMGSZ) & ESPC_VER_IMGSZ_IMGSZ);
8387a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val >>= ESPC_VER_IMGSZ_IMGSZ_SHIFT;
8388a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	len = val / 4;
8389a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8390a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->eeprom_len = len;
8391a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8392f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, probe, KERN_DEBUG, np->dev,
8393f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "SPROM: Image size %llu\n", (unsigned long long)val);
8394a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8395a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	sum = 0;
8396a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < len; i++) {
8397a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		val = nr64(ESPC_NCR(i));
8398a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		sum += (val >>  0) & 0xff;
8399a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		sum += (val >>  8) & 0xff;
8400a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		sum += (val >> 16) & 0xff;
8401a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		sum += (val >> 24) & 0xff;
8402a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8403f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, probe, KERN_DEBUG, np->dev,
8404f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "SPROM: Checksum %x\n", (int)(sum & 0xff));
8405a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if ((sum & 0xff) != 0xab) {
8406f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(np->device, "Bad SPROM checksum (%x, should be 0xab)\n", (int)(sum & 0xff));
8407a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
8408a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8409a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8410a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(ESPC_PHY_TYPE);
8411a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	switch (np->port) {
8412a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 0:
8413a9d41192b96559aa3658bc7886468a46da911c76Al Viro		val8 = (val & ESPC_PHY_TYPE_PORT0) >>
8414a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			ESPC_PHY_TYPE_PORT0_SHIFT;
8415a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
8416a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 1:
8417a9d41192b96559aa3658bc7886468a46da911c76Al Viro		val8 = (val & ESPC_PHY_TYPE_PORT1) >>
8418a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			ESPC_PHY_TYPE_PORT1_SHIFT;
8419a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
8420a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 2:
8421a9d41192b96559aa3658bc7886468a46da911c76Al Viro		val8 = (val & ESPC_PHY_TYPE_PORT2) >>
8422a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			ESPC_PHY_TYPE_PORT2_SHIFT;
8423a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
8424a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 3:
8425a9d41192b96559aa3658bc7886468a46da911c76Al Viro		val8 = (val & ESPC_PHY_TYPE_PORT3) >>
8426a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			ESPC_PHY_TYPE_PORT3_SHIFT;
8427a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
8428a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	default:
8429f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(np->device, "Bogus port number %u\n",
8430a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			np->port);
8431a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
8432a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8433f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, probe, KERN_DEBUG, np->dev,
8434f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "SPROM: PHY type %x\n", val8);
8435a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8436a9d41192b96559aa3658bc7886468a46da911c76Al Viro	switch (val8) {
8437a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case ESPC_PHY_TYPE_1G_COPPER:
8438a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* 1G copper, MII */
8439a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags &= ~(NIU_FLAGS_FIBER |
8440a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       NIU_FLAGS_10G);
8441a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->mac_xcvr = MAC_XCVR_MII;
8442a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
8443a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8444a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case ESPC_PHY_TYPE_1G_FIBER:
8445a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* 1G fiber, PCS */
8446a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags &= ~NIU_FLAGS_10G;
8447a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags |= NIU_FLAGS_FIBER;
8448a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->mac_xcvr = MAC_XCVR_PCS;
8449a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
8450a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8451a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case ESPC_PHY_TYPE_10G_COPPER:
8452a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* 10G copper, XPCS */
8453a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags |= NIU_FLAGS_10G;
8454a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags &= ~NIU_FLAGS_FIBER;
8455a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->mac_xcvr = MAC_XCVR_XPCS;
8456a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
8457a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8458a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case ESPC_PHY_TYPE_10G_FIBER:
8459a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* 10G fiber, XPCS */
8460a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags |= (NIU_FLAGS_10G |
8461a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			      NIU_FLAGS_FIBER);
8462a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->mac_xcvr = MAC_XCVR_XPCS;
8463a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
8464a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8465a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	default:
8466f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(np->device, "Bogus SPROM phy type %u\n", val8);
8467a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
8468a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8469a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8470a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(ESPC_MAC_ADDR0);
8471f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, probe, KERN_DEBUG, np->dev,
8472f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "SPROM: MAC_ADDR0[%08llx]\n", (unsigned long long)val);
8473a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev->perm_addr[0] = (val >>  0) & 0xff;
8474a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev->perm_addr[1] = (val >>  8) & 0xff;
8475a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev->perm_addr[2] = (val >> 16) & 0xff;
8476a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev->perm_addr[3] = (val >> 24) & 0xff;
8477a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8478a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(ESPC_MAC_ADDR1);
8479f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, probe, KERN_DEBUG, np->dev,
8480f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "SPROM: MAC_ADDR1[%08llx]\n", (unsigned long long)val);
8481a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev->perm_addr[4] = (val >>  0) & 0xff;
8482a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev->perm_addr[5] = (val >>  8) & 0xff;
8483a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8484a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!is_valid_ether_addr(&dev->perm_addr[0])) {
8485f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(np->device, "SPROM MAC address invalid [ %pM ]\n",
8486f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			dev->perm_addr);
8487a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
8488a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8489a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8490a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val8 = dev->perm_addr[5];
8491a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev->perm_addr[5] += np->port;
8492a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (dev->perm_addr[5] < val8)
8493a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		dev->perm_addr[4]++;
8494a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8495a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
8496a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8497a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(ESPC_MOD_STR_LEN);
8498f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, probe, KERN_DEBUG, np->dev,
8499f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "SPROM: MOD_STR_LEN[%llu]\n", (unsigned long long)val);
8500e6a5fdf56e3a5fc179cd8c8c19081a9a11882b0cDavid S. Miller	if (val >= 8 * 4)
8501a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
8502a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8503a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < val; i += 4) {
8504a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u64 tmp = nr64(ESPC_NCR(5 + (i / 4)));
8505a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8506a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->vpd.model[i + 3] = (tmp >>  0) & 0xff;
8507a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->vpd.model[i + 2] = (tmp >>  8) & 0xff;
8508a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->vpd.model[i + 1] = (tmp >> 16) & 0xff;
8509a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->vpd.model[i + 0] = (tmp >> 24) & 0xff;
8510a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8511a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->vpd.model[val] = '\0';
8512a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8513a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val = nr64(ESPC_BD_MOD_STR_LEN);
8514f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, probe, KERN_DEBUG, np->dev,
8515f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "SPROM: BD_MOD_STR_LEN[%llu]\n", (unsigned long long)val);
8516e6a5fdf56e3a5fc179cd8c8c19081a9a11882b0cDavid S. Miller	if (val >= 4 * 4)
8517a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
8518a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8519a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < val; i += 4) {
8520a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		u64 tmp = nr64(ESPC_NCR(14 + (i / 4)));
8521a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8522a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->vpd.board_model[i + 3] = (tmp >>  0) & 0xff;
8523a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->vpd.board_model[i + 2] = (tmp >>  8) & 0xff;
8524a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->vpd.board_model[i + 1] = (tmp >> 16) & 0xff;
8525a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->vpd.board_model[i + 0] = (tmp >> 24) & 0xff;
8526a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8527a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->vpd.board_model[val] = '\0';
8528a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8529a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->vpd.mac_num =
8530a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nr64(ESPC_NUM_PORTS_MACS) & ESPC_NUM_PORTS_MACS_VAL;
8531f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, probe, KERN_DEBUG, np->dev,
8532f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "SPROM: NUM_PORTS_MACS[%d]\n", np->vpd.mac_num);
8533a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8534a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
8535a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8536a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8537a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_get_and_validate_port(struct niu *np)
8538a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8539a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent = np->parent;
8540a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8541a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->port <= 1)
8542a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags |= NIU_FLAGS_XMAC;
8543a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8544a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!parent->num_ports) {
8545a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (parent->plat_type == PLAT_TYPE_NIU) {
8546a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			parent->num_ports = 2;
8547a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		} else {
85487f7c4072ea552f97a0898331322f71986a97299cMatheos Worku			parent->num_ports = niu_pci_vpd_get_nports(np);
85497f7c4072ea552f97a0898331322f71986a97299cMatheos Worku			if (!parent->num_ports) {
85507f7c4072ea552f97a0898331322f71986a97299cMatheos Worku				/* Fall back to SPROM as last resort.
85517f7c4072ea552f97a0898331322f71986a97299cMatheos Worku				 * This will fail on most cards.
85527f7c4072ea552f97a0898331322f71986a97299cMatheos Worku				 */
85537f7c4072ea552f97a0898331322f71986a97299cMatheos Worku				parent->num_ports = nr64(ESPC_NUM_PORTS_MACS) &
85547f7c4072ea552f97a0898331322f71986a97299cMatheos Worku					ESPC_NUM_PORTS_MACS_VAL;
85557f7c4072ea552f97a0898331322f71986a97299cMatheos Worku
8556be0c007ac64f880a946995d6d1fc654acc81484dDavid S. Miller				/* All of the current probing methods fail on
8557be0c007ac64f880a946995d6d1fc654acc81484dDavid S. Miller				 * Maramba on-board parts.
8558be0c007ac64f880a946995d6d1fc654acc81484dDavid S. Miller				 */
85597f7c4072ea552f97a0898331322f71986a97299cMatheos Worku				if (!parent->num_ports)
8560be0c007ac64f880a946995d6d1fc654acc81484dDavid S. Miller					parent->num_ports = 4;
85617f7c4072ea552f97a0898331322f71986a97299cMatheos Worku			}
8562a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
8563a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8564a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8565a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->port >= parent->num_ports)
8566a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
8567a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8568a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
8569a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8570a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8571a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit phy_record(struct niu_parent *parent,
8572a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				struct phy_probe_info *p,
8573a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				int dev_id_1, int dev_id_2, u8 phy_port,
8574a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				int type)
8575a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8576a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u32 id = (dev_id_1 << 16) | dev_id_2;
8577a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u8 idx;
8578a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8579a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (dev_id_1 < 0 || dev_id_2 < 0)
8580a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return 0;
8581a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) {
85821d214fa34fc7878d90e0963f9eb4895510db5e48David S. Miller		/* Because of the NIU_PHY_ID_MASK being applied, the 8704
858363ec3c83e7ba6f23227d3ff69c5792911266bd75David S. Miller		 * test covers the 8706 as well.
858463ec3c83e7ba6f23227d3ff69c5792911266bd75David S. Miller		 */
8585b0de8e402dc5d3ee04f4d0f669ae492a3e569933Mirko Lindner		if (((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704) &&
858663ec3c83e7ba6f23227d3ff69c5792911266bd75David S. Miller		    ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_MRVL88X2011))
8587a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return 0;
8588a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
8589a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R)
8590a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return 0;
8591a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8592a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8593a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pr_info("niu%d: Found PHY %08x type %s at phy_port %u\n",
8594a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		parent->index, id,
8595f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		type == PHY_TYPE_PMA_PMD ? "PMA/PMD" :
8596f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		type == PHY_TYPE_PCS ? "PCS" : "MII",
8597a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		phy_port);
8598a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8599a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (p->cur[type] >= NIU_MAX_PORTS) {
8600f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_err("Too many PHY ports\n");
8601a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
8602a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8603a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	idx = p->cur[type];
8604a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	p->phy_id[type][idx] = id;
8605a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	p->phy_port[type][idx] = phy_port;
8606a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	p->cur[type] = idx + 1;
8607a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
8608a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8609a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8610a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit port_has_10g(struct phy_probe_info *p, int port)
8611a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8612a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
8613a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8614a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < p->cur[PHY_TYPE_PMA_PMD]; i++) {
8615a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (p->phy_port[PHY_TYPE_PMA_PMD][i] == port)
8616a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return 1;
8617a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8618a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < p->cur[PHY_TYPE_PCS]; i++) {
8619a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (p->phy_port[PHY_TYPE_PCS][i] == port)
8620a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return 1;
8621a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8622a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8623a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
8624a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8625a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8626a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit count_10g_ports(struct phy_probe_info *p, int *lowest)
8627a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8628a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int port, cnt;
8629a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8630a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	cnt = 0;
8631a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	*lowest = 32;
8632a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (port = 8; port < 32; port++) {
8633a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (port_has_10g(p, port)) {
8634a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (!cnt)
8635a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				*lowest = port;
8636a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			cnt++;
8637a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
8638a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8639a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8640a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return cnt;
8641a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8642a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8643a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit count_1g_ports(struct phy_probe_info *p, int *lowest)
8644a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8645a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	*lowest = 32;
8646a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (p->cur[PHY_TYPE_MII])
8647a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		*lowest = p->phy_port[PHY_TYPE_MII][0];
8648a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8649a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return p->cur[PHY_TYPE_MII];
8650a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8651a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8652a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __devinit niu_n2_divide_channels(struct niu_parent *parent)
8653a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8654a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int num_ports = parent->num_ports;
8655a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
8656a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8657a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < num_ports; i++) {
8658a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		parent->rxchan_per_port[i] = (16 / num_ports);
8659a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		parent->txchan_per_port[i] = (16 / num_ports);
8660a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8661f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_info("niu%d: Port %u [%u RX chans] [%u TX chans]\n",
8662a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			parent->index, i,
8663a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			parent->rxchan_per_port[i],
8664a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			parent->txchan_per_port[i]);
8665a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8666a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8667a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8668a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __devinit niu_divide_channels(struct niu_parent *parent,
8669a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					  int num_10g, int num_1g)
8670a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8671a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int num_ports = parent->num_ports;
8672a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int rx_chans_per_10g, rx_chans_per_1g;
8673a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int tx_chans_per_10g, tx_chans_per_1g;
8674a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, tot_rx, tot_tx;
8675a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8676a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!num_10g || !num_1g) {
8677a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rx_chans_per_10g = rx_chans_per_1g =
8678a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			(NIU_NUM_RXCHAN / num_ports);
8679a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		tx_chans_per_10g = tx_chans_per_1g =
8680a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			(NIU_NUM_TXCHAN / num_ports);
8681a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else {
8682a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rx_chans_per_1g = NIU_NUM_RXCHAN / 8;
8683a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rx_chans_per_10g = (NIU_NUM_RXCHAN -
8684a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    (rx_chans_per_1g * num_1g)) /
8685a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			num_10g;
8686a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8687a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		tx_chans_per_1g = NIU_NUM_TXCHAN / 6;
8688a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		tx_chans_per_10g = (NIU_NUM_TXCHAN -
8689a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    (tx_chans_per_1g * num_1g)) /
8690a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			num_10g;
8691a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8692a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8693a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	tot_rx = tot_tx = 0;
8694a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < num_ports; i++) {
8695a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int type = phy_decode(parent->port_phy, i);
8696a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8697a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (type == PORT_TYPE_10G) {
8698a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			parent->rxchan_per_port[i] = rx_chans_per_10g;
8699a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			parent->txchan_per_port[i] = tx_chans_per_10g;
8700a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		} else {
8701a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			parent->rxchan_per_port[i] = rx_chans_per_1g;
8702a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			parent->txchan_per_port[i] = tx_chans_per_1g;
8703a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
8704f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_info("niu%d: Port %u [%u RX chans] [%u TX chans]\n",
8705a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			parent->index, i,
8706a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			parent->rxchan_per_port[i],
8707a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			parent->txchan_per_port[i]);
8708a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		tot_rx += parent->rxchan_per_port[i];
8709a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		tot_tx += parent->txchan_per_port[i];
8710a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8711a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8712a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (tot_rx > NIU_NUM_RXCHAN) {
8713f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_err("niu%d: Too many RX channels (%d), resetting to one per port\n",
8714a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       parent->index, tot_rx);
8715a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		for (i = 0; i < num_ports; i++)
8716a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			parent->rxchan_per_port[i] = 1;
8717a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8718a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (tot_tx > NIU_NUM_TXCHAN) {
8719f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_err("niu%d: Too many TX channels (%d), resetting to one per port\n",
8720a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       parent->index, tot_tx);
8721a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		for (i = 0; i < num_ports; i++)
8722a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			parent->txchan_per_port[i] = 1;
8723a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8724a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (tot_rx < NIU_NUM_RXCHAN || tot_tx < NIU_NUM_TXCHAN) {
8725f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		pr_warning("niu%d: Driver bug, wasted channels, RX[%d] TX[%d]\n",
8726f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   parent->index, tot_rx, tot_tx);
8727a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8728a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8729a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8730a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __devinit niu_divide_rdc_groups(struct niu_parent *parent,
8731a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					    int num_10g, int num_1g)
8732a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8733a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, num_ports = parent->num_ports;
8734a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int rdc_group, rdc_groups_per_port;
8735a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int rdc_channel_base;
8736a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8737a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rdc_group = 0;
8738a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rdc_groups_per_port = NIU_NUM_RDC_TABLES / num_ports;
8739a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8740a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	rdc_channel_base = 0;
8741a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8742a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < num_ports; i++) {
8743a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct niu_rdc_tables *tp = &parent->rdc_group_cfg[i];
8744a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int grp, num_channels = parent->rxchan_per_port[i];
8745a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int this_channel_offset;
8746a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8747a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		tp->first_table_num = rdc_group;
8748a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		tp->num_tables = rdc_groups_per_port;
8749a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		this_channel_offset = 0;
8750a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		for (grp = 0; grp < tp->num_tables; grp++) {
8751a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			struct rdc_table *rt = &tp->tables[grp];
8752a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			int slot;
8753a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8754f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			pr_info("niu%d: Port %d RDC tbl(%d) [ ",
8755a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				parent->index, i, tp->first_table_num + grp);
8756a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			for (slot = 0; slot < NIU_RDC_TABLE_SLOTS; slot++) {
8757a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				rt->rxdma_channel[slot] =
8758a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					rdc_channel_base + this_channel_offset;
8759a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8760f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches				pr_cont("%d ", rt->rxdma_channel[slot]);
8761a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8762a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				if (++this_channel_offset == num_channels)
8763a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					this_channel_offset = 0;
8764a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			}
8765f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			pr_cont("]\n");
8766a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
8767a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8768a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		parent->rdc_default[i] = rdc_channel_base;
8769a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8770a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rdc_channel_base += num_channels;
8771a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		rdc_group += rdc_groups_per_port;
8772a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8773a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8774a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8775a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit fill_phy_probe_info(struct niu *np,
8776a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					 struct niu_parent *parent,
8777a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					 struct phy_probe_info *info)
8778a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8779a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long flags;
8780a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int port, err;
8781a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8782a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	memset(info, 0, sizeof(*info));
8783a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8784a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* Port 0 to 7 are reserved for onboard Serdes, probe the rest.  */
8785a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_lock_parent(np, flags);
8786a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = 0;
8787a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (port = 8; port < 32; port++) {
8788a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int dev_id_1, dev_id_2;
8789a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8790a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		dev_id_1 = mdio_read(np, port,
8791a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				     NIU_PMA_PMD_DEV_ADDR, MII_PHYSID1);
8792a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		dev_id_2 = mdio_read(np, port,
8793a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				     NIU_PMA_PMD_DEV_ADDR, MII_PHYSID2);
8794a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = phy_record(parent, info, dev_id_1, dev_id_2, port,
8795a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 PHY_TYPE_PMA_PMD);
8796a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
8797a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
8798a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		dev_id_1 = mdio_read(np, port,
8799a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				     NIU_PCS_DEV_ADDR, MII_PHYSID1);
8800a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		dev_id_2 = mdio_read(np, port,
8801a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				     NIU_PCS_DEV_ADDR, MII_PHYSID2);
8802a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = phy_record(parent, info, dev_id_1, dev_id_2, port,
8803a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 PHY_TYPE_PCS);
8804a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
8805a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
8806a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		dev_id_1 = mii_read(np, port, MII_PHYSID1);
8807a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		dev_id_2 = mii_read(np, port, MII_PHYSID2);
8808a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = phy_record(parent, info, dev_id_1, dev_id_2, port,
8809a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 PHY_TYPE_MII);
8810a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
8811a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
8812a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8813a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_unlock_parent(np, flags);
8814a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8815a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
8816a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8817a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8818a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit walk_phys(struct niu *np, struct niu_parent *parent)
8819a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8820a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct phy_probe_info *info = &parent->phy_probe_info;
8821a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int lowest_10g, lowest_1g;
8822a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int num_10g, num_1g;
8823a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u32 val;
8824a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
8825a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8826e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	num_10g = num_1g = 0;
8827e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera
8828f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	if (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR) ||
8829f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	    !strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) {
88305fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		num_10g = 0;
88315fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		num_1g = 2;
88325fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		parent->plat_type = PLAT_TYPE_ATCA_CP3220;
88335fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		parent->num_ports = 4;
88345fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		val = (phy_encode(PORT_TYPE_1G, 0) |
88355fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		       phy_encode(PORT_TYPE_1G, 1) |
8836a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       phy_encode(PORT_TYPE_1G, 2) |
8837a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		       phy_encode(PORT_TYPE_1G, 3));
8838f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	} else if (!strcmp(np->vpd.model, NIU_FOXXY_MDL_STR)) {
8839a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		num_10g = 2;
8840a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		num_1g = 0;
8841a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		parent->num_ports = 2;
8842a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		val = (phy_encode(PORT_TYPE_10G, 0) |
8843a5d6ab56daa439d681aab29955498486e452224dMatheos Worku		       phy_encode(PORT_TYPE_10G, 1));
8844e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera	} else if ((np->flags & NIU_FLAGS_XCVR_SERDES) &&
8845e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		   (parent->plat_type == PLAT_TYPE_NIU)) {
8846e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		/* this is the Monza case */
8847e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		if (np->flags & NIU_FLAGS_10G) {
8848e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			val = (phy_encode(PORT_TYPE_10G, 0) |
8849e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			       phy_encode(PORT_TYPE_10G, 1));
8850e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		} else {
8851e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			val = (phy_encode(PORT_TYPE_1G, 0) |
8852e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera			       phy_encode(PORT_TYPE_1G, 1));
8853e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera		}
88545fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	} else {
88555fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		err = fill_phy_probe_info(np, parent, info);
88565fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		if (err)
88575fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			return err;
8858a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
88595fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		num_10g = count_10g_ports(info, &lowest_10g);
88605fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		num_1g = count_1g_ports(info, &lowest_1g);
8861a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
88625fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		switch ((num_10g << 4) | num_1g) {
88635fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		case 0x24:
88645fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			if (lowest_1g == 10)
88655fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				parent->plat_type = PLAT_TYPE_VF_P0;
88665fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			else if (lowest_1g == 26)
88675fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				parent->plat_type = PLAT_TYPE_VF_P1;
88685fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			else
88695fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				goto unknown_vg_1g_port;
8870a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
88715fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			/* fallthru */
88725fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		case 0x22:
8873a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			val = (phy_encode(PORT_TYPE_10G, 0) |
8874a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       phy_encode(PORT_TYPE_10G, 1) |
8875a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       phy_encode(PORT_TYPE_1G, 2) |
8876a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       phy_encode(PORT_TYPE_1G, 3));
88775fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			break;
8878a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
88795fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		case 0x20:
88805fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			val = (phy_encode(PORT_TYPE_10G, 0) |
88815fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			       phy_encode(PORT_TYPE_10G, 1));
88825fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			break;
8883a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
88845fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		case 0x10:
88855fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			val = phy_encode(PORT_TYPE_10G, np->port);
88865fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			break;
8887a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
88885fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		case 0x14:
88895fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			if (lowest_1g == 10)
88905fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				parent->plat_type = PLAT_TYPE_VF_P0;
88915fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			else if (lowest_1g == 26)
88925fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				parent->plat_type = PLAT_TYPE_VF_P1;
88935fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			else
88945fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				goto unknown_vg_1g_port;
88955fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
88965fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			/* fallthru */
88975fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		case 0x13:
88985fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			if ((lowest_10g & 0x7) == 0)
88995fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				val = (phy_encode(PORT_TYPE_10G, 0) |
89005fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				       phy_encode(PORT_TYPE_1G, 1) |
89015fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				       phy_encode(PORT_TYPE_1G, 2) |
89025fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				       phy_encode(PORT_TYPE_1G, 3));
89035fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			else
89045fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				val = (phy_encode(PORT_TYPE_1G, 0) |
89055fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				       phy_encode(PORT_TYPE_10G, 1) |
89065fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				       phy_encode(PORT_TYPE_1G, 2) |
89075fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				       phy_encode(PORT_TYPE_1G, 3));
89085fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			break;
89095fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
89105fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		case 0x04:
89115fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			if (lowest_1g == 10)
89125fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				parent->plat_type = PLAT_TYPE_VF_P0;
89135fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			else if (lowest_1g == 26)
89145fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				parent->plat_type = PLAT_TYPE_VF_P1;
89155fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			else
89165fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				goto unknown_vg_1g_port;
89175fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
89185fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			val = (phy_encode(PORT_TYPE_1G, 0) |
89195fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			       phy_encode(PORT_TYPE_1G, 1) |
89205fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			       phy_encode(PORT_TYPE_1G, 2) |
89215fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			       phy_encode(PORT_TYPE_1G, 3));
89225fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			break;
89235fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku
89245fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		default:
8925f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			pr_err("Unsupported port config 10G[%d] 1G[%d]\n",
89265fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			       num_10g, num_1g);
89275fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku			return -EINVAL;
89285fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		}
8929a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8930a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8931a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	parent->port_phy = val;
8932a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8933a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (parent->plat_type == PLAT_TYPE_NIU)
8934a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_n2_divide_channels(parent);
8935a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
8936a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_divide_channels(parent, num_10g, num_1g);
8937a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8938a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_divide_rdc_groups(parent, num_10g, num_1g);
8939a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8940a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
8941a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8942a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerunknown_vg_1g_port:
8943f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	pr_err("Cannot identify platform type, 1gport=%d\n", lowest_1g);
8944a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return -EINVAL;
8945a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8946a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8947a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_probe_ports(struct niu *np)
8948a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8949a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent = np->parent;
8950a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err, i;
8951a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8952a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (parent->port_phy == PORT_PHY_UNKNOWN) {
8953a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = walk_phys(np, parent);
8954a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
8955a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
8956a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8957a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_set_ldg_timer_res(np, 2);
8958a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		for (i = 0; i <= LDN_MAX; i++)
8959a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			niu_ldn_irq_enable(np, i, 0);
8960a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
8961a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8962a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (parent->port_phy == PORT_PHY_INVALID)
8963a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
8964a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8965a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
8966a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8967a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8968a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_classifier_swstate_init(struct niu *np)
8969a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8970a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_classifier *cp = &np->clas;
8971a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
89722d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	cp->tcam_top = (u16) np->port;
89732d96cf8cdfd625da51e5d237d564cd75d3147547Santwona Behera	cp->tcam_sz = np->parent->tcam_num_entries / np->parent->num_ports;
8974a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	cp->h1_init = 0xffffffff;
8975a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	cp->h2_init = 0xffff;
8976a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8977a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return fflp_early_init(np);
8978a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
8979a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8980a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __devinit niu_link_config_init(struct niu *np)
8981a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
8982a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_link_config *lp = &np->link_config;
8983a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
8984a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	lp->advertising = (ADVERTISED_10baseT_Half |
8985a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			   ADVERTISED_10baseT_Full |
8986a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			   ADVERTISED_100baseT_Half |
8987a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			   ADVERTISED_100baseT_Full |
8988a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			   ADVERTISED_1000baseT_Half |
8989a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			   ADVERTISED_1000baseT_Full |
8990a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			   ADVERTISED_10000baseT_Full |
8991a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			   ADVERTISED_Autoneg);
8992a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	lp->speed = lp->active_speed = SPEED_INVALID;
899338bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	lp->duplex = DUPLEX_FULL;
899438bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	lp->active_duplex = DUPLEX_INVALID;
899538bb045d493cc166920834087acd934dedc1b5d5Constantin Baranov	lp->autoneg = 1;
8996a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#if 0
8997a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	lp->loopback_mode = LOOPBACK_MAC;
8998a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	lp->active_speed = SPEED_10000;
8999a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	lp->active_duplex = DUPLEX_FULL;
9000a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#else
9001a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	lp->loopback_mode = LOOPBACK_DISABLED;
9002a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif
9003a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9004a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9005a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_init_mac_ipp_pcs_base(struct niu *np)
9006a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9007a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	switch (np->port) {
9008a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 0:
9009a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->mac_regs = np->regs + XMAC_PORT0_OFF;
9010a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->ipp_off  = 0x00000;
9011a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->pcs_off  = 0x04000;
9012a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->xpcs_off = 0x02000;
9013a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
9014a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9015a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 1:
9016a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->mac_regs = np->regs + XMAC_PORT1_OFF;
9017a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->ipp_off  = 0x08000;
9018a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->pcs_off  = 0x0a000;
9019a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->xpcs_off = 0x08000;
9020a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
9021a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9022a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 2:
9023a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->mac_regs = np->regs + BMAC_PORT2_OFF;
9024a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->ipp_off  = 0x04000;
9025a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->pcs_off  = 0x0e000;
9026a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->xpcs_off = ~0UL;
9027a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
9028a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9029a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case 3:
9030a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->mac_regs = np->regs + BMAC_PORT3_OFF;
9031a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->ipp_off  = 0x0c000;
9032a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->pcs_off  = 0x12000;
9033a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->xpcs_off = ~0UL;
9034a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
9035a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9036a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	default:
9037f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(np->device, "Port %u is invalid, cannot compute MAC block offset\n", np->port);
9038a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
9039a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9040a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9041a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
9042a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9043a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9044a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __devinit niu_try_msix(struct niu *np, u8 *ldg_num_map)
9045a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9046a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct msix_entry msi_vec[NIU_NUM_LDG];
9047a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent = np->parent;
9048a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct pci_dev *pdev = np->pdev;
9049a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, num_irqs, err;
9050a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u8 first_ldg;
9051a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9052a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	first_ldg = (NIU_NUM_LDG / parent->num_ports) * np->port;
9053a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < (NIU_NUM_LDG / parent->num_ports); i++)
9054a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ldg_num_map[i] = first_ldg + i;
9055a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9056a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	num_irqs = (parent->rxchan_per_port[np->port] +
9057a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    parent->txchan_per_port[np->port] +
9058a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		    (np->port == 0 ? 3 : 1));
9059a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	BUG_ON(num_irqs > (NIU_NUM_LDG / parent->num_ports));
9060a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9061a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerretry:
9062a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < num_irqs; i++) {
9063a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		msi_vec[i].vector = 0;
9064a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		msi_vec[i].entry = i;
9065a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9066a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9067a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = pci_enable_msix(pdev, msi_vec, num_irqs);
9068a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err < 0) {
9069a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->flags &= ~NIU_FLAGS_MSIX;
9070a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return;
9071a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9072a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err > 0) {
9073a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		num_irqs = err;
9074a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto retry;
9075a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9076a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9077a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->flags |= NIU_FLAGS_MSIX;
9078a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < num_irqs; i++)
9079a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->ldg[i].irq = msi_vec[i].vector;
9080a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->num_ldg = num_irqs;
9081a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9082a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9083a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_n2_irq_init(struct niu *np, u8 *ldg_num_map)
9084a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9085a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#ifdef CONFIG_SPARC64
90862dc11581376829303b98eadb2de253bee065a56aGrant Likely	struct platform_device *op = np->op;
9087a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const u32 *int_prop;
9088a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
9089a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
909061c7a080a5a061c976988fd4b844dfb468dda255Grant Likely	int_prop = of_get_property(op->dev.of_node, "interrupts", NULL);
9091a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!int_prop)
9092a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
9093a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
90941636f8ac2b08410df4766449f7c86b912443cd99Grant Likely	for (i = 0; i < op->archdata.num_irqs; i++) {
9095a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ldg_num_map[i] = int_prop[i];
90961636f8ac2b08410df4766449f7c86b912443cd99Grant Likely		np->ldg[i].irq = op->archdata.irqs[i];
9097a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9098a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
90991636f8ac2b08410df4766449f7c86b912443cd99Grant Likely	np->num_ldg = op->archdata.num_irqs;
9100a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9101a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
9102a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#else
9103a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return -EINVAL;
9104a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif
9105a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9106a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9107a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_ldg_init(struct niu *np)
9108a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9109a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *parent = np->parent;
9110a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u8 ldg_num_map[NIU_NUM_LDG];
9111a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int first_chan, num_chan;
9112a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i, err, ldg_rotor;
9113a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u8 port;
9114a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9115a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->num_ldg = 1;
9116a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->ldg[0].irq = np->dev->irq;
9117a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (parent->plat_type == PLAT_TYPE_NIU) {
9118a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_n2_irq_init(np, ldg_num_map);
9119a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
9120a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
9121a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	} else
9122a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_try_msix(np, ldg_num_map);
9123a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9124a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	port = np->port;
9125a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < np->num_ldg; i++) {
9126a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct niu_ldg *lp = &np->ldg[i];
9127a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9128a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		netif_napi_add(np->dev, &lp->napi, niu_poll, 64);
9129a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9130a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		lp->np = np;
9131a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		lp->ldg_num = ldg_num_map[i];
9132a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		lp->timer = 2; /* XXX */
9133a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9134a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		/* On N2 NIU the firmware has setup the SID mappings so they go
9135a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 * to the correct values that will route the LDG to the proper
9136a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 * interrupt in the NCU interrupt table.
9137a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		 */
9138a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (np->parent->plat_type != PLAT_TYPE_NIU) {
9139a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			err = niu_set_ldg_sid(np, lp->ldg_num, port, i);
9140a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (err)
9141a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				return err;
9142a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
9143a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9144a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9145a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* We adopt the LDG assignment ordering used by the N2 NIU
9146a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 * 'interrupt' properties because that simplifies a lot of
9147a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 * things.  This ordering is:
9148a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 *
9149a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 *	MAC
9150a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 *	MIF	(if port zero)
9151a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 *	SYSERR	(if port zero)
9152a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 *	RX channels
9153a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 *	TX channels
9154a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	 */
9155a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9156a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	ldg_rotor = 0;
9157a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9158a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_ldg_assign_ldn(np, parent, ldg_num_map[ldg_rotor],
9159a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  LDN_MAC(port));
9160a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
9161a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
9162a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9163a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	ldg_rotor++;
9164a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (ldg_rotor == np->num_ldg)
9165a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ldg_rotor = 0;
9166a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9167a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (port == 0) {
9168a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_ldg_assign_ldn(np, parent,
9169a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					 ldg_num_map[ldg_rotor],
9170a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					 LDN_MIF);
9171a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
9172a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
9173a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9174a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ldg_rotor++;
9175a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (ldg_rotor == np->num_ldg)
9176a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			ldg_rotor = 0;
9177a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9178a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_ldg_assign_ldn(np, parent,
9179a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					 ldg_num_map[ldg_rotor],
9180a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					 LDN_DEVICE_ERROR);
9181a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
9182a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
9183a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9184a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ldg_rotor++;
9185a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (ldg_rotor == np->num_ldg)
9186a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			ldg_rotor = 0;
9187a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9188a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9189a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9190a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	first_chan = 0;
9191a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < port; i++)
9192956837f7c954443f426a82ba6f17b33488cf9a0cJulia Lawall		first_chan += parent->rxchan_per_port[i];
9193a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	num_chan = parent->rxchan_per_port[port];
9194a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9195a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = first_chan; i < (first_chan + num_chan); i++) {
9196a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_ldg_assign_ldn(np, parent,
9197a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					 ldg_num_map[ldg_rotor],
9198a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					 LDN_RXDMA(i));
9199a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
9200a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
9201a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ldg_rotor++;
9202a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (ldg_rotor == np->num_ldg)
9203a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			ldg_rotor = 0;
9204a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9205a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9206a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	first_chan = 0;
9207a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < port; i++)
9208956837f7c954443f426a82ba6f17b33488cf9a0cJulia Lawall		first_chan += parent->txchan_per_port[i];
9209a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	num_chan = parent->txchan_per_port[port];
9210a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = first_chan; i < (first_chan + num_chan); i++) {
9211a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_ldg_assign_ldn(np, parent,
9212a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					 ldg_num_map[ldg_rotor],
9213a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					 LDN_TXDMA(i));
9214a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
9215a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return err;
9216a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		ldg_rotor++;
9217a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (ldg_rotor == np->num_ldg)
9218a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			ldg_rotor = 0;
9219a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9220a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9221a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
9222a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9223a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9224a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __devexit niu_ldg_free(struct niu *np)
9225a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9226a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->flags & NIU_FLAGS_MSIX)
9227a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		pci_disable_msix(np->pdev);
9228a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9229a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9230a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_get_of_props(struct niu *np)
9231a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9232a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#ifdef CONFIG_SPARC64
9233a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct net_device *dev = np->dev;
9234a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct device_node *dp;
9235a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const char *phy_type;
9236a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const u8 *mac_addr;
9237f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	const char *model;
9238a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int prop_len;
9239a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9240a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->parent->plat_type == PLAT_TYPE_NIU)
924161c7a080a5a061c976988fd4b844dfb468dda255Grant Likely		dp = np->op->dev.of_node;
9242a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	else
9243a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		dp = pci_device_to_OF_node(np->pdev);
9244a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9245a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	phy_type = of_get_property(dp, "phy-type", &prop_len);
9246a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!phy_type) {
9247f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(dev, "%s: OF node lacks phy-type property\n",
9248f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   dp->full_name);
9249a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
9250a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9251a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9252a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!strcmp(phy_type, "none"))
9253a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
9254a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9255a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	strcpy(np->vpd.phy_type, phy_type);
9256a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9257a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
9258f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(dev, "%s: Illegal phy string [%s]\n",
9259f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   dp->full_name, np->vpd.phy_type);
9260a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
9261a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9262a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9263a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mac_addr = of_get_property(dp, "local-mac-address", &prop_len);
9264a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!mac_addr) {
9265f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(dev, "%s: OF node lacks local-mac-address property\n",
9266f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   dp->full_name);
9267a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
9268a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9269a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (prop_len != dev->addr_len) {
9270f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(dev, "%s: OF MAC address prop len (%d) is wrong\n",
9271f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   dp->full_name, prop_len);
9272a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9273a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	memcpy(dev->perm_addr, mac_addr, dev->addr_len);
9274a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!is_valid_ether_addr(&dev->perm_addr[0])) {
9275f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(dev, "%s: OF MAC address is invalid\n",
9276f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			   dp->full_name);
9277f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netdev_err(dev, "%s: [ %pM ]\n", dp->full_name, dev->perm_addr);
9278a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -EINVAL;
9279a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9280a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9281a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
9282f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku
9283f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	model = of_get_property(dp, "model", &prop_len);
9284f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku
9285f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku	if (model)
9286f9af857489cc19ee3acd0d5248dca7d243e353a5Matheos Worku		strcpy(np->vpd.model, model);
9287a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
92889c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang	if (of_find_property(dp, "hot-swappable-phy", &prop_len)) {
92899c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang		np->flags |= (NIU_FLAGS_10G | NIU_FLAGS_FIBER |
92909c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang			NIU_FLAGS_HOTPLUG_PHY);
92919c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang	}
92929c5cd6708008fcc3dbced6e4b97aa5ecd0634a85Tanli Chang
9293a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
9294a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#else
9295a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return -EINVAL;
9296a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif
9297a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9298a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9299a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_get_invariants(struct niu *np)
9300a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9301a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err, have_props;
9302a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u32 offset;
9303a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9304a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_get_of_props(np);
9305a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err == -ENODEV)
9306a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
9307a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9308a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	have_props = !err;
9309a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9310a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_init_mac_ipp_pcs_base(np);
9311a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
9312a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
9313a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
93147f7c4072ea552f97a0898331322f71986a97299cMatheos Worku	if (have_props) {
93157f7c4072ea552f97a0898331322f71986a97299cMatheos Worku		err = niu_get_and_validate_port(np);
93167f7c4072ea552f97a0898331322f71986a97299cMatheos Worku		if (err)
93177f7c4072ea552f97a0898331322f71986a97299cMatheos Worku			return err;
93187f7c4072ea552f97a0898331322f71986a97299cMatheos Worku
93197f7c4072ea552f97a0898331322f71986a97299cMatheos Worku	} else  {
9320a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (np->parent->plat_type == PLAT_TYPE_NIU)
9321a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			return -EINVAL;
9322a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9323a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64(ESPC_PIO_EN, ESPC_PIO_EN_ENABLE);
9324a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		offset = niu_pci_vpd_offset(np);
9325f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		netif_printk(np, probe, KERN_DEBUG, np->dev,
9326f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			     "%s() VPD offset [%08x]\n", __func__, offset);
9327a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (offset)
9328a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			niu_pci_vpd_fetch(np, offset);
9329a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		nw64(ESPC_PIO_EN, 0);
9330a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
93317f7c4072ea552f97a0898331322f71986a97299cMatheos Worku		if (np->flags & NIU_FLAGS_VPD_VALID) {
9332a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			niu_pci_vpd_validate(np);
93337f7c4072ea552f97a0898331322f71986a97299cMatheos Worku			err = niu_get_and_validate_port(np);
93347f7c4072ea552f97a0898331322f71986a97299cMatheos Worku			if (err)
93357f7c4072ea552f97a0898331322f71986a97299cMatheos Worku				return err;
93367f7c4072ea552f97a0898331322f71986a97299cMatheos Worku		}
9337a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9338a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!(np->flags & NIU_FLAGS_VPD_VALID)) {
93397f7c4072ea552f97a0898331322f71986a97299cMatheos Worku			err = niu_get_and_validate_port(np);
93407f7c4072ea552f97a0898331322f71986a97299cMatheos Worku			if (err)
93417f7c4072ea552f97a0898331322f71986a97299cMatheos Worku				return err;
9342a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			err = niu_pci_probe_sprom(np);
9343a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			if (err)
9344a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				return err;
9345a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
9346a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9347a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9348a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_probe_ports(np);
9349a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err)
9350a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
9351a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9352a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_ldg_init(np);
9353a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9354a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_classifier_swstate_init(np);
9355a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_link_config_init(np);
9356a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9357a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_determine_phy_disposition(np);
9358a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err)
9359a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = niu_init_link(np);
9360a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9361a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
9362a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9363a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9364a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic LIST_HEAD(niu_parent_list);
9365a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic DEFINE_MUTEX(niu_parent_lock);
9366a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_parent_index;
9367a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9368a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic ssize_t show_port_phy(struct device *dev,
9369a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			     struct device_attribute *attr, char *buf)
9370a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9371a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct platform_device *plat_dev = to_platform_device(dev);
9372a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *p = plat_dev->dev.platform_data;
9373a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u32 port_phy = p->port_phy;
9374a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	char *orig_buf = buf;
9375a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
9376a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9377a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (port_phy == PORT_PHY_UNKNOWN ||
9378a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    port_phy == PORT_PHY_INVALID)
9379a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return 0;
9380a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9381a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < p->num_ports; i++) {
9382a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		const char *type_str;
9383a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int type;
9384a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9385a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		type = phy_decode(port_phy, i);
9386a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (type == PORT_TYPE_10G)
9387a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			type_str = "10G";
9388a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		else
9389a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			type_str = "1G";
9390a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		buf += sprintf(buf,
9391a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       (i == 0) ? "%s" : " %s",
9392a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       type_str);
9393a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9394a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	buf += sprintf(buf, "\n");
9395a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return buf - orig_buf;
9396a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9397a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9398a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic ssize_t show_plat_type(struct device *dev,
9399a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			      struct device_attribute *attr, char *buf)
9400a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9401a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct platform_device *plat_dev = to_platform_device(dev);
9402a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *p = plat_dev->dev.platform_data;
9403a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const char *type_str;
9404a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9405a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	switch (p->plat_type) {
9406a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case PLAT_TYPE_ATLAS:
9407a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		type_str = "atlas";
9408a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
9409a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case PLAT_TYPE_NIU:
9410a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		type_str = "niu";
9411a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
9412a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case PLAT_TYPE_VF_P0:
9413a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		type_str = "vf_p0";
9414a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
9415a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	case PLAT_TYPE_VF_P1:
9416a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		type_str = "vf_p1";
9417a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
9418a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	default:
9419a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		type_str = "unknown";
9420a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		break;
9421a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9422a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9423a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return sprintf(buf, "%s\n", type_str);
9424a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9425a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9426a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic ssize_t __show_chan_per_port(struct device *dev,
9427a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    struct device_attribute *attr, char *buf,
9428a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    int rx)
9429a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9430a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct platform_device *plat_dev = to_platform_device(dev);
9431a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *p = plat_dev->dev.platform_data;
9432a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	char *orig_buf = buf;
9433a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u8 *arr;
9434a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
9435a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9436a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	arr = (rx ? p->rxchan_per_port : p->txchan_per_port);
9437a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9438a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < p->num_ports; i++) {
9439a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		buf += sprintf(buf,
9440a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       (i == 0) ? "%d" : " %d",
9441a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       arr[i]);
9442a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9443a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	buf += sprintf(buf, "\n");
9444a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9445a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return buf - orig_buf;
9446a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9447a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9448a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic ssize_t show_rxchan_per_port(struct device *dev,
9449a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    struct device_attribute *attr, char *buf)
9450a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9451a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return __show_chan_per_port(dev, attr, buf, 1);
9452a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9453a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9454a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic ssize_t show_txchan_per_port(struct device *dev,
9455a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    struct device_attribute *attr, char *buf)
9456a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9457a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return __show_chan_per_port(dev, attr, buf, 1);
9458a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9459a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9460a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic ssize_t show_num_ports(struct device *dev,
9461a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			      struct device_attribute *attr, char *buf)
9462a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9463a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct platform_device *plat_dev = to_platform_device(dev);
9464a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *p = plat_dev->dev.platform_data;
9465a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9466a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return sprintf(buf, "%d\n", p->num_ports);
9467a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9468a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9469a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic struct device_attribute niu_parent_attributes[] = {
9470a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	__ATTR(port_phy, S_IRUGO, show_port_phy, NULL),
9471a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	__ATTR(plat_type, S_IRUGO, show_plat_type, NULL),
9472a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	__ATTR(rxchan_per_port, S_IRUGO, show_rxchan_per_port, NULL),
9473a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	__ATTR(txchan_per_port, S_IRUGO, show_txchan_per_port, NULL),
9474a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	__ATTR(num_ports, S_IRUGO, show_num_ports, NULL),
9475a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{}
9476a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
9477a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9478a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic struct niu_parent * __devinit niu_new_parent(struct niu *np,
9479a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller						    union niu_parent_id *id,
9480a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller						    u8 ptype)
9481a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9482a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct platform_device *plat_dev;
9483a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *p;
9484a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int i;
9485a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9486a769f4968396093d5cc1b1a86204cef579784b24David S. Miller	plat_dev = platform_device_register_simple("niu-board", niu_parent_index,
9487a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller						   NULL, 0);
948858f3e0a864c46dadbeadf682e6bbdcab14ba19d3Dan Carpenter	if (IS_ERR(plat_dev))
9489a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return NULL;
9490a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9491a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; attr_name(niu_parent_attributes[i]); i++) {
9492a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int err = device_create_file(&plat_dev->dev,
9493a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					     &niu_parent_attributes[i]);
9494a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
9495a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			goto fail_unregister;
9496a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9497a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9498a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	p = kzalloc(sizeof(*p), GFP_KERNEL);
9499a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!p)
9500a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto fail_unregister;
9501a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9502a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	p->index = niu_parent_index++;
9503a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9504a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	plat_dev->dev.platform_data = p;
9505a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	p->plat_dev = plat_dev;
9506a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9507a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	memcpy(&p->id, id, sizeof(*id));
9508a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	p->plat_type = ptype;
9509a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	INIT_LIST_HEAD(&p->list);
9510a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	atomic_set(&p->refcnt, 0);
9511a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	list_add(&p->list, &niu_parent_list);
9512a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_lock_init(&p->lock);
9513a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9514a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	p->rxdma_clock_divider = 7500;
9515a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9516a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	p->tcam_num_entries = NIU_PCI_TCAM_ENTRIES;
9517a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (p->plat_type == PLAT_TYPE_NIU)
9518a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		p->tcam_num_entries = NIU_NONPCI_TCAM_ENTRIES;
9519a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9520a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_SCTP_IPV6; i++) {
9521a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int index = i - CLASS_CODE_USER_PROG1;
9522a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9523a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		p->tcam_key[index] = TCAM_KEY_TSEL;
9524a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		p->flow_key[index] = (FLOW_KEY_IPSA |
9525a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				      FLOW_KEY_IPDA |
9526a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				      FLOW_KEY_PROTO |
9527a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				      (FLOW_KEY_L4_BYTE12 <<
9528a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				       FLOW_KEY_L4_0_SHIFT) |
9529a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				      (FLOW_KEY_L4_BYTE12 <<
9530a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				       FLOW_KEY_L4_1_SHIFT));
9531a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9532a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9533a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	for (i = 0; i < LDN_MAX + 1; i++)
9534a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		p->ldg_map[i] = LDG_INVALID;
9535a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9536a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return p;
9537a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9538a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerfail_unregister:
9539a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	platform_device_unregister(plat_dev);
9540a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return NULL;
9541a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9542a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9543a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic struct niu_parent * __devinit niu_get_parent(struct niu *np,
9544a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller						    union niu_parent_id *id,
9545a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller						    u8 ptype)
9546a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9547a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *p, *tmp;
9548a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int port = np->port;
9549a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9550a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mutex_lock(&niu_parent_lock);
9551a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	p = NULL;
9552a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	list_for_each_entry(tmp, &niu_parent_list, list) {
9553a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!memcmp(id, &tmp->id, sizeof(*id))) {
9554a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			p = tmp;
9555a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			break;
9556a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
9557a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9558a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!p)
9559a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		p = niu_new_parent(np, id, ptype);
9560a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9561a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (p) {
9562a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		char port_name[6];
9563a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		int err;
9564a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9565a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		sprintf(port_name, "port%d", port);
9566a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = sysfs_create_link(&p->plat_dev->dev.kobj,
9567a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					&np->device->kobj,
9568a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller					port_name);
9569a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (!err) {
9570a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			p->ports[port] = np;
9571a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			atomic_inc(&p->refcnt);
9572a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
9573a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9574a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mutex_unlock(&niu_parent_lock);
9575a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9576a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return p;
9577a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9578a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9579a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_put_parent(struct niu *np)
9580a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9581a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu_parent *p = np->parent;
9582a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u8 port = np->port;
9583a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	char port_name[6];
9584a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9585a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	BUG_ON(!p || p->ports[port] != np);
9586a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9587f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches	netif_printk(np, probe, KERN_DEBUG, np->dev,
9588f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		     "%s() port[%u]\n", __func__, port);
9589a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9590a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	sprintf(port_name, "port%d", port);
9591a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9592a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mutex_lock(&niu_parent_lock);
9593a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9594a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	sysfs_remove_link(&p->plat_dev->dev.kobj, port_name);
9595a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9596a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	p->ports[port] = NULL;
9597a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->parent = NULL;
9598a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9599a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (atomic_dec_and_test(&p->refcnt)) {
9600a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		list_del(&p->list);
9601a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		platform_device_unregister(p->plat_dev);
9602a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9603a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9604a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	mutex_unlock(&niu_parent_lock);
9605a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9606a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9607a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void *niu_pci_alloc_coherent(struct device *dev, size_t size,
9608a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    u64 *handle, gfp_t flag)
9609a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9610a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dma_addr_t dh;
9611a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	void *ret;
9612a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9613a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	ret = dma_alloc_coherent(dev, size, &dh, flag);
9614a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (ret)
9615a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		*handle = dh;
9616a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return ret;
9617a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9618a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9619a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_pci_free_coherent(struct device *dev, size_t size,
9620a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  void *cpu_addr, u64 handle)
9621a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9622a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dma_free_coherent(dev, size, cpu_addr, handle);
9623a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9624a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9625a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic u64 niu_pci_map_page(struct device *dev, struct page *page,
9626a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			    unsigned long offset, size_t size,
9627a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			    enum dma_data_direction direction)
9628a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9629a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return dma_map_page(dev, page, offset, size, direction);
9630a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9631a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9632a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_pci_unmap_page(struct device *dev, u64 dma_address,
9633a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       size_t size, enum dma_data_direction direction)
9634a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9635a08b32df1417146b1a4c43e641ec1177da51896cHannes Eder	dma_unmap_page(dev, dma_address, size, direction);
9636a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9637a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9638a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic u64 niu_pci_map_single(struct device *dev, void *cpu_addr,
9639a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			      size_t size,
9640a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			      enum dma_data_direction direction)
9641a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9642a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return dma_map_single(dev, cpu_addr, size, direction);
9643a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9644a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9645a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_pci_unmap_single(struct device *dev, u64 dma_address,
9646a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 size_t size,
9647a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 enum dma_data_direction direction)
9648a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9649a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dma_unmap_single(dev, dma_address, size, direction);
9650a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9651a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9652a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct niu_ops niu_pci_ops = {
9653a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.alloc_coherent	= niu_pci_alloc_coherent,
9654a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.free_coherent	= niu_pci_free_coherent,
9655a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.map_page	= niu_pci_map_page,
9656a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.unmap_page	= niu_pci_unmap_page,
9657a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.map_single	= niu_pci_map_single,
9658a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.unmap_single	= niu_pci_unmap_single,
9659a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
9660a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9661a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __devinit niu_driver_version(void)
9662a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9663a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	static int niu_version_printed;
9664a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9665a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (niu_version_printed++ == 0)
9666a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		pr_info("%s", version);
9667a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9668a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9669a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic struct net_device * __devinit niu_alloc_and_init(
9670a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct device *gen_dev, struct pci_dev *pdev,
96712dc11581376829303b98eadb2de253bee065a56aGrant Likely	struct platform_device *op, const struct niu_ops *ops,
9672a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u8 port)
9673a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9674b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller	struct net_device *dev;
9675a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np;
9676a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9677b4c21639ab0f6df07ab7624a8c2f974936708ae5David S. Miller	dev = alloc_etherdev_mq(sizeof(struct niu), NIU_NUM_TXCHAN);
967841de8d4cff21a2e81e3d9ff66f5f7c903f9c3ab1Joe Perches	if (!dev)
9679a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return NULL;
9680a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9681a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	SET_NETDEV_DEV(dev, gen_dev);
9682a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9683a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np = netdev_priv(dev);
9684a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->dev = dev;
9685a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->pdev = pdev;
9686a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->op = op;
9687a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->device = gen_dev;
9688a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->ops = ops;
9689a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9690a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->msg_enable = niu_debug;
9691a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9692a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_lock_init(&np->lock);
9693a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	INIT_WORK(&np->reset_task, niu_reset_task);
9694a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9695a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->port = port;
9696a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9697a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return dev;
9698a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9699a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
97002c9171d4ef431d8ed897daf4fee6798979cbb432Stephen Hemmingerstatic const struct net_device_ops niu_netdev_ops = {
97012c9171d4ef431d8ed897daf4fee6798979cbb432Stephen Hemminger	.ndo_open		= niu_open,
97022c9171d4ef431d8ed897daf4fee6798979cbb432Stephen Hemminger	.ndo_stop		= niu_close,
9703008298231abbeb91bc7be9e8b078607b816d1a4aStephen Hemminger	.ndo_start_xmit		= niu_start_xmit,
97041a7a10325d370e2cbed0c5bb7313904545f6dac8stephen hemminger	.ndo_get_stats64	= niu_get_stats,
970501789349ee52e4a3faf376f1485303d9723c4f1fJiri Pirko	.ndo_set_rx_mode	= niu_set_rx_mode,
97062c9171d4ef431d8ed897daf4fee6798979cbb432Stephen Hemminger	.ndo_validate_addr	= eth_validate_addr,
97072c9171d4ef431d8ed897daf4fee6798979cbb432Stephen Hemminger	.ndo_set_mac_address	= niu_set_mac_addr,
97082c9171d4ef431d8ed897daf4fee6798979cbb432Stephen Hemminger	.ndo_do_ioctl		= niu_ioctl,
97092c9171d4ef431d8ed897daf4fee6798979cbb432Stephen Hemminger	.ndo_tx_timeout		= niu_tx_timeout,
97102c9171d4ef431d8ed897daf4fee6798979cbb432Stephen Hemminger	.ndo_change_mtu		= niu_change_mtu,
97112c9171d4ef431d8ed897daf4fee6798979cbb432Stephen Hemminger};
97122c9171d4ef431d8ed897daf4fee6798979cbb432Stephen Hemminger
9713a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __devinit niu_assign_netdev_ops(struct net_device *dev)
9714a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
97152c9171d4ef431d8ed897daf4fee6798979cbb432Stephen Hemminger	dev->netdev_ops = &niu_netdev_ops;
9716a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev->ethtool_ops = &niu_ethtool_ops;
9717a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev->watchdog_timeo = NIU_TX_TIMEOUT;
9718a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9719a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9720a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __devinit niu_device_announce(struct niu *np)
9721a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9722a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct net_device *dev = np->dev;
9723a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9724e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg	pr_info("%s: NIU Ethernet %pM\n", dev->name, dev->dev_addr);
9725a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
97265fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	if (np->parent->plat_type == PLAT_TYPE_ATCA_CP3220) {
97275fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n",
97285fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				dev->name,
97295fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				(np->flags & NIU_FLAGS_XMAC ? "XMAC" : "BMAC"),
97305fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				(np->flags & NIU_FLAGS_10G ? "10G" : "1G"),
97315fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				(np->flags & NIU_FLAGS_FIBER ? "RGMII FIBER" : "SERDES"),
97325fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				(np->mac_xcvr == MAC_XCVR_MII ? "MII" :
97335fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				 (np->mac_xcvr == MAC_XCVR_PCS ? "PCS" : "XPCS")),
97345fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				np->vpd.phy_type);
97355fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	} else {
97365fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku		pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n",
97375fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				dev->name,
97385fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				(np->flags & NIU_FLAGS_XMAC ? "XMAC" : "BMAC"),
97395fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				(np->flags & NIU_FLAGS_10G ? "10G" : "1G"),
9740e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera				(np->flags & NIU_FLAGS_FIBER ? "FIBER" :
9741e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera				 (np->flags & NIU_FLAGS_XCVR_SERDES ? "SERDES" :
9742e3e081e1d5c4791f4416ed57b7a2f143ab9e5b09Santwona Behera				  "COPPER")),
97435fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				(np->mac_xcvr == MAC_XCVR_MII ? "MII" :
97445fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				 (np->mac_xcvr == MAC_XCVR_PCS ? "PCS" : "XPCS")),
97455fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku				np->vpd.phy_type);
97465fbd7e24da874a1c7b06ae6b10bbf2d71c1b6a11Matheos Worku	}
9747a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9748a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
97493cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Millerstatic void __devinit niu_set_basic_features(struct net_device *dev)
97503cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller{
97513cd8ef4b6071834fd432bbccbec0611591908643Michał Mirosław	dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXHASH;
97523cd8ef4b6071834fd432bbccbec0611591908643Michał Mirosław	dev->features |= dev->hw_features | NETIF_F_RXCSUM;
97533cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller}
97543cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller
9755a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __devinit niu_pci_init_one(struct pci_dev *pdev,
9756a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				      const struct pci_device_id *ent)
9757a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9758a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	union niu_parent_id parent_id;
9759a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct net_device *dev;
9760a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np;
9761a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err, pos;
9762a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u64 dma_mask;
9763a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	u16 val16;
9764a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9765a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_driver_version();
9766a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9767a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = pci_enable_device(pdev);
9768a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err) {
9769f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
9770a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return err;
9771a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9772a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9773a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
9774a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	    !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
9775f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(&pdev->dev, "Cannot find proper PCI device base addresses, aborting\n");
9776a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = -ENODEV;
9777a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out_disable_pdev;
9778a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9779a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9780a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = pci_request_regions(pdev, DRV_MODULE_NAME);
9781a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err) {
9782f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
9783a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out_disable_pdev;
9784a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9785a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9786d3aa0cb44f2cfcdfa6df1bd40b9c182b35528849Jon Mason	pos = pci_pcie_cap(pdev);
9787a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (pos <= 0) {
9788f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(&pdev->dev, "Cannot find PCI Express capability, aborting\n");
9789a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out_free_res;
9790a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9791a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9792a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev = niu_alloc_and_init(&pdev->dev, pdev, NULL,
9793a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 &niu_pci_ops, PCI_FUNC(pdev->devfn));
9794a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!dev) {
9795a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = -ENOMEM;
9796a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out_free_res;
9797a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9798a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np = netdev_priv(dev);
9799a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9800a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	memset(&parent_id, 0, sizeof(parent_id));
9801a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	parent_id.pci.domain = pci_domain_nr(pdev->bus);
9802a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	parent_id.pci.bus = pdev->bus->number;
9803a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	parent_id.pci.device = PCI_SLOT(pdev->devfn);
9804a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9805a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->parent = niu_get_parent(np, &parent_id,
9806a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    PLAT_TYPE_ATLAS);
9807a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!np->parent) {
9808a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = -ENOMEM;
9809a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out_free_dev;
9810a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9811a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9812a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &val16);
9813a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val16 &= ~PCI_EXP_DEVCTL_NOSNOOP_EN;
9814a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	val16 |= (PCI_EXP_DEVCTL_CERE |
9815a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		  PCI_EXP_DEVCTL_NFERE |
9816a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		  PCI_EXP_DEVCTL_FERE |
9817a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		  PCI_EXP_DEVCTL_URRE |
9818a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		  PCI_EXP_DEVCTL_RELAX_EN);
9819a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pci_write_config_word(pdev, pos + PCI_EXP_DEVCTL, val16);
9820a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
98218cbd9623da7e7a99c6bd0f0b7d21d17c233c6abbMarin Mitov	dma_mask = DMA_BIT_MASK(44);
9822a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = pci_set_dma_mask(pdev, dma_mask);
9823a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err) {
9824a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		dev->features |= NETIF_F_HIGHDMA;
9825a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = pci_set_consistent_dma_mask(pdev, dma_mask);
9826a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err) {
9827f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			dev_err(&pdev->dev, "Unable to obtain 44 bit DMA for consistent allocations, aborting\n");
9828a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			goto err_out_release_parent;
9829a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
9830a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9831284901a90a9e0b812ca3f5f852cbbfb60d10249dYang Hongyang	if (err || dma_mask == DMA_BIT_MASK(32)) {
9832284901a90a9e0b812ca3f5f852cbbfb60d10249dYang Hongyang		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
9833a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err) {
9834f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			dev_err(&pdev->dev, "No usable DMA configuration, aborting\n");
9835a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			goto err_out_release_parent;
9836a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
9837a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9838a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
98393cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller	niu_set_basic_features(dev);
9840a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
984101789349ee52e4a3faf376f1485303d9723c4f1fJiri Pirko	dev->priv_flags |= IFF_UNICAST_FLT;
984201789349ee52e4a3faf376f1485303d9723c4f1fJiri Pirko
984319ecb6ba800765743bb4525c66562f0d30993f8dDavid S. Miller	np->regs = pci_ioremap_bar(pdev, 0);
9844a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!np->regs) {
9845f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(&pdev->dev, "Cannot map device registers, aborting\n");
9846a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = -ENOMEM;
9847a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out_release_parent;
9848a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9849a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9850a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pci_set_master(pdev);
9851a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pci_save_state(pdev);
9852a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9853a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev->irq = pdev->irq;
9854a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9855a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_assign_netdev_ops(dev);
9856a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9857a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_get_invariants(np);
9858a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err) {
9859a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err != -ENODEV)
9860f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			dev_err(&pdev->dev, "Problem fetching invariants of chip, aborting\n");
9861a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out_iounmap;
9862a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9863a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9864a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = register_netdev(dev);
9865a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err) {
9866f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(&pdev->dev, "Cannot register net device, aborting\n");
9867a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out_iounmap;
9868a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9869a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9870a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pci_set_drvdata(pdev, dev);
9871a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9872a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_device_announce(np);
9873a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9874a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
9875a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9876a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millererr_out_iounmap:
9877a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->regs) {
9878a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		iounmap(np->regs);
9879a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->regs = NULL;
9880a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9881a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9882a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millererr_out_release_parent:
9883a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_put_parent(np);
9884a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9885a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millererr_out_free_dev:
9886a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	free_netdev(dev);
9887a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9888a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millererr_out_free_res:
9889a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pci_release_regions(pdev);
9890a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9891a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millererr_out_disable_pdev:
9892a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pci_disable_device(pdev);
9893a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pci_set_drvdata(pdev, NULL);
9894a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9895a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
9896a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9897a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9898a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __devexit niu_pci_remove_one(struct pci_dev *pdev)
9899a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9900a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct net_device *dev = pci_get_drvdata(pdev);
9901a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9902a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (dev) {
9903a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct niu *np = netdev_priv(dev);
9904a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9905a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		unregister_netdev(dev);
9906a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (np->regs) {
9907a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			iounmap(np->regs);
9908a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			np->regs = NULL;
9909a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
9910a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9911a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_ldg_free(np);
9912a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9913a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_put_parent(np);
9914a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9915a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		free_netdev(dev);
9916a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		pci_release_regions(pdev);
9917a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		pci_disable_device(pdev);
9918a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		pci_set_drvdata(pdev, NULL);
9919a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9920a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9921a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9922a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_suspend(struct pci_dev *pdev, pm_message_t state)
9923a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9924a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct net_device *dev = pci_get_drvdata(pdev);
9925a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
9926a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long flags;
9927a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9928a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!netif_running(dev))
9929a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return 0;
9930a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
993123f333a2bfafba80339315b724808982a9de57d9Tejun Heo	flush_work_sync(&np->reset_task);
9932a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_netif_stop(np);
9933a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9934a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	del_timer_sync(&np->timer);
9935a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9936a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_lock_irqsave(&np->lock, flags);
9937a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_enable_interrupts(np, 0);
9938a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_unlock_irqrestore(&np->lock, flags);
9939a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9940a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	netif_device_detach(dev);
9941a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9942a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_lock_irqsave(&np->lock, flags);
9943a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_stop_hw(np);
9944a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_unlock_irqrestore(&np->lock, flags);
9945a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9946a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pci_save_state(pdev);
9947a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9948a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
9949a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9950a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9951a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int niu_resume(struct pci_dev *pdev)
9952a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9953a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct net_device *dev = pci_get_drvdata(pdev);
9954a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np = netdev_priv(dev);
9955a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long flags;
9956a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
9957a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9958a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!netif_running(dev))
9959a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return 0;
9960a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9961a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pci_restore_state(pdev);
9962a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9963a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	netif_device_attach(dev);
9964a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9965a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_lock_irqsave(&np->lock, flags);
9966a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9967a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_init_hw(np);
9968a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err) {
9969a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->timer.expires = jiffies + HZ;
9970a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		add_timer(&np->timer);
9971a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_netif_start(np);
9972a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
9973a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9974a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	spin_unlock_irqrestore(&np->lock, flags);
9975a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9976a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
9977a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
9978a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9979a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic struct pci_driver niu_pci_driver = {
9980a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.name		= DRV_MODULE_NAME,
9981a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.id_table	= niu_pci_tbl,
9982a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.probe		= niu_pci_init_one,
9983a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.remove		= __devexit_p(niu_pci_remove_one),
9984a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.suspend	= niu_suspend,
9985a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.resume		= niu_resume,
9986a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
9987a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9988a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#ifdef CONFIG_SPARC64
9989a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void *niu_phys_alloc_coherent(struct device *dev, size_t size,
9990a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				     u64 *dma_addr, gfp_t flag)
9991a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
9992a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long order = get_order(size);
9993a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long page = __get_free_pages(flag, order);
9994a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
9995a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (page == 0UL)
9996a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return NULL;
9997a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	memset((char *)page, 0, PAGE_SIZE << order);
9998a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	*dma_addr = __pa(page);
9999a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10000a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return (void *) page;
10001a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
10002a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10003a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_phys_free_coherent(struct device *dev, size_t size,
10004a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				   void *cpu_addr, u64 handle)
10005a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
10006a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	unsigned long order = get_order(size);
10007a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10008a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	free_pages((unsigned long) cpu_addr, order);
10009a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
10010a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10011a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic u64 niu_phys_map_page(struct device *dev, struct page *page,
10012a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			     unsigned long offset, size_t size,
10013a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			     enum dma_data_direction direction)
10014a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
10015a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return page_to_phys(page) + offset;
10016a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
10017a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10018a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_phys_unmap_page(struct device *dev, u64 dma_address,
10019a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				size_t size, enum dma_data_direction direction)
10020a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
10021a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* Nothing to do.  */
10022a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
10023a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10024a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic u64 niu_phys_map_single(struct device *dev, void *cpu_addr,
10025a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       size_t size,
10026a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			       enum dma_data_direction direction)
10027a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
10028a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return __pa(cpu_addr);
10029a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
10030a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10031a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void niu_phys_unmap_single(struct device *dev, u64 dma_address,
10032a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  size_t size,
10033a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				  enum dma_data_direction direction)
10034a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
10035a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	/* Nothing to do.  */
10036a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
10037a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10038a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic const struct niu_ops niu_phys_ops = {
10039a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.alloc_coherent	= niu_phys_alloc_coherent,
10040a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.free_coherent	= niu_phys_free_coherent,
10041a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.map_page	= niu_phys_map_page,
10042a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.unmap_page	= niu_phys_unmap_page,
10043a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.map_single	= niu_phys_map_single,
10044a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.unmap_single	= niu_phys_unmap_single,
10045a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
10046a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1004774888760d40b3ac9054f9c5fa07b566c0676ba2dGrant Likelystatic int __devinit niu_of_probe(struct platform_device *op)
10048a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
10049a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	union niu_parent_id parent_id;
10050a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct net_device *dev;
10051a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct niu *np;
10052a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	const u32 *reg;
10053a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err;
10054a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10055a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_driver_version();
10056a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1005761c7a080a5a061c976988fd4b844dfb468dda255Grant Likely	reg = of_get_property(op->dev.of_node, "reg", NULL);
10058a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!reg) {
10059f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(&op->dev, "%s: No 'reg' property, aborting\n",
1006061c7a080a5a061c976988fd4b844dfb468dda255Grant Likely			op->dev.of_node->full_name);
10061a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		return -ENODEV;
10062a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
10063a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10064a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev = niu_alloc_and_init(&op->dev, NULL, op,
10065a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				 &niu_phys_ops, reg[0] & 0x1);
10066a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!dev) {
10067a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = -ENOMEM;
10068a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out;
10069a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
10070a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np = netdev_priv(dev);
10071a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10072a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	memset(&parent_id, 0, sizeof(parent_id));
1007361c7a080a5a061c976988fd4b844dfb468dda255Grant Likely	parent_id.of = of_get_parent(op->dev.of_node);
10074a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10075a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->parent = niu_get_parent(np, &parent_id,
10076a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    PLAT_TYPE_NIU);
10077a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!np->parent) {
10078a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = -ENOMEM;
10079a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out_free_dev;
10080a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
10081a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
100823cfa856d6d43894ebffdc28d2f0587595280893bDavid S. Miller	niu_set_basic_features(dev);
10083a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10084a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->regs = of_ioremap(&op->resource[1], 0,
100856f0e013548fd15fddb952f657a3cc81282641191Tobias Klauser			      resource_size(&op->resource[1]),
10086a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			      "niu regs");
10087a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!np->regs) {
10088f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(&op->dev, "Cannot map device registers, aborting\n");
10089a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = -ENOMEM;
10090a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out_release_parent;
10091a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
10092a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10093a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->vir_regs_1 = of_ioremap(&op->resource[2], 0,
100946f0e013548fd15fddb952f657a3cc81282641191Tobias Klauser				    resource_size(&op->resource[2]),
10095a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    "niu vregs-1");
10096a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!np->vir_regs_1) {
10097f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(&op->dev, "Cannot map device vir registers 1, aborting\n");
10098a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = -ENOMEM;
10099a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out_iounmap;
10100a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
10101a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10102a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	np->vir_regs_2 = of_ioremap(&op->resource[3], 0,
101036f0e013548fd15fddb952f657a3cc81282641191Tobias Klauser				    resource_size(&op->resource[3]),
10104a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller				    "niu vregs-2");
10105a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!np->vir_regs_2) {
10106f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(&op->dev, "Cannot map device vir registers 2, aborting\n");
10107a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = -ENOMEM;
10108a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out_iounmap;
10109a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
10110a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10111a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_assign_netdev_ops(dev);
10112a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10113a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = niu_get_invariants(np);
10114a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err) {
10115a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err != -ENODEV)
10116f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches			dev_err(&op->dev, "Problem fetching invariants of chip, aborting\n");
10117a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out_iounmap;
10118a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
10119a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10120a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	err = register_netdev(dev);
10121a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (err) {
10122f10a1f2e7e93a35cb603b63090ff0e70a576a641Joe Perches		dev_err(&op->dev, "Cannot register net device, aborting\n");
10123a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		goto err_out_iounmap;
10124a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
10125a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10126a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	dev_set_drvdata(&op->dev, dev);
10127a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10128a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_device_announce(np);
10129a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10130a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
10131a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10132a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millererr_out_iounmap:
10133a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->vir_regs_1) {
10134a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		of_iounmap(&op->resource[2], np->vir_regs_1,
101356f0e013548fd15fddb952f657a3cc81282641191Tobias Klauser			   resource_size(&op->resource[2]));
10136a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->vir_regs_1 = NULL;
10137a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
10138a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10139a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->vir_regs_2) {
10140a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		of_iounmap(&op->resource[3], np->vir_regs_2,
101416f0e013548fd15fddb952f657a3cc81282641191Tobias Klauser			   resource_size(&op->resource[3]));
10142a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->vir_regs_2 = NULL;
10143a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
10144a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10145a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (np->regs) {
10146a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		of_iounmap(&op->resource[1], np->regs,
101476f0e013548fd15fddb952f657a3cc81282641191Tobias Klauser			   resource_size(&op->resource[1]));
10148a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		np->regs = NULL;
10149a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
10150a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10151a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millererr_out_release_parent:
10152a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_put_parent(np);
10153a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10154a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millererr_out_free_dev:
10155a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	free_netdev(dev);
10156a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10157a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millererr_out:
10158a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
10159a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
10160a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
101612dc11581376829303b98eadb2de253bee065a56aGrant Likelystatic int __devexit niu_of_remove(struct platform_device *op)
10162a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
10163a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	struct net_device *dev = dev_get_drvdata(&op->dev);
10164a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10165a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (dev) {
10166a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		struct niu *np = netdev_priv(dev);
10167a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10168a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		unregister_netdev(dev);
10169a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10170a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (np->vir_regs_1) {
10171a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			of_iounmap(&op->resource[2], np->vir_regs_1,
101726f0e013548fd15fddb952f657a3cc81282641191Tobias Klauser				   resource_size(&op->resource[2]));
10173a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			np->vir_regs_1 = NULL;
10174a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
10175a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10176a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (np->vir_regs_2) {
10177a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			of_iounmap(&op->resource[3], np->vir_regs_2,
101786f0e013548fd15fddb952f657a3cc81282641191Tobias Klauser				   resource_size(&op->resource[3]));
10179a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			np->vir_regs_2 = NULL;
10180a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
10181a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10182a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (np->regs) {
10183a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			of_iounmap(&op->resource[1], np->regs,
101846f0e013548fd15fddb952f657a3cc81282641191Tobias Klauser				   resource_size(&op->resource[1]));
10185a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller			np->regs = NULL;
10186a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		}
10187a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10188a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_ldg_free(np);
10189a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10190a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		niu_put_parent(np);
10191a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10192a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		free_netdev(dev);
10193a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		dev_set_drvdata(&op->dev, NULL);
10194a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
10195a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return 0;
10196a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
10197a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10198fd098316ef533e8441576f020ead4beab93154ceDavid S. Millerstatic const struct of_device_id niu_match[] = {
10199a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{
10200a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		.name = "network",
10201a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		.compatible = "SUNW,niusl",
10202a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	},
10203a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	{},
10204a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
10205a3138df9f20e726c517f8df7387b5d83f5df5566David S. MillerMODULE_DEVICE_TABLE(of, niu_match);
10206a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1020774888760d40b3ac9054f9c5fa07b566c0676ba2dGrant Likelystatic struct platform_driver niu_of_driver = {
102084018294b53d1dae026880e45f174c1cc63b5d435Grant Likely	.driver = {
102094018294b53d1dae026880e45f174c1cc63b5d435Grant Likely		.name = "niu",
102104018294b53d1dae026880e45f174c1cc63b5d435Grant Likely		.owner = THIS_MODULE,
102114018294b53d1dae026880e45f174c1cc63b5d435Grant Likely		.of_match_table = niu_match,
102124018294b53d1dae026880e45f174c1cc63b5d435Grant Likely	},
10213a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.probe		= niu_of_probe,
10214a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	.remove		= __devexit_p(niu_of_remove),
10215a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller};
10216a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10217a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif /* CONFIG_SPARC64 */
10218a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10219a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic int __init niu_init(void)
10220a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
10221a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	int err = 0;
10222a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
1022381429973cfff7745792c877dd083eec29724ec97Olof Johansson	BUILD_BUG_ON(PAGE_SIZE < 4 * 1024);
10224a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10225a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	niu_debug = netif_msg_init(debug, NIU_MSG_DEFAULT);
10226a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10227a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#ifdef CONFIG_SPARC64
1022874888760d40b3ac9054f9c5fa07b566c0676ba2dGrant Likely	err = platform_driver_register(&niu_of_driver);
10229a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif
10230a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10231a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	if (!err) {
10232a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		err = pci_register_driver(&niu_pci_driver);
10233a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#ifdef CONFIG_SPARC64
10234a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller		if (err)
1023574888760d40b3ac9054f9c5fa07b566c0676ba2dGrant Likely			platform_driver_unregister(&niu_of_driver);
10236a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif
10237a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	}
10238a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10239a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	return err;
10240a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
10241a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10242a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millerstatic void __exit niu_exit(void)
10243a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller{
10244a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller	pci_unregister_driver(&niu_pci_driver);
10245a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#ifdef CONFIG_SPARC64
1024674888760d40b3ac9054f9c5fa07b566c0676ba2dGrant Likely	platform_driver_unregister(&niu_of_driver);
10247a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller#endif
10248a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller}
10249a3138df9f20e726c517f8df7387b5d83f5df5566David S. Miller
10250a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millermodule_init(niu_init);
10251a3138df9f20e726c517f8df7387b5d83f5df5566David S. Millermodule_exit(niu_exit);
10252