1 /* Copyright (c) 2003-2011
2 * Stefano Ceccherini <stefano.ceccherini@gmail.com>. All rights reserved.
3 * This file is released under the MIT license
4 */
5 #include <KernelExport.h>
6 #include <Errors.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10
11 #include <net/if_media.h>
12
13 #include "debug.h"
14 #include "device.h"
15 #include "driver.h"
16 #include "interface.h"
17 #include "wb840.h"
18
19
20 #define MAX_CARDS 4
21
22 extern char* gDevNameList[];
23 extern pci_info* gDevList[];
24
25 static int32 sOpenMask = 0;
26
27 static status_t
wb840_open(const char * name,uint32 flags,void ** cookie)28 wb840_open(const char* name, uint32 flags, void** cookie)
29 {
30 char* deviceName = NULL;
31 int32 i;
32 int32 mask;
33 struct wb_device* data;
34 status_t status;
35
36 LOG((DEVICE_NAME ": open()\n"));
37
38 for (i = 0; (deviceName = gDevNameList[i]) != NULL; i++) {
39 if (!strcmp(name, deviceName))
40 break;
41 }
42
43 if (deviceName == NULL) {
44 LOG(("invalid device name"));
45 return EINVAL;
46 }
47
48 // There can be only one access at time
49 mask = 1L << i;
50 if (atomic_or(&sOpenMask, mask) & mask)
51 return B_BUSY;
52
53 // Allocate a wb_device structure
54 if (!(data = (wb_device*)calloc(1, sizeof(wb_device)))) {
55 sOpenMask &= ~(1L << i);
56 return B_NO_MEMORY;
57 }
58
59 *cookie = data;
60
61 data->devId = i;
62 data->pciInfo = gDevList[i];
63 data->deviceName = gDevNameList[i];
64 data->blockFlag = 0;
65 data->reg_base = data->pciInfo->u.h0.base_registers[0];
66 data->wb_cachesize = gPci->read_pci_config(data->pciInfo->bus,
67 data->pciInfo->device, data->pciInfo->function, PCI_line_size,
68 sizeof(PCI_line_size)) & 0xff;
69
70 wb_read_eeprom(data, &data->MAC_Address, 0, 3, false);
71
72 status = wb_create_semaphores(data);
73 if (status < B_OK) {
74 LOG((DEVICE_NAME": couldn't create semaphores\n"));
75 goto err;
76 }
77
78 status = wb_stop(data);
79 if (status < B_OK) {
80 LOG((DEVICE_NAME": can't stop device\n"));
81 goto err1;
82 }
83
84 status = wb_initPHYs(data);
85 if (status < B_OK) {
86 LOG((DEVICE_NAME": can't init PHYs\n"));
87 goto err1;
88 }
89
90 wb_init(data);
91
92 /* Setup interrupts */
93 data->irq = data->pciInfo->u.h0.interrupt_line;
94 status = install_io_interrupt_handler(data->irq, wb_interrupt, data, 0);
95 if (status < B_OK) {
96 LOG((DEVICE_NAME
97 ": can't install interrupt handler: %s\n", strerror(status)));
98 goto err1;
99 }
100
101 LOG((DEVICE_NAME ": interrupts installed at irq line %x\n", data->irq));
102
103 status = wb_create_rings(data);
104 if (status < B_OK) {
105 LOG((DEVICE_NAME": can't create ring buffers\n"));
106 goto err2;
107 }
108
109 wb_enable_interrupts(data);
110
111 WB_SETBIT(data->reg_base + WB_NETCFG, WB_NETCFG_RX_ON);
112 write32(data->reg_base + WB_RXSTART, 0xFFFFFFFF);
113 WB_SETBIT(data->reg_base + WB_NETCFG, WB_NETCFG_TX_ON);
114
115 add_timer(&data->timer, wb_tick, 1000000LL, B_PERIODIC_TIMER);
116
117 return B_OK; // Everything after this line is an error
118
119 err2:
120 remove_io_interrupt_handler(data->irq, wb_interrupt, data);
121
122 err1:
123 wb_delete_semaphores(data);
124
125 err:
126 sOpenMask &= ~(1L << i);
127
128 free(data);
129 LOG(("wb840: Open Failed\n"));
130
131 return status;
132 }
133
134
135 static status_t
wb840_read(void * cookie,off_t position,void * buf,size_t * num_bytes)136 wb840_read(void* cookie, off_t position, void* buf, size_t* num_bytes)
137 {
138 wb_device* device = (wb_device*)cookie;
139 int16 current;
140 status_t status;
141 size_t size;
142 int32 blockFlag;
143 uint32 check;
144
145 LOG((DEVICE_NAME ": read()\n"));
146
147 blockFlag = device->blockFlag;
148
149 if (atomic_or(&device->rxLock, 1)) {
150 *num_bytes = 0;
151 return B_ERROR;
152 }
153
154 status = acquire_sem_etc(device->rxSem, 1, B_CAN_INTERRUPT | blockFlag, 0);
155 if (status < B_OK) {
156 atomic_and(&device->rxLock, 0);
157 *num_bytes = 0;
158 return status;
159 }
160
161 current = device->rxCurrent;
162 check = device->rxDescriptor[current].wb_status;
163 if (check & WB_RXSTAT_OWN) {
164 LOG((DEVICE_NAME ":ERROR: read: buffer %d still in use: %x\n",
165 (int)current, (int)status));
166 atomic_and(&device->rxLock, 0);
167 *num_bytes = 0;
168 return B_BUSY;
169 }
170
171 if (check & (WB_RXSTAT_RXERR | WB_RXSTAT_CRCERR | WB_RXSTAT_RUNT)) {
172 LOG(("Error read: packet with errors."));
173 *num_bytes = 0;
174 } else {
175 size = WB_RXBYTES(check);
176 size -= CRC_SIZE;
177 LOG((DEVICE_NAME": received %ld bytes\n", size));
178 if (size > WB_MAX_FRAMELEN || size > *num_bytes) {
179 LOG(("ERROR: Bad frame size: %ld", size));
180 size = *num_bytes;
181 }
182 *num_bytes = size;
183 memcpy(buf, (void*)device->rxBuffer[current], size);
184 }
185
186 device->rxCurrent = (current + 1) & WB_RX_CNT_MASK;
187 {
188 cpu_status former;
189 former = disable_interrupts();
190 acquire_spinlock(&device->rxSpinlock);
191
192 // release buffer to ring
193 wb_put_rx_descriptor(&device->rxDescriptor[current]);
194 device->rxFree++;
195
196 release_spinlock(&device->rxSpinlock);
197 restore_interrupts(former);
198 }
199
200 atomic_and(&device->rxLock, 0);
201
202 return B_OK;
203 }
204
205
206 static status_t
wb840_write(void * cookie,off_t position,const void * buffer,size_t * num_bytes)207 wb840_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
208 {
209 wb_device* device = (wb_device*)cookie;
210 status_t status = B_OK;
211 uint16 frameSize;
212 int16 current;
213 uint32 check;
214
215 LOG((DEVICE_NAME ": write()\n"));
216
217 atomic_add(&device->txLock, 1);
218
219 if (*num_bytes > WB_MAX_FRAMELEN)
220 *num_bytes = WB_MAX_FRAMELEN;
221
222 frameSize = *num_bytes;
223 current = device->txCurrent;
224
225 // block until a free tx descriptor is available
226 status = acquire_sem_etc(device->txSem, 1, B_TIMEOUT, ETHER_TRANSMIT_TIMEOUT);
227 if (status < B_OK) {
228 write32(device->reg_base + WB_TXSTART, 0xFFFFFFFF);
229 LOG((DEVICE_NAME": write: acquiring sem failed: %ld, %s\n",
230 status, strerror(status)));
231 atomic_add(&device->txLock, -1);
232 *num_bytes = 0;
233 return status;
234 }
235
236 check = device->txDescriptor[current].wb_status;
237 if (check & WB_TXSTAT_OWN) {
238 // descriptor is still in use
239 dprintf(DEVICE_NAME ": card owns buffer %d\n", (int)current);
240 atomic_add(&device->txLock, -1);
241 *num_bytes = 0;
242 return B_ERROR;
243 }
244
245 /* Copy data to tx buffer */
246 memcpy((void*)device->txBuffer[current], buffer, frameSize);
247 device->txCurrent = (current + 1) & WB_TX_CNT_MASK;
248 LOG((DEVICE_NAME ": %d bytes written\n", frameSize));
249
250 {
251 cpu_status former = disable_interrupts();
252 acquire_spinlock(&device->txSpinlock);
253
254 device->txDescriptor[current].wb_ctl = WB_TXCTL_TLINK | frameSize;
255 device->txDescriptor[current].wb_ctl |= WB_TXCTL_FIRSTFRAG
256 | WB_TXCTL_LASTFRAG;
257 device->txDescriptor[current].wb_status = WB_TXSTAT_OWN;
258 device->txSent++;
259
260 release_spinlock(&device->txSpinlock);
261 restore_interrupts(former);
262 }
263
264 // re-enable transmit state machine
265 write32(device->reg_base + WB_TXSTART, 0xFFFFFFFF);
266
267 atomic_add(&device->txLock, -1);
268
269 return B_OK;
270 }
271
272
273 static status_t
wb840_control(void * cookie,uint32 op,void * arg,size_t len)274 wb840_control (void* cookie, uint32 op, void* arg, size_t len)
275 {
276 wb_device* data = (wb_device*)cookie;
277
278 LOG((DEVICE_NAME ": control()\n"));
279 switch (op) {
280 case ETHER_INIT:
281 LOG(("%s: ETHER_INIT\n", data->deviceName));
282 return B_OK;
283
284 case ETHER_GETADDR:
285 LOG(("%s: ETHER_GETADDR\n", data->deviceName));
286 memcpy(arg, &data->MAC_Address, sizeof(data->MAC_Address));
287 print_address(arg);
288 return B_OK;
289
290 case ETHER_NONBLOCK:
291 LOG(("ETHER_NON_BLOCK\n"));
292 data->blockFlag = *(int32*)arg ? B_TIMEOUT : 0;
293 return B_OK;
294
295 case ETHER_GETFRAMESIZE:
296 LOG(("ETHER_GETFRAMESIZE\n"));
297 *(uint32 *)arg = WB_MAX_FRAMELEN;
298 return B_OK;
299
300 case ETHER_GET_LINK_STATE:
301 {
302 ether_link_state_t state;
303 LOG(("ETHER_GET_LINK_STATE"));
304
305 state.media = (data->link ? IFM_ACTIVE : 0) | IFM_ETHER
306 | (data->full_duplex ? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX)
307 | (data->speed == LINK_SPEED_100_MBIT ? IFM_100_TX : IFM_10_T);
308 state.speed = data->speed == LINK_SPEED_100_MBIT
309 ? 100000000 : 10000000;
310 state.quality = 1000;
311
312 return user_memcpy(arg, &state, sizeof(ether_link_state_t));
313 }
314
315 case ETHER_ADDMULTI:
316 LOG(("ETHER_ADDMULTI\n"));
317 break;
318
319 case ETHER_REMMULTI:
320 LOG(("ETHER_REMMULTI\n"));
321 break;
322
323 case ETHER_SETPROMISC:
324 LOG(("ETHER_SETPROMISC\n"));
325 break;
326
327 default:
328 LOG(("Invalid command\n"));
329 break;
330 }
331
332 return B_ERROR;
333 }
334
335
336 static status_t
wb840_close(void * cookie)337 wb840_close(void* cookie)
338 {
339 wb_device* device = (wb_device*)cookie;
340
341 LOG((DEVICE_NAME ": close()\n"));
342
343 cancel_timer(&device->timer);
344
345 wb_stop(device);
346
347 write32(device->reg_base + WB_TXADDR, 0x00000000);
348 write32(device->reg_base + WB_RXADDR, 0x00000000);
349
350 wb_disable_interrupts(device);
351 remove_io_interrupt_handler(device->irq, wb_interrupt, device);
352
353 delete_sem(device->rxSem);
354 delete_sem(device->txSem);
355
356 return B_OK;
357 }
358
359
360 static status_t
wb840_free(void * cookie)361 wb840_free(void* cookie)
362 {
363 wb_device* device = (wb_device*)cookie;
364
365 LOG((DEVICE_NAME ": free()\n"));
366
367 sOpenMask &= ~(1L << device->devId);
368
369 wb_delete_rings(device);
370 free(device->firstPHY);
371 free(device);
372
373 return B_OK;
374 }
375
376
377 device_hooks
378 gDeviceHooks = {
379 wb840_open, /* -> open entry point */
380 wb840_close, /* -> close entry point */
381 wb840_free, /* -> free cookie */
382 wb840_control, /* -> control entry point */
383 wb840_read, /* -> read entry point */
384 wb840_write, /* -> write entry point */
385 NULL,
386 NULL,
387 NULL,
388 NULL
389 };
390