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
22extern char* gDevNameList[];
23extern pci_info* gDevList[];
24
25static int32 sOpenMask = 0;
26
27static status_t
28wb840_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
119err2:
120	remove_io_interrupt_handler(data->irq, wb_interrupt, data);
121
122err1:
123	wb_delete_semaphores(data);
124
125err:
126	sOpenMask &= ~(1L << i);
127
128	free(data);
129	LOG(("wb840: Open Failed\n"));
130
131	return status;
132}
133
134
135static status_t
136wb840_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
206static status_t
207wb840_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
273static status_t
274wb840_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
336static status_t
337wb840_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
360static status_t
361wb840_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
377device_hooks
378gDeviceHooks = {
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