source: mainline/uspace/drv/nic/rtl8169/driver.c@ 320bd52

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 320bd52 was 320bd52, checked in by Agnieszka Tabaka <nufcia@…>, 11 years ago

Add proper receive filtering for broadcast, multicast and unicast frames.

  • Property mode set to 100644
File size: 32.3 KB
Line 
1/*
2 * Copyright (c) 2014 Agnieszka Tabaka
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <assert.h>
30#include <errno.h>
31#include <align.h>
32#include <byteorder.h>
33#include <irc.h>
34#include <libarch/barrier.h>
35
36#include <as.h>
37#include <ddf/log.h>
38#include <ddf/interrupt.h>
39#include <io/log.h>
40#include <nic.h>
41#include <pci_dev_iface.h>
42
43#include <ipc/irc.h>
44#include <sysinfo.h>
45#include <ipc/ns.h>
46
47#include <str.h>
48
49#include "defs.h"
50#include "driver.h"
51
52/** Global mutex for work with shared irq structure */
53FIBRIL_MUTEX_INITIALIZE(irq_reg_lock);
54
55static int rtl8169_set_addr(ddf_fun_t *fun, const nic_address_t *addr);
56static int rtl8169_get_device_info(ddf_fun_t *fun, nic_device_info_t *info);
57static int rtl8169_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state);
58static int rtl8169_get_operation_mode(ddf_fun_t *fun, int *speed,
59 nic_channel_mode_t *duplex, nic_role_t *role);
60static int rtl8169_set_operation_mode(ddf_fun_t *fun, int speed,
61 nic_channel_mode_t duplex, nic_role_t role);
62static int rtl8169_pause_get(ddf_fun_t *fun, nic_result_t *we_send,
63 nic_result_t *we_receive, uint16_t *time);
64static int rtl8169_pause_set(ddf_fun_t *fun, int allow_send, int allow_receive,
65 uint16_t time);
66static int rtl8169_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement);
67static int rtl8169_autoneg_disable(ddf_fun_t *fun);
68static int rtl8169_autoneg_probe(ddf_fun_t *fun, uint32_t *advertisement,
69 uint32_t *their_adv, nic_result_t *result, nic_result_t *their_result);
70static int rtl8169_autoneg_restart(ddf_fun_t *fun);
71static int rtl8169_defective_get_mode(ddf_fun_t *fun, uint32_t *mode);
72static int rtl8169_defective_set_mode(ddf_fun_t *fun, uint32_t mode);
73static int rtl8169_on_activated(nic_t *nic_data);
74static int rtl8169_on_stopped(nic_t *nic_data);
75static void rtl8169_send_frame(nic_t *nic_data, void *data, size_t size);
76static void rtl8169_irq_handler(ddf_dev_t *dev, ipc_callid_t iid,
77 ipc_call_t *icall);
78static inline int rtl8169_register_int_handler(nic_t *nic_data);
79static inline void rtl8169_get_hwaddr(rtl8169_t *rtl8169, nic_address_t *addr);
80static inline void rtl8169_set_hwaddr(rtl8169_t *rtl8169, const nic_address_t *addr);
81
82static void rtl8169_reset(rtl8169_t *rtl8169);
83static int rtl8169_get_resource_info(ddf_dev_t *dev);
84static int rtl8169_fill_resource_info(ddf_dev_t *dev, const hw_res_list_parsed_t *hw_resources);
85static rtl8169_t *rtl8169_create_dev_data(ddf_dev_t *dev);
86
87static int rtl8169_unicast_set(nic_t *nic_data, nic_unicast_mode_t mode,
88 const nic_address_t *, size_t);
89static int rtl8169_multicast_set(nic_t *nic_data, nic_multicast_mode_t mode,
90 const nic_address_t *addr, size_t addr_count);
91static int rtl8169_broadcast_set(nic_t *nic_data, nic_broadcast_mode_t mode);
92
93static uint16_t rtl8169_mii_read(rtl8169_t *rtl8169, uint8_t addr);
94static void rtl8169_mii_write(rtl8169_t *rtl8169, uint8_t addr, uint16_t value);
95static void rtl8169_rx_ring_refill(rtl8169_t *rtl8169, unsigned int first,
96 unsigned int last);
97
98/** Network interface options for RTL8169 card driver */
99static nic_iface_t rtl8169_nic_iface = {
100 .set_address = &rtl8169_set_addr,
101 .get_device_info = &rtl8169_get_device_info,
102 .get_cable_state = &rtl8169_get_cable_state,
103 .get_operation_mode = &rtl8169_get_operation_mode,
104 .set_operation_mode = &rtl8169_set_operation_mode,
105
106 .get_pause = &rtl8169_pause_get,
107 .set_pause = &rtl8169_pause_set,
108
109 .autoneg_enable = &rtl8169_autoneg_enable,
110 .autoneg_disable = &rtl8169_autoneg_disable,
111 .autoneg_probe = &rtl8169_autoneg_probe,
112 .autoneg_restart = &rtl8169_autoneg_restart,
113
114 .defective_get_mode = &rtl8169_defective_get_mode,
115 .defective_set_mode = &rtl8169_defective_set_mode,
116};
117
118irq_pio_range_t rtl8169_irq_pio_ranges[] = {
119 {
120 .base = 0,
121 .size = RTL8169_IO_SIZE
122 }
123};
124
125irq_cmd_t rtl8169_irq_commands[] = {
126 {
127 /* Get the interrupt status */
128 .cmd = CMD_PIO_READ_16,
129 .addr = NULL,
130 .dstarg = 2
131 },
132 {
133 .cmd = CMD_PREDICATE,
134 .value = 3,
135 .srcarg = 2
136 },
137 {
138 /* Mark interrupts as solved */
139 .cmd = CMD_PIO_WRITE_16,
140 .addr = NULL,
141 .value = 0xFFFF
142 },
143 {
144 /* Disable interrupts until interrupt routine is finished */
145 .cmd = CMD_PIO_WRITE_16,
146 .addr = NULL,
147 .value = 0x0000
148 },
149 {
150 .cmd = CMD_ACCEPT
151 }
152};
153
154/** Interrupt code definition */
155irq_code_t rtl8169_irq_code = {
156 .rangecount = sizeof(rtl8169_irq_pio_ranges) / sizeof(irq_pio_range_t),
157 .ranges = rtl8169_irq_pio_ranges,
158 .cmdcount = sizeof(rtl8169_irq_commands) / sizeof(irq_cmd_t),
159 .cmds = rtl8169_irq_commands
160};
161
162/** Basic device operations for RTL8169 driver */
163static ddf_dev_ops_t rtl8169_dev_ops;
164
165static int rtl8169_dev_add(ddf_dev_t *dev);
166
167/** Basic driver operations for RTL8169 driver */
168static driver_ops_t rtl8169_driver_ops = {
169 .dev_add = &rtl8169_dev_add,
170};
171
172/** Driver structure for RTL8169 driver */
173static driver_t rtl8169_driver = {
174 .name = NAME,
175 .driver_ops = &rtl8169_driver_ops
176};
177
178static int rtl8169_get_resource_info(ddf_dev_t *dev)
179{
180 assert(dev);
181
182 nic_t *nic_data = nic_get_from_ddf_dev(dev);
183 assert(nic_data);
184
185 hw_res_list_parsed_t hw_res_parsed;
186 hw_res_list_parsed_init(&hw_res_parsed);
187
188 /* Get hw resources form parent driver */
189 int rc = nic_get_resources(nic_data, &hw_res_parsed);
190 if (rc != EOK)
191 return rc;
192
193 /* Fill resources information to the device */
194 int ret = rtl8169_fill_resource_info(dev, &hw_res_parsed);
195 hw_res_list_parsed_clean(&hw_res_parsed);
196
197 return ret;
198}
199
200static int rtl8169_fill_resource_info(ddf_dev_t *dev, const hw_res_list_parsed_t
201 *hw_resources)
202{
203 assert(dev);
204 assert(hw_resources);
205
206 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_dev(dev));
207 assert(rtl8169);
208
209 if (hw_resources->irqs.count != 1) {
210 ddf_msg(LVL_ERROR, "%s device: unexpected irq count", ddf_dev_get_name(dev));
211 return EINVAL;
212 };
213
214 if (hw_resources->io_ranges.count != 1) {
215 ddf_msg(LVL_ERROR, "%s device: unexpected io ranges count", ddf_dev_get_name(dev));
216 return EINVAL;
217 }
218
219 rtl8169->irq = hw_resources->irqs.irqs[0];
220 ddf_msg(LVL_DEBUG, "%s device: irq 0x%x assigned", ddf_dev_get_name(dev), rtl8169->irq);
221
222 rtl8169->regs_phys = (void *)((size_t)RNGABS(hw_resources->io_ranges.ranges[0]));
223 if (hw_resources->io_ranges.ranges[0].size < RTL8169_IO_SIZE) {
224 ddf_msg(LVL_ERROR, "I/O range assigned to the device "
225 "%s is too small.", ddf_dev_get_name(dev));
226 return EINVAL;
227 }
228 ddf_msg(LVL_DEBUG, "%s device: i/o addr %p assigned.", ddf_dev_get_name(dev), rtl8169->regs_phys);
229
230 return EOK;
231}
232
233static int rtl8169_allocate_buffers(rtl8169_t *rtl8169)
234{
235 int rc;
236
237 ddf_msg(LVL_DEBUG, "Allocating DMA buffer rings");
238
239 /* Allocate TX ring */
240 rtl8169->tx_ring = AS_AREA_ANY;
241 rc = dmamem_map_anonymous(TX_RING_SIZE, DMAMEM_4GiB,
242 AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->tx_ring_phys,
243 (void **)&rtl8169->tx_ring);
244
245 if (rc != EOK)
246 return rc;
247
248 ddf_msg(LVL_DEBUG, "TX ring address: phys=0x%#" PRIxn ", virt=%p",
249 rtl8169->tx_ring_phys, rtl8169->tx_ring);
250
251 memset(rtl8169->tx_ring, 0, TX_RING_SIZE);
252
253 /* Allocate RX ring */
254 rtl8169->rx_ring = AS_AREA_ANY;
255 rc = dmamem_map_anonymous(RX_RING_SIZE, DMAMEM_4GiB,
256 AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->rx_ring_phys,
257 (void **)&rtl8169->rx_ring);
258
259 if (rc != EOK)
260 return rc;
261
262 ddf_msg(LVL_DEBUG, "RX ring address: phys=0x%#" PRIxn ", virt=%p",
263 rtl8169->rx_ring_phys, rtl8169->rx_ring);
264
265 memset(rtl8169->rx_ring, 0, RX_RING_SIZE);
266
267 /* Allocate TX buffers */
268 rtl8169->tx_buff = AS_AREA_ANY;
269 rc = dmamem_map_anonymous(TX_BUFFERS_SIZE, DMAMEM_4GiB,
270 AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->tx_buff_phys,
271 &rtl8169->tx_buff);
272
273 if (rc != EOK)
274 return rc;
275
276 ddf_msg(LVL_DEBUG, "TX buffers base address: phys=0x%#" PRIxn " virt=%p",
277 rtl8169->tx_buff_phys, rtl8169->tx_buff);
278
279 /* Allocate RX buffers */
280 rtl8169->rx_buff = AS_AREA_ANY;
281 rc = dmamem_map_anonymous(RX_BUFFERS_SIZE, DMAMEM_4GiB,
282 AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->rx_buff_phys,
283 &rtl8169->rx_buff);
284
285 if (rc != EOK)
286 return rc;
287
288 ddf_msg(LVL_DEBUG, "RX buffers base address: phys=0x%#" PRIxn ", virt=%p",
289 rtl8169->rx_buff_phys, rtl8169->rx_buff);
290
291 return EOK;
292}
293
294static rtl8169_t *rtl8169_create_dev_data(ddf_dev_t *dev)
295{
296 assert(dev);
297 assert(!nic_get_from_ddf_dev(dev));
298
299 nic_t *nic_data = nic_create_and_bind(dev);
300 if (!nic_data)
301 return NULL;
302
303 rtl8169_t *rtl8169 = malloc(sizeof(rtl8169_t));
304 if (!rtl8169) {
305 nic_unbind_and_destroy(dev);
306 return NULL;
307 }
308
309 memset(rtl8169, 0, sizeof(rtl8169_t));
310
311 rtl8169->nic_data = nic_data;
312 nic_set_specific(nic_data, rtl8169);
313 nic_set_send_frame_handler(nic_data, rtl8169_send_frame);
314 nic_set_state_change_handlers(nic_data,
315 rtl8169_on_activated, NULL, rtl8169_on_stopped);
316 nic_set_filtering_change_handlers(nic_data,
317 rtl8169_unicast_set, rtl8169_multicast_set, rtl8169_broadcast_set,
318 NULL, NULL);
319
320 fibril_mutex_initialize(&rtl8169->rx_lock);
321 fibril_mutex_initialize(&rtl8169->tx_lock);
322
323 nic_set_wol_max_caps(nic_data, NIC_WV_BROADCAST, 1);
324 nic_set_wol_max_caps(nic_data, NIC_WV_LINK_CHANGE, 1);
325 nic_set_wol_max_caps(nic_data, NIC_WV_MAGIC_PACKET, 1);
326
327 return rtl8169;
328}
329
330static void rtl8169_dev_cleanup(ddf_dev_t *dev)
331{
332 assert(dev);
333
334 if (ddf_dev_data_get(dev))
335 nic_unbind_and_destroy(dev);
336}
337
338static int rtl8169_dev_initialize(ddf_dev_t *dev)
339{
340 int ret;
341
342 rtl8169_t *rtl8169 = rtl8169_create_dev_data(dev);
343 if (rtl8169 == NULL) {
344 ddf_msg(LVL_ERROR, "Not enough memory for initializing %s.", ddf_dev_get_name(dev));
345 return ENOMEM;
346 }
347
348 ret = rtl8169_get_resource_info(dev);
349 if (ret != EOK) {
350 ddf_msg(LVL_ERROR, "Can't obtain H/W resources information");
351 goto failed;
352 }
353
354 ddf_msg(LVL_DEBUG, "The device is initialized");
355 return ret;
356
357failed:
358 ddf_msg(LVL_ERROR, "The device initialization failed");
359 rtl8169_dev_cleanup(dev);
360 return ret;
361
362}
363
364inline static int rtl8169_register_int_handler(nic_t *nic_data)
365{
366 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
367
368 rtl8169_irq_code.ranges[0].base = (uintptr_t) rtl8169->regs;
369 rtl8169_irq_code.cmds[0].addr = rtl8169->regs + ISR;
370 rtl8169_irq_code.cmds[2].addr = rtl8169->regs + ISR;
371 rtl8169_irq_code.cmds[3].addr = rtl8169->regs + IMR;
372 int rc = register_interrupt_handler(nic_get_ddf_dev(nic_data),
373 rtl8169->irq, rtl8169_irq_handler, &rtl8169_irq_code);
374
375 return rc;
376}
377
378static int rtl8169_dev_add(ddf_dev_t *dev)
379{
380 ddf_fun_t *fun;
381 nic_address_t nic_addr;
382 int rc;
383
384 assert(dev);
385 ddf_msg(LVL_NOTE, "RTL8169_dev_add %s (handle = %zu)",
386 ddf_dev_get_name(dev), ddf_dev_get_handle(dev));
387
388
389 /* Init structures */
390 rc = rtl8169_dev_initialize(dev);
391 if (rc != EOK)
392 return rc;
393
394 nic_t *nic_data = nic_get_from_ddf_dev(dev);
395 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
396
397 /* Get PCI VID & PID */
398 rc = pci_config_space_read_16(ddf_dev_parent_sess_get(dev),
399 PCI_VENDOR_ID, &rtl8169->pci_vid);
400 if (rc != EOK)
401 return rc;
402
403 rc = pci_config_space_read_16(ddf_dev_parent_sess_get(dev),
404 PCI_DEVICE_ID, &rtl8169->pci_pid);
405 if (rc != EOK)
406 return rc;
407
408 /* Map register space */
409 rc = pio_enable(rtl8169->regs_phys, RTL8169_IO_SIZE, &rtl8169->regs);
410 if (rc != EOK) {
411 ddf_msg(LVL_ERROR, "Cannot map register space for device %s.",
412 ddf_dev_get_name(dev));
413 goto err_destroy;
414 }
415
416 /* Read MAC address and print it */
417 rtl8169_get_hwaddr(rtl8169, &nic_addr);
418 ddf_msg(LVL_NOTE, "MAC address: %02x:%02x:%02x:%02x:%02x:%02x",
419 nic_addr.address[0], nic_addr.address[1],
420 nic_addr.address[2], nic_addr.address[3],
421 nic_addr.address[4], nic_addr.address[5]);
422
423 rc = nic_report_address(nic_data, &nic_addr);
424 if (rc != EOK)
425 goto err_pio;
426
427 rc = rtl8169_register_int_handler(nic_data);
428 if (rc != EOK) {
429 ddf_msg(LVL_ERROR, "Failed to register IRQ handler (%d)", rc);
430 goto err_irq;
431
432 }
433
434 ddf_msg(LVL_DEBUG, "Interrupt handler installed");
435
436 uint8_t cr_value = pio_read_8(rtl8169->regs + CR);
437 pio_write_8(rtl8169->regs + CR, cr_value | CR_TE | CR_RE);
438
439 fun = ddf_fun_create(nic_get_ddf_dev(nic_data), fun_exposed, "port0");
440 if (fun == NULL) {
441 ddf_msg(LVL_ERROR, "Failed creating device function");
442 goto err_srv;
443 }
444
445 nic_set_ddf_fun(nic_data, fun);
446 ddf_fun_set_ops(fun, &rtl8169_dev_ops);
447
448 rc = ddf_fun_bind(fun);
449 if (rc != EOK) {
450 ddf_msg(LVL_ERROR, "Failed binding device function");
451 goto err_fun_create;
452 }
453
454 rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
455 if (rc != EOK) {
456 ddf_msg(LVL_ERROR, "Failed adding function to category");
457 goto err_fun_bind;
458 }
459
460 ddf_msg(LVL_NOTE, "The %s device has been successfully initialized.",
461 ddf_dev_get_name(dev));
462 return EOK;
463
464err_fun_bind:
465 ddf_fun_unbind(fun);
466err_fun_create:
467 ddf_fun_destroy(fun);
468err_srv:
469 /* XXX Disconnect from services */
470err_irq:
471 //unregister_interrupt_handler(dev, rtl8169->irq);
472err_pio:
473err_destroy:
474 rtl8169_dev_cleanup(dev);
475 return rc;
476
477 return EOK;
478}
479
480static int rtl8169_set_addr(ddf_fun_t *fun, const nic_address_t *addr)
481{
482 nic_t *nic_data = nic_get_from_ddf_fun(fun);
483 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
484 int rc;
485
486 fibril_mutex_lock(&rtl8169->rx_lock);
487 fibril_mutex_lock(&rtl8169->tx_lock);
488
489 rc = nic_report_address(nic_data, addr);
490 if (rc != EOK)
491 return rc;
492
493 rtl8169_set_hwaddr(rtl8169, addr);
494
495 fibril_mutex_unlock(&rtl8169->rx_lock);
496 fibril_mutex_unlock(&rtl8169->tx_lock);
497
498 return EOK;
499}
500
501static int rtl8169_get_device_info(ddf_fun_t *fun, nic_device_info_t *info)
502{
503 nic_t *nic_data = nic_get_from_ddf_fun(fun);
504 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
505
506 str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH, "Unknown");
507 str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "Unknown");
508
509 if (rtl8169->pci_vid == PCI_VID_REALTEK)
510 str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH, "Realtek");
511
512 if (rtl8169->pci_vid == PCI_VID_DLINK)
513 str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH, "D-Link");
514
515 if (rtl8169->pci_pid == 0x8168)
516 str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "RTL8168");
517
518 if (rtl8169->pci_pid == 0x8169)
519 str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "RTL8169");
520
521 if (rtl8169->pci_pid == 0x8110)
522 str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "RTL8110");
523
524 return EOK;
525}
526
527static int rtl8169_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state)
528{
529 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
530 uint8_t phystatus = pio_read_8(rtl8169->regs + PHYSTATUS);
531
532 if (phystatus & PHYSTATUS_LINK)
533 *state = NIC_CS_PLUGGED;
534 else
535 *state = NIC_CS_UNPLUGGED;
536
537 return EOK;
538}
539
540static int rtl8169_get_operation_mode(ddf_fun_t *fun, int *speed,
541 nic_channel_mode_t *duplex, nic_role_t *role)
542{
543 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
544 uint8_t phystatus = pio_read_8(rtl8169->regs + PHYSTATUS);
545
546 *duplex = phystatus & PHYSTATUS_FDX
547 ? NIC_CM_FULL_DUPLEX : NIC_CM_HALF_DUPLEX;
548
549 if (phystatus & PHYSTATUS_10M)
550 *speed = 10;
551
552 if (phystatus & PHYSTATUS_100M)
553 *speed = 100;
554
555 if (phystatus & PHYSTATUS_1000M)
556 *speed = 1000;
557
558 *role = NIC_ROLE_UNKNOWN;
559 return EOK;
560}
561
562static int rtl8169_set_operation_mode(ddf_fun_t *fun, int speed,
563 nic_channel_mode_t duplex, nic_role_t role)
564{
565 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
566 uint16_t bmcr;
567
568 if (speed != 10 && speed != 100 && speed != 1000)
569 return EINVAL;
570
571 if (duplex != NIC_CM_HALF_DUPLEX && duplex != NIC_CM_FULL_DUPLEX)
572 return EINVAL;
573
574 bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
575 bmcr &= ~(BMCR_DUPLEX | BMCR_SPD_100 | BMCR_SPD_1000);
576
577 /* Disable autonegotiation */
578 bmcr &= ~BMCR_AN_ENABLE;
579
580 if (duplex == NIC_CM_FULL_DUPLEX)
581 bmcr |= BMCR_DUPLEX;
582
583 if (speed == 100)
584 bmcr |= BMCR_SPD_100;
585
586 if (speed == 1000)
587 bmcr |= BMCR_SPD_1000;
588
589 rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
590 return EOK;
591}
592
593static int rtl8169_pause_get(ddf_fun_t *fun, nic_result_t *we_send,
594 nic_result_t *we_receive, uint16_t *time)
595{
596 return EOK;
597}
598
599static int rtl8169_pause_set(ddf_fun_t *fun, int allow_send, int allow_receive,
600 uint16_t time)
601{
602 return EOK;
603}
604
605static int rtl8169_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement)
606{
607 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
608 uint16_t bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
609 uint16_t anar = ANAR_SELECTOR;
610
611 if (advertisement & ETH_AUTONEG_10BASE_T_FULL)
612 anar |= ANAR_10_FD;
613 if (advertisement & ETH_AUTONEG_10BASE_T_HALF)
614 anar |= ANAR_10_HD;
615 if (advertisement & ETH_AUTONEG_100BASE_TX_FULL)
616 anar |= ANAR_100TX_FD;
617 if (advertisement & ETH_AUTONEG_100BASE_TX_HALF)
618 anar |= ANAR_100TX_HD;
619 if (advertisement & ETH_AUTONEG_PAUSE_SYMETRIC)
620 anar |= ANAR_PAUSE;
621
622 bmcr |= BMCR_AN_ENABLE;
623 rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
624 rtl8169_mii_write(rtl8169, MII_ANAR, anar);
625
626 return EOK;
627}
628
629static int rtl8169_autoneg_disable(ddf_fun_t *fun)
630{
631 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
632 uint16_t bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
633
634 bmcr &= ~BMCR_AN_ENABLE;
635 rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
636
637 return EOK;
638}
639
640static int rtl8169_autoneg_probe(ddf_fun_t *fun, uint32_t *advertisement,
641 uint32_t *their_adv, nic_result_t *result, nic_result_t *their_result)
642{
643 return EOK;
644}
645
646static int rtl8169_autoneg_restart(ddf_fun_t *fun)
647{
648 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
649 uint16_t bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
650
651 bmcr |= BMCR_AN_ENABLE;
652 rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
653 return EOK;
654}
655
656static int rtl8169_defective_get_mode(ddf_fun_t *fun, uint32_t *mode)
657{
658 return EOK;
659}
660
661static int rtl8169_defective_set_mode(ddf_fun_t *fun, uint32_t mode)
662{
663 return EOK;
664}
665
666static void rtl8169_rx_ring_refill(rtl8169_t *rtl8169, unsigned int first,
667 unsigned int last)
668{
669 rtl8169_descr_t *descr;
670 uint64_t buff_phys;
671 unsigned int i = first;
672
673 for (;;) {
674 descr = &rtl8169->rx_ring[i];
675 buff_phys = rtl8169->rx_buff_phys + (BUFFER_SIZE * i);
676 descr->control = BUFFER_SIZE | CONTROL_OWN;
677 descr->buf_low = buff_phys & 0xffffffff;
678 descr->buf_high = (buff_phys >> 32) & 0xffffffff;
679
680 if (i == RX_BUFFERS_COUNT - 1)
681 descr->control |= CONTROL_EOR;
682
683 if (i == last)
684 break;
685
686 i = (i + 1) % RX_BUFFERS_COUNT;
687 }
688}
689
690static int rtl8169_on_activated(nic_t *nic_data)
691{
692 int rc;
693 uint64_t tmp;
694
695 ddf_msg(LVL_NOTE, "Activating device");
696
697 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
698
699 /* Reset card */
700 pio_write_8(rtl8169->regs + CONFIG0, 0);
701 rtl8169_reset(rtl8169);
702
703 /* Allocate buffers */
704 rc = rtl8169_allocate_buffers(rtl8169);
705 if (rc != EOK) {
706 ddf_msg(LVL_ERROR, "Error allocating buffers: %d", rc);
707 return 0;
708 }
709
710 /* Initialize RX ring */
711 rtl8169_rx_ring_refill(rtl8169, 0, RX_BUFFERS_COUNT - 1);
712
713 /* Write address of descriptor as start of TX ring */
714 tmp = rtl8169->tx_ring_phys;
715 pio_write_32(rtl8169->regs + TNPDS, tmp & 0xffffffff);
716 pio_write_32(rtl8169->regs + TNPDS + 4, (tmp >> 32) & 0xffffffff);
717 rtl8169->tx_head = 0;
718 rtl8169->tx_tail = 0;
719 rtl8169->tx_ring[15].control = CONTROL_EOR;
720
721 /* Write RX ring address */
722 tmp = rtl8169->rx_ring_phys;
723 pio_write_32(rtl8169->regs + RDSAR, tmp & 0xffffffff);
724 pio_write_32(rtl8169->regs + RDSAR + 4, (tmp >> 32) & 0xffffffff);
725 rtl8169->rx_head = 0;
726 rtl8169->rx_tail = 0;
727
728 /* Clear pending interrupts */
729 pio_write_16(rtl8169->regs + ISR, 0xffff);
730
731 /* Enable TX and RX */
732 uint8_t cr = pio_read_8(rtl8169->regs + CR);
733 cr |= CR_TE | CR_RE;
734 pio_write_8(rtl8169->regs + CR, cr);
735 pio_write_32(rtl8169->regs + MAR0, 0xffffffff);
736 pio_write_32(rtl8169->regs + MAR0 + 4, 0xffffffff);
737
738 /* Configure Receive Control Register */
739 uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
740 rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH;
741 rcr |= RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ERROR | RCR_ACCEPT_RUNT;
742 pio_write_32(rtl8169->regs + RCR, rcr);
743 pio_write_16(rtl8169->regs + RMS, BUFFER_SIZE);
744
745 pio_write_16(rtl8169->regs + IMR, 0xffff);
746 irc_enable_interrupt(rtl8169->irq);
747
748 return EOK;
749}
750
751static int rtl8169_on_stopped(nic_t *nic_data)
752{
753 ddf_msg(LVL_NOTE, "Stopping device");
754 return EOK;
755}
756
757inline static void rtl8169_reset(rtl8169_t *rtl8169)
758{
759 pio_write_8(rtl8169->regs + CR, CR_RST);
760 memory_barrier();
761 while (pio_read_8(rtl8169->regs + CR) & CR_RST) {
762 usleep(1);
763 read_barrier();
764 }
765}
766
767static void rtl8169_link_change(ddf_dev_t *dev)
768{
769 nic_t *nic_data = nic_get_from_ddf_dev(dev);
770 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
771
772 uint8_t phystatus = pio_read_8(rtl8169->regs + PHYSTATUS);
773
774 if (phystatus & PHYSTATUS_LINK) {
775 ddf_msg(LVL_NOTE, "%s: Link up", ddf_dev_get_name(dev));
776
777 int speed;
778 const char *fdx = phystatus & PHYSTATUS_FDX ? "full duplex" : "half duplex";
779
780 if (phystatus & PHYSTATUS_10M)
781 speed = 10;
782
783 if (phystatus & PHYSTATUS_100M)
784 speed = 100;
785
786 if (phystatus & PHYSTATUS_1000M)
787 speed = 1000;
788
789 ddf_msg(LVL_NOTE, "%s: Speed %dMbit/s, %s", ddf_dev_get_name(dev), speed, fdx);
790 } else {
791 ddf_msg(LVL_NOTE, "%s: Link down", ddf_dev_get_name(dev));
792 }
793
794}
795
796/** Notify NIC framework about HW filtering state when promisc mode was disabled
797 *
798 * @param nic_data The NIC data
799 * @param mcast_mode Current multicast mode
800 * @param was_promisc Sign if the promiscuous mode was active before disabling
801 */
802inline static void rtl8169_rcx_promics_rem(nic_t *nic_data,
803 nic_multicast_mode_t mcast_mode, uint8_t was_promisc)
804{
805 assert(nic_data);
806
807 if (was_promisc != 0) {
808 if (mcast_mode == NIC_MULTICAST_LIST)
809 nic_report_hw_filtering(nic_data, 1, 0, -1);
810 else
811 nic_report_hw_filtering(nic_data, 1, 1, -1);
812 } else {
813 nic_report_hw_filtering(nic_data, 1, -1, -1);
814 }
815}
816
817static int rtl8169_unicast_set(nic_t *nic_data, nic_unicast_mode_t mode,
818 const nic_address_t *addr, size_t addr_count)
819{
820 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
821 uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
822 uint8_t was_promisc = rcr & RCR_ACCEPT_ALL_PHYS;
823 nic_multicast_mode_t mcast_mode;
824
825 nic_query_multicast(nic_data, &mcast_mode, 0, NULL, NULL);
826
827 ddf_msg(LVL_DEBUG, "Unicast RX filter mode: %d", mode);
828
829
830 switch (mode) {
831 case NIC_UNICAST_BLOCKED:
832 rtl8169->rcr_ucast = 0;
833 rtl8169_rcx_promics_rem(nic_data, mcast_mode, was_promisc);
834 break;
835 case NIC_UNICAST_DEFAULT:
836 rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH;
837 rtl8169_rcx_promics_rem(nic_data, mcast_mode, was_promisc);
838 break;
839 case NIC_UNICAST_LIST:
840 rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS;
841
842 if (mcast_mode == NIC_MULTICAST_PROMISC)
843 nic_report_hw_filtering(nic_data, 0, 1, -1);
844 else
845 nic_report_hw_filtering(nic_data, 0, 0, -1);
846 break;
847 case NIC_UNICAST_PROMISC:
848 rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS;
849
850 if (mcast_mode == NIC_MULTICAST_PROMISC)
851 nic_report_hw_filtering(nic_data, 1, 1, -1);
852 else
853 nic_report_hw_filtering(nic_data, 1, 0, -1);
854 break;
855 default:
856 return ENOTSUP;
857 }
858
859 fibril_mutex_lock(&rtl8169->rx_lock);
860
861 rcr &= ~(RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS);
862 pio_write_32(rtl8169->regs + RCR, rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
863 ddf_msg(LVL_DEBUG, "new RCR value: 0x%08x", rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
864
865 fibril_mutex_unlock(&rtl8169->rx_lock);
866 return EOK;
867}
868
869static int rtl8169_multicast_set(nic_t *nic_data, nic_multicast_mode_t mode,
870 const nic_address_t *addr, size_t addr_count)
871{
872 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
873 uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
874 uint64_t mask;
875
876 ddf_msg(LVL_DEBUG, "Multicast RX filter mode: %d", mode);
877
878 switch (mode) {
879 case NIC_MULTICAST_BLOCKED:
880 rtl8169->rcr_mcast = 0;
881 if ((rtl8169->rcr_ucast & RCR_ACCEPT_ALL_PHYS) != 0)
882 nic_report_hw_filtering(nic_data, -1, 0, -1);
883 else
884 nic_report_hw_filtering(nic_data, -1, 1, -1);
885 break;
886 case NIC_MULTICAST_LIST:
887 mask = nic_mcast_hash(addr, addr_count);
888 pio_write_32(rtl8169->regs + MAR0, (uint32_t)mask);
889 pio_write_32(rtl8169->regs + MAR0 + 4, (uint32_t)(mask >> 32));
890 rtl8169->rcr_mcast = RCR_ACCEPT_MULTICAST;
891 nic_report_hw_filtering(nic_data, -1, 0, -1);
892 break;
893 case NIC_MULTICAST_PROMISC:
894 pio_write_32(rtl8169->regs + MAR0, 0xffffffffULL);
895 pio_write_32(rtl8169->regs + MAR0 + 4, (uint32_t)(0xffffffffULL >> 32));
896 rtl8169->rcr_mcast = RCR_ACCEPT_MULTICAST;
897 nic_report_hw_filtering(nic_data, -1, 1, -1);
898 break;
899 default:
900 return ENOTSUP;
901 }
902
903 fibril_mutex_lock(&rtl8169->rx_lock);
904
905 rcr &= ~(RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS);
906 pio_write_32(rtl8169->regs + RCR, rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
907 ddf_msg(LVL_DEBUG, "new RCR value: 0x%08x", rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
908
909 fibril_mutex_unlock(&rtl8169->rx_lock);
910 return EOK;
911}
912
913static int rtl8169_broadcast_set(nic_t *nic_data, nic_broadcast_mode_t mode)
914{
915 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
916
917 /* Configure Receive Control Register */
918 uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
919
920 ddf_msg(LVL_DEBUG, "Broadcast RX filter mode: %d", mode);
921
922 switch (mode) {
923 case NIC_BROADCAST_BLOCKED:
924 rcr &= RCR_ACCEPT_BROADCAST;
925 break;
926 case NIC_BROADCAST_ACCEPTED:
927 rcr |= RCR_ACCEPT_BROADCAST;
928 break;
929 default:
930 return ENOTSUP;
931 }
932
933 pio_write_32(rtl8169->regs + RCR, rcr);
934 ddf_msg(LVL_DEBUG," new RCR value: 0x%08x", rcr);
935
936 return EOK;
937}
938
939static void rtl8169_transmit_done(ddf_dev_t *dev)
940{
941 unsigned int tail, head;
942 nic_t *nic_data = nic_get_from_ddf_dev(dev);
943 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
944 rtl8169_descr_t *descr;
945 int sent = 0;
946
947 ddf_msg(LVL_DEBUG, "rtl8169_transmit_done()");
948
949 fibril_mutex_lock(&rtl8169->tx_lock);
950
951 head = rtl8169->tx_head;
952 tail = rtl8169->tx_tail;
953
954 while (tail != head) {
955 descr = &rtl8169->tx_ring[tail];
956 descr->control &= (~CONTROL_OWN);
957 write_barrier();
958 ddf_msg(LVL_DEBUG, "TX status for descr %d: 0x%08x", tail, descr->control);
959
960 tail = (tail + 1) % TX_BUFFERS_COUNT;
961 sent++;
962 }
963
964 if (sent != 0)
965 nic_set_tx_busy(nic_data, 0);
966
967 rtl8169->tx_tail = tail;
968
969 fibril_mutex_unlock(&rtl8169->tx_lock);
970}
971
972static void rtl8169_receive_done(ddf_dev_t *dev)
973{
974 nic_t *nic_data = nic_get_from_ddf_dev(dev);
975 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
976 rtl8169_descr_t *descr;
977 nic_frame_list_t *frames = nic_alloc_frame_list();
978 nic_frame_t *frame;
979 void *buffer;
980 unsigned int tail, fsidx = 0;
981 int frame_size;
982
983 ddf_msg(LVL_DEBUG, "rtl8169_receive_done()");
984
985 fibril_mutex_lock(&rtl8169->rx_lock);
986
987 tail = rtl8169->rx_tail;
988
989 for (;;) {
990 descr = &rtl8169->rx_ring[tail];
991
992 if (descr->control & CONTROL_OWN)
993 break;
994
995 if (descr->control & RXSTATUS_RES) {
996 ddf_msg(LVL_WARN, "error at slot %d: 0x%08x\n", tail, descr->control);
997 tail = (tail + 1) % RX_BUFFERS_COUNT;
998 continue;
999 }
1000
1001 if (descr->control & CONTROL_FS)
1002 fsidx = tail;
1003
1004 if (descr->control & CONTROL_LS) {
1005 ddf_msg(LVL_DEBUG, "received message at slot %d, control 0x%08x", tail, descr->control);
1006
1007 if (fsidx != tail)
1008 ddf_msg(LVL_WARN, "single frame spanning multiple descriptors");
1009
1010 frame_size = descr->control & 0x1fff;
1011 buffer = rtl8169->rx_buff + (BUFFER_SIZE * tail);
1012 frame = nic_alloc_frame(nic_data, frame_size);
1013 memcpy(frame->data, buffer, frame_size);
1014 nic_frame_list_append(frames, frame);
1015 }
1016
1017 tail = (tail + 1) % RX_BUFFERS_COUNT;
1018 }
1019
1020 rtl8169_rx_ring_refill(rtl8169, rtl8169->rx_tail, tail);
1021
1022 rtl8169->rx_tail = tail;
1023
1024 fibril_mutex_unlock(&rtl8169->rx_lock);
1025
1026 nic_received_frame_list(nic_data, frames);
1027
1028}
1029
1030static void rtl8169_irq_handler(ddf_dev_t *dev, ipc_callid_t iid,
1031 ipc_call_t *icall)
1032{
1033 assert(dev);
1034 assert(icall);
1035
1036 uint16_t isr = (uint16_t) IPC_GET_ARG2(*icall) & INT_KNOWN;
1037 nic_t *nic_data = nic_get_from_ddf_dev(dev);
1038 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
1039
1040 ddf_msg(LVL_DEBUG, "rtl8169_irq_handler(): isr=0x%04x", isr);
1041 pio_write_16(rtl8169->regs + IMR, 0xffff);
1042
1043 while (isr != 0) {
1044 ddf_msg(LVL_DEBUG, "irq handler: remaining isr=0x%04x", isr);
1045
1046 /* Packet underrun or link change */
1047 if (isr & INT_PUN) {
1048 rtl8169_link_change(dev);
1049 pio_write_16(rtl8169->regs + ISR, INT_PUN);
1050 }
1051
1052 /* Transmit notification */
1053 if (isr & (INT_TER | INT_TOK | INT_TDU)) {
1054 rtl8169_transmit_done(dev);
1055 pio_write_16(rtl8169->regs + ISR, (INT_TER | INT_TOK | INT_TDU));
1056 }
1057
1058 /* Receive underrun */
1059 if (isr & INT_RXOVW) {
1060 /* just ack.. */
1061 pio_write_16(rtl8169->regs + ISR, INT_RXOVW);
1062 }
1063
1064 if (isr & INT_SERR) {
1065 ddf_msg(LVL_ERROR, "System error interrupt");
1066 pio_write_16(rtl8169->regs + ISR, INT_SERR);
1067 }
1068
1069 if (isr & (INT_RER | INT_ROK)) {
1070 rtl8169_receive_done(dev);
1071 pio_write_16(rtl8169->regs + ISR, (INT_RER | INT_ROK));
1072 }
1073
1074 isr = pio_read_16(rtl8169->regs + ISR) & INT_KNOWN;
1075 }
1076
1077 pio_write_16(rtl8169->regs + ISR, 0xffff);
1078}
1079
1080static void rtl8169_send_frame(nic_t *nic_data, void *data, size_t size)
1081{
1082 rtl8169_descr_t *descr, *prev;
1083 unsigned int head, tail;
1084 void *buff;
1085 uint64_t buff_phys;
1086 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
1087
1088 if (size > RTL8169_FRAME_MAX_LENGTH) {
1089 ddf_msg(LVL_ERROR, "Send frame: frame too long, %zu bytes",
1090 size);
1091 nic_report_send_error(nic_data, NIC_SEC_OTHER, 1);
1092 }
1093
1094 fibril_mutex_lock(&rtl8169->tx_lock);
1095
1096 ddf_msg(LVL_DEBUG, "send_frame: size: %zu, tx_head=%d tx_tail=%d",
1097 size, rtl8169->tx_head, rtl8169->tx_tail);
1098
1099 head = rtl8169->tx_head;
1100 tail = rtl8169->tx_tail;
1101
1102 if ((head + 1) % TX_BUFFERS_COUNT == tail) {
1103 /* Queue is full */
1104 ddf_msg(LVL_WARN, "TX queue full!");
1105 nic_set_tx_busy(nic_data, 1);
1106 }
1107
1108 /* Calculate address of next free buffer and descriptor */
1109 buff = rtl8169->tx_buff + (BUFFER_SIZE * head);
1110 buff_phys = rtl8169->tx_buff_phys + (BUFFER_SIZE * head);
1111
1112 /* Copy frame */
1113 memcpy(buff, data, size);
1114
1115 /* Setup descriptor */
1116 descr = &rtl8169->tx_ring[head];
1117 prev = &rtl8169->tx_ring[(head - 1) % TX_BUFFERS_COUNT];
1118
1119 ddf_msg(LVL_DEBUG, "current_descr=%p, prev_descr=%p", descr, prev);
1120
1121 descr->control = CONTROL_OWN | CONTROL_FS | CONTROL_LS;
1122 descr->control |= size & 0xffff;
1123 descr->vlan = 0;
1124 descr->buf_low = buff_phys & 0xffffffff;
1125 descr->buf_high = (buff_phys >> 32) & 0xffffffff;
1126
1127 if (head == TX_BUFFERS_COUNT - 1)
1128 descr->control |= CONTROL_EOR;
1129
1130 rtl8169->tx_head = (head + 1) % TX_BUFFERS_COUNT;
1131
1132 ddf_msg(LVL_DEBUG, "control: 0x%08x", descr->control);
1133
1134 write_barrier();
1135
1136 /* Notify NIC of pending packets */
1137 pio_write_8(rtl8169->regs + TPPOLL, TPPOLL_NPQ);
1138 write_barrier();
1139
1140 fibril_mutex_unlock(&rtl8169->tx_lock);
1141}
1142
1143static inline void rtl8169_get_hwaddr(rtl8169_t *rtl8169, nic_address_t *addr)
1144{
1145 int i;
1146
1147 assert(rtl8169);
1148 assert(addr);
1149
1150 for (i = 0; i < 6; i++)
1151 addr->address[i] = pio_read_8(rtl8169->regs + MAC0 + i);
1152}
1153
1154static inline void rtl8169_set_hwaddr(rtl8169_t *rtl8169, const nic_address_t *addr)
1155{
1156 int i;
1157
1158 assert(rtl8169);
1159 assert(addr);
1160
1161 for (i = 0; i < 6; i++)
1162 pio_write_8(rtl8169->regs + MAC0 + i, addr->address[i]);
1163}
1164
1165static uint16_t rtl8169_mii_read(rtl8169_t *rtl8169, uint8_t addr)
1166{
1167 uint32_t phyar;
1168
1169 phyar = PHYAR_RW_READ
1170 | ((addr & PHYAR_ADDR_MASK) << PHYAR_ADDR_SHIFT);
1171
1172 pio_write_32(rtl8169->regs + PHYAR, phyar);
1173
1174 do {
1175 phyar = pio_read_32(rtl8169->regs + PHYAR);
1176 usleep(20);
1177 } while ((phyar & PHYAR_RW_WRITE) == 0);
1178
1179 return phyar & PHYAR_DATA_MASK;
1180}
1181
1182static void rtl8169_mii_write(rtl8169_t *rtl8169, uint8_t addr, uint16_t value)
1183{
1184 uint32_t phyar;
1185
1186 phyar = PHYAR_RW_WRITE
1187 | ((addr & PHYAR_ADDR_MASK) << PHYAR_ADDR_SHIFT)
1188 | (value & PHYAR_DATA_MASK);
1189
1190 pio_write_32(rtl8169->regs + PHYAR, phyar);
1191
1192 do {
1193 phyar = pio_read_32(rtl8169->regs + PHYAR);
1194 usleep(20);
1195 } while ((phyar & PHYAR_RW_WRITE) != 0);
1196
1197 usleep(20);
1198}
1199
1200/** Main function of RTL8169 driver
1201*
1202 * Just initialize the driver structures and
1203 * put it into the device drivers interface
1204 */
1205int main(void)
1206{
1207 int rc = nic_driver_init(NAME);
1208 if (rc != EOK)
1209 return rc;
1210 nic_driver_implement(
1211 &rtl8169_driver_ops, &rtl8169_dev_ops, &rtl8169_nic_iface);
1212
1213 ddf_log_init(NAME);
1214 ddf_msg(LVL_NOTE, "HelenOS RTL8169 driver started");
1215 return ddf_driver_main(&rtl8169_driver);
1216}
Note: See TracBrowser for help on using the repository browser.