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

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

Eliminate uses of thread_usleep() in favor of async_usleep(). Obvious cases are in components that don't explicitly create threads.

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