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

Last change on this file since e846bec was fafb8e5, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Mechanically lowercase IPC_SET_*/IPC_GET_*

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