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

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

Let leaf drivers enable/disable/clear interrupts via hw_res instead of directly using irc.

  • Property mode set to 100644
File size: 32.6 KB
Line 
1/*
2 * Copyright (c) 2014 Agnieszka Tabaka
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <assert.h>
30#include <errno.h>
31#include <align.h>
32#include <byteorder.h>
33#include <libarch/barrier.h>
34
35#include <as.h>
36#include <thread.h>
37#include <ddf/log.h>
38#include <ddf/interrupt.h>
39#include <device/hw_res.h>
40#include <device/hw_res_parsed.h>
41#include <io/log.h>
42#include <nic.h>
43#include <pci_dev_iface.h>
44
45#include <sysinfo.h>
46#include <ipc/ns.h>
47
48#include <str.h>
49
50#include "defs.h"
51#include "driver.h"
52
53/** Global mutex for work with shared irq structure */
54FIBRIL_MUTEX_INITIALIZE(irq_reg_lock);
55
56static int rtl8169_set_addr(ddf_fun_t *fun, const nic_address_t *addr);
57static int rtl8169_get_device_info(ddf_fun_t *fun, nic_device_info_t *info);
58static int rtl8169_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state);
59static int rtl8169_get_operation_mode(ddf_fun_t *fun, int *speed,
60 nic_channel_mode_t *duplex, nic_role_t *role);
61static int rtl8169_set_operation_mode(ddf_fun_t *fun, int speed,
62 nic_channel_mode_t duplex, nic_role_t role);
63static int rtl8169_pause_get(ddf_fun_t *fun, nic_result_t *we_send,
64 nic_result_t *we_receive, uint16_t *time);
65static int rtl8169_pause_set(ddf_fun_t *fun, int allow_send, int allow_receive,
66 uint16_t time);
67static int rtl8169_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement);
68static int rtl8169_autoneg_disable(ddf_fun_t *fun);
69static int rtl8169_autoneg_probe(ddf_fun_t *fun, uint32_t *advertisement,
70 uint32_t *their_adv, nic_result_t *result, nic_result_t *their_result);
71static int rtl8169_autoneg_restart(ddf_fun_t *fun);
72static int rtl8169_defective_get_mode(ddf_fun_t *fun, uint32_t *mode);
73static int rtl8169_defective_set_mode(ddf_fun_t *fun, uint32_t mode);
74static int rtl8169_on_activated(nic_t *nic_data);
75static int rtl8169_on_stopped(nic_t *nic_data);
76static void rtl8169_send_frame(nic_t *nic_data, void *data, size_t size);
77static void rtl8169_irq_handler(ipc_callid_t iid, ipc_call_t *icall,
78 ddf_dev_t *dev);
79static inline int rtl8169_register_int_handler(nic_t *nic_data);
80static inline void rtl8169_get_hwaddr(rtl8169_t *rtl8169, nic_address_t *addr);
81static inline void rtl8169_set_hwaddr(rtl8169_t *rtl8169, const nic_address_t *addr);
82
83static void rtl8169_reset(rtl8169_t *rtl8169);
84static int rtl8169_get_resource_info(ddf_dev_t *dev);
85static int rtl8169_fill_resource_info(ddf_dev_t *dev, const hw_res_list_parsed_t *hw_resources);
86static rtl8169_t *rtl8169_create_dev_data(ddf_dev_t *dev);
87
88static int rtl8169_unicast_set(nic_t *nic_data, nic_unicast_mode_t mode,
89 const nic_address_t *, size_t);
90static int rtl8169_multicast_set(nic_t *nic_data, nic_multicast_mode_t mode,
91 const nic_address_t *addr, size_t addr_count);
92static int rtl8169_broadcast_set(nic_t *nic_data, nic_broadcast_mode_t mode);
93
94static uint16_t rtl8169_mii_read(rtl8169_t *rtl8169, uint8_t addr);
95static void rtl8169_mii_write(rtl8169_t *rtl8169, uint8_t addr, uint16_t value);
96static void rtl8169_rx_ring_refill(rtl8169_t *rtl8169, unsigned int first,
97 unsigned int last);
98
99/** Network interface options for RTL8169 card driver */
100static nic_iface_t rtl8169_nic_iface = {
101 .set_address = &rtl8169_set_addr,
102 .get_device_info = &rtl8169_get_device_info,
103 .get_cable_state = &rtl8169_get_cable_state,
104 .get_operation_mode = &rtl8169_get_operation_mode,
105 .set_operation_mode = &rtl8169_set_operation_mode,
106
107 .get_pause = &rtl8169_pause_get,
108 .set_pause = &rtl8169_pause_set,
109
110 .autoneg_enable = &rtl8169_autoneg_enable,
111 .autoneg_disable = &rtl8169_autoneg_disable,
112 .autoneg_probe = &rtl8169_autoneg_probe,
113 .autoneg_restart = &rtl8169_autoneg_restart,
114
115 .defective_get_mode = &rtl8169_defective_get_mode,
116 .defective_set_mode = &rtl8169_defective_set_mode,
117};
118
119irq_pio_range_t rtl8169_irq_pio_ranges[] = {
120 {
121 .base = 0,
122 .size = RTL8169_IO_SIZE
123 }
124};
125
126irq_cmd_t rtl8169_irq_commands[] = {
127 {
128 /* Get the interrupt status */
129 .cmd = CMD_PIO_READ_16,
130 .addr = NULL,
131 .dstarg = 2
132 },
133 {
134 .cmd = CMD_PREDICATE,
135 .value = 3,
136 .srcarg = 2
137 },
138 {
139 /* Mark interrupts as solved */
140 .cmd = CMD_PIO_WRITE_16,
141 .addr = NULL,
142 .value = 0xFFFF
143 },
144 {
145 /* Disable interrupts until interrupt routine is finished */
146 .cmd = CMD_PIO_WRITE_16,
147 .addr = NULL,
148 .value = 0x0000
149 },
150 {
151 .cmd = CMD_ACCEPT
152 }
153};
154
155/** Interrupt code definition */
156irq_code_t rtl8169_irq_code = {
157 .rangecount = sizeof(rtl8169_irq_pio_ranges) / sizeof(irq_pio_range_t),
158 .ranges = rtl8169_irq_pio_ranges,
159 .cmdcount = sizeof(rtl8169_irq_commands) / sizeof(irq_cmd_t),
160 .cmds = rtl8169_irq_commands
161};
162
163/** Basic device operations for RTL8169 driver */
164static ddf_dev_ops_t rtl8169_dev_ops;
165
166static int rtl8169_dev_add(ddf_dev_t *dev);
167
168/** Basic driver operations for RTL8169 driver */
169static driver_ops_t rtl8169_driver_ops = {
170 .dev_add = &rtl8169_dev_add,
171};
172
173/** Driver structure for RTL8169 driver */
174static driver_t rtl8169_driver = {
175 .name = NAME,
176 .driver_ops = &rtl8169_driver_ops
177};
178
179static int rtl8169_get_resource_info(ddf_dev_t *dev)
180{
181 assert(dev);
182
183 nic_t *nic_data = nic_get_from_ddf_dev(dev);
184 assert(nic_data);
185
186 hw_res_list_parsed_t hw_res_parsed;
187 hw_res_list_parsed_init(&hw_res_parsed);
188
189 /* Get hw resources form parent driver */
190 int rc = nic_get_resources(nic_data, &hw_res_parsed);
191 if (rc != EOK)
192 return rc;
193
194 /* Fill resources information to the device */
195 int ret = rtl8169_fill_resource_info(dev, &hw_res_parsed);
196 hw_res_list_parsed_clean(&hw_res_parsed);
197
198 return ret;
199}
200
201static int rtl8169_fill_resource_info(ddf_dev_t *dev, const hw_res_list_parsed_t
202 *hw_resources)
203{
204 assert(dev);
205 assert(hw_resources);
206
207 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_dev(dev));
208 assert(rtl8169);
209
210 if (hw_resources->irqs.count != 1) {
211 ddf_msg(LVL_ERROR, "%s device: unexpected irq count", ddf_dev_get_name(dev));
212 return EINVAL;
213 };
214
215 if (hw_resources->io_ranges.count != 1) {
216 ddf_msg(LVL_ERROR, "%s device: unexpected io ranges count", ddf_dev_get_name(dev));
217 return EINVAL;
218 }
219
220 rtl8169->irq = hw_resources->irqs.irqs[0];
221 ddf_msg(LVL_DEBUG, "%s device: irq 0x%x assigned", ddf_dev_get_name(dev), rtl8169->irq);
222
223 rtl8169->regs_phys = (void *)((size_t)RNGABS(hw_resources->io_ranges.ranges[0]));
224 if (hw_resources->io_ranges.ranges[0].size < RTL8169_IO_SIZE) {
225 ddf_msg(LVL_ERROR, "I/O range assigned to the device "
226 "%s is too small.", ddf_dev_get_name(dev));
227 return EINVAL;
228 }
229 ddf_msg(LVL_DEBUG, "%s device: i/o addr %p assigned.", ddf_dev_get_name(dev), rtl8169->regs_phys);
230
231 return EOK;
232}
233
234static int rtl8169_allocate_buffers(rtl8169_t *rtl8169)
235{
236 int rc;
237
238 ddf_msg(LVL_DEBUG, "Allocating DMA buffer rings");
239
240 /* Allocate TX ring */
241 rtl8169->tx_ring = AS_AREA_ANY;
242 rc = dmamem_map_anonymous(TX_RING_SIZE, DMAMEM_4GiB,
243 AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->tx_ring_phys,
244 (void **)&rtl8169->tx_ring);
245
246 if (rc != EOK)
247 return rc;
248
249 ddf_msg(LVL_DEBUG, "TX ring address: phys=0x%#" PRIxn ", virt=%p",
250 rtl8169->tx_ring_phys, rtl8169->tx_ring);
251
252 memset(rtl8169->tx_ring, 0, TX_RING_SIZE);
253
254 /* Allocate RX ring */
255 rtl8169->rx_ring = AS_AREA_ANY;
256 rc = dmamem_map_anonymous(RX_RING_SIZE, DMAMEM_4GiB,
257 AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->rx_ring_phys,
258 (void **)&rtl8169->rx_ring);
259
260 if (rc != EOK)
261 return rc;
262
263 ddf_msg(LVL_DEBUG, "RX ring address: phys=0x%#" PRIxn ", virt=%p",
264 rtl8169->rx_ring_phys, rtl8169->rx_ring);
265
266 memset(rtl8169->rx_ring, 0, RX_RING_SIZE);
267
268 /* Allocate TX buffers */
269 rtl8169->tx_buff = AS_AREA_ANY;
270 rc = dmamem_map_anonymous(TX_BUFFERS_SIZE, DMAMEM_4GiB,
271 AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->tx_buff_phys,
272 &rtl8169->tx_buff);
273
274 if (rc != EOK)
275 return rc;
276
277 ddf_msg(LVL_DEBUG, "TX buffers base address: phys=0x%#" PRIxn " virt=%p",
278 rtl8169->tx_buff_phys, rtl8169->tx_buff);
279
280 /* Allocate RX buffers */
281 rtl8169->rx_buff = AS_AREA_ANY;
282 rc = dmamem_map_anonymous(RX_BUFFERS_SIZE, DMAMEM_4GiB,
283 AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->rx_buff_phys,
284 &rtl8169->rx_buff);
285
286 if (rc != EOK)
287 return rc;
288
289 ddf_msg(LVL_DEBUG, "RX buffers base address: phys=0x%#" PRIxn ", virt=%p",
290 rtl8169->rx_buff_phys, rtl8169->rx_buff);
291
292 return EOK;
293}
294
295static rtl8169_t *rtl8169_create_dev_data(ddf_dev_t *dev)
296{
297 assert(dev);
298 assert(!nic_get_from_ddf_dev(dev));
299
300 nic_t *nic_data = nic_create_and_bind(dev);
301 if (!nic_data)
302 return NULL;
303
304 rtl8169_t *rtl8169 = malloc(sizeof(rtl8169_t));
305 if (!rtl8169) {
306 nic_unbind_and_destroy(dev);
307 return NULL;
308 }
309
310 memset(rtl8169, 0, sizeof(rtl8169_t));
311
312 rtl8169->nic_data = nic_data;
313 nic_set_specific(nic_data, rtl8169);
314 nic_set_send_frame_handler(nic_data, rtl8169_send_frame);
315 nic_set_state_change_handlers(nic_data,
316 rtl8169_on_activated, NULL, rtl8169_on_stopped);
317 nic_set_filtering_change_handlers(nic_data,
318 rtl8169_unicast_set, rtl8169_multicast_set, rtl8169_broadcast_set,
319 NULL, NULL);
320
321 fibril_mutex_initialize(&rtl8169->rx_lock);
322 fibril_mutex_initialize(&rtl8169->tx_lock);
323
324 nic_set_wol_max_caps(nic_data, NIC_WV_BROADCAST, 1);
325 nic_set_wol_max_caps(nic_data, NIC_WV_LINK_CHANGE, 1);
326 nic_set_wol_max_caps(nic_data, NIC_WV_MAGIC_PACKET, 1);
327
328 return rtl8169;
329}
330
331static void rtl8169_dev_cleanup(ddf_dev_t *dev)
332{
333 assert(dev);
334
335 if (ddf_dev_data_get(dev))
336 nic_unbind_and_destroy(dev);
337}
338
339static int rtl8169_dev_initialize(ddf_dev_t *dev)
340{
341 int ret;
342
343 rtl8169_t *rtl8169 = rtl8169_create_dev_data(dev);
344 if (rtl8169 == NULL) {
345 ddf_msg(LVL_ERROR, "Not enough memory for initializing %s.", ddf_dev_get_name(dev));
346 return ENOMEM;
347 }
348
349 ret = rtl8169_get_resource_info(dev);
350 if (ret != EOK) {
351 ddf_msg(LVL_ERROR, "Can't obtain H/W resources information");
352 goto failed;
353 }
354
355 ddf_msg(LVL_DEBUG, "The device is initialized");
356 return ret;
357
358failed:
359 ddf_msg(LVL_ERROR, "The device initialization failed");
360 rtl8169_dev_cleanup(dev);
361 return ret;
362
363}
364
365inline static int rtl8169_register_int_handler(nic_t *nic_data)
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 int irq_cap = register_interrupt_handler(nic_get_ddf_dev(nic_data),
374 rtl8169->irq, rtl8169_irq_handler, &rtl8169_irq_code);
375
376 return irq_cap;
377}
378
379static int rtl8169_dev_add(ddf_dev_t *dev)
380{
381 ddf_fun_t *fun;
382 nic_address_t nic_addr;
383 int 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 int irq_cap = rtl8169_register_int_handler(nic_data);
434 if (irq_cap < 0) {
435 rc = irq_cap;
436 ddf_msg(LVL_ERROR, "Failed to register IRQ handler (%d)", 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_cap);
477err_irq:
478err_pio:
479err_destroy:
480 rtl8169_dev_cleanup(dev);
481 return rc;
482
483 return EOK;
484}
485
486static int 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 int 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 int 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 int 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 int 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 int 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 int 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 int rtl8169_pause_set(ddf_fun_t *fun, int allow_send, int allow_receive,
606 uint16_t time)
607{
608 return EOK;
609}
610
611static int 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 int 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 int 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 int 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 int rtl8169_defective_get_mode(ddf_fun_t *fun, uint32_t *mode)
663{
664 return EOK;
665}
666
667static int 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 for (;;) {
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 int rtl8169_on_activated(nic_t *nic_data)
697{
698 int 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: %d", 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 int 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 thread_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 int 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 int 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 int 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 for (;;) {
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_callid_t iid, ipc_call_t *icall,
1038 ddf_dev_t *dev)
1039{
1040 assert(dev);
1041 assert(icall);
1042
1043 uint16_t isr = (uint16_t) IPC_GET_ARG2(*icall) & INT_KNOWN;
1044 nic_t *nic_data = nic_get_from_ddf_dev(dev);
1045 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
1046
1047 ddf_msg(LVL_DEBUG, "rtl8169_irq_handler(): isr=0x%04x", isr);
1048 pio_write_16(rtl8169->regs + IMR, 0xffff);
1049
1050 while (isr != 0) {
1051 ddf_msg(LVL_DEBUG, "irq handler: remaining isr=0x%04x", isr);
1052
1053 /* Packet underrun or link change */
1054 if (isr & INT_PUN) {
1055 rtl8169_link_change(dev);
1056 pio_write_16(rtl8169->regs + ISR, INT_PUN);
1057 }
1058
1059 /* Transmit notification */
1060 if (isr & (INT_TER | INT_TOK | INT_TDU)) {
1061 rtl8169_transmit_done(dev);
1062 pio_write_16(rtl8169->regs + ISR, (INT_TER | INT_TOK | INT_TDU));
1063 }
1064
1065 /* Receive underrun */
1066 if (isr & INT_RXOVW) {
1067 /* just ack.. */
1068 pio_write_16(rtl8169->regs + ISR, INT_RXOVW);
1069 }
1070
1071 if (isr & INT_SERR) {
1072 ddf_msg(LVL_ERROR, "System error interrupt");
1073 pio_write_16(rtl8169->regs + ISR, INT_SERR);
1074 }
1075
1076 if (isr & (INT_RER | INT_ROK)) {
1077 rtl8169_receive_done(dev);
1078 pio_write_16(rtl8169->regs + ISR, (INT_RER | INT_ROK));
1079 }
1080
1081 isr = pio_read_16(rtl8169->regs + ISR) & INT_KNOWN;
1082 }
1083
1084 pio_write_16(rtl8169->regs + ISR, 0xffff);
1085}
1086
1087static void rtl8169_send_frame(nic_t *nic_data, void *data, size_t size)
1088{
1089 rtl8169_descr_t *descr, *prev;
1090 unsigned int head, tail;
1091 void *buff;
1092 uint64_t buff_phys;
1093 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
1094
1095 if (size > RTL8169_FRAME_MAX_LENGTH) {
1096 ddf_msg(LVL_ERROR, "Send frame: frame too long, %zu bytes",
1097 size);
1098 nic_report_send_error(nic_data, NIC_SEC_OTHER, 1);
1099 }
1100
1101 fibril_mutex_lock(&rtl8169->tx_lock);
1102
1103 ddf_msg(LVL_DEBUG, "send_frame: size: %zu, tx_head=%d tx_tail=%d",
1104 size, rtl8169->tx_head, rtl8169->tx_tail);
1105
1106 head = rtl8169->tx_head;
1107 tail = rtl8169->tx_tail;
1108
1109 if ((head + 1) % TX_BUFFERS_COUNT == tail) {
1110 /* Queue is full */
1111 ddf_msg(LVL_WARN, "TX queue full!");
1112 nic_set_tx_busy(nic_data, 1);
1113 }
1114
1115 /* Calculate address of next free buffer and descriptor */
1116 buff = rtl8169->tx_buff + (BUFFER_SIZE * head);
1117 buff_phys = rtl8169->tx_buff_phys + (BUFFER_SIZE * head);
1118
1119 /* Copy frame */
1120 memcpy(buff, data, size);
1121
1122 /* Setup descriptor */
1123 descr = &rtl8169->tx_ring[head];
1124 prev = &rtl8169->tx_ring[(head - 1) % TX_BUFFERS_COUNT];
1125
1126 ddf_msg(LVL_DEBUG, "current_descr=%p, prev_descr=%p", descr, prev);
1127
1128 descr->control = CONTROL_OWN | CONTROL_FS | CONTROL_LS;
1129 descr->control |= size & 0xffff;
1130 descr->vlan = 0;
1131 descr->buf_low = buff_phys & 0xffffffff;
1132 descr->buf_high = (buff_phys >> 32) & 0xffffffff;
1133
1134 if (head == TX_BUFFERS_COUNT - 1)
1135 descr->control |= CONTROL_EOR;
1136
1137 rtl8169->tx_head = (head + 1) % TX_BUFFERS_COUNT;
1138
1139 ddf_msg(LVL_DEBUG, "control: 0x%08x", descr->control);
1140
1141 write_barrier();
1142
1143 /* Notify NIC of pending packets */
1144 pio_write_8(rtl8169->regs + TPPOLL, TPPOLL_NPQ);
1145 write_barrier();
1146
1147 fibril_mutex_unlock(&rtl8169->tx_lock);
1148}
1149
1150static inline void rtl8169_get_hwaddr(rtl8169_t *rtl8169, nic_address_t *addr)
1151{
1152 int i;
1153
1154 assert(rtl8169);
1155 assert(addr);
1156
1157 for (i = 0; i < 6; i++)
1158 addr->address[i] = pio_read_8(rtl8169->regs + MAC0 + i);
1159}
1160
1161static inline void rtl8169_set_hwaddr(rtl8169_t *rtl8169, const nic_address_t *addr)
1162{
1163 int i;
1164
1165 assert(rtl8169);
1166 assert(addr);
1167
1168 for (i = 0; i < 6; i++)
1169 pio_write_8(rtl8169->regs + MAC0 + i, addr->address[i]);
1170}
1171
1172static uint16_t rtl8169_mii_read(rtl8169_t *rtl8169, uint8_t addr)
1173{
1174 uint32_t phyar;
1175
1176 phyar = PHYAR_RW_READ
1177 | ((addr & PHYAR_ADDR_MASK) << PHYAR_ADDR_SHIFT);
1178
1179 pio_write_32(rtl8169->regs + PHYAR, phyar);
1180
1181 do {
1182 phyar = pio_read_32(rtl8169->regs + PHYAR);
1183 thread_usleep(20);
1184 } while ((phyar & PHYAR_RW_WRITE) == 0);
1185
1186 return phyar & PHYAR_DATA_MASK;
1187}
1188
1189static void rtl8169_mii_write(rtl8169_t *rtl8169, uint8_t addr, uint16_t value)
1190{
1191 uint32_t phyar;
1192
1193 phyar = PHYAR_RW_WRITE
1194 | ((addr & PHYAR_ADDR_MASK) << PHYAR_ADDR_SHIFT)
1195 | (value & PHYAR_DATA_MASK);
1196
1197 pio_write_32(rtl8169->regs + PHYAR, phyar);
1198
1199 do {
1200 phyar = pio_read_32(rtl8169->regs + PHYAR);
1201 thread_usleep(20);
1202 } while ((phyar & PHYAR_RW_WRITE) != 0);
1203
1204 thread_usleep(20);
1205}
1206
1207/** Main function of RTL8169 driver
1208*
1209 * Just initialize the driver structures and
1210 * put it into the device drivers interface
1211 */
1212int main(void)
1213{
1214 int rc = nic_driver_init(NAME);
1215 if (rc != EOK)
1216 return rc;
1217 nic_driver_implement(
1218 &rtl8169_driver_ops, &rtl8169_dev_ops, &rtl8169_nic_iface);
1219
1220 ddf_log_init(NAME);
1221 ddf_msg(LVL_NOTE, "HelenOS RTL8169 driver started");
1222 return ddf_driver_main(&rtl8169_driver);
1223}
Note: See TracBrowser for help on using the repository browser.