1/* $Date: 2007/08/03 18:52:46 $ $RCSfile: mac.c,v $ $Revision: 1.1.1.1 $ */
2#include "gmac.h"
3#include "regs.h"
4#include "fpga_defs.h"
5
6#define MAC_CSR_INTERFACE_GMII      0x0
7#define MAC_CSR_INTERFACE_TBI       0x1
8#define MAC_CSR_INTERFACE_MII       0x2
9#define MAC_CSR_INTERFACE_RMII      0x3
10
11/* Chelsio's MAC statistics. */
12struct mac_statistics {
13
14	/* Transmit */
15	u32 TxFramesTransmittedOK;
16	u32 TxReserved1;
17	u32 TxReserved2;
18	u32 TxOctetsTransmittedOK;
19	u32 TxFramesWithDeferredXmissions;
20	u32 TxLateCollisions;
21	u32 TxFramesAbortedDueToXSCollisions;
22	u32 TxFramesLostDueToIntMACXmitError;
23	u32 TxReserved3;
24	u32 TxMulticastFrameXmittedOK;
25	u32 TxBroadcastFramesXmittedOK;
26	u32 TxFramesWithExcessiveDeferral;
27	u32 TxPAUSEMACCtrlFramesTransmitted;
28
29	/* Receive */
30	u32 RxFramesReceivedOK;
31	u32 RxFrameCheckSequenceErrors;
32	u32 RxAlignmentErrors;
33	u32 RxOctetsReceivedOK;
34	u32 RxFramesLostDueToIntMACRcvError;
35	u32 RxMulticastFramesReceivedOK;
36	u32 RxBroadcastFramesReceivedOK;
37	u32 RxInRangeLengthErrors;
38	u32 RxTxOutOfRangeLengthField;
39	u32 RxFrameTooLongErrors;
40	u32 RxPAUSEMACCtrlFramesReceived;
41};
42
43static int static_aPorts[] = {
44	FPGA_GMAC_INTERRUPT_PORT0,
45	FPGA_GMAC_INTERRUPT_PORT1,
46	FPGA_GMAC_INTERRUPT_PORT2,
47	FPGA_GMAC_INTERRUPT_PORT3
48};
49
50struct _cmac_instance {
51	u32 index;
52};
53
54static int mac_intr_enable(struct cmac *mac)
55{
56	u32 mac_intr;
57
58	if (t1_is_asic(mac->adapter)) {
59		/* ASIC */
60
61		/* We don't use the on chip MAC for ASIC products. */
62	} else {
63		/* FPGA */
64
65		/* Set parent gmac interrupt. */
66		mac_intr = readl(mac->adapter->regs + A_PL_ENABLE);
67		mac_intr |= FPGA_PCIX_INTERRUPT_GMAC;
68		writel(mac_intr, mac->adapter->regs + A_PL_ENABLE);
69
70		mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
71		mac_intr |= static_aPorts[mac->instance->index];
72		writel(mac_intr,
73		       mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
74	}
75
76	return 0;
77}
78
79static int mac_intr_disable(struct cmac *mac)
80{
81	u32 mac_intr;
82
83	if (t1_is_asic(mac->adapter)) {
84		/* ASIC */
85
86		/* We don't use the on chip MAC for ASIC products. */
87	} else {
88		/* FPGA */
89
90		/* Set parent gmac interrupt. */
91		mac_intr = readl(mac->adapter->regs + A_PL_ENABLE);
92		mac_intr &= ~FPGA_PCIX_INTERRUPT_GMAC;
93		writel(mac_intr, mac->adapter->regs + A_PL_ENABLE);
94
95		mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
96		mac_intr &= ~(static_aPorts[mac->instance->index]);
97		writel(mac_intr,
98		       mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
99	}
100
101	return 0;
102}
103
104static int mac_intr_clear(struct cmac *mac)
105{
106	u32 mac_intr;
107
108	if (t1_is_asic(mac->adapter)) {
109		/* ASIC */
110
111		/* We don't use the on chip MAC for ASIC products. */
112	} else {
113		/* FPGA */
114
115		/* Set parent gmac interrupt. */
116		writel(FPGA_PCIX_INTERRUPT_GMAC,
117		       mac->adapter->regs +  A_PL_CAUSE);
118		mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
119		mac_intr |= (static_aPorts[mac->instance->index]);
120		writel(mac_intr,
121		       mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
122	}
123
124	return 0;
125}
126
127static int mac_get_address(struct cmac *mac, u8 addr[6])
128{
129	u32 data32_lo, data32_hi;
130
131	data32_lo = readl(mac->adapter->regs
132			  + MAC_REG_IDLO(mac->instance->index));
133	data32_hi = readl(mac->adapter->regs
134			  + MAC_REG_IDHI(mac->instance->index));
135
136	addr[0] = (u8) ((data32_hi >> 8) & 0xFF);
137	addr[1] = (u8) ((data32_hi) & 0xFF);
138	addr[2] = (u8) ((data32_lo >> 24) & 0xFF);
139	addr[3] = (u8) ((data32_lo >> 16) & 0xFF);
140	addr[4] = (u8) ((data32_lo >> 8) & 0xFF);
141	addr[5] = (u8) ((data32_lo) & 0xFF);
142	return 0;
143}
144
145static int mac_reset(struct cmac *mac)
146{
147	u32 data32;
148	int mac_in_reset, time_out = 100;
149	int idx = mac->instance->index;
150
151	data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx));
152	writel(data32 | F_MAC_RESET,
153	       mac->adapter->regs + MAC_REG_CSR(idx));
154
155	do {
156		data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx));
157
158		mac_in_reset = data32 & F_MAC_RESET;
159		if (mac_in_reset)
160			udelay(1);
161	} while (mac_in_reset && --time_out);
162
163	if (mac_in_reset) {
164		CH_ERR("%s: MAC %d reset timed out\n",
165		       mac->adapter->name, idx);
166		return 2;
167	}
168
169	return 0;
170}
171
172static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
173{
174	u32 val;
175
176	val = readl(mac->adapter->regs
177			    + MAC_REG_CSR(mac->instance->index));
178	val &= ~(F_MAC_PROMISC | F_MAC_MC_ENABLE);
179	val |= V_MAC_PROMISC(t1_rx_mode_promisc(rm) != 0);
180	val |= V_MAC_MC_ENABLE(t1_rx_mode_allmulti(rm) != 0);
181	writel(val,
182	       mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
183
184	return 0;
185}
186
187static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex,
188				   int fc)
189{
190	u32 data32;
191
192	data32 = readl(mac->adapter->regs
193			       + MAC_REG_CSR(mac->instance->index));
194	data32 &= ~(F_MAC_HALF_DUPLEX | V_MAC_SPEED(M_MAC_SPEED) |
195		V_INTERFACE(M_INTERFACE) | F_MAC_TX_PAUSE_ENABLE |
196		F_MAC_RX_PAUSE_ENABLE);
197
198	switch (speed) {
199	case SPEED_10:
200	case SPEED_100:
201		data32 |= V_INTERFACE(MAC_CSR_INTERFACE_MII);
202		data32 |= V_MAC_SPEED(speed == SPEED_10 ? 0 : 1);
203		break;
204	case SPEED_1000:
205		data32 |= V_INTERFACE(MAC_CSR_INTERFACE_GMII);
206		data32 |= V_MAC_SPEED(2);
207		break;
208	}
209
210	if (duplex >= 0)
211		data32 |= V_MAC_HALF_DUPLEX(duplex == DUPLEX_HALF);
212
213	if (fc >= 0) {
214		data32 |= V_MAC_RX_PAUSE_ENABLE((fc & PAUSE_RX) != 0);
215		data32 |= V_MAC_TX_PAUSE_ENABLE((fc & PAUSE_TX) != 0);
216	}
217
218	writel(data32,
219	       mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
220	return 0;
221}
222
223static int mac_enable(struct cmac *mac, int which)
224{
225	u32 val;
226
227	val = readl(mac->adapter->regs
228			    + MAC_REG_CSR(mac->instance->index));
229	if (which & MAC_DIRECTION_RX)
230		val |= F_MAC_RX_ENABLE;
231	if (which & MAC_DIRECTION_TX)
232		val |= F_MAC_TX_ENABLE;
233	writel(val,
234	       mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
235	return 0;
236}
237
238static int mac_disable(struct cmac *mac, int which)
239{
240	u32 val;
241
242	val = readl(mac->adapter->regs
243			    + MAC_REG_CSR(mac->instance->index));
244	if (which & MAC_DIRECTION_RX)
245		val &= ~F_MAC_RX_ENABLE;
246	if (which & MAC_DIRECTION_TX)
247		val &= ~F_MAC_TX_ENABLE;
248	writel(val,
249	       mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
250	return 0;
251}
252
253
254static int mac_set_mtu(struct cmac *mac, int mtu)
255{
256	if (mtu > 9600)
257		return -EINVAL;
258	writel(mtu + ETH_HLEN + VLAN_HLEN,
259	       mac->adapter->regs + MAC_REG_LARGEFRAMELENGTH(mac->instance->index));
260
261	return 0;
262}
263
264static const struct cmac_statistics *mac_update_statistics(struct cmac *mac,
265							   int flag)
266{
267	struct mac_statistics st;
268	u32 *p = (u32 *) & st, i;
269
270	writel(0,
271	       mac->adapter->regs + MAC_REG_RMCNT(mac->instance->index));
272
273	for (i = 0; i < sizeof(st) / sizeof(u32); i++)
274		*p++ = readl(mac->adapter->regs
275			     + MAC_REG_RMDATA(mac->instance->index));
276
277	return &mac->stats;
278}
279
280static void mac_destroy(struct cmac *mac)
281{
282	kfree(mac);
283}
284
285static struct cmac_ops chelsio_mac_ops = {
286	.destroy                 = mac_destroy,
287	.reset                   = mac_reset,
288	.interrupt_enable        = mac_intr_enable,
289	.interrupt_disable       = mac_intr_disable,
290	.interrupt_clear         = mac_intr_clear,
291	.enable                  = mac_enable,
292	.disable                 = mac_disable,
293	.set_mtu                 = mac_set_mtu,
294	.set_rx_mode             = mac_set_rx_mode,
295	.set_speed_duplex_fc     = mac_set_speed_duplex_fc,
296	.macaddress_get          = mac_get_address,
297	.statistics_update       = mac_update_statistics,
298};
299
300static struct cmac *mac_create(adapter_t *adapter, int index)
301{
302	struct cmac *mac;
303	u32 data32;
304
305	if (index >= 4)
306		return NULL;
307
308	mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
309	if (!mac)
310		return NULL;
311
312	mac->ops = &chelsio_mac_ops;
313	mac->instance = (cmac_instance *) (mac + 1);
314
315	mac->instance->index = index;
316	mac->adapter = adapter;
317
318	data32 = readl(adapter->regs + MAC_REG_CSR(mac->instance->index));
319	data32 &= ~(F_MAC_RESET | F_MAC_PROMISC | F_MAC_PROMISC |
320		    F_MAC_LB_ENABLE | F_MAC_RX_ENABLE | F_MAC_TX_ENABLE);
321	data32 |= F_MAC_JUMBO_ENABLE;
322	writel(data32, adapter->regs + MAC_REG_CSR(mac->instance->index));
323
324	/* Initialize the random backoff seed. */
325	data32 = 0x55aa + (3 * index);
326	writel(data32,
327	       adapter->regs + MAC_REG_GMRANDBACKOFFSEED(mac->instance->index));
328
329	/* Check to see if the mac address needs to be set manually. */
330	data32 = readl(adapter->regs + MAC_REG_IDLO(mac->instance->index));
331	if (data32 == 0 || data32 == 0xffffffff) {
332		/*
333		 * Add a default MAC address if we can't read one.
334		 */
335		writel(0x43FFFFFF - index,
336		       adapter->regs + MAC_REG_IDLO(mac->instance->index));
337		writel(0x0007,
338		       adapter->regs + MAC_REG_IDHI(mac->instance->index));
339	}
340
341	(void) mac_set_mtu(mac, 1500);
342	return mac;
343}
344
345const struct gmac t1_chelsio_mac_ops = {
346	.create = mac_create
347};
348