xref: /plan9-contrib/sys/src/9/pc/etherwavelan.c (revision aa72973a2891ccbd3fb042462446761159389e19)
1 /* Pci/pcmcia code for wavelan.c */
2 
3 #include "u.h"
4 #include "../port/lib.h"
5 #include "mem.h"
6 #include "dat.h"
7 #include "fns.h"
8 #include "io.h"
9 #include "../port/error.h"
10 #include "../port/netif.h"
11 #include "etherif.h"
12 
13 #include "wavelan.h"
14 
15 static int
wavelanpcmciareset(Ether * ether)16 wavelanpcmciareset(Ether *ether)
17 {
18 	int i;
19 	char *p;
20 	Ctlr *ctlr;
21 
22 	if((ctlr = malloc(sizeof(Ctlr))) == nil)
23 		return -1;
24 
25 	ilock(ctlr);
26 	ctlr->ctlrno = ether->ctlrno;
27 
28 	if (ether->port==0)
29 		ether->port=WDfltIOB;
30 	ctlr->iob = ether->port;
31 
32 	if (ether->irq==0)
33 		ether->irq=WDfltIRQ;
34 
35 	if (ioalloc(ether->port,WIOLen,0,"wavelan")<0){
36 	//	print("#l%d: port 0x%lx in use\n",
37 	//			ether->ctlrno, ether->port);
38 		goto abort1;
39 	}
40 
41 	/*
42 	 * If id= is specified, card must match.  Otherwise try generic.
43 	 */
44 	ctlr->slot = -1;
45 	for(i=0; i<ether->nopt; i++){
46 		if(cistrncmp(ether->opt[i], "id=", 3) == 0){
47 			if((ctlr->slot = pcmspecial(&ether->opt[i][3], ether)) < 0)
48 				goto abort;
49 			break;
50 		}
51 	}
52 	if(ctlr->slot == -1){
53 		for (i=0; wavenames[i]; i++)
54 			if((ctlr->slot = pcmspecial(wavenames[i], ether))>=0)
55 				break;
56 		if(!wavenames[i]){
57 			DEBUG("no wavelan found\n");
58 			goto abort;
59 		}
60 	}
61 
62 	// DEBUG("#l%d: port=0x%lx irq=%ld\n",
63 	//		ether->ctlrno, ether->port, ether->irq);
64 
65 	if(wavelanreset(ether, ctlr) < 0){
66 	abort:
67 		iofree(ether->port);
68 	abort1:
69 		iunlock(ctlr);
70 		free(ctlr);
71 		ether->ctlr = nil;
72 		return -1;
73 	}
74 
75 	for(i = 0; i < ether->nopt; i++){
76 		if(p = strchr(ether->opt[i], '='))
77 			*p = ' ';
78 		w_option(ctlr, ether->opt[i], strlen(ether->opt[i]));
79 	}
80 
81 	iunlock(ctlr);
82 	return 0;
83 }
84 
85 static struct {
86 	int vid;
87 	int did;
88 } wavelanpci[] = {
89 	0x1260, 0x3873,	/* Intersil Prism2.5 */
90 	0x1737,	0x0019,	/* Linksys WPC-11 untested */
91 };
92 
93 static Ctlr *ctlrhead, *ctlrtail;
94 
95 static void
wavelanpciscan(void)96 wavelanpciscan(void)
97 {
98 	int i;
99 	void *mem;
100 	Pcidev *p;
101 	Ctlr *ctlr;
102 
103 	p = nil;
104 	while(p = pcimatch(p, 0, 0)){
105 		for(i=0; i<nelem(wavelanpci); i++)
106 			if(p->vid == wavelanpci[i].vid && p->did == wavelanpci[i].did)
107 				break;
108 		if(i==nelem(wavelanpci))
109 			continue;
110 
111 		/*
112 		 * On the Prism, bar[0] is the memory-mapped register address (4KB),
113 		 */
114 		if(p->mem[0].size != 4096){
115 			print("wavelanpci: %.4ux %.4ux: unlikely mmio size\n", p->vid, p->did);
116 			continue;
117 		}
118 
119 		ctlr = malloc(sizeof(Ctlr));
120 		if(ctlr == nil)
121 			error(Enomem);
122 		ctlr->pcidev = p;
123 		mem = vmap(p->mem[0].bar&~0xF, p->mem[0].size);
124 		if(mem == nil){
125 			print("wavelanpci: %.4ux %.4ux: vmap 0x%.8lux %d failed\n", p->vid, p->did, p->mem[0].bar&~0xF, p->mem[0].size);
126 			free(ctlr);
127 			continue;
128 		}
129 		ctlr->mmb = mem;
130 		if(ctlrhead != nil)
131 			ctlrtail->next = ctlr;
132 		else
133 			ctlrhead = ctlr;
134 		ctlrtail = ctlr;
135 		pcisetbme(p);
136 	}
137 }
138 
139 static int
wavelanpcireset(Ether * ether)140 wavelanpcireset(Ether *ether)
141 {
142 	int i;
143 	char *p;
144 	Ctlr *ctlr;
145 
146 	if(ctlrhead == nil)
147 		wavelanpciscan();
148 
149 	/*
150 	 * Allow plan9.ini to set vid, did?
151 	 */
152 	for(ctlr=ctlrhead; ctlr!=nil; ctlr=ctlr->next)
153 		if(ctlr->active == 0)
154 			break;
155 	if(ctlr == nil)
156 		return -1;
157 
158 	ctlr->active = 1;
159 	ilock(ctlr);
160 	ether->irq = ctlr->pcidev->intl;
161 	ether->tbdf = ctlr->pcidev->tbdf;
162 
163 	/*
164 	 * Really hard reset.
165 	 */
166 	csr_outs(ctlr, WR_PciCor, 0x0080);
167 	delay(250);
168 	csr_outs(ctlr, WR_PciCor, 0x0000);
169 	delay(500);
170 	for(i=0; i<2*10; i++){
171 		if(!(csr_ins(ctlr, WR_Cmd)&WCmdBusy))
172 			break;
173 		delay(100);
174 	}
175 	if(i >= 2*10)
176 		print("wavelan pci %.4ux %.4ux: reset timeout %.4ux\n",
177 			ctlr->pcidev->vid, ctlr->pcidev->did, csr_ins(ctlr, WR_Cmd));
178 
179 	if(wavelanreset(ether, ctlr) < 0){
180 		iunlock(ctlr);
181 		ether->ctlr = nil;
182 		return -1;
183 	}
184 
185 	for(i = 0; i < ether->nopt; i++){
186 		if(p = strchr(ether->opt[i], '='))
187 			*p = ' ';
188 		w_option(ctlr, ether->opt[i], strlen(ether->opt[i]));
189 	}
190 	iunlock(ctlr);
191 	return 0;
192 }
193 
194 void
etherwavelanlink(void)195 etherwavelanlink(void)
196 {
197 	addethercard("wavelan", wavelanpcmciareset);
198 	addethercard("wavelanpci", wavelanpcireset);
199 }
200