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

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

Merge commit '50f19b7ee8e94570b5c63896736c4eb49cfa18db' into forwardport

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

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