Changeset 90782c36 in mainline


Ignore:
Timestamp:
2014-05-21T19:36:59Z (10 years ago)
Author:
Agnieszka Tabaka <nufcia@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
f1ac202
Parents:
fef725d
Message:

Work-in-progress driver skeleton, able to read MAC address from the card.

Files:
5 edited

Legend:

Unmodified
Added
Removed
  • boot/Makefile.common

    rfef725d r90782c36  
    138138        nic/e1k \
    139139        nic/rtl8139 \
     140        nic/rtl8169 \
    140141        block/ahci
    141142
  • uspace/drv/nic/rtl8169/Makefile

    rfef725d r90782c36  
    3434
    3535SOURCES = \
    36         driver.c \
    37         general.c \
    38         defs.c
     36        driver.c
    3937
    4038include $(USPACE_PREFIX)/Makefile.common
  • uspace/drv/nic/rtl8169/defs.h

    rfef725d r90782c36  
    8787        WAKEUP3LD = 0xa4, /**< Power Management Wakeup frame3 low dword, 8b */
    8888        WAKEUP3HD = 0xac, /**< Power Management Wakeup frame3 high dword, 8b */
    89         WAKEUP2LD = 0xb4, /**< Power Management Wakeup frame4 low dword, 8b */
    90         WAKEUP2HD = 0xbc, /**< Power Management Wakeup frame4 high dword, 8b */
     89        WAKEUP4LD = 0xb4, /**< Power Management Wakeup frame4 low dword, 8b */
     90        WAKEUP4HD = 0xbc, /**< Power Management Wakeup frame4 high dword, 8b */
    9191        CRC0 = 0xc4, /**< 16-bit CRC of wakeup frame 0, 2b */
    9292        CRC1 = 0xc6, /**< 16-bit CRC of wakeup frame 1, 2b */
     
    132132        CONFIG2_PCICLKF_SHIFT = 0,
    133133        CONFIG2_PCICLKF_SIZE = 2
    134 }'
     134};
    135135
    136136enum rtl8169_config3 {
     
    240240        ANAR_10_FD = (1 << 6), /**< 10BASE_T full duplex */
    241241        ANAR_10_HD = (1 << 5), /**< 10BASE_T half duplex */
    242         ANAR_SELECTOR = 0x1. /**< Selector */
     242        ANAR_SELECTOR = 0x1, /**< Selector */
     243};
     244
     245enum rtl8169_phystatus {
     246        PHYSTATUS_TBIEN = (1 << 7), /**< TBI enabled */
     247        PHYSTATUS_TXFLOW = (1 << 6), /**< TX flow control enabled */
     248        PHYSTATUS_RXFLOW = (1 << 5), /**< RX flow control enabled */
     249        PHYSTATUS_1000M = (1 << 4), /**< Link speed is 1000Mbit/s */
     250        PHYSTATUS_100M = (1 << 3), /**< Link speed is 100Mbit/s */
     251        PHYSTATUS_10M = (1 << 2), /**< Link speed is 10Mbit/s */
     252        PHYSTATUS_LINK = (1 << 1), /**< Link up */
     253        PHYSTATUS_FDX = (1 << 0), /**< Link is full duplex */
    243254};
    244255
  • uspace/drv/nic/rtl8169/driver.c

    rfef725d r90782c36  
    5555FIBRIL_MUTEX_INITIALIZE(irq_reg_lock);
    5656
     57static int rtl8169_set_addr(ddf_fun_t *fun, const nic_address_t *addr);
     58static int rtl8169_get_device_info(ddf_fun_t *fun, nic_device_info_t *info);
     59static int rtl8169_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state);
     60static int rtl8169_get_operation_mode(ddf_fun_t *fun, int *speed,
     61    nic_channel_mode_t *duplex, nic_role_t *role);
     62static int rtl8169_set_operation_mode(ddf_fun_t *fun, int speed,
     63    nic_channel_mode_t duplex, nic_role_t role);
     64static int rtl8169_pause_get(ddf_fun_t *fun, nic_result_t *we_send,
     65    nic_result_t *we_receive, uint16_t *time);
     66static int rtl8169_pause_set(ddf_fun_t *fun, int allow_send, int allow_receive,
     67    uint16_t time);
     68static int rtl8169_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement);
     69static int rtl8169_autoneg_disable(ddf_fun_t *fun);
     70static int rtl8169_autoneg_probe(ddf_fun_t *fun, uint32_t *advertisement,
     71    uint32_t *their_adv, nic_result_t *result, nic_result_t *their_result);
     72static int rtl8169_autoneg_restart(ddf_fun_t *fun);
     73static int rtl8169_defective_get_mode(ddf_fun_t *fun, uint32_t *mode);
     74static int rtl8169_defective_set_mode(ddf_fun_t *fun, uint32_t mode);
     75static int rtl8169_on_activated(nic_t *nic_data);
     76static int rtl8169_on_stopped(nic_t *nic_data);
     77static void rtl8169_send_frame(nic_t *nic_data, void *data, size_t size);
     78static void rtl8169_irq_handler(ddf_dev_t *dev, ipc_callid_t iid,
     79    ipc_call_t *icall);
     80static inline int rtl8169_register_int_handler(nic_t *nic_data);
     81static inline void rtl8169_get_hwaddr(rtl8169_t *rtl8169, nic_address_t *addr);
     82static inline void rtl8169_set_hwaddr(rtl8169_t *rtl8169, nic_address_t *addr);
     83
     84static void rtl8169_reset(rtl8169_t *rtl8169);
     85static int rtl8169_get_resource_info(ddf_dev_t *dev);
     86static int rtl8169_fill_resource_info(ddf_dev_t *dev, const hw_res_list_parsed_t *hw_resources);
     87static rtl8169_t *rtl8169_create_dev_data(ddf_dev_t *dev);
     88
    5789/** Network interface options for RTL8169 card driver */
    5890static nic_iface_t rtl8169_nic_iface = {
     
    75107};
    76108
     109irq_pio_range_t rtl8169_irq_pio_ranges[] = {
     110        {
     111                .base = 0,
     112                .size = RTL8169_IO_SIZE
     113        }
     114};
     115
     116irq_cmd_t rtl8169_irq_commands[] = {
     117        {
     118                /* Get the interrupt status */
     119                .cmd = CMD_PIO_READ_16,
     120                .addr = NULL,
     121                .dstarg = 2
     122        },
     123        {
     124                .cmd = CMD_PREDICATE,
     125                .value = 3,
     126                .srcarg = 2
     127        },
     128        {
     129                /* Mark interrupts as solved */
     130                .cmd = CMD_PIO_WRITE_16,
     131                .addr = NULL,
     132                .value = 0xFFFF
     133        },
     134        {
     135                /* Disable interrupts until interrupt routine is finished */
     136                .cmd = CMD_PIO_WRITE_16,
     137                .addr = NULL,
     138                .value = 0x0000
     139        },
     140        {
     141                .cmd = CMD_ACCEPT
     142        }
     143};
     144
     145/** Interrupt code definition */
     146irq_code_t rtl8169_irq_code = {
     147        .rangecount = sizeof(rtl8169_irq_pio_ranges) / sizeof(irq_pio_range_t),
     148        .ranges = rtl8169_irq_pio_ranges,
     149        .cmdcount = sizeof(rtl8169_irq_commands) / sizeof(irq_cmd_t),
     150        .cmds = rtl8169_irq_commands
     151};
     152
    77153/** Basic device operations for RTL8169 driver */
    78154static ddf_dev_ops_t rtl8169_dev_ops;
     
    91167};
    92168
     169static int rtl8169_get_resource_info(ddf_dev_t *dev)
     170{
     171        assert(dev);
     172
     173        nic_t *nic_data = nic_get_from_ddf_dev(dev);
     174        assert(nic_data);
     175
     176        hw_res_list_parsed_t hw_res_parsed;
     177        hw_res_list_parsed_init(&hw_res_parsed);
     178
     179        /* Get hw resources form parent driver */
     180        int rc = nic_get_resources(nic_data, &hw_res_parsed);
     181        if (rc != EOK)
     182                return rc;
     183
     184        /* Fill resources information to the device */
     185        int ret = rtl8169_fill_resource_info(dev, &hw_res_parsed);
     186        hw_res_list_parsed_clean(&hw_res_parsed);
     187
     188        return ret;
     189}
     190
     191static int rtl8169_fill_resource_info(ddf_dev_t *dev, const hw_res_list_parsed_t
     192    *hw_resources)
     193{
     194        assert(dev);
     195        assert(hw_resources);
     196
     197        rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_dev(dev));
     198        assert(rtl8169);
     199
     200        if (hw_resources->irqs.count != 1) {
     201                ddf_msg(LVL_ERROR, "%s device: unexpected irq count", ddf_dev_get_name(dev));
     202                return EINVAL;
     203        };
     204        if (hw_resources->io_ranges.count != 1) {
     205                ddf_msg(LVL_ERROR, "%s device: unexpected io ranges count", ddf_dev_get_name(dev));
     206                return EINVAL;
     207        }
     208
     209        rtl8169->irq = hw_resources->irqs.irqs[0];
     210        ddf_msg(LVL_DEBUG, "%s device: irq 0x%x assigned", ddf_dev_get_name(dev), rtl8169->irq);
     211
     212        rtl8169->regs_phys = (void *)((size_t)RNGABS(hw_resources->io_ranges.ranges[0]));
     213        if (hw_resources->io_ranges.ranges[0].size < RTL8169_IO_SIZE) {
     214                ddf_msg(LVL_ERROR, "I/O range assigned to the device "
     215                    "%s is too small.", ddf_dev_get_name(dev));
     216                return EINVAL;
     217        }
     218        ddf_msg(LVL_DEBUG, "%s device: i/o addr %p assigned.", ddf_dev_get_name(dev), rtl8169->regs_phys);
     219
     220        return EOK;
     221}
     222
     223static rtl8169_t *rtl8169_create_dev_data(ddf_dev_t *dev)
     224{
     225        assert(dev);
     226        assert(!nic_get_from_ddf_dev(dev));
     227
     228        nic_t *nic_data = nic_create_and_bind(dev);
     229        if (!nic_data)
     230                return NULL;
     231
     232        rtl8169_t *rtl8169 = malloc(sizeof(rtl8169_t));
     233        if (!rtl8169) {
     234                nic_unbind_and_destroy(dev);
     235                return NULL;
     236        }
     237
     238        memset(rtl8169, 0, sizeof(rtl8169_t));
     239
     240        rtl8169->nic_data = nic_data;
     241        nic_set_specific(nic_data, rtl8169);
     242        nic_set_send_frame_handler(nic_data, rtl8169_send_frame);
     243        nic_set_state_change_handlers(nic_data,
     244                rtl8169_on_activated, NULL, rtl8169_on_stopped);
     245        nic_set_filtering_change_handlers(nic_data,
     246                NULL, NULL, NULL, NULL, NULL);
     247
     248        fibril_mutex_initialize(&rtl8169->rx_lock);
     249        fibril_mutex_initialize(&rtl8169->tx_lock);
     250
     251        nic_set_wol_max_caps(nic_data, NIC_WV_BROADCAST, 1);
     252        nic_set_wol_max_caps(nic_data, NIC_WV_LINK_CHANGE, 1);
     253        nic_set_wol_max_caps(nic_data, NIC_WV_MAGIC_PACKET, 1);
     254
     255        return rtl8169;
     256}
     257
     258
     259static int rtl8169_dev_initialize(ddf_dev_t *dev)
     260{
     261        int ret;
     262
     263        rtl8169_t *rtl8169 = rtl8169_create_dev_data(dev);
     264        if (rtl8169 == NULL) {
     265                ddf_msg(LVL_ERROR, "Not enough memory for initializing %s.", ddf_dev_get_name(dev));
     266                return ENOMEM;
     267        }
     268
     269        ret = rtl8169_get_resource_info(dev);
     270        if (ret != EOK) {
     271                ddf_msg(LVL_ERROR, "Can't obtain H/W resources information");
     272                goto failed;
     273        }
     274
     275        ddf_msg(LVL_DEBUG, "The device is initialized");
     276        return ret;
     277       
     278failed:
     279        ddf_msg(LVL_ERROR, "The device initialization failed");
     280//      rtl8139_dev_cleanup(dev);
     281        return ret;
     282
     283}
     284
     285inline static int rtl8169_register_int_handler(nic_t *nic_data)
     286{
     287        rtl8169_t *rtl8169 = nic_get_specific(nic_data);
     288
     289        rtl8169_irq_code.ranges[0].base = (uintptr_t) rtl8169->regs;
     290        rtl8169_irq_code.cmds[0].addr = rtl8169->regs + ISR;
     291        rtl8169_irq_code.cmds[2].addr = rtl8169->regs + ISR;
     292        rtl8169_irq_code.cmds[3].addr = rtl8169->regs + IMR;
     293        int rc = register_interrupt_handler(nic_get_ddf_dev(nic_data),
     294            rtl8169->irq, rtl8169_irq_handler, &rtl8169_irq_code);
     295
     296        return rc;
     297}
     298
    93299static int rtl8169_dev_add(ddf_dev_t *dev)
    94300{
    95301        ddf_fun_t *fun;
     302        nic_address_t nic_addr;
    96303        int rc;
    97304
     
    99306        ddf_msg(LVL_NOTE, "RTL8169_dev_add %s (handle = %zu)",
    100307            ddf_dev_get_name(dev), ddf_dev_get_handle(dev));
     308
    101309
    102310        /* Init structures */
     
    105313                return rc;
    106314
     315        nic_t *nic_data = nic_get_from_ddf_dev(dev);
     316        rtl8169_t *rtl8169 = nic_get_specific(nic_data);
     317
     318        /* Map register space */
     319        rc = pio_enable(rtl8169->regs_phys, RTL8169_IO_SIZE, &rtl8169->regs);
     320        if (rc != EOK) {
     321                ddf_msg(LVL_ERROR, "Cannot map register space for device %s.",
     322                    ddf_dev_get_name(dev));
     323                goto err_destroy;
     324        }
     325
     326        /* Read MAC address and print it */
     327        rtl8169_get_hwaddr(rtl8169, &nic_addr);
     328        ddf_msg(LVL_NOTE, "MAC address: %02x:%02x:%02x:%02x:%02x:%02x",
     329            nic_addr.address[0], nic_addr.address[1],
     330            nic_addr.address[2], nic_addr.address[3],
     331            nic_addr.address[4], nic_addr.address[5]);
     332
     333        rc = nic_report_address(nic_data, &nic_addr);
     334        if (rc != EOK)
     335                goto err_pio;
     336
     337        rc = rtl8169_register_int_handler(nic_data);
     338        if (rc != EOK) {
     339                ddf_msg(LVL_ERROR, "Failed to register IRQ handler (%d)", rc);
     340                goto err_irq;
     341
     342        }
     343
     344        ddf_msg(LVL_DEBUG, "Interrupt handler installed");
     345
     346        rtl8169_reset(rtl8169);
     347        pio_write_16(rtl8169->regs + IMR, 0xffff);
     348
     349        uint8_t cr_value = pio_read_8(rtl8169->regs + CR);
     350        pio_write_8(rtl8169->regs + CR, cr_value | CR_TE | CR_RE);
     351
     352        rc = nic_connect_to_services(nic_data);
     353        if (rc != EOK) {
     354                ddf_msg(LVL_ERROR, "Failed to connect to services (%d)", rc);
     355                goto err_irq;
     356        }
     357
     358        fun = ddf_fun_create(nic_get_ddf_dev(nic_data), fun_exposed, "port0");
     359        if (fun == NULL) {
     360                ddf_msg(LVL_ERROR, "Failed creating device function");
     361                goto err_srv;
     362        }
     363
     364        nic_set_ddf_fun(nic_data, fun);
     365        ddf_fun_set_ops(fun, &rtl8169_dev_ops);
     366        ddf_fun_data_implant(fun, nic_data);
     367
     368        rc = ddf_fun_bind(fun);
     369        if (rc != EOK) {
     370                ddf_msg(LVL_ERROR, "Failed binding device function");
     371                goto err_fun_create;
     372        }
     373
     374        rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
     375        if (rc != EOK) {
     376                ddf_msg(LVL_ERROR, "Failed adding function to category");
     377                goto err_fun_bind;
     378        }
     379
     380        ddf_msg(LVL_NOTE, "The %s device has been successfully initialized.",
     381            ddf_dev_get_name(dev));
     382        return EOK;
     383
     384err_fun_bind:
     385        ddf_fun_unbind(fun);
     386err_fun_create:
     387        ddf_fun_destroy(fun);
     388err_srv:
     389        /* XXX Disconnect from services */
     390err_irq:
     391        //unregister_interrupt_handler(dev, rtl8169->irq);
     392err_pio:
     393err_destroy:
     394        //rtl8169_dev_cleanup(dev);
     395        return rc;
     396
    107397        return EOK;
    108398}
     
    139429{
    140430        return EOK;
    141 {
     431}
    142432
    143433static int rtl8169_pause_set(ddf_fun_t *fun, int allow_send, int allow_receive,
     
    178468}
    179469
     470static int rtl8169_on_activated(nic_t *nic_data)
     471{
     472        ddf_msg(LVL_NOTE, "Activating device");
     473
     474        rtl8169_t *rtl8169 = nic_get_specific(nic_data);
     475
     476        pio_write_16(rtl8169->regs + IMR, 0xffff);
     477
     478        return EOK;
     479}
     480
     481static int rtl8169_on_stopped(nic_t *nic_data)
     482{
     483        return EOK;
     484}
     485
     486inline static void rtl8169_reset(rtl8169_t *rtl8169)
     487{
     488        pio_write_8(rtl8169->regs + CR, CR_RST);
     489        memory_barrier();
     490        while (pio_read_8(rtl8169->regs + CR) & CR_RST) {
     491                usleep(1);
     492                read_barrier();
     493        }
     494}
     495
     496static void rtl8169_link_change(ddf_dev_t *dev)
     497{
     498        nic_t *nic_data = nic_get_from_ddf_dev(dev);
     499        rtl8169_t *rtl8169 = nic_get_specific(nic_data);
     500
     501        uint8_t phystatus = pio_read_8(rtl8169->regs + PHYSTATUS);
     502
     503        if (phystatus & PHYSTATUS_LINK) {
     504                ddf_msg(LVL_NOTE, "%s: Link up", ddf_dev_get_name(dev));
     505
     506                int speed;
     507                const char *fdx = phystatus & PHYSTATUS_FDX ? "full duplex" : "half duplex";
     508
     509                if (phystatus & PHYSTATUS_10M)
     510                        speed = 10;
     511
     512                if (phystatus & PHYSTATUS_100M)
     513                        speed = 100;
     514
     515                if (phystatus & PHYSTATUS_1000M)
     516                        speed = 1000;
     517
     518                ddf_msg(LVL_NOTE, "%s: Speed %dMbit/s, %s", ddf_dev_get_name(dev), speed, fdx);
     519        } else {
     520                ddf_msg(LVL_NOTE, "%s: Link down", ddf_dev_get_name(dev));
     521        }
     522
     523}
     524
     525static void rtl8169_irq_handler(ddf_dev_t *dev, ipc_callid_t iid,
     526    ipc_call_t *icall)
     527{
     528        assert(dev);
     529        assert(icall);
     530
     531        ddf_msg(LVL_NOTE, "rtl8169_irq_handler()");
     532
     533        uint16_t isr = (uint16_t) IPC_GET_ARG2(*icall);
     534        nic_t *nic_data = nic_get_from_ddf_dev(dev);
     535        rtl8169_t *rtl8169 = nic_get_specific(nic_data);
     536
     537        /* Packet underrun or link change */
     538        if (isr & INT_PUN)
     539                rtl8169_link_change(dev);       
     540
     541        pio_write_16(rtl8169->regs + IMR, 0xffff);
     542}
     543
    180544static void rtl8169_send_frame(nic_t *nic_data, void *data, size_t size)
    181545{
    182546
     547}
     548
     549static inline void rtl8169_get_hwaddr(rtl8169_t *rtl8169, nic_address_t *addr)
     550{
     551        int i;
     552
     553        assert(rtl8169);
     554        assert(addr);
     555
     556        for (i = 0; i < 6; i++)
     557                addr->address[i] = pio_read_8(rtl8169->regs + MAC0 + i);
     558}
     559
     560static inline void rtl8169_set_hwaddr(rtl8169_t *rtl8169, nic_address_t *addr)
     561{
     562        int i;
     563
     564        assert(rtl8169);
     565        assert(addr);
     566
     567        for (i = 0; i < 6; i++)
     568                addr->address[i] = pio_read_8(rtl8169->regs + MAC0 + i);
    183569}
    184570
  • uspace/drv/nic/rtl8169/driver.h

    rfef725d r90782c36  
    3838#define NAME  "rtl8169"
    3939
     40#define TX_BUFF_COUNT   16
     41
     42/** RTL8139 device data */
     43typedef struct rtl8169_data {
     44        /** I/O address of the device */
     45        void *regs_phys;
     46        /** Mapped I/O port */
     47        void *regs;
     48        /** The irq assigned */
     49        int irq;
     50
     51        /** Mask of the turned interupts (IMR value) */
     52        uint16_t int_mask;
     53
     54        /** The memory allocated for the transmittion buffers
     55         *  Each buffer takes 2kB
     56         */
     57        uintptr_t tx_buff_phys;
     58        void *tx_buff_virt;
     59
     60        /** Virtual adresses of the Tx buffers */
     61        void *tx_buff[TX_BUFF_COUNT];
     62
     63        /** The nubmer of the next buffer to use, index = tx_next % TX_BUFF_COUNT */
     64        size_t tx_next;
     65        /** The number of the first used buffer in the row
     66         *
     67         *  tx_used is in the interval tx_next - TX_BUFF_COUNT and tx_next:
     68         *      tx_next - TX_BUFF_COUNT: there is no useable Tx descriptor
     69         *      tx_next: all Tx descriptors are can be used
     70         */
     71        size_t tx_used;
     72
     73        /** Buffer for receiving frames */
     74        uintptr_t rx_buff_phys;
     75        void *rx_buff_virt;
     76
     77        /** Lock for receiver */
     78        fibril_mutex_t rx_lock;
     79        /** Lock for transmitter */
     80        fibril_mutex_t tx_lock;
     81
     82        /** Backward pointer to nic_data */
     83        nic_t *nic_data;
     84
     85} rtl8169_t;
     86
    4087#endif
Note: See TracChangeset for help on using the changeset viewer.