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