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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 961a5ee was 5a6cc679, checked in by Jenda <jenda.jzqk73@…>, 8 years ago

Merge commit '50f19b7ee8e94570b5c63896736c4eb49cfa18db' into forwardport

Not all ints are converted to errno_t in xhci tree yet, however it compiles and works :)

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