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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b19131c5 was 582a0b8, checked in by Jakub Jermar <jakub@…>, 8 years ago

Remove unistd.h

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