1/* $NetBSD: i82557.c,v 1.10 2008/02/11 13:51:35 mlelstv Exp $ */
2
3/*
4 * Copyright (c) 1998, 1999
5 * 	Matthias Drochner.  All rights reserved.
6 * Copyright (c) 1995, David Greenman
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice unmodified, this list of conditions, and the following
14 *    disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/types.h>
33#include <machine/pio.h>
34
35#include <dev/ic/i82557reg.h>
36
37#include <lib/libsa/stand.h>
38
39#include <libi386.h>
40#include <pcivar.h>
41
42#if defined(_STANDALONE) && !defined(SUPPORT_NO_NETBSD)
43#include <lib/libkern/libkern.h>
44#include <bootinfo.h>
45#endif
46
47#include "etherdrv.h"
48
49#define RECVBUF_SIZE 1600 /* struct fxp_rfa + packet */
50
51#ifdef _STANDALONE
52static pcihdl_t mytag;
53static char recvbuf[RECVBUF_SIZE];
54#define RECVBUF_PHYS vtophys(recvbuf)
55#define RECVBUF_VIRT ((void *)recvbuf)
56static union _sndbuf {
57	struct fxp_cb_config cbp;
58	struct fxp_cb_ias cb_ias;
59	struct fxp_cb_tx txp;
60} sndbuf;
61#define SNDBUF_PHYS vtophys(&sndbuf)
62#define SNDBUF_VIRT ((void *)&sndbuf)
63#else /* !standalone, userspace testing environment */
64#define	PCI_MODE1_ENABLE	0x80000000UL
65static pcihdl_t mytag = PCI_MODE1_ENABLE | (PCIDEVNO << 11);
66
67extern void *mapmem(int, int);
68void *dmamem; /* virtual */
69#define RECVBUF_PHYS DMABASE
70#define RECVBUF_VIRT dmamem
71#define SNDBUF_PHYS (DMABASE + RECVBUF_SIZE)
72#define SNDBUF_VIRT ((void *)(((char *)dmamem) + RECVBUF_SIZE))
73#endif /* _STANDALONE */
74
75static void fxp_read_eeprom(uint16_t *, int, int);
76static inline void fxp_scb_wait(void);
77#ifdef DEBUG
78static void fxp_checkintr(char *);
79#else
80#define fxp_checkintr(x)
81#endif
82static void fxp_startreceiver(void);
83
84/*
85 * Template for default configuration parameters.
86 * See struct fxp_cb_config for the bit definitions.
87 */
88static uint8_t fxp_cb_config_template[] = {
89	0x0, 0x0,		/* cb_status */
90	0x80, 0x2,		/* cb_command */
91	0xff, 0xff, 0xff, 0xff,	/* link_addr */
92	0x16,	/*  0 */
93	0x8,	/*  1 */
94	0x0,	/*  2 */
95	0x0,	/*  3 */
96	0x0,	/*  4 */
97	0x80,	/*  5 */
98	0xb2,	/*  6 */
99	0x3,	/*  7 */
100	0x1,	/*  8 */
101	0x0,	/*  9 */
102	0x26,	/* 10 */
103	0x0,	/* 11 */
104	0x60,	/* 12 */
105	0x0,	/* 13 */
106	0xf2,	/* 14 */
107	0x48,	/* 15 */
108	0x0,	/* 16 */
109	0x40,	/* 17 */
110	0xf3,	/* 18 */
111	0x0,	/* 19 */
112	0x3f,	/* 20 */
113	0x5	/* 21 */
114};
115
116static int tx_threshold = 64; /* x8, max 192 */
117
118#define CSR_READ_1(reg) inb(iobase + (reg))
119#define CSR_READ_2(reg) inw(iobase + (reg))
120#define CSR_WRITE_1(reg, val) outb(iobase + (reg), val)
121#define CSR_WRITE_2(reg, val) outw(iobase + (reg), val)
122#define CSR_WRITE_4(reg, val) outl(iobase + (reg), val)
123#define DELAY(n) delay(n)
124
125static int iobase;
126
127#if defined(_STANDALONE) && !defined(SUPPORT_NO_NETBSD)
128static struct btinfo_netif bi_netif;
129#endif
130
131/*
132 * Wait for the previous command to be accepted (but not necessarily
133 * completed).
134 */
135static inline void
136fxp_scb_wait(void)
137{
138	int i = 10000;
139
140	while (CSR_READ_1(FXP_CSR_SCB_COMMAND) && --i)
141		DELAY(1);
142	if (i == 0)
143		printf("fxp: WARNING: SCB timed out!\n");
144}
145
146#ifdef DEBUG
147static void
148fxp_checkintr(char *msg)
149{
150	uint8_t statack;
151	int i = 10000;
152
153	do {
154		statack = CSR_READ_1(FXP_CSR_SCB_STATACK);
155	} while ((statack == 0) && (--i > 0));
156
157	if (statack != 0) {
158		CSR_WRITE_1(FXP_CSR_SCB_STATACK, statack);
159		printf("%s: ack'd irq %x, i=%d\n", msg, statack, i);
160	}
161}
162#endif
163
164int
165EtherInit(unsigned char *myadr)
166{
167#ifndef _STANDALONE
168	uint32_t id;
169#endif
170	volatile struct fxp_cb_config *cbp;
171	volatile struct fxp_cb_ias *cb_ias;
172	int i;
173
174	if (pcicheck()) {
175		printf("pcicheck failed\n");
176		return 0;
177	}
178#ifdef _STANDALONE
179	if (pcifinddev(0x8086, 0x1229, &mytag)) {
180		printf("no fxp\n");
181		return 0;
182	}
183#else
184	pcicfgread(&mytag, 0, &id);
185	if (id != 0x12298086) {
186		printf("no fxp\n");
187		return 0;
188	}
189#endif
190
191	pcicfgread(&mytag, FXP_PCI_IOBA, &iobase);
192	iobase &= ~3;
193
194#ifndef _STANDALONE
195	dmamem = mapmem(DMABASE, DMASIZE);
196	if (!dmamem)
197		return 0;
198#endif
199
200	fxp_read_eeprom((void *)myadr, 0, 3);
201
202	/*
203	 * Initialize base of CBL and RFA memory. Loading with zero
204	 * sets it up for regular linear addressing.
205	 */
206	CSR_WRITE_4(FXP_CSR_SCB_GENERAL, 0);
207	CSR_WRITE_1(FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_BASE);
208
209	fxp_scb_wait();
210	CSR_WRITE_1(FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_BASE);
211
212	cbp = SNDBUF_VIRT;
213	/*
214	 * This memcpy is kind of disgusting, but there are a bunch of must be
215	 * zero and must be one bits in this structure and this is the easiest
216	 * way to initialize them all to proper values.
217	 */
218	memcpy((void *)cbp, fxp_cb_config_template,
219	      sizeof(fxp_cb_config_template));
220
221#define prm 0
222#define phy_10Mbps_only 0
223#define all_mcasts 0
224	cbp->cb_status =	0;
225	cbp->cb_command =	FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL;
226	cbp->link_addr =	-1;	/* (no) next command */
227	cbp->byte_count =	22;	/* (22) bytes to config */
228	cbp->rx_fifo_limit =	8;	/* rx fifo threshold (32 bytes) */
229	cbp->tx_fifo_limit =	0;	/* tx fifo threshold (0 bytes) */
230	cbp->adaptive_ifs =	0;	/* (no) adaptive interframe spacing */
231	cbp->rx_dma_bytecount =	0;	/* (no) rx DMA max */
232	cbp->tx_dma_bytecount =	0;	/* (no) tx DMA max */
233	cbp->dma_mbce =		0;	/* (disable) dma max counters */
234	cbp->late_scb =		0;	/* (don't) defer SCB update */
235	cbp->tno_int_or_tco_en = 0;	/* (disable) tx not okay interrupt */
236	cbp->ci_int =		0;	/* interrupt on CU not active */
237	cbp->save_bf =		prm;	/* save bad frames */
238	cbp->disc_short_rx =	!prm;	/* discard short packets */
239	cbp->underrun_retry =	1;	/* retry mode (1) on DMA underrun */
240	cbp->mediatype =	!phy_10Mbps_only; /* interface mode */
241	cbp->nsai =		1;     /* (don't) disable source addr insert */
242	cbp->preamble_length =	2;	/* (7 byte) preamble */
243	cbp->loopback =		0;	/* (don't) loopback */
244	cbp->linear_priority =	0;	/* (normal CSMA/CD operation) */
245	cbp->linear_pri_mode =	0;	/* (wait after xmit only) */
246	cbp->interfrm_spacing =	6;	/* (96 bits of) interframe spacing */
247	cbp->promiscuous =	prm;	/* promiscuous mode */
248	cbp->bcast_disable =	0;	/* (don't) disable broadcasts */
249	cbp->crscdt =		0;	/* (CRS only) */
250	cbp->stripping =	!prm;	/* truncate rx packet to byte count */
251	cbp->padding =		1;	/* (do) pad short tx packets */
252	cbp->rcv_crc_xfer =	0;	/* (don't) xfer CRC to host */
253	cbp->force_fdx =	0;	/* (don't) force full duplex */
254	cbp->fdx_pin_en =	1;	/* (enable) FDX# pin */
255	cbp->multi_ia =		0;	/* (don't) accept multiple IAs */
256	cbp->mc_all =		all_mcasts;/* accept all multicasts */
257#undef prm
258#undef phy_10Mbps_only
259#undef all_mcasts
260
261	/*
262	 * Start the config command/DMA.
263	 */
264	fxp_scb_wait();
265	CSR_WRITE_4(FXP_CSR_SCB_GENERAL, SNDBUF_PHYS);
266	CSR_WRITE_1(FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
267	/* ...and wait for it to complete. */
268	i = 10000;
269	while (!(cbp->cb_status & FXP_CB_STATUS_C) && (--i > 0))
270		DELAY(1);
271	if (i == 0)
272		printf("config timeout");
273
274	fxp_checkintr("config");
275
276	cb_ias = SNDBUF_VIRT;
277	/*
278	 * Now initialize the station address. Temporarily use the TxCB
279	 * memory area like we did above for the config CB.
280	 */
281	cb_ias->cb_status = 0;
282	cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL;
283	cb_ias->link_addr = -1;
284	memcpy((void *)cb_ias->macaddr, myadr, 6);
285
286	/*
287	 * Start the IAS (Individual Address Setup) command/DMA.
288	 */
289	fxp_scb_wait();
290	/* address is still there */
291	CSR_WRITE_1(FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
292	/* ...and wait for it to complete. */
293	i = 10000;
294	while (!(cb_ias->cb_status & FXP_CB_STATUS_C) && (--i > 0))
295		DELAY(1);
296	if (i == 0)
297		printf("ias timeout");
298
299	fxp_checkintr("ias");
300
301	fxp_startreceiver();
302
303#if defined(_STANDALONE) && !defined(SUPPORT_NO_NETBSD)
304	strncpy(bi_netif.ifname, "fxp", sizeof(bi_netif.ifname));
305	bi_netif.bus = BI_BUS_PCI;
306	bi_netif.addr.tag = mytag;
307
308	BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
309#endif
310
311	return 1;
312}
313
314void
315EtherStop(void)
316{
317
318	/*
319	 * Issue software reset
320	 */
321	CSR_WRITE_4(FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
322	DELAY(10);
323}
324
325int
326EtherSend(char *pkt, int len)
327{
328	volatile struct fxp_cb_tx *txp;
329#ifdef _STANDALONE
330	static volatile struct fxp_tbd tbd;
331#endif
332	volatile struct fxp_tbd *tbdp;
333	int i;
334
335	txp = SNDBUF_VIRT;
336#ifdef _STANDALONE
337	tbdp = &tbd;
338	txp->tbd_array_addr = vtophys((void *)&tbd);
339	tbdp->tb_addr = vtophys(pkt);
340#else
341	/* XXX assuming we send at max 400 bytes */
342	tbdp = (struct fxp_tbd *)(SNDBUF_VIRT + 440);
343	txp->tbd_array_addr = SNDBUF_PHYS + 440;
344	memcpy(SNDBUF_VIRT + 400, pkt, len);
345	tbdp->tb_addr = SNDBUF_PHYS + 400;
346#endif
347	tbdp->tb_size = len;
348	txp->tbd_number = 1;
349	txp->cb_status = 0;
350	txp->cb_command =
351	    FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_EL;
352	txp->tx_threshold = tx_threshold;
353
354	txp->link_addr = -1;
355	txp->byte_count = 0;
356
357	fxp_scb_wait();
358	CSR_WRITE_4(FXP_CSR_SCB_GENERAL, SNDBUF_PHYS);
359	CSR_WRITE_1(FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
360	/* ...and wait for it to complete. */
361	i = 10000;
362	while (!(txp->cb_status & FXP_CB_STATUS_C) && (--i > 0))
363		DELAY(1);
364	if (i == 0)
365		printf("send timeout");
366
367	fxp_checkintr("send");
368
369	return len;
370}
371
372static void
373fxp_startreceiver(void)
374{
375	volatile struct fxp_rfa *rfa;
376	uint32_t v;
377
378	rfa = RECVBUF_VIRT;
379	rfa->size = RECVBUF_SIZE - sizeof(struct fxp_rfa);
380	rfa->rfa_status = 0;
381	rfa->rfa_control = FXP_RFA_CONTROL_S;
382	rfa->actual_size = 0;
383	v = RECVBUF_PHYS; /* close the "ring" */
384	memcpy((void *)&rfa->link_addr, &v, sizeof(v));
385	v = -1;
386	memcpy((void *)&rfa->rbd_addr, &v, sizeof(v));
387
388	fxp_scb_wait();
389	CSR_WRITE_4(FXP_CSR_SCB_GENERAL, RECVBUF_PHYS);
390	CSR_WRITE_1(FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_START);
391}
392
393int
394EtherReceive(char *pkt, int maxlen)
395{
396	uint8_t ruscus;
397	volatile struct fxp_rfa *rfa;
398	int len = 0;
399
400	ruscus = CSR_READ_1(FXP_CSR_SCB_RUSCUS);
401	if (((ruscus >> 2) & 0x0f) == FXP_SCB_RUS_READY)
402		return 0;
403	if (((ruscus >> 2) & 0x0f) != FXP_SCB_RUS_SUSPENDED) {
404		printf("rcv: ruscus=%x\n", ruscus);
405		return 0;
406	}
407
408	rfa = RECVBUF_VIRT;
409	if (rfa->rfa_status & FXP_RFA_STATUS_C) {
410		len = rfa->actual_size & 0x7ff;
411		if (len <= maxlen) {
412			memcpy(pkt, (char *) rfa + RFA_SIZE, maxlen);
413#if 0
414			printf("rfa status=%x, len=%x\n",
415			       rfa->rfa_status, len);
416#endif
417		} else
418			len = 0;
419	}
420
421	fxp_scb_wait();
422	CSR_WRITE_1(FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_RESUME);
423
424	return len;
425}
426
427/*
428 * Read from the serial EEPROM. Basically, you manually shift in
429 * the read opcode (one bit at a time) and then shift in the address,
430 * and then you shift out the data (all of this one bit at a time).
431 * The word size is 16 bits, so you have to provide the address for
432 * every 16 bits of data.
433 */
434static void
435fxp_read_eeprom(uint16_t *data, int offset, int words)
436{
437	uint16_t reg;
438	int i, x;
439
440	for (i = 0; i < words; i++) {
441		CSR_WRITE_2(FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
442		/*
443		 * Shift in read opcode.
444		 */
445		for (x = 3; x > 0; x--) {
446			if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) {
447				reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
448			} else {
449				reg = FXP_EEPROM_EECS;
450			}
451			CSR_WRITE_2(FXP_CSR_EEPROMCONTROL, reg);
452			CSR_WRITE_2(FXP_CSR_EEPROMCONTROL,
453			    reg | FXP_EEPROM_EESK);
454			DELAY(1);
455			CSR_WRITE_2(FXP_CSR_EEPROMCONTROL, reg);
456			DELAY(1);
457		}
458		/*
459		 * Shift in address.
460		 */
461		for (x = 6; x > 0; x--) {
462			if ((i + offset) & (1 << (x - 1))) {
463				reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
464			} else {
465				reg = FXP_EEPROM_EECS;
466			}
467			CSR_WRITE_2(FXP_CSR_EEPROMCONTROL, reg);
468			CSR_WRITE_2(FXP_CSR_EEPROMCONTROL,
469			    reg | FXP_EEPROM_EESK);
470			DELAY(1);
471			CSR_WRITE_2(FXP_CSR_EEPROMCONTROL, reg);
472			DELAY(1);
473		}
474		reg = FXP_EEPROM_EECS;
475		data[i] = 0;
476		/*
477		 * Shift out data.
478		 */
479		for (x = 16; x > 0; x--) {
480			CSR_WRITE_2(FXP_CSR_EEPROMCONTROL,
481			    reg | FXP_EEPROM_EESK);
482			DELAY(1);
483			if (CSR_READ_2(FXP_CSR_EEPROMCONTROL) &
484			    FXP_EEPROM_EEDO)
485				data[i] |= (1 << (x - 1));
486			CSR_WRITE_2(FXP_CSR_EEPROMCONTROL, reg);
487			DELAY(1);
488		}
489		CSR_WRITE_2(FXP_CSR_EEPROMCONTROL, 0);
490		DELAY(1);
491	}
492}
493