1#include <PCI.h>
2#include <Drivers.h>
3#include <malloc.h>
4#include <ether_driver.h>
5
6#ifdef HAIKU_TARGET_PLATFORM_HAIKU
7#	include <net/if_media.h>
8#endif
9
10#include "mm.h"
11#include "lm.h"
12#include "mempool.h"
13
14struct pci_module_info *pci = NULL;
15
16const char *dev_list[11];
17struct be_b57_dev be_b57_dev_cards[10];
18int cards_found = 0;
19
20int b57_Packet_Desc_Size = sizeof(struct B_UM_PACKET);
21
22#define ROUND_UP_TO_PAGE(size) ((size % 4096 != 0) ? 4096 - (size % 4096) + size : size)
23
24struct pci_device_id {
25	unsigned int vendor, device;		/* Vendor and device ID or PCI_ANY_ID */
26	unsigned int subvendor, subdevice;	/* Subsystem ID's or PCI_ANY_ID */
27	unsigned int class, class_mask;		/* (class,subclass,prog-if) triplet */
28	unsigned long driver_data;		/* Data private to the driver */
29};
30
31#define PCI_ANY_ID		0
32
33typedef enum {
34	BCM5700A6 = 0,
35	BCM5700T6,
36	BCM5700A9,
37	BCM5700T9,
38	BCM5700,
39	BCM5701A5,
40	BCM5701T1,
41	BCM5701T8,
42	BCM5701A7,
43	BCM5701A10,
44	BCM5701A12,
45	BCM5701,
46	BCM5702,
47	BCM5703,
48	BCM5703A31,
49	BCM5703ARBUCKLE,
50	TC996T,
51	TC996ST,
52	TC996SSX,
53	TC996SX,
54	TC996BT,
55	TC997T,
56	TC997SX,
57	TC1000T,
58	TC1000BT,
59	TC940BR01,
60	TC942BR01,
61	TC998T,
62	TC998SX,
63	TC999T,
64	NC6770,
65	NC1020,
66	NC150T,
67	NC7760,
68	NC7761,
69	NC7770,
70	NC7771,
71	NC7780,
72	NC7781,
73	NC7772,
74	NC7782,
75	NC7783,
76	NC320T,
77	BCM5704CIOBE,
78	BCM5704,
79	BCM5704S,
80	BCM5705,
81	BCM5705M,
82	BCM5705F,
83	BCM5901,
84	BCM5782,
85	BCM5788,
86	BCM5789,
87	BCM5750,
88	BCM5750M,
89	BCM5720,
90	BCM5751,
91	BCM5751M,
92	BCM5751F,
93	BCM5721,
94} board_t;
95
96
97/* indexed by board_t, above */
98static struct {
99	char *name;
100} board_info[] = {
101	{ "Broadcom BCM5700 1000Base-T" },
102	{ "Broadcom BCM5700 1000Base-SX" },
103	{ "Broadcom BCM5700 1000Base-SX" },
104	{ "Broadcom BCM5700 1000Base-T" },
105	{ "Broadcom BCM5700" },
106	{ "Broadcom BCM5701 1000Base-T" },
107	{ "Broadcom BCM5701 1000Base-T" },
108	{ "Broadcom BCM5701 1000Base-T" },
109	{ "Broadcom BCM5701 1000Base-SX" },
110	{ "Broadcom BCM5701 1000Base-T" },
111	{ "Broadcom BCM5701 1000Base-T" },
112	{ "Broadcom BCM5701" },
113	{ "Broadcom BCM5702 1000Base-T" },
114	{ "Broadcom BCM5703 1000Base-T" },
115	{ "Broadcom BCM5703 1000Base-SX" },
116	{ "Broadcom B5703 1000Base-SX" },
117	{ "3Com 3C996 10/100/1000 Server NIC" },
118	{ "3Com 3C996 10/100/1000 Server NIC" },
119	{ "3Com 3C996 Gigabit Fiber-SX Server NIC" },
120	{ "3Com 3C996 Gigabit Fiber-SX Server NIC" },
121	{ "3Com 3C996B Gigabit Server NIC" },
122	{ "3Com 3C997 Gigabit Server NIC" },
123	{ "3Com 3C997 Gigabit Fiber-SX Server NIC" },
124	{ "3Com 3C1000 Gigabit NIC" },
125	{ "3Com 3C1000B-T 10/100/1000 PCI" },
126	{ "3Com 3C940 Gigabit LOM (21X21)" },
127	{ "3Com 3C942 Gigabit LOM (31X31)" },
128	{ "3Com 3C998-T Dual Port 10/100/1000 PCI-X Server NIC" },
129	{ "3Com 3C998-SX Dual Port 1000-SX PCI-X Server NIC" },
130	{ "3Com 3C999-T Quad Port 10/100/1000 PCI-X Server NIC" },
131	{ "HP NC6770 Gigabit Server Adapter" },
132	{ "NC1020 HP ProLiant Gigabit Server Adapter 32 PCI" },
133	{ "HP ProLiant NC 150T PCI 4-port Gigabit Combo Switch Adapter" },
134	{ "HP NC7760 Gigabit Server Adapter" },
135	{ "HP NC7761 Gigabit Server Adapter" },
136	{ "HP NC7770 Gigabit Server Adapter" },
137	{ "HP NC7771 Gigabit Server Adapter" },
138	{ "HP NC7780 Gigabit Server Adapter" },
139	{ "HP NC7781 Gigabit Server Adapter" },
140	{ "HP NC7772 Gigabit Server Adapter" },
141	{ "HP NC7782 Gigabit Server Adapter" },
142	{ "HP NC7783 Gigabit Server Adapter" },
143	{ "HP ProLiant NC 320T PCI Express Gigabit Server Adapter" },
144	{ "Broadcom BCM5704 CIOB-E 1000Base-T" },
145	{ "Broadcom BCM5704 1000Base-T" },
146	{ "Broadcom BCM5704 1000Base-SX" },
147	{ "Broadcom BCM5705 1000Base-T" },
148	{ "Broadcom BCM5705M 1000Base-T" },
149	{ "Broadcom 570x 10/100 Integrated Controller" },
150	{ "Broadcom BCM5901 100Base-TX" },
151	{ "Broadcom NetXtreme Gigabit Ethernet for hp" },
152	{ "Broadcom BCM5788 NetLink 1000Base-T" },
153	{ "Broadcom BCM5789 NetLink 1000Base-T PCI Express" },
154	{ "Broadcom BCM5750 1000Base-T PCI" },
155	{ "Broadcom BCM5750M 1000Base-T PCI" },
156	{ "Broadcom BCM5720 1000Base-T PCI" },
157	{ "Broadcom BCM5751 1000Base-T PCI Express" },
158	{ "Broadcom BCM5751M 1000Base-T PCI Express" },
159	{ "Broadcom BCM5751F 100Base-TX PCI Express" },
160	{ "Broadcom BCM5721 1000Base-T PCI Express" },
161	{ 0 },
162	};
163
164static struct pci_device_id bcm5700_pci_tbl[] = {
165	{0x14e4, 0x1644, 0x14e4, 0x1644, 0, 0, BCM5700A6 },
166	{0x14e4, 0x1644, 0x14e4, 0x2, 0, 0, BCM5700T6 },
167	{0x14e4, 0x1644, 0x14e4, 0x3, 0, 0, BCM5700A9 },
168	{0x14e4, 0x1644, 0x14e4, 0x4, 0, 0, BCM5700T9 },
169	{0x14e4, 0x1644, 0x1028, 0xd1, 0, 0, BCM5700 },
170	{0x14e4, 0x1644, 0x1028, 0x0106, 0, 0, BCM5700 },
171	{0x14e4, 0x1644, 0x1028, 0x0109, 0, 0, BCM5700 },
172	{0x14e4, 0x1644, 0x1028, 0x010a, 0, 0, BCM5700 },
173	{0x14e4, 0x1644, 0x10b7, 0x1000, 0, 0, TC996T },
174	{0x14e4, 0x1644, 0x10b7, 0x1001, 0, 0, TC996ST },
175	{0x14e4, 0x1644, 0x10b7, 0x1002, 0, 0, TC996SSX },
176	{0x14e4, 0x1644, 0x10b7, 0x1003, 0, 0, TC997T },
177	{0x14e4, 0x1644, 0x10b7, 0x1005, 0, 0, TC997SX },
178	{0x14e4, 0x1644, 0x10b7, 0x1008, 0, 0, TC942BR01 },
179	{0x14e4, 0x1644, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5700 },
180	{0x14e4, 0x1645, 0x14e4, 1, 0, 0, BCM5701A5 },
181	{0x14e4, 0x1645, 0x14e4, 5, 0, 0, BCM5701T1 },
182	{0x14e4, 0x1645, 0x14e4, 6, 0, 0, BCM5701T8 },
183	{0x14e4, 0x1645, 0x14e4, 7, 0, 0, BCM5701A7 },
184	{0x14e4, 0x1645, 0x14e4, 8, 0, 0, BCM5701A10 },
185	{0x14e4, 0x1645, 0x14e4, 0x8008, 0, 0, BCM5701A12 },
186	{0x14e4, 0x1645, 0x0e11, 0xc1, 0, 0, NC6770 },
187	{0x14e4, 0x1645, 0x0e11, 0x7c, 0, 0, NC7770 },
188	{0x14e4, 0x1645, 0x0e11, 0x85, 0, 0, NC7780 },
189	{0x14e4, 0x1645, 0x1028, 0x0121, 0, 0, BCM5701 },
190	{0x14e4, 0x1645, 0x10b7, 0x1004, 0, 0, TC996SX },
191	{0x14e4, 0x1645, 0x10b7, 0x1006, 0, 0, TC996BT },
192	{0x14e4, 0x1645, 0x10b7, 0x1007, 0, 0, TC1000T },
193	{0x14e4, 0x1645, 0x10b7, 0x1008, 0, 0, TC940BR01 },
194	{0x14e4, 0x1645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5701 },
195	{0x14e4, 0x1646, 0x14e4, 0x8009, 0, 0, BCM5702 },
196	{0x14e4, 0x1646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702 },
197	{0x14e4, 0x16a6, 0x14e4, 0x8009, 0, 0, BCM5702 },
198	{0x14e4, 0x16a6, 0x14e4, 0x000c, 0, 0, BCM5702 },
199	{0x14e4, 0x16a6, 0x0e11, 0xbb, 0, 0, NC7760 },
200	{0x14e4, 0x16a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702 },
201	{0x14e4, 0x16c6, 0x10b7, 0x1100, 0, 0, TC1000BT },
202	{0x14e4, 0x16c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702 },
203	{0x14e4, 0x1647, 0x14e4, 0x0009, 0, 0, BCM5703 },
204	{0x14e4, 0x1647, 0x14e4, 0x000a, 0, 0, BCM5703A31 },
205	{0x14e4, 0x1647, 0x14e4, 0x000b, 0, 0, BCM5703 },
206	{0x14e4, 0x1647, 0x14e4, 0x800a, 0, 0, BCM5703 },
207	{0x14e4, 0x1647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703 },
208	{0x14e4, 0x16a7, 0x14e4, 0x0009, 0, 0, BCM5703 },
209	{0x14e4, 0x16a7, 0x14e4, 0x000a, 0, 0, BCM5703A31 },
210	{0x14e4, 0x16a7, 0x14e4, 0x000b, 0, 0, BCM5703 },
211	{0x14e4, 0x16a7, 0x14e4, 0x800a, 0, 0, BCM5703 },
212	{0x14e4, 0x16a7, 0x0e11, 0xca, 0, 0, NC7771 },
213	{0x14e4, 0x16a7, 0x0e11, 0xcb, 0, 0, NC7781 },
214	{0x14e4, 0x16a7, 0x1014, 0x0281, 0, 0, BCM5703ARBUCKLE },
215	{0x14e4, 0x16a7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703 },
216	{0x14e4, 0x16c7, 0x14e4, 0x000a, 0, 0, BCM5703A31 },
217	{0x14e4, 0x16c7, 0x0e11, 0xca, 0, 0, NC7771 },
218	{0x14e4, 0x16c7, 0x0e11, 0xcb, 0, 0, NC7781 },
219	{0x14e4, 0x16c7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703 },
220	{0x14e4, 0x1648, 0x0e11, 0xcf, 0, 0, NC7772 },
221	{0x14e4, 0x1648, 0x0e11, 0xd0, 0, 0, NC7782 },
222	{0x14e4, 0x1648, 0x0e11, 0xd1, 0, 0, NC7783 },
223	{0x14e4, 0x1648, 0x10b7, 0x2000, 0, 0, TC998T },
224	{0x14e4, 0x1648, 0x10b7, 0x3000, 0, 0, TC999T },
225	{0x14e4, 0x1648, 0x1166, 0x1648, 0, 0, BCM5704CIOBE },
226	{0x14e4, 0x1648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5704 },
227	{0x14e4, 0x1649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5704S },
228	{0x14e4, 0x16a8, 0x14e4, 0x16a8, 0, 0, BCM5704S },
229	{0x14e4, 0x16a8, 0x10b7, 0x2001, 0, 0, TC998SX },
230	{0x14e4, 0x16a8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5704S },
231	{0x14e4, 0x1653, 0x0e11, 0x00e3, 0, 0, NC7761 },
232	{0x14e4, 0x1653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705 },
233	{0x14e4, 0x1654, 0x0e11, 0x00e3, 0, 0, NC7761 },
234	{0x14e4, 0x1654, 0x103c, 0x3100, 0, 0, NC1020 },
235	{0x14e4, 0x1654, 0x103c, 0x3226, 0, 0, NC150T },
236	{0x14e4, 0x1654, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705 },
237	{0x14e4, 0x165d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705M },
238	{0x14e4, 0x165e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705M },
239	{0x14e4, 0x166e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705F },
240	{0x14e4, 0x1696, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5782 },
241	{0x14e4, 0x169c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5788 },
242	{0x14e4, 0x169d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5789 },
243	{0x14e4, 0x170d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5901 },
244	{0x14e4, 0x170e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5901 },
245	{0x14e4, 0x1676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5750 },
246	{0x14e4, 0x167c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5750M },
247	{0x14e4, 0x1677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5751 },
248	{0x14e4, 0x167d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5751M },
249	{0x14e4, 0x167e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5751F },
250	{0x14e4, 0x1658, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5720 },
251	{0x14e4, 0x1659, 0x103c, 0x7031, 0, 0, NC320T },
252	{0x14e4, 0x1659, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5721 },
253	{0,}
254};
255
256/* -------- BeOS Driver Hooks ------------ */
257
258static status_t b57_open(const char *name, uint32 flags, void **cookie);
259static status_t b57_close(void *cookie);
260static status_t b57_free(void *cookie);
261static status_t b57_ioctl(void *cookie,uint32 op,void *data,size_t len);
262static status_t b57_read(void *cookie,off_t pos,void *data,size_t *numBytes);
263static status_t b57_write(void *cookie,off_t pos,const void *data,size_t *numBytes);
264static int32 b57_interrupt(void *cookie);
265static int32 tx_cleanup_thread(void *us);
266
267device_hooks b57_hooks = {b57_open,b57_close,b57_free,b57_ioctl,b57_read,b57_write,NULL,NULL,NULL,NULL};
268int32 api_version = B_CUR_DRIVER_API_VERSION;
269
270//int debug_fd;
271
272
273status_t
274init_hardware(void)
275{
276	return B_OK;
277}
278
279
280const char **
281publish_devices(void)
282{
283	return dev_list;
284}
285
286
287device_hooks *
288find_device(const char *name)
289{
290	return &b57_hooks;
291}
292
293
294status_t
295init_driver(void)
296{
297	int i = 0, j = 0, is_detected;
298	pci_info dev_info;
299
300	//debug_fd = open("/tmp/broadcom_traffic_log",O_RDWR | B_CREATE_FILE);
301
302	if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci) != B_OK)
303		return B_ERROR;
304
305	while (pci->get_nth_pci_info(i++, &dev_info) == 0) {
306		is_detected = 0;
307		if ((dev_info.class_base == PCI_network) && (dev_info.class_sub == PCI_ethernet)) {
308			for (j = 0; bcm5700_pci_tbl[j].vendor != 0; j++) {
309				if ((dev_info.vendor_id == bcm5700_pci_tbl[j].vendor) && (dev_info.device_id == bcm5700_pci_tbl[j].device)) {
310					is_detected = 1;
311					break;
312				}
313			}
314		}
315
316		if (!is_detected)
317			continue;
318
319		if (cards_found >= 10)
320			break;
321
322		dev_list[cards_found] = (char *)malloc(16 /* net/bcm570x/xx */);
323		sprintf(dev_list[cards_found],"net/bcm570x/%d",cards_found);
324		be_b57_dev_cards[cards_found].pci_data = dev_info;
325		be_b57_dev_cards[cards_found].packet_release_sem = create_sem(0,dev_list[cards_found]);
326		be_b57_dev_cards[cards_found].mem_list_num = 0;
327		be_b57_dev_cards[cards_found].lockmem_list_num = 0;
328		be_b57_dev_cards[cards_found].opened = 0;
329		be_b57_dev_cards[cards_found].block = 1;
330		be_b57_dev_cards[cards_found].lock = 0;
331#ifdef HAIKU_TARGET_PLATFORM_HAIKU
332		be_b57_dev_cards[cards_found].linkChangeSem = -1;
333#endif
334
335		if (LM_GetAdapterInfo(&be_b57_dev_cards[cards_found].lm_dev) != LM_STATUS_SUCCESS) {
336			for (j = 0; j < cards_found; j++) {
337				free(dev_list[j]);
338				delete_sem(be_b57_dev_cards[j].packet_release_sem);
339			}
340			put_module(B_PCI_MODULE_NAME);
341			return ENODEV;
342		}
343
344		QQ_InitQueue(&be_b57_dev_cards[cards_found].RxPacketReadQ.Container,MAX_RX_PACKET_DESC_COUNT);
345
346		cards_found++;
347	}
348
349 	mempool_init((MAX_RX_PACKET_DESC_COUNT+MAX_TX_PACKET_DESC_COUNT) * cards_found);
350 	dev_list[cards_found] = NULL;
351
352	return B_OK;
353}
354
355
356void
357uninit_driver(void)
358{
359	struct be_b57_dev *pUmDevice;
360	int i, j;
361
362	for (j = 0; j < cards_found; j++) {
363		pUmDevice = &be_b57_dev_cards[j];
364
365		for (i = 0; i < pUmDevice->mem_list_num; i++)
366			free(pUmDevice->mem_list[i]);
367		for (i = 0; i < pUmDevice->lockmem_list_num; i++)
368			delete_area(pUmDevice->lockmem_list[i]);
369
370		delete_area(pUmDevice->mem_base);
371		delete_sem(be_b57_dev_cards[j].packet_release_sem);
372		free((void *)dev_list[j]);
373	}
374
375	mempool_exit();
376	put_module(B_PCI_MODULE_NAME);
377}
378
379
380//	#pragma mark -
381
382
383static status_t
384b57_open(const char *name, uint32 flags, void **cookie)
385{
386	struct be_b57_dev *pDevice = NULL;
387	int i;
388
389	*cookie = NULL;
390	for (i = 0; i < cards_found; i++) {
391		if (strcmp(dev_list[i],name) == 0) {
392			*cookie = pDevice = &be_b57_dev_cards[i];
393			break;
394		}
395	}
396
397	if (*cookie == NULL)
398		return B_FILE_NOT_FOUND;
399
400	if (atomic_or(&pDevice->opened, 1)) {
401		*cookie = pDevice = NULL;
402		return B_BUSY;
403	}
404
405	install_io_interrupt_handler(pDevice->pci_data.u.h0.interrupt_line,
406		b57_interrupt, *cookie, 0);
407	if (LM_InitializeAdapter(&pDevice->lm_dev) != LM_STATUS_SUCCESS) {
408		atomic_and(&pDevice->opened,0);
409		remove_io_interrupt_handler(pDevice->pci_data.u.h0.interrupt_line, b57_interrupt, *cookie);
410		*cookie = NULL;
411		return B_ERROR;
412	}
413
414	/*QQ_InitQueue(&pDevice->rx_out_of_buf_q.Container,
415        MAX_RX_PACKET_DESC_COUNT);*/
416
417	//pDevice->lm_dev.PhyCrcCount = 0;
418	LM_EnableInterrupt(&pDevice->lm_dev);
419
420	dprintf("Broadcom 57xx adapter successfully inited at %s:\n", name);
421	dprintf("MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
422		pDevice->lm_dev.NodeAddress[0], pDevice->lm_dev.NodeAddress[1],
423		pDevice->lm_dev.NodeAddress[2], pDevice->lm_dev.NodeAddress[3],
424		pDevice->lm_dev.NodeAddress[4], pDevice->lm_dev.NodeAddress[5]);
425	dprintf("PCI Data: 0x%08x\n", pDevice->pci_data.u.h0.base_registers[0]);
426	dprintf("IRQ: %d\n", pDevice->pci_data.u.h0.interrupt_line);
427
428	return B_OK;
429}
430
431
432static status_t
433b57_close(void *cookie)
434{
435	struct be_b57_dev *pUmDevice = (struct be_b57_dev *)(cookie);
436
437	if (cookie == NULL)
438		return B_OK;
439
440	LM_DisableInterrupt(&pUmDevice->lm_dev);
441	LM_Halt(&pUmDevice->lm_dev);
442	pUmDevice->lm_dev.InitDone = 0;
443	atomic_and(&pUmDevice->opened, 0);
444
445	return B_OK;
446}
447
448
449static status_t
450b57_free(void *cookie)
451{
452	struct be_b57_dev *pUmDevice = (struct be_b57_dev *)(cookie);
453
454	if (cookie == NULL)
455		return B_OK;
456
457	remove_io_interrupt_handler(pUmDevice->pci_data.u.h1.interrupt_line, b57_interrupt, cookie);
458	return B_OK;
459}
460
461
462static status_t
463b57_ioctl(void *cookie,uint32 op,void *data,size_t len)
464{
465	struct be_b57_dev *pUmDevice = (struct be_b57_dev *)(cookie);
466
467	switch (op) {
468		case ETHER_INIT:
469			return B_OK;
470		case ETHER_GETADDR:
471			if (data == NULL)
472				return B_ERROR;
473
474			memcpy(data, pUmDevice->lm_dev.NodeAddress, 6);
475			return B_OK;
476		case ETHER_NONBLOCK:
477			pUmDevice->block = !*((uint8 *)(data));
478			return B_OK;
479		case ETHER_ADDMULTI:
480			return (LM_MulticastAdd(&pUmDevice->lm_dev,
481				(PLM_UINT8)(data)) == LM_STATUS_SUCCESS) ? B_OK : B_ERROR;
482		case ETHER_REMMULTI:
483			return (LM_MulticastDel(&pUmDevice->lm_dev,
484				(PLM_UINT8)(data)) == LM_STATUS_SUCCESS) ? B_OK : B_ERROR;
485		case ETHER_SETPROMISC:
486			if (*((uint8 *)(data))) {
487				LM_SetReceiveMask(&pUmDevice->lm_dev,
488					pUmDevice->lm_dev.ReceiveMask | LM_PROMISCUOUS_MODE);
489			} else {
490				 LM_SetReceiveMask(&pUmDevice->lm_dev,
491					pUmDevice->lm_dev.ReceiveMask & ~LM_PROMISCUOUS_MODE);
492			}
493			return B_OK;
494#ifndef HAIKU_TARGET_PLATFORM_HAIKU
495		case ETHER_GETLINKSTATE:
496		{
497			ether_link_state_t *state_buffer = (ether_link_state_t *)(data);
498			state_buffer->link_speed = pUmDevice->lm_dev.LineSpeed;
499			state_buffer->link_quality = (pUmDevice->lm_dev.LinkStatus == LM_STATUS_LINK_DOWN) ? 0.0 : 1.0;
500			state_buffer->duplex_mode = (pUmDevice->lm_dev.DuplexMode == LM_DUPLEX_MODE_FULL);
501			return B_OK;
502		}
503#else
504		case ETHER_GET_LINK_STATE:
505		{
506			ether_link_state_t state;
507			state.media = (pUmDevice->lm_dev.LinkStatus
508				== LM_STATUS_LINK_DOWN ? 0 : IFM_ACTIVE) | IFM_ETHER;
509			switch (pUmDevice->lm_dev.LineSpeed) {
510				case LM_LINE_SPEED_10MBPS:
511					state.media |= IFM_10_T;
512					state.speed = 10000000;
513					break;
514				case LM_LINE_SPEED_100MBPS:
515					state.media |= IFM_100_TX;
516					state.speed = 100000000;
517					break;
518				case LM_LINE_SPEED_1000MBPS:
519					state.media |= IFM_1000_T;
520					state.speed = 1000000000;
521					break;
522				default:
523					state.speed = 0;
524			}
525			state.media |= (pUmDevice->lm_dev.DuplexMode
526				== LM_DUPLEX_MODE_FULL ? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX);
527			state.quality = 1000;
528
529			return user_memcpy(data, &state, sizeof(ether_link_state_t));
530		}
531		case ETHER_SET_LINK_STATE_SEM:
532		{
533			if (user_memcpy(&pUmDevice->linkChangeSem, data, sizeof(sem_id)) < B_OK) {
534				pUmDevice->linkChangeSem = -1;
535				return B_BAD_ADDRESS;
536			}
537			return B_OK;
538		}
539
540#endif
541	}
542	return B_ERROR;
543}
544
545
546static int32
547b57_interrupt(void *cookie)
548{
549	struct be_b57_dev *pUmDevice = (struct be_b57_dev *)cookie;
550	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
551	unsigned int handled = 1;
552	int i, max_intr_loop;
553	LM_UINT32 oldtag, newtag;
554
555	if (!pDevice->InitDone)
556		return B_UNHANDLED_INTERRUPT;
557
558	if (pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) {
559		max_intr_loop = 50;
560		if (pDevice->Flags & USE_TAGGED_STATUS_FLAG) {
561			MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 1);
562			oldtag = pDevice->pStatusBlkVirt->StatusTag;
563
564			for (i = 0; ; i++) {
565   				pDevice->pStatusBlkVirt->Status &=
566					~STATUS_BLOCK_UPDATED;
567
568				LM_ServiceInterrupts(pDevice);
569				newtag = pDevice->pStatusBlkVirt->StatusTag;
570				if ((newtag == oldtag) || (i > max_intr_loop)) {
571					MB_REG_WR(pDevice,
572						Mailbox.Interrupt[0].Low,
573						oldtag << 24);
574					pDevice->LastTag = oldtag;
575					if (pDevice->Flags & UNDI_FIX_FLAG) {
576						REG_WR(pDevice, Grc.LocalCtrl,
577						pDevice->GrcLocalCtrl | 0x2);
578					}
579					break;
580				}
581				oldtag = newtag;
582			}
583		} else {
584			i = 0;
585			do {
586				uint dummy;
587
588				MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 1);
589   				pDevice->pStatusBlkVirt->Status &=
590					~STATUS_BLOCK_UPDATED;
591				LM_ServiceInterrupts(pDevice);
592				MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 0);
593				dummy = MB_REG_RD(pDevice,
594					Mailbox.Interrupt[0].Low);
595				i++;
596			}
597
598			while ((pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) != 0
599				&& i < max_intr_loop)
600				;
601
602			if (pDevice->Flags & UNDI_FIX_FLAG) {
603				REG_WR(pDevice, Grc.LocalCtrl,
604					pDevice->GrcLocalCtrl | 0x2);
605			}
606		}
607	} else
608		handled = 0;
609
610	if (QQ_GetEntryCnt(&pDevice->RxPacketFreeQ.Container)
611		|| pDevice->QueueAgain) {
612		LM_QueueRxPackets(pDevice);
613	}
614
615	return handled ? B_INVOKE_SCHEDULER : B_UNHANDLED_INTERRUPT;
616}
617
618
619static status_t
620b57_read(void *cookie,off_t pos,void *data,size_t *numBytes)
621{
622	struct be_b57_dev *pUmDevice = (struct be_b57_dev *)cookie;
623	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
624	PLM_PACKET pPacket;
625	struct B_UM_PACKET *pUmPacket;
626	cpu_status cpu;
627
628	if (pUmDevice->block)
629		acquire_sem(pUmDevice->packet_release_sem);
630	else {
631		/* Decrement the receive sem anyway, but don't block
632		   this is a horrible hack, but it works. */
633		acquire_sem_etc(pUmDevice->packet_release_sem, 1, B_RELATIVE_TIMEOUT, 0);
634	}
635
636	cpu = disable_interrupts();
637	acquire_spinlock(&pUmDevice->lock);
638
639	pPacket = (PLM_PACKET)
640		QQ_PopHead(&pUmDevice->RxPacketReadQ.Container);
641
642	release_spinlock(&pUmDevice->lock);
643	restore_interrupts(cpu);
644
645	if (pPacket == 0) {
646		*numBytes = -1;
647		return B_ERROR;
648	}
649
650	pUmPacket = (struct B_UM_PACKET *) pPacket;
651	if (pPacket->PacketStatus != LM_STATUS_SUCCESS
652		|| pPacket->PacketSize > 1518) {
653		cpu = disable_interrupts();
654		acquire_spinlock(&pUmDevice->lock);
655
656		QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
657
658		release_spinlock(&pUmDevice->lock);
659		restore_interrupts(cpu);
660		*numBytes = -1;
661		return B_ERROR;
662	}
663
664	if ((pPacket->PacketSize) < *numBytes)
665		*numBytes = pPacket->PacketSize;
666
667	memcpy(data,pUmPacket->data,*numBytes);
668	cpu = disable_interrupts();
669	acquire_spinlock(&pUmDevice->lock);
670
671	QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
672
673	release_spinlock(&pUmDevice->lock);
674	restore_interrupts(cpu);
675
676	return B_OK;
677}
678
679
680static status_t
681b57_write(void *cookie,off_t pos,const void *data,size_t *numBytes)
682{
683	struct be_b57_dev *pUmDevice = (struct be_b57_dev *)cookie;
684	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
685	PLM_PACKET pPacket;
686	struct B_UM_PACKET *pUmPacket;
687	cpu_status cpu;
688
689	/*if ((pDevice->LinkStatus == LM_STATUS_LINK_DOWN) || !pDevice->InitDone)
690	{
691		return ENETDOWN;
692	}*/
693
694	pPacket = (PLM_PACKET)
695		QQ_PopHead(&pDevice->TxPacketFreeQ.Container);
696
697	if (pPacket == 0)
698		return B_ERROR;
699
700	pUmPacket = (struct B_UM_PACKET *)pPacket;
701	pUmPacket->data = chunk_pool_get();
702
703	memcpy(pUmPacket->data,data,*numBytes); /* no guarantee data is contiguous, so we have to copy */
704	pPacket->PacketSize = pUmPacket->size = *numBytes;
705
706	pPacket->u.Tx.FragCount = 1;
707	pPacket->Flags = 0;
708
709	tx_cleanup_thread(pUmDevice);
710
711	cpu = disable_interrupts();
712	acquire_spinlock(&pUmDevice->lock);
713
714	LM_SendPacket(pDevice, pPacket);
715
716	release_spinlock(&pUmDevice->lock);
717	restore_interrupts(cpu);
718
719	return B_OK;
720}
721
722
723//	#pragma mark -
724/* -------- Broadcom MM hooks ----------- */
725
726
727LM_STATUS
728MM_ReadConfig16(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset,
729    LM_UINT16 *pValue16)
730{
731	*pValue16 = (LM_UINT16)pci->read_pci_config(((struct be_b57_dev *)(pDevice))->pci_data.bus,
732		((struct be_b57_dev *)(pDevice))->pci_data.device,
733		((struct be_b57_dev *)(pDevice))->pci_data.function,
734		(uchar)Offset, sizeof(LM_UINT16));
735	return LM_STATUS_SUCCESS;
736}
737
738
739LM_STATUS
740MM_WriteConfig16(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset,
741    LM_UINT16 Value16)
742{
743	pci->write_pci_config(((struct be_b57_dev *)(pDevice))->pci_data.bus,
744		((struct be_b57_dev *)(pDevice))->pci_data.device,
745		((struct be_b57_dev *)(pDevice))->pci_data.function,
746		(uchar)Offset, sizeof(LM_UINT16), (uint32)Value16);
747	return LM_STATUS_SUCCESS;
748}
749
750
751LM_STATUS
752MM_ReadConfig32(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset,
753    LM_UINT32 *pValue32)
754{
755	*pValue32 = (LM_UINT32)pci->read_pci_config(((struct be_b57_dev *)(pDevice))->pci_data.bus,
756		((struct be_b57_dev *)(pDevice))->pci_data.device,
757		((struct be_b57_dev *)(pDevice))->pci_data.function,
758		(uchar)Offset, sizeof(LM_UINT32));
759	return LM_STATUS_SUCCESS;
760}
761
762
763LM_STATUS
764MM_WriteConfig32(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset,
765    LM_UINT32 Value32)
766{
767	pci->write_pci_config(((struct be_b57_dev *)(pDevice))->pci_data.bus,
768		((struct be_b57_dev *)(pDevice))->pci_data.device,
769		((struct be_b57_dev *)(pDevice))->pci_data.function,
770		(uchar)Offset, sizeof(LM_UINT32), (uint32)Value32);
771	return LM_STATUS_SUCCESS;
772}
773
774
775LM_STATUS
776MM_MapMemBase(PLM_DEVICE_BLOCK pDevice)
777{
778	struct be_b57_dev *pUmDevice = (struct be_b57_dev *)(pDevice);
779	size_t size = pUmDevice->pci_data.u.h0.base_register_sizes[0];
780
781	size = ROUND_UP_TO_PAGE(size);
782	pUmDevice->mem_base = map_physical_memory("broadcom_regs",
783		pUmDevice->pci_data.u.h0.base_registers[0], size,
784		B_ANY_KERNEL_BLOCK_ADDRESS, 0,
785		(void **)(&pDevice->pMappedMemBase));
786
787	return LM_STATUS_SUCCESS;
788}
789
790/*
791LM_STATUS
792MM_MapIoBase(PLM_DEVICE_BLOCK pDevice)
793{
794	pDevice->pMappedMemBase = pci->ram_address(((struct be_b57_dev *)(pDevice))->pci_data.memory_base);
795	return LM_STATUS_SUCCESS;
796}
797*/
798
799LM_STATUS
800MM_IndicateRxPackets(PLM_DEVICE_BLOCK pDevice)
801{
802	struct be_b57_dev *dev = (struct be_b57_dev *)pDevice;
803	PLM_PACKET pPacket;
804
805	while (1) {
806		pPacket = (PLM_PACKET)
807			QQ_PopHead(&pDevice->RxPacketReceivedQ.Container);
808		if (pPacket == 0)
809			break;
810
811		acquire_spinlock(&dev->lock);
812		release_sem_etc(dev->packet_release_sem, 1, B_DO_NOT_RESCHEDULE);
813		release_spinlock(&dev->lock);
814		QQ_PushTail(&dev->RxPacketReadQ.Container, pPacket);
815	}
816
817	return LM_STATUS_SUCCESS;
818}
819
820
821LM_STATUS
822MM_IndicateTxPackets(PLM_DEVICE_BLOCK pDevice)
823{
824	return LM_STATUS_SUCCESS;
825}
826
827
828int32
829tx_cleanup_thread(void *us)
830{
831	PLM_PACKET pPacket;
832	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK)(us);
833	struct be_b57_dev *pUmDevice = (struct be_b57_dev *)(us);
834	struct B_UM_PACKET *pUmPacket;
835	cpu_status cpu;
836
837	while (1) {
838		cpu = disable_interrupts();
839		acquire_spinlock(&pUmDevice->lock);
840
841		pPacket = (PLM_PACKET)
842			QQ_PopHead(&pDevice->TxPacketXmittedQ.Container);
843
844		release_spinlock(&pUmDevice->lock);
845		restore_interrupts(cpu);
846		if (pPacket == 0)
847			break;
848		pUmPacket = (struct B_UM_PACKET *)(pPacket);
849		chunk_pool_put(pUmPacket->data);
850		pUmPacket->data = NULL;
851
852		cpu = disable_interrupts();
853		acquire_spinlock(&pUmDevice->lock);
854		QQ_PushTail(&pDevice->TxPacketFreeQ.Container, pPacket);
855		release_spinlock(&pUmDevice->lock);
856		restore_interrupts(cpu);
857	}
858	return LM_STATUS_SUCCESS;
859}
860
861/*LM_STATUS MM_StartTxDma(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket);
862LM_STATUS MM_CompleteTxDma(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket);*/
863
864LM_STATUS
865MM_AllocateMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
866	PLM_VOID *pMemoryBlockVirt)
867{
868	struct be_b57_dev *dev = (struct be_b57_dev *)(pDevice);
869
870	if (dev->mem_list_num == 16)
871		return LM_STATUS_FAILURE;
872
873	*pMemoryBlockVirt = dev->mem_list[(dev->mem_list_num)++] = (void *)malloc(BlockSize);
874	return LM_STATUS_SUCCESS;
875}
876
877
878LM_STATUS
879MM_AllocateSharedMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
880	PLM_VOID *pMemoryBlockVirt, PLM_PHYSICAL_ADDRESS pMemoryBlockPhy,
881	LM_BOOL cached /* we ignore this */)
882{
883	struct be_b57_dev *dev;
884	void *pvirt = NULL;
885	area_id area_desc;
886	physical_entry entry;
887
888	dev = (struct be_b57_dev *)(pDevice);
889	area_desc = dev->lockmem_list[dev->lockmem_list_num++] = create_area("broadcom_shared_mem",
890		&pvirt, B_ANY_KERNEL_ADDRESS, ROUND_UP_TO_PAGE(BlockSize),
891		B_CONTIGUOUS, 0);
892
893	if (area_desc < B_OK)
894		return LM_STATUS_FAILURE;
895
896	memset(pvirt, 0, BlockSize);
897	*pMemoryBlockVirt = (PLM_VOID) pvirt;
898
899	get_memory_map(pvirt,BlockSize,&entry,1);
900	pMemoryBlockPhy->Low = (uint32)entry.address;
901	pMemoryBlockPhy->High = (uint32)(entry.address >> 32);
902		/* We only support 32 bit */
903
904	return LM_STATUS_SUCCESS;
905}
906
907
908LM_STATUS
909MM_GetConfig(PLM_DEVICE_BLOCK pDevice)
910{
911	pDevice->DisableAutoNeg = FALSE;
912	pDevice->RequestedLineSpeed = LM_LINE_SPEED_AUTO;
913	pDevice->RequestedDuplexMode = LM_DUPLEX_MODE_FULL;
914	pDevice->FlowControlCap = LM_FLOW_CONTROL_AUTO_PAUSE;
915	pDevice->RxPacketDescCnt = DEFAULT_RX_PACKET_DESC_COUNT;
916	pDevice->TxPacketDescCnt = DEFAULT_TX_PACKET_DESC_COUNT;
917	pDevice->TxMaxCoalescedFrames = DEFAULT_TX_MAX_COALESCED_FRAMES;
918	pDevice->RxMaxCoalescedFrames = DEFAULT_RX_MAX_COALESCED_FRAMES;
919	pDevice->RxStdDescCnt = DEFAULT_STD_RCV_DESC_COUNT;
920	pDevice->RxCoalescingTicks = DEFAULT_RX_COALESCING_TICKS;
921	pDevice->TxCoalescingTicks = DEFAULT_TX_COALESCING_TICKS;
922	pDevice->StatsCoalescingTicks = DEFAULT_STATS_COALESCING_TICKS;
923	pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
924
925	return LM_STATUS_SUCCESS;
926}
927
928
929LM_STATUS
930MM_IndicateStatus(PLM_DEVICE_BLOCK pDevice, LM_STATUS Status)
931{
932#ifdef HAIKU_TARGET_PLATFORM_HAIKU
933	struct be_b57_dev *pUmDevice = (struct be_b57_dev *)pDevice;
934
935	if (pUmDevice->linkChangeSem != -1)
936		release_sem_etc(pUmDevice->linkChangeSem, 1,
937			B_DO_NOT_RESCHEDULE);
938#endif
939
940	return LM_STATUS_SUCCESS;
941}
942
943
944LM_STATUS
945MM_InitializeUmPackets(PLM_DEVICE_BLOCK pDevice)
946{
947	int i;
948	struct be_b57_dev *pUmDevice = (struct be_b57_dev *) pDevice;
949	struct B_UM_PACKET *pUmPacket;
950	PLM_PACKET pPacket;
951
952	for (i = 0; i < pDevice->RxPacketDescCnt; i++) {
953		pPacket = QQ_PopHead(&pDevice->RxPacketFreeQ.Container);
954		pUmPacket = (struct B_UM_PACKET *) pPacket;
955		pUmPacket->data = chunk_pool_get();
956		if (pUmPacket->data == 0) {
957			//QQ_PushTail(&pUmDevice->rx_out_of_buf_q.Container, pPacket);
958			// No pretty rx_out_of_buf_q, but we sure as hell don't want anything to do with these packets, so we leak them.
959			// Probably not the best idea, but it works.
960			continue;
961		}
962		QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
963	}
964
965	return LM_STATUS_SUCCESS;
966}
967
968LM_STATUS MM_FreeRxBuffer(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket) {
969	struct B_UM_PACKET *pUmPacket;
970	struct be_b57_dev *pUmDevice = (struct be_b57_dev *) pDevice;
971	pUmPacket = (struct B_UM_PACKET *) pPacket;
972	chunk_pool_put(pUmPacket->data);
973	pUmPacket->data = NULL;
974	return LM_STATUS_SUCCESS;
975}
976
977
978void
979MM_UnmapRxDma(LM_DEVICE_BLOCK *pDevice, LM_PACKET *pPacket)
980{
981}
982
983
984LM_STATUS
985MM_CoalesceTxBuffer(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
986{
987	/* Our buffers are pre-coalesced (which slows things down a little) */
988	return LM_STATUS_SUCCESS;
989}
990
991
992LM_DEVICE_BLOCK *
993MM_FindPeerDev(LM_DEVICE_BLOCK *pDevice)
994{
995	/* I have no idea what this routine does. I think it's optional... */
996	return 0;
997}
998
999
1000LM_STATUS
1001MM_Sleep(LM_DEVICE_BLOCK *pDevice, LM_UINT32 msec)
1002{
1003	snooze(msec*1e3);
1004	return LM_STATUS_SUCCESS;
1005}
1006