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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d6f73b92 was ae7d03c, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Selected ccheck-proposed comment fixes.

  • Property mode set to 100644
File size: 32.9 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 <async.h>
31#include <errno.h>
32#include <str_error.h>
33#include <align.h>
34#include <byteorder.h>
35#include <libarch/barrier.h>
36#include <stdbool.h>
37
38#include <as.h>
39#include <ddf/log.h>
40#include <ddf/interrupt.h>
41#include <device/hw_res.h>
42#include <device/hw_res_parsed.h>
43#include <io/log.h>
44#include <nic.h>
45#include <pci_dev_iface.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 errno_t rtl8169_set_addr(ddf_fun_t *fun, const nic_address_t *addr);
56static errno_t rtl8169_get_device_info(ddf_fun_t *fun, nic_device_info_t *info);
57static errno_t rtl8169_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state);
58static errno_t rtl8169_get_operation_mode(ddf_fun_t *fun, int *speed,
59 nic_channel_mode_t *duplex, nic_role_t *role);
60static errno_t rtl8169_set_operation_mode(ddf_fun_t *fun, int speed,
61 nic_channel_mode_t duplex, nic_role_t role);
62static errno_t rtl8169_pause_get(ddf_fun_t *fun, nic_result_t *we_send,
63 nic_result_t *we_receive, uint16_t *time);
64static errno_t rtl8169_pause_set(ddf_fun_t *fun, int allow_send, int allow_receive,
65 uint16_t time);
66static errno_t rtl8169_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement);
67static errno_t rtl8169_autoneg_disable(ddf_fun_t *fun);
68static errno_t 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 errno_t rtl8169_autoneg_restart(ddf_fun_t *fun);
71static errno_t rtl8169_defective_get_mode(ddf_fun_t *fun, uint32_t *mode);
72static errno_t rtl8169_defective_set_mode(ddf_fun_t *fun, uint32_t mode);
73static errno_t rtl8169_on_activated(nic_t *nic_data);
74static errno_t 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(ipc_call_t *icall, ddf_dev_t *dev);
77static inline errno_t rtl8169_register_int_handler(nic_t *nic_data,
78 cap_irq_handle_t *handle);
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 errno_t rtl8169_get_resource_info(ddf_dev_t *dev);
84static errno_t 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 errno_t rtl8169_unicast_set(nic_t *nic_data, nic_unicast_mode_t mode,
88 const nic_address_t *, size_t);
89static errno_t rtl8169_multicast_set(nic_t *nic_data, nic_multicast_mode_t mode,
90 const nic_address_t *addr, size_t addr_count);
91static errno_t 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 errno_t 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 errno_t 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 errno_t 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 errno_t 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 errno_t 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 errno_t rtl8169_allocate_buffers(rtl8169_t *rtl8169)
234{
235 errno_t 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 errno_t rtl8169_dev_initialize(ddf_dev_t *dev)
339{
340 errno_t 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 errno_t rtl8169_register_int_handler(nic_t *nic_data,
365 cap_irq_handle_t *handle)
366{
367 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
368
369 rtl8169_irq_code.ranges[0].base = (uintptr_t) rtl8169->regs;
370 rtl8169_irq_code.cmds[0].addr = rtl8169->regs + ISR;
371 rtl8169_irq_code.cmds[2].addr = rtl8169->regs + ISR;
372 rtl8169_irq_code.cmds[3].addr = rtl8169->regs + IMR;
373 errno_t rc = register_interrupt_handler(nic_get_ddf_dev(nic_data),
374 rtl8169->irq, rtl8169_irq_handler, &rtl8169_irq_code, handle);
375
376 return rc;
377}
378
379static errno_t rtl8169_dev_add(ddf_dev_t *dev)
380{
381 ddf_fun_t *fun;
382 nic_address_t nic_addr;
383 errno_t rc;
384
385 assert(dev);
386 ddf_msg(LVL_NOTE, "RTL8169_dev_add %s (handle = %zu)",
387 ddf_dev_get_name(dev), ddf_dev_get_handle(dev));
388
389
390 /* Init structures */
391 rc = rtl8169_dev_initialize(dev);
392 if (rc != EOK)
393 return rc;
394
395 nic_t *nic_data = nic_get_from_ddf_dev(dev);
396 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
397
398 rtl8169->dev = dev;
399 rtl8169->parent_sess = ddf_dev_parent_sess_get(dev);
400 if (rtl8169->parent_sess == NULL)
401 return EIO;
402
403 /* Get PCI VID & PID */
404 rc = pci_config_space_read_16(rtl8169->parent_sess, PCI_VENDOR_ID,
405 &rtl8169->pci_vid);
406 if (rc != EOK)
407 return rc;
408
409 rc = pci_config_space_read_16(rtl8169->parent_sess, PCI_DEVICE_ID,
410 &rtl8169->pci_pid);
411 if (rc != EOK)
412 return rc;
413
414 /* Map register space */
415 rc = pio_enable(rtl8169->regs_phys, RTL8169_IO_SIZE, &rtl8169->regs);
416 if (rc != EOK) {
417 ddf_msg(LVL_ERROR, "Cannot map register space for device %s.",
418 ddf_dev_get_name(dev));
419 goto err_destroy;
420 }
421
422 /* Read MAC address and print it */
423 rtl8169_get_hwaddr(rtl8169, &nic_addr);
424 ddf_msg(LVL_NOTE, "MAC address: %02x:%02x:%02x:%02x:%02x:%02x",
425 nic_addr.address[0], nic_addr.address[1],
426 nic_addr.address[2], nic_addr.address[3],
427 nic_addr.address[4], nic_addr.address[5]);
428
429 rc = nic_report_address(nic_data, &nic_addr);
430 if (rc != EOK)
431 goto err_pio;
432
433 cap_irq_handle_t irq_handle;
434 rc = rtl8169_register_int_handler(nic_data, &irq_handle);
435 if (rc != EOK) {
436 ddf_msg(LVL_ERROR, "Failed to register IRQ handler (%s)", str_error_name(rc));
437 goto err_irq;
438 }
439
440 ddf_msg(LVL_DEBUG, "Interrupt handler installed");
441
442 uint8_t cr_value = pio_read_8(rtl8169->regs + CR);
443 pio_write_8(rtl8169->regs + CR, cr_value | CR_TE | CR_RE);
444
445 fun = ddf_fun_create(nic_get_ddf_dev(nic_data), fun_exposed, "port0");
446 if (fun == NULL) {
447 ddf_msg(LVL_ERROR, "Failed creating device function");
448 goto err_srv;
449 }
450
451 nic_set_ddf_fun(nic_data, fun);
452 ddf_fun_set_ops(fun, &rtl8169_dev_ops);
453
454 rc = ddf_fun_bind(fun);
455 if (rc != EOK) {
456 ddf_msg(LVL_ERROR, "Failed binding device function");
457 goto err_fun_create;
458 }
459
460 rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
461 if (rc != EOK) {
462 ddf_msg(LVL_ERROR, "Failed adding function to category");
463 goto err_fun_bind;
464 }
465
466 ddf_msg(LVL_NOTE, "The %s device has been successfully initialized.",
467 ddf_dev_get_name(dev));
468 return EOK;
469
470err_fun_bind:
471 ddf_fun_unbind(fun);
472err_fun_create:
473 ddf_fun_destroy(fun);
474err_srv:
475 /* XXX Disconnect from services */
476 unregister_interrupt_handler(dev, irq_handle);
477err_irq:
478err_pio:
479err_destroy:
480 rtl8169_dev_cleanup(dev);
481 return rc;
482
483 return EOK;
484}
485
486static errno_t rtl8169_set_addr(ddf_fun_t *fun, const nic_address_t *addr)
487{
488 nic_t *nic_data = nic_get_from_ddf_fun(fun);
489 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
490 errno_t rc;
491
492 fibril_mutex_lock(&rtl8169->rx_lock);
493 fibril_mutex_lock(&rtl8169->tx_lock);
494
495 rc = nic_report_address(nic_data, addr);
496 if (rc != EOK)
497 return rc;
498
499 rtl8169_set_hwaddr(rtl8169, addr);
500
501 fibril_mutex_unlock(&rtl8169->rx_lock);
502 fibril_mutex_unlock(&rtl8169->tx_lock);
503
504 return EOK;
505}
506
507static errno_t rtl8169_get_device_info(ddf_fun_t *fun, nic_device_info_t *info)
508{
509 nic_t *nic_data = nic_get_from_ddf_fun(fun);
510 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
511
512 str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH, "Unknown");
513 str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "Unknown");
514
515 if (rtl8169->pci_vid == PCI_VID_REALTEK)
516 str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH, "Realtek");
517
518 if (rtl8169->pci_vid == PCI_VID_DLINK)
519 str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH, "D-Link");
520
521 if (rtl8169->pci_pid == 0x8168)
522 str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "RTL8168");
523
524 if (rtl8169->pci_pid == 0x8169)
525 str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "RTL8169");
526
527 if (rtl8169->pci_pid == 0x8110)
528 str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "RTL8110");
529
530 return EOK;
531}
532
533static errno_t rtl8169_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state)
534{
535 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
536 uint8_t phystatus = pio_read_8(rtl8169->regs + PHYSTATUS);
537
538 if (phystatus & PHYSTATUS_LINK)
539 *state = NIC_CS_PLUGGED;
540 else
541 *state = NIC_CS_UNPLUGGED;
542
543 return EOK;
544}
545
546static errno_t rtl8169_get_operation_mode(ddf_fun_t *fun, int *speed,
547 nic_channel_mode_t *duplex, nic_role_t *role)
548{
549 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
550 uint8_t phystatus = pio_read_8(rtl8169->regs + PHYSTATUS);
551
552 *duplex = phystatus & PHYSTATUS_FDX ?
553 NIC_CM_FULL_DUPLEX : NIC_CM_HALF_DUPLEX;
554
555 if (phystatus & PHYSTATUS_10M)
556 *speed = 10;
557
558 if (phystatus & PHYSTATUS_100M)
559 *speed = 100;
560
561 if (phystatus & PHYSTATUS_1000M)
562 *speed = 1000;
563
564 *role = NIC_ROLE_UNKNOWN;
565 return EOK;
566}
567
568static errno_t rtl8169_set_operation_mode(ddf_fun_t *fun, int speed,
569 nic_channel_mode_t duplex, nic_role_t role)
570{
571 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
572 uint16_t bmcr;
573
574 if (speed != 10 && speed != 100 && speed != 1000)
575 return EINVAL;
576
577 if (duplex != NIC_CM_HALF_DUPLEX && duplex != NIC_CM_FULL_DUPLEX)
578 return EINVAL;
579
580 bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
581 bmcr &= ~(BMCR_DUPLEX | BMCR_SPD_100 | BMCR_SPD_1000);
582
583 /* Disable autonegotiation */
584 bmcr &= ~BMCR_AN_ENABLE;
585
586 if (duplex == NIC_CM_FULL_DUPLEX)
587 bmcr |= BMCR_DUPLEX;
588
589 if (speed == 100)
590 bmcr |= BMCR_SPD_100;
591
592 if (speed == 1000)
593 bmcr |= BMCR_SPD_1000;
594
595 rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
596 return EOK;
597}
598
599static errno_t rtl8169_pause_get(ddf_fun_t *fun, nic_result_t *we_send,
600 nic_result_t *we_receive, uint16_t *time)
601{
602 return EOK;
603}
604
605static errno_t rtl8169_pause_set(ddf_fun_t *fun, int allow_send, int allow_receive,
606 uint16_t time)
607{
608 return EOK;
609}
610
611static errno_t rtl8169_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement)
612{
613 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
614 uint16_t bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
615 uint16_t anar = ANAR_SELECTOR;
616
617 if (advertisement & ETH_AUTONEG_10BASE_T_FULL)
618 anar |= ANAR_10_FD;
619 if (advertisement & ETH_AUTONEG_10BASE_T_HALF)
620 anar |= ANAR_10_HD;
621 if (advertisement & ETH_AUTONEG_100BASE_TX_FULL)
622 anar |= ANAR_100TX_FD;
623 if (advertisement & ETH_AUTONEG_100BASE_TX_HALF)
624 anar |= ANAR_100TX_HD;
625 if (advertisement & ETH_AUTONEG_PAUSE_SYMETRIC)
626 anar |= ANAR_PAUSE;
627
628 bmcr |= BMCR_AN_ENABLE;
629 rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
630 rtl8169_mii_write(rtl8169, MII_ANAR, anar);
631
632 return EOK;
633}
634
635static errno_t rtl8169_autoneg_disable(ddf_fun_t *fun)
636{
637 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
638 uint16_t bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
639
640 bmcr &= ~BMCR_AN_ENABLE;
641 rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
642
643 return EOK;
644}
645
646static errno_t rtl8169_autoneg_probe(ddf_fun_t *fun, uint32_t *advertisement,
647 uint32_t *their_adv, nic_result_t *result, nic_result_t *their_result)
648{
649 return EOK;
650}
651
652static errno_t rtl8169_autoneg_restart(ddf_fun_t *fun)
653{
654 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
655 uint16_t bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
656
657 bmcr |= BMCR_AN_ENABLE;
658 rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
659 return EOK;
660}
661
662static errno_t rtl8169_defective_get_mode(ddf_fun_t *fun, uint32_t *mode)
663{
664 return EOK;
665}
666
667static errno_t rtl8169_defective_set_mode(ddf_fun_t *fun, uint32_t mode)
668{
669 return EOK;
670}
671
672static void rtl8169_rx_ring_refill(rtl8169_t *rtl8169, unsigned int first,
673 unsigned int last)
674{
675 rtl8169_descr_t *descr;
676 uint64_t buff_phys;
677 unsigned int i = first;
678
679 while (true) {
680 descr = &rtl8169->rx_ring[i];
681 buff_phys = rtl8169->rx_buff_phys + (BUFFER_SIZE * i);
682 descr->control = BUFFER_SIZE | CONTROL_OWN;
683 descr->buf_low = buff_phys & 0xffffffff;
684 descr->buf_high = (buff_phys >> 32) & 0xffffffff;
685
686 if (i == RX_BUFFERS_COUNT - 1)
687 descr->control |= CONTROL_EOR;
688
689 if (i == last)
690 break;
691
692 i = (i + 1) % RX_BUFFERS_COUNT;
693 }
694}
695
696static errno_t rtl8169_on_activated(nic_t *nic_data)
697{
698 errno_t rc;
699 uint64_t tmp;
700
701 ddf_msg(LVL_NOTE, "Activating device");
702
703 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
704
705 /* Reset card */
706 pio_write_8(rtl8169->regs + CONFIG0, 0);
707 rtl8169_reset(rtl8169);
708
709 /* Allocate buffers */
710 rc = rtl8169_allocate_buffers(rtl8169);
711 if (rc != EOK) {
712 ddf_msg(LVL_ERROR, "Error allocating buffers: %s", str_error_name(rc));
713 return 0;
714 }
715
716 /* Initialize RX ring */
717 rtl8169_rx_ring_refill(rtl8169, 0, RX_BUFFERS_COUNT - 1);
718
719 /* Write address of descriptor as start of TX ring */
720 tmp = rtl8169->tx_ring_phys;
721 pio_write_32(rtl8169->regs + TNPDS, tmp & 0xffffffff);
722 pio_write_32(rtl8169->regs + TNPDS + 4, (tmp >> 32) & 0xffffffff);
723 rtl8169->tx_head = 0;
724 rtl8169->tx_tail = 0;
725 rtl8169->tx_ring[15].control = CONTROL_EOR;
726
727 /* Write RX ring address */
728 tmp = rtl8169->rx_ring_phys;
729 pio_write_32(rtl8169->regs + RDSAR, tmp & 0xffffffff);
730 pio_write_32(rtl8169->regs + RDSAR + 4, (tmp >> 32) & 0xffffffff);
731 rtl8169->rx_head = 0;
732 rtl8169->rx_tail = 0;
733
734 /* Clear pending interrupts */
735 pio_write_16(rtl8169->regs + ISR, 0xffff);
736
737 /* Enable TX and RX */
738 uint8_t cr = pio_read_8(rtl8169->regs + CR);
739 cr |= CR_TE | CR_RE;
740 pio_write_8(rtl8169->regs + CR, cr);
741 pio_write_32(rtl8169->regs + MAR0, 0xffffffff);
742 pio_write_32(rtl8169->regs + MAR0 + 4, 0xffffffff);
743
744 /* Configure Receive Control Register */
745 uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
746 rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH;
747 rcr |= RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ERROR | RCR_ACCEPT_RUNT;
748 pio_write_32(rtl8169->regs + RCR, rcr);
749 pio_write_16(rtl8169->regs + RMS, BUFFER_SIZE);
750
751 pio_write_16(rtl8169->regs + IMR, 0xffff);
752 /* XXX Check return value */
753 hw_res_enable_interrupt(rtl8169->parent_sess, rtl8169->irq);
754
755 return EOK;
756}
757
758static errno_t rtl8169_on_stopped(nic_t *nic_data)
759{
760 ddf_msg(LVL_NOTE, "Stopping device");
761 return EOK;
762}
763
764inline static void rtl8169_reset(rtl8169_t *rtl8169)
765{
766 pio_write_8(rtl8169->regs + CR, CR_RST);
767 memory_barrier();
768 while (pio_read_8(rtl8169->regs + CR) & CR_RST) {
769 async_usleep(1);
770 read_barrier();
771 }
772}
773
774static void rtl8169_link_change(ddf_dev_t *dev)
775{
776 nic_t *nic_data = nic_get_from_ddf_dev(dev);
777 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
778
779 uint8_t phystatus = pio_read_8(rtl8169->regs + PHYSTATUS);
780
781 if (phystatus & PHYSTATUS_LINK) {
782 ddf_msg(LVL_NOTE, "%s: Link up", ddf_dev_get_name(dev));
783
784 int speed;
785 const char *fdx = phystatus & PHYSTATUS_FDX ? "full duplex" : "half duplex";
786
787 if (phystatus & PHYSTATUS_10M)
788 speed = 10;
789
790 if (phystatus & PHYSTATUS_100M)
791 speed = 100;
792
793 if (phystatus & PHYSTATUS_1000M)
794 speed = 1000;
795
796 ddf_msg(LVL_NOTE, "%s: Speed %dMbit/s, %s", ddf_dev_get_name(dev), speed, fdx);
797 } else {
798 ddf_msg(LVL_NOTE, "%s: Link down", ddf_dev_get_name(dev));
799 }
800
801}
802
803/** Notify NIC framework about HW filtering state when promisc mode was disabled
804 *
805 * @param nic_data The NIC data
806 * @param mcast_mode Current multicast mode
807 * @param was_promisc Sign if the promiscuous mode was active before disabling
808 */
809inline static void rtl8169_rcx_promics_rem(nic_t *nic_data,
810 nic_multicast_mode_t mcast_mode, uint8_t was_promisc)
811{
812 assert(nic_data);
813
814 if (was_promisc != 0) {
815 if (mcast_mode == NIC_MULTICAST_LIST)
816 nic_report_hw_filtering(nic_data, 1, 0, -1);
817 else
818 nic_report_hw_filtering(nic_data, 1, 1, -1);
819 } else {
820 nic_report_hw_filtering(nic_data, 1, -1, -1);
821 }
822}
823
824static errno_t rtl8169_unicast_set(nic_t *nic_data, nic_unicast_mode_t mode,
825 const nic_address_t *addr, size_t addr_count)
826{
827 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
828 uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
829 uint8_t was_promisc = rcr & RCR_ACCEPT_ALL_PHYS;
830 nic_multicast_mode_t mcast_mode;
831
832 nic_query_multicast(nic_data, &mcast_mode, 0, NULL, NULL);
833
834 ddf_msg(LVL_DEBUG, "Unicast RX filter mode: %d", mode);
835
836
837 switch (mode) {
838 case NIC_UNICAST_BLOCKED:
839 rtl8169->rcr_ucast = 0;
840 rtl8169_rcx_promics_rem(nic_data, mcast_mode, was_promisc);
841 break;
842 case NIC_UNICAST_DEFAULT:
843 rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH;
844 rtl8169_rcx_promics_rem(nic_data, mcast_mode, was_promisc);
845 break;
846 case NIC_UNICAST_LIST:
847 rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS;
848
849 if (mcast_mode == NIC_MULTICAST_PROMISC)
850 nic_report_hw_filtering(nic_data, 0, 1, -1);
851 else
852 nic_report_hw_filtering(nic_data, 0, 0, -1);
853 break;
854 case NIC_UNICAST_PROMISC:
855 rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS;
856
857 if (mcast_mode == NIC_MULTICAST_PROMISC)
858 nic_report_hw_filtering(nic_data, 1, 1, -1);
859 else
860 nic_report_hw_filtering(nic_data, 1, 0, -1);
861 break;
862 default:
863 return ENOTSUP;
864 }
865
866 fibril_mutex_lock(&rtl8169->rx_lock);
867
868 rcr &= ~(RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS);
869 pio_write_32(rtl8169->regs + RCR, rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
870 ddf_msg(LVL_DEBUG, "new RCR value: 0x%08x", rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
871
872 fibril_mutex_unlock(&rtl8169->rx_lock);
873 return EOK;
874}
875
876static errno_t rtl8169_multicast_set(nic_t *nic_data, nic_multicast_mode_t mode,
877 const nic_address_t *addr, size_t addr_count)
878{
879 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
880 uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
881 uint64_t mask;
882
883 ddf_msg(LVL_DEBUG, "Multicast RX filter mode: %d", mode);
884
885 switch (mode) {
886 case NIC_MULTICAST_BLOCKED:
887 rtl8169->rcr_mcast = 0;
888 if ((rtl8169->rcr_ucast & RCR_ACCEPT_ALL_PHYS) != 0)
889 nic_report_hw_filtering(nic_data, -1, 0, -1);
890 else
891 nic_report_hw_filtering(nic_data, -1, 1, -1);
892 break;
893 case NIC_MULTICAST_LIST:
894 mask = nic_mcast_hash(addr, addr_count);
895 pio_write_32(rtl8169->regs + MAR0, (uint32_t)mask);
896 pio_write_32(rtl8169->regs + MAR0 + 4, (uint32_t)(mask >> 32));
897 rtl8169->rcr_mcast = RCR_ACCEPT_MULTICAST;
898 nic_report_hw_filtering(nic_data, -1, 0, -1);
899 break;
900 case NIC_MULTICAST_PROMISC:
901 pio_write_32(rtl8169->regs + MAR0, 0xffffffffULL);
902 pio_write_32(rtl8169->regs + MAR0 + 4, (uint32_t)(0xffffffffULL >> 32));
903 rtl8169->rcr_mcast = RCR_ACCEPT_MULTICAST;
904 nic_report_hw_filtering(nic_data, -1, 1, -1);
905 break;
906 default:
907 return ENOTSUP;
908 }
909
910 fibril_mutex_lock(&rtl8169->rx_lock);
911
912 rcr &= ~(RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS);
913 pio_write_32(rtl8169->regs + RCR, rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
914 ddf_msg(LVL_DEBUG, "new RCR value: 0x%08x", rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
915
916 fibril_mutex_unlock(&rtl8169->rx_lock);
917 return EOK;
918}
919
920static errno_t rtl8169_broadcast_set(nic_t *nic_data, nic_broadcast_mode_t mode)
921{
922 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
923
924 /* Configure Receive Control Register */
925 uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
926
927 ddf_msg(LVL_DEBUG, "Broadcast RX filter mode: %d", mode);
928
929 switch (mode) {
930 case NIC_BROADCAST_BLOCKED:
931 rcr &= ~RCR_ACCEPT_BROADCAST;
932 break;
933 case NIC_BROADCAST_ACCEPTED:
934 rcr |= RCR_ACCEPT_BROADCAST;
935 break;
936 default:
937 return ENOTSUP;
938 }
939
940 pio_write_32(rtl8169->regs + RCR, rcr);
941 ddf_msg(LVL_DEBUG, " new RCR value: 0x%08x", rcr);
942
943 return EOK;
944}
945
946static void rtl8169_transmit_done(ddf_dev_t *dev)
947{
948 unsigned int tail, head;
949 nic_t *nic_data = nic_get_from_ddf_dev(dev);
950 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
951 rtl8169_descr_t *descr;
952 int sent = 0;
953
954 ddf_msg(LVL_DEBUG, "rtl8169_transmit_done()");
955
956 fibril_mutex_lock(&rtl8169->tx_lock);
957
958 head = rtl8169->tx_head;
959 tail = rtl8169->tx_tail;
960
961 while (tail != head) {
962 descr = &rtl8169->tx_ring[tail];
963 descr->control &= (~CONTROL_OWN);
964 write_barrier();
965 ddf_msg(LVL_DEBUG, "TX status for descr %d: 0x%08x", tail, descr->control);
966
967 tail = (tail + 1) % TX_BUFFERS_COUNT;
968 sent++;
969 }
970
971 if (sent != 0)
972 nic_set_tx_busy(nic_data, 0);
973
974 rtl8169->tx_tail = tail;
975
976 fibril_mutex_unlock(&rtl8169->tx_lock);
977}
978
979static void rtl8169_receive_done(ddf_dev_t *dev)
980{
981 nic_t *nic_data = nic_get_from_ddf_dev(dev);
982 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
983 rtl8169_descr_t *descr;
984 nic_frame_list_t *frames = nic_alloc_frame_list();
985 nic_frame_t *frame;
986 void *buffer;
987 unsigned int tail, fsidx = 0;
988 int frame_size;
989
990 ddf_msg(LVL_DEBUG, "rtl8169_receive_done()");
991
992 fibril_mutex_lock(&rtl8169->rx_lock);
993
994 tail = rtl8169->rx_tail;
995
996 while (true) {
997 descr = &rtl8169->rx_ring[tail];
998
999 if (descr->control & CONTROL_OWN)
1000 break;
1001
1002 if (descr->control & RXSTATUS_RES) {
1003 ddf_msg(LVL_WARN, "error at slot %d: 0x%08x\n", tail, descr->control);
1004 tail = (tail + 1) % RX_BUFFERS_COUNT;
1005 continue;
1006 }
1007
1008 if (descr->control & CONTROL_FS)
1009 fsidx = tail;
1010
1011 if (descr->control & CONTROL_LS) {
1012 ddf_msg(LVL_DEBUG, "received message at slot %d, control 0x%08x", tail, descr->control);
1013
1014 if (fsidx != tail)
1015 ddf_msg(LVL_WARN, "single frame spanning multiple descriptors");
1016
1017 frame_size = descr->control & 0x1fff;
1018 buffer = rtl8169->rx_buff + (BUFFER_SIZE * tail);
1019 frame = nic_alloc_frame(nic_data, frame_size);
1020 memcpy(frame->data, buffer, frame_size);
1021 nic_frame_list_append(frames, frame);
1022 }
1023
1024 tail = (tail + 1) % RX_BUFFERS_COUNT;
1025 }
1026
1027 rtl8169_rx_ring_refill(rtl8169, rtl8169->rx_tail, tail);
1028
1029 rtl8169->rx_tail = tail;
1030
1031 fibril_mutex_unlock(&rtl8169->rx_lock);
1032
1033 nic_received_frame_list(nic_data, frames);
1034
1035}
1036
1037static void rtl8169_irq_handler(ipc_call_t *icall, ddf_dev_t *dev)
1038{
1039 assert(dev);
1040 assert(icall);
1041
1042 uint16_t isr = (uint16_t) IPC_GET_ARG2(*icall) & INT_KNOWN;
1043 nic_t *nic_data = nic_get_from_ddf_dev(dev);
1044 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
1045
1046 ddf_msg(LVL_DEBUG, "rtl8169_irq_handler(): isr=0x%04x", isr);
1047 pio_write_16(rtl8169->regs + IMR, 0xffff);
1048
1049 while (isr != 0) {
1050 ddf_msg(LVL_DEBUG, "irq handler: remaining isr=0x%04x", isr);
1051
1052 /* Packet underrun or link change */
1053 if (isr & INT_PUN) {
1054 rtl8169_link_change(dev);
1055 pio_write_16(rtl8169->regs + ISR, INT_PUN);
1056 }
1057
1058 /* Transmit notification */
1059 if (isr & (INT_TER | INT_TOK | INT_TDU)) {
1060 rtl8169_transmit_done(dev);
1061 pio_write_16(rtl8169->regs + ISR, (INT_TER | INT_TOK | INT_TDU));
1062 }
1063
1064 /* Receive underrun */
1065 if (isr & INT_RXOVW) {
1066 /* just ack.. */
1067 pio_write_16(rtl8169->regs + ISR, INT_RXOVW);
1068 }
1069
1070 if (isr & INT_SERR) {
1071 ddf_msg(LVL_ERROR, "System error interrupt");
1072 pio_write_16(rtl8169->regs + ISR, INT_SERR);
1073 }
1074
1075 if (isr & (INT_RER | INT_ROK)) {
1076 rtl8169_receive_done(dev);
1077 pio_write_16(rtl8169->regs + ISR, (INT_RER | INT_ROK));
1078 }
1079
1080 isr = pio_read_16(rtl8169->regs + ISR) & INT_KNOWN;
1081 }
1082
1083 pio_write_16(rtl8169->regs + ISR, 0xffff);
1084}
1085
1086static void rtl8169_send_frame(nic_t *nic_data, void *data, size_t size)
1087{
1088 rtl8169_descr_t *descr, *prev;
1089 unsigned int head, tail;
1090 void *buff;
1091 uint64_t buff_phys;
1092 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
1093
1094 if (size > RTL8169_FRAME_MAX_LENGTH) {
1095 ddf_msg(LVL_ERROR, "Send frame: frame too long, %zu bytes",
1096 size);
1097 nic_report_send_error(nic_data, NIC_SEC_OTHER, 1);
1098 }
1099
1100 fibril_mutex_lock(&rtl8169->tx_lock);
1101
1102 ddf_msg(LVL_DEBUG, "send_frame: size: %zu, tx_head=%d tx_tail=%d",
1103 size, rtl8169->tx_head, rtl8169->tx_tail);
1104
1105 head = rtl8169->tx_head;
1106 tail = rtl8169->tx_tail;
1107
1108 if ((head + 1) % TX_BUFFERS_COUNT == tail) {
1109 /* Queue is full */
1110 ddf_msg(LVL_WARN, "TX queue full!");
1111 nic_set_tx_busy(nic_data, 1);
1112 }
1113
1114 /* Calculate address of next free buffer and descriptor */
1115 buff = rtl8169->tx_buff + (BUFFER_SIZE * head);
1116 buff_phys = rtl8169->tx_buff_phys + (BUFFER_SIZE * head);
1117
1118 /* Copy frame */
1119 memcpy(buff, data, size);
1120
1121 /* Setup descriptor */
1122 descr = &rtl8169->tx_ring[head];
1123 prev = &rtl8169->tx_ring[(head - 1) % TX_BUFFERS_COUNT];
1124
1125 ddf_msg(LVL_DEBUG, "current_descr=%p, prev_descr=%p", descr, prev);
1126
1127 descr->control = CONTROL_OWN | CONTROL_FS | CONTROL_LS;
1128 descr->control |= size & 0xffff;
1129 descr->vlan = 0;
1130 descr->buf_low = buff_phys & 0xffffffff;
1131 descr->buf_high = (buff_phys >> 32) & 0xffffffff;
1132
1133 if (head == TX_BUFFERS_COUNT - 1)
1134 descr->control |= CONTROL_EOR;
1135
1136 rtl8169->tx_head = (head + 1) % TX_BUFFERS_COUNT;
1137
1138 ddf_msg(LVL_DEBUG, "control: 0x%08x", descr->control);
1139
1140 write_barrier();
1141
1142 /* Notify NIC of pending packets */
1143 pio_write_8(rtl8169->regs + TPPOLL, TPPOLL_NPQ);
1144 write_barrier();
1145
1146 fibril_mutex_unlock(&rtl8169->tx_lock);
1147}
1148
1149static inline void rtl8169_get_hwaddr(rtl8169_t *rtl8169, nic_address_t *addr)
1150{
1151 int i;
1152
1153 assert(rtl8169);
1154 assert(addr);
1155
1156 for (i = 0; i < 6; i++)
1157 addr->address[i] = pio_read_8(rtl8169->regs + MAC0 + i);
1158}
1159
1160static inline void rtl8169_set_hwaddr(rtl8169_t *rtl8169, const nic_address_t *addr)
1161{
1162 int i;
1163
1164 assert(rtl8169);
1165 assert(addr);
1166
1167 for (i = 0; i < 6; i++)
1168 pio_write_8(rtl8169->regs + MAC0 + i, addr->address[i]);
1169}
1170
1171static uint16_t rtl8169_mii_read(rtl8169_t *rtl8169, uint8_t addr)
1172{
1173 uint32_t phyar;
1174
1175 phyar = PHYAR_RW_READ |
1176 ((addr & PHYAR_ADDR_MASK) << PHYAR_ADDR_SHIFT);
1177
1178 pio_write_32(rtl8169->regs + PHYAR, phyar);
1179
1180 do {
1181 phyar = pio_read_32(rtl8169->regs + PHYAR);
1182 async_usleep(20);
1183 } while ((phyar & PHYAR_RW_WRITE) == 0);
1184
1185 return phyar & PHYAR_DATA_MASK;
1186}
1187
1188static void rtl8169_mii_write(rtl8169_t *rtl8169, uint8_t addr, uint16_t value)
1189{
1190 uint32_t phyar;
1191
1192 phyar = PHYAR_RW_WRITE |
1193 ((addr & PHYAR_ADDR_MASK) << PHYAR_ADDR_SHIFT) |
1194 (value & PHYAR_DATA_MASK);
1195
1196 pio_write_32(rtl8169->regs + PHYAR, phyar);
1197
1198 do {
1199 phyar = pio_read_32(rtl8169->regs + PHYAR);
1200 async_usleep(20);
1201 } while ((phyar & PHYAR_RW_WRITE) != 0);
1202
1203 async_usleep(20);
1204}
1205
1206/** Main function of RTL8169 driver
1207 *
1208 * Just initialize the driver structures and
1209 * put it into the device drivers interface
1210 */
1211int main(void)
1212{
1213 errno_t rc = nic_driver_init(NAME);
1214 if (rc != EOK)
1215 return rc;
1216 nic_driver_implement(
1217 &rtl8169_driver_ops, &rtl8169_dev_ops, &rtl8169_nic_iface);
1218
1219 ddf_log_init(NAME);
1220 ddf_msg(LVL_NOTE, "HelenOS RTL8169 driver started");
1221 return ddf_driver_main(&rtl8169_driver);
1222}
Note: See TracBrowser for help on using the repository browser.