iPXE
Functions
efx_hunt.c File Reference
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <byteswap.h>
#include <ipxe/io.h>
#include <ipxe/pci.h>
#include <ipxe/malloc.h>
#include <ipxe/iobuf.h>
#include <ipxe/netdevice.h>
#include "efx_hunt.h"
#include "efx_bitfield.h"
#include "ef10_regs.h"

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
void efx_hunt_free_special_buffer (void *buf, int bytes)
static void * efx_hunt_alloc_special_buffer (int bytes, struct efx_special_buffer *entry)
static void efx_hunt_build_tx_desc (efx_tx_desc_t *txd, struct io_buffer *iob)
static void efx_hunt_notify_tx_desc (struct efx_nic *efx)
int efx_hunt_transmit (struct net_device *netdev, struct io_buffer *iob)
static void efx_hunt_transmit_done (struct efx_nic *efx, int id)
int efx_hunt_tx_init (struct net_device *netdev, dma_addr_t *dma_addr)
static void efx_hunt_build_rx_desc (efx_rx_desc_t *rxd, struct io_buffer *iob)
static void efx_hunt_notify_rx_desc (struct efx_nic *efx)
static void efx_hunt_rxq_fill (struct efx_nic *efx)
static void efx_hunt_receive (struct efx_nic *efx, unsigned int id, int len, int drop)
int efx_hunt_rx_init (struct net_device *netdev, dma_addr_t *dma_addr)
int efx_hunt_ev_init (struct net_device *netdev, dma_addr_t *dma_addr)
static void efx_hunt_clear_interrupts (struct efx_nic *efx)
static int efx_hunt_event_present (efx_event_t *event)
 See if an event is present.
static void efx_hunt_evq_read_ack (struct efx_nic *efx)
static unsigned int efx_hunt_handle_event (struct efx_nic *efx, efx_event_t *evt)
void efx_hunt_poll (struct net_device *netdev)
void efx_hunt_irq (struct net_device *netdev, int enable)
int efx_hunt_open (struct net_device *netdev)
void efx_hunt_close (struct net_device *netdev)

Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
void efx_hunt_free_special_buffer ( void *  buf,
int  bytes 
)

Definition at line 38 of file efx_hunt.c.

References free_dma().

Referenced by hunt_ev_fini(), hunt_rx_fini(), and hunt_tx_fini().

{
        free_dma(buf, bytes);
}
static void* efx_hunt_alloc_special_buffer ( int  bytes,
struct efx_special_buffer entry 
) [static]

Definition at line 43 of file efx_hunt.c.

References assert, buffer, DBGP, efx_special_buffer::dma_addr, EFX_BUF_ALIGN, efx_special_buffer::id, malloc_dma(), NULL, and virt_to_bus().

Referenced by efx_hunt_ev_init(), efx_hunt_rx_init(), and efx_hunt_tx_init().

{
        void *buffer;
        dma_addr_t dma_addr;

        /* Allocate the buffer, aligned on a buffer address boundary.  This
         * buffer will be passed into an MC_CMD_INIT_*Q command to setup the
         * appropriate type of queue via MCDI.
         */
        buffer = malloc_dma(bytes, EFX_BUF_ALIGN);
        if (!buffer)
                return NULL;

        entry->dma_addr = dma_addr = virt_to_bus(buffer);
        assert((dma_addr & (EFX_BUF_ALIGN - 1)) == 0);

        /* Buffer table entries aren't allocated, so set id to zero */
        entry->id = 0;
        DBGP("Allocated 0x%x bytes at %p\n", bytes, buffer);

        return buffer;
}
static void efx_hunt_build_tx_desc ( efx_tx_desc_t txd,
struct io_buffer iob 
) [static]

Definition at line 75 of file efx_hunt.c.

References io_buffer::data, EFX_POPULATE_QWORD_4, iob_len(), and virt_to_bus().

Referenced by efx_hunt_transmit().

{
        dma_addr_t dma_addr;

        dma_addr = virt_to_bus(iob->data);

        EFX_POPULATE_QWORD_4(*txd,
                             ESF_DZ_TX_KER_TYPE, 0,
                             ESF_DZ_TX_KER_CONT, 0,
                             ESF_DZ_TX_KER_BYTE_CNT, iob_len(iob),
                             ESF_DZ_TX_KER_BUF_ADDR, dma_addr);
}
static void efx_hunt_notify_tx_desc ( struct efx_nic efx) [static]

Definition at line 89 of file efx_hunt.c.

References EFX_POPULATE_DWORD_1, EFX_TXD_MASK, efx_writel_page, ER_DZ_TX_DESC_UPD_DWORD, reg, efx_nic::txq, and efx_tx_queue::write_ptr.

Referenced by efx_hunt_transmit().

{
        struct efx_tx_queue *txq = &efx->txq;
        int ptr = txq->write_ptr & EFX_TXD_MASK;
        efx_dword_t reg;

        EFX_POPULATE_DWORD_1(reg, ERF_DZ_TX_DESC_WPTR_DWORD, ptr);
        efx_writel_page(efx, &reg, 0, ER_DZ_TX_DESC_UPD_DWORD);
}
int efx_hunt_transmit ( struct net_device netdev,
struct io_buffer iob 
)

Definition at line 100 of file efx_hunt.c.

References assert, efx_tx_queue::buf, io_buffer::data, DBGCIO, efx_hunt_build_tx_desc(), efx_hunt_notify_tx_desc(), EFX_TXD_MASK, EFX_TXD_SIZE, ENOBUFS, iob_len(), netdev_priv(), NULL, efx_tx_queue::read_ptr, efx_tx_queue::ring, txd, efx_nic::txq, and efx_tx_queue::write_ptr.

{
        struct efx_nic *efx = netdev_priv(netdev);
        struct efx_tx_queue *txq = &efx->txq;
        int fill_level, space;
        efx_tx_desc_t *txd;
        int buf_id;

        fill_level = txq->write_ptr - txq->read_ptr;
        space = EFX_TXD_SIZE - fill_level - 1;
        if (space < 1)
                return -ENOBUFS;

        /* Save the iobuffer for later completion */
        buf_id = txq->write_ptr & EFX_TXD_MASK;
        assert(txq->buf[buf_id] == NULL);
        txq->buf[buf_id] = iob;

        DBGCIO(efx, "tx_buf[%d] for iob %p data %p len %zd\n",
               buf_id, iob, iob->data, iob_len(iob));

        /* Form the descriptor, and push it to hardware */
        txd = txq->ring + buf_id;
        efx_hunt_build_tx_desc(txd, iob);
        ++txq->write_ptr;
        efx_hunt_notify_tx_desc(efx);

        return 0;
}
static void efx_hunt_transmit_done ( struct efx_nic efx,
int  id 
) [static]

Definition at line 131 of file efx_hunt.c.

References assert, efx_tx_queue::buf, DBGCIO, EFX_TXD_MASK, efx_nic::netdev, netdev_tx_complete(), NULL, efx_tx_queue::read_ptr, and efx_nic::txq.

Referenced by efx_hunt_handle_event().

{
        struct efx_tx_queue *txq = &efx->txq;
        unsigned int read_ptr, stop;

        /* Complete all buffers from read_ptr up to and including id */
        read_ptr = txq->read_ptr & EFX_TXD_MASK;
        stop = (id + 1) & EFX_TXD_MASK;

        while (read_ptr != stop) {
                struct io_buffer *iob = txq->buf[read_ptr];

                assert(iob);
                /* Complete the tx buffer */
                if (iob)
                        netdev_tx_complete(efx->netdev, iob);
                DBGCIO(efx, "tx_buf[%d] for iob %p done\n", read_ptr, iob);
                txq->buf[read_ptr] = NULL;

                ++txq->read_ptr;
                read_ptr = txq->read_ptr & EFX_TXD_MASK;
        }
}
int efx_hunt_tx_init ( struct net_device netdev,
dma_addr_t dma_addr 
)

Definition at line 155 of file efx_hunt.c.

References bytes, efx_special_buffer::dma_addr, efx_hunt_alloc_special_buffer(), EFX_TXD_SIZE, ENOMEM, efx_tx_queue::entry, netdev_priv(), efx_tx_queue::read_ptr, efx_tx_queue::ring, efx_nic::txq, and efx_tx_queue::write_ptr.

Referenced by hunt_tx_init().

{
        struct efx_nic *efx = netdev_priv(netdev);
        struct efx_tx_queue *txq = &efx->txq;
        size_t bytes;

        /* Allocate hardware transmit queue */
        bytes = sizeof(efx_tx_desc_t) * EFX_TXD_SIZE;
        txq->ring = efx_hunt_alloc_special_buffer(bytes, &txq->entry);
        if (!txq->ring)
                return -ENOMEM;

        txq->read_ptr = txq->write_ptr = 0;
        *dma_addr = txq->entry.dma_addr;
        return 0;
}
static void efx_hunt_build_rx_desc ( efx_rx_desc_t rxd,
struct io_buffer iob 
) [static]

Definition at line 180 of file efx_hunt.c.

References io_buffer::data, EFX_POPULATE_QWORD_2, EFX_RX_BUF_SIZE, and virt_to_bus().

Referenced by efx_hunt_rxq_fill().

{
        dma_addr_t dma_addr = virt_to_bus(iob->data);

        EFX_POPULATE_QWORD_2(*rxd,
                             ESF_DZ_RX_KER_BYTE_CNT, EFX_RX_BUF_SIZE,
                             ESF_DZ_RX_KER_BUF_ADDR, dma_addr);
}
static void efx_hunt_notify_rx_desc ( struct efx_nic efx) [static]

Definition at line 190 of file efx_hunt.c.

References EFX_POPULATE_DWORD_1, EFX_RXD_MASK, efx_writel_page, ER_DZ_RX_DESC_UPD, reg, efx_nic::rxq, and efx_rx_queue::write_ptr.

Referenced by efx_hunt_rxq_fill().

{
        struct efx_rx_queue *rxq = &efx->rxq;
        int ptr = rxq->write_ptr & EFX_RXD_MASK;
        efx_dword_t reg;

        EFX_POPULATE_DWORD_1(reg, ERF_DZ_RX_DESC_WPTR, ptr);
        efx_writel_page(efx, &reg, 0, ER_DZ_RX_DESC_UPD);
}
static void efx_hunt_rxq_fill ( struct efx_nic efx) [static]

Definition at line 201 of file efx_hunt.c.

References alloc_iob(), assert, efx_rx_queue::buf, io_buffer::data, DBGCP, efx_hunt_build_rx_desc(), efx_hunt_notify_rx_desc(), EFX_NUM_RX_DESC, EFX_RX_BUF_SIZE, EFX_RXD_MASK, NULL, efx_rx_queue::read_ptr, efx_rx_queue::ring, rxd, efx_nic::rxq, and efx_rx_queue::write_ptr.

Referenced by efx_hunt_open(), and efx_hunt_poll().

{
        struct efx_rx_queue *rxq = &efx->rxq;
        int fill_level = rxq->write_ptr - rxq->read_ptr;
        int space = EFX_NUM_RX_DESC - fill_level - 1;
        int pushed = 0;

        while (space) {
                int buf_id = rxq->write_ptr & (EFX_NUM_RX_DESC - 1);
                int desc_id = rxq->write_ptr & EFX_RXD_MASK;
                struct io_buffer *iob;
                efx_rx_desc_t *rxd;

                assert(rxq->buf[buf_id] == NULL);
                iob = alloc_iob(EFX_RX_BUF_SIZE);
                if (!iob)
                        break;

                DBGCP(efx, "pushing rx_buf[%d] iob %p data %p\n",
                      buf_id, iob, iob->data);

                rxq->buf[buf_id] = iob;
                rxd = rxq->ring + desc_id;
                efx_hunt_build_rx_desc(rxd, iob);
                ++rxq->write_ptr;
                ++pushed;
                --space;
        }

        /* Push the ptr to hardware */
        if (pushed > 0) {
                efx_hunt_notify_rx_desc(efx);

                DBGCP(efx, "pushed %d rx buffers to fill level %d\n",
                      pushed, rxq->write_ptr - rxq->read_ptr);
        }
}
static void efx_hunt_receive ( struct efx_nic efx,
unsigned int  id,
int  len,
int  drop 
) [static]

Definition at line 240 of file efx_hunt.c.

References assert, efx_rx_queue::buf, io_buffer::data, DBGCIO, EBADMSG, EFX_NUM_RX_DESC_MASK, EFX_RXD_MASK, iob_pull, iob_put, efx_nic::netdev, netdev_rx(), netdev_rx_err(), NULL, efx_rx_queue::read_ptr, efx_nic::rx_prefix_size, and efx_nic::rxq.

Referenced by efx_hunt_handle_event().

{
        struct efx_rx_queue *rxq = &efx->rxq;
        unsigned int read_ptr = rxq->read_ptr & EFX_RXD_MASK;
        unsigned int buf_ptr = rxq->read_ptr & EFX_NUM_RX_DESC_MASK;
        struct io_buffer *iob;

        /* id is the lower 4 bits of the desc index + 1 in huntington*/
        /* hence anding with 15 */
        assert((id & 15) == ((read_ptr + (len != 0)) & 15));

        /* Pop this rx buffer out of the software ring */
        iob = rxq->buf[buf_ptr];
        rxq->buf[buf_ptr] = NULL;

        DBGCIO(efx, "popping rx_buf[%d] iob %p data %p with %d bytes %s %x\n",
               read_ptr, iob, iob->data, len, drop ? "bad" : "ok", drop);

        /* Pass the packet up if required */
        if (drop)
                netdev_rx_err(efx->netdev, iob, EBADMSG);
        else {
                iob_put(iob, len);
                iob_pull(iob, efx->rx_prefix_size);
                netdev_rx(efx->netdev, iob);
        }

        ++rxq->read_ptr;
}
int efx_hunt_rx_init ( struct net_device netdev,
dma_addr_t dma_addr 
)

Definition at line 270 of file efx_hunt.c.

References bytes, efx_special_buffer::dma_addr, efx_hunt_alloc_special_buffer(), EFX_RXD_SIZE, ENOMEM, efx_rx_queue::entry, netdev_priv(), NULL, efx_rx_queue::read_ptr, efx_rx_queue::ring, efx_nic::rxq, and efx_rx_queue::write_ptr.

Referenced by hunt_rx_init().

{
        struct efx_nic *efx = netdev_priv(netdev);
        struct efx_rx_queue *rxq = &efx->rxq;
        size_t bytes;

        /* Allocate hardware receive queue */
        bytes = sizeof(efx_rx_desc_t) * EFX_RXD_SIZE;
        rxq->ring = efx_hunt_alloc_special_buffer(bytes, &rxq->entry);
        if (rxq->ring == NULL)
                return -ENOMEM;

        rxq->read_ptr = rxq->write_ptr = 0;
        *dma_addr = rxq->entry.dma_addr;
        return 0;
}
int efx_hunt_ev_init ( struct net_device netdev,
dma_addr_t dma_addr 
)

Definition at line 294 of file efx_hunt.c.

References bytes, efx_special_buffer::dma_addr, EFX_EVQ_SIZE, efx_hunt_alloc_special_buffer(), ENOMEM, efx_ev_queue::entry, efx_nic::evq, memset(), netdev_priv(), NULL, efx_ev_queue::read_ptr, and efx_ev_queue::ring.

Referenced by hunt_ev_init().

{
        struct efx_nic *efx = netdev_priv(netdev);
        struct efx_ev_queue *evq = &efx->evq;
        size_t bytes;

        /* Allocate the hardware event queue */
        bytes = sizeof(efx_event_t) * EFX_EVQ_SIZE;
        evq->ring = efx_hunt_alloc_special_buffer(bytes, &evq->entry);
        if (evq->ring == NULL)
                return -ENOMEM;

        memset(evq->ring, 0xff, bytes);
        evq->read_ptr = 0;
        *dma_addr = evq->entry.dma_addr;
        return 0;
}
static void efx_hunt_clear_interrupts ( struct efx_nic efx) [static]

Definition at line 313 of file efx_hunt.c.

References efx_readl(), ER_DZ_BIU_INT_ISR, and reg.

Referenced by efx_hunt_close(), efx_hunt_irq(), and efx_hunt_poll().

{
        efx_dword_t reg;
        /* read the ISR */
        efx_readl(efx, &reg, ER_DZ_BIU_INT_ISR);
}
static int efx_hunt_event_present ( efx_event_t event) [inline, static]

See if an event is present.

Parameters:
eventEFX event structure
Return values:
TrueAn event is pending
FalseNo event is pending

We check both the high and low dword of the event for all ones. We wrote all ones when we cleared the event, and no valid event can have all ones in either its high or low dwords. This approach is robust against reordering.

Note that using a single 64-bit comparison is incorrect; even though the CPU read will be atomic, the DMA write may not be.

Definition at line 336 of file efx_hunt.c.

References efx_qword::dword, and EFX_DWORD_IS_ALL_ONES.

Referenced by efx_hunt_poll().

{
        return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) |
                  EFX_DWORD_IS_ALL_ONES(event->dword[1])));
}
static void efx_hunt_evq_read_ack ( struct efx_nic efx) [static]
static unsigned int efx_hunt_handle_event ( struct efx_nic efx,
efx_event_t evt 
) [static]

Definition at line 366 of file efx_hunt.c.

References DBGCP, efx_hunt_receive(), efx_hunt_transmit_done(), EFX_QWORD_FIELD, ESE_DZ_EV_CODE_RX_EV, ESE_DZ_EV_CODE_TX_EV, len, efx_rx_queue::rx_cont_prev, and efx_nic::rxq.

Referenced by efx_hunt_poll().

{
        struct efx_rx_queue *rxq = &efx->rxq;
        int ev_code, desc_ptr, len;
        int next_ptr_lbits, packet_drop;
        int rx_cont;

        /* Decode event */
        ev_code = EFX_QWORD_FIELD(*evt, ESF_DZ_EV_CODE);

        switch (ev_code) {
        case ESE_DZ_EV_CODE_TX_EV:
                desc_ptr = EFX_QWORD_FIELD(*evt, ESF_DZ_TX_DESCR_INDX);
                efx_hunt_transmit_done(efx, desc_ptr);
                break;

        case ESE_DZ_EV_CODE_RX_EV:
                len = EFX_QWORD_FIELD(*evt, ESF_DZ_RX_BYTES);
                next_ptr_lbits = EFX_QWORD_FIELD(*evt, ESF_DZ_RX_DSC_PTR_LBITS);
                rx_cont = EFX_QWORD_FIELD(*evt, ESF_DZ_RX_CONT);

                /* We don't expect to receive scattered packets, so drop the
                 * packet if RX_CONT is set on the current or previous event, or
                 * if len is zero.
                 */
                packet_drop = (len == 0) | (rx_cont << 1) |
                              (rxq->rx_cont_prev << 2);
                efx_hunt_receive(efx, next_ptr_lbits, len, packet_drop);
                rxq->rx_cont_prev = rx_cont;
                return 1;

        default:
                DBGCP(efx, "Unknown event type %d\n", ev_code);
                break;
        }
        return 0;
}
void efx_hunt_poll ( struct net_device netdev)

Definition at line 404 of file efx_hunt.c.

References DBGCP, EFX_EVQ_MASK, efx_hunt_clear_interrupts(), efx_hunt_event_present(), efx_hunt_evq_read_ack(), efx_hunt_handle_event(), efx_hunt_rxq_fill(), EFX_QWORD_FMT, EFX_QWORD_VAL, EFX_SET_QWORD, efx_nic::evq, efx_nic::int_en, netdev_priv(), efx_ev_queue::read_ptr, and efx_ev_queue::ring.

Referenced by hunt_poll().

{
        struct efx_nic *efx = netdev_priv(netdev);
        struct efx_ev_queue *evq = &efx->evq;
        efx_event_t *evt;
        int budget = 10;

        /* Read the event queue by directly looking for events
         * (we don't even bother to read the eventq write ptr)
         */
        evt = evq->ring + evq->read_ptr;
        while (efx_hunt_event_present(evt) && (budget > 0)) {
                DBGCP(efx, "Event at index 0x%x address %p is "
                      EFX_QWORD_FMT "\n", evq->read_ptr,
                      evt, EFX_QWORD_VAL(*evt));

                budget -= efx_hunt_handle_event(efx, evt);

                /* Clear the event */
                EFX_SET_QWORD(*evt);

                /* Move to the next event. We don't ack the event
                 * queue until the end
                 */
                evq->read_ptr = ((evq->read_ptr + 1) & EFX_EVQ_MASK);
                evt = evq->ring + evq->read_ptr;
        }

        /* Push more rx buffers if needed */
        efx_hunt_rxq_fill(efx);

        /* Clear any pending interrupts */
        efx_hunt_clear_interrupts(efx);

        /* Ack the event queue if interrupts are enabled */
        if (efx->int_en)
                efx_hunt_evq_read_ack(efx);
}
void efx_hunt_irq ( struct net_device netdev,
int  enable 
)

Definition at line 443 of file efx_hunt.c.

References efx_hunt_clear_interrupts(), efx_hunt_evq_read_ack(), efx_nic::int_en, efx_nic::netdev, NETDEV_OPEN, netdev_priv(), and net_device::state.

{
        struct efx_nic *efx = netdev_priv(netdev);

        efx->int_en = enable;

        /* If interrupts are enabled, prime the event queue.  Otherwise ack any
         * pending interrupts
         */
        if (enable)
                efx_hunt_evq_read_ack(efx);
        else if (efx->netdev->state & NETDEV_OPEN)
                efx_hunt_clear_interrupts(efx);
}
int efx_hunt_open ( struct net_device netdev)

Definition at line 465 of file efx_hunt.c.

References cmd, efx_hunt_evq_read_ack(), efx_hunt_rxq_fill(), EFX_POPULATE_DWORD_2, efx_writel_page, ER_DZ_EVQ_TMR, efx_nic::int_en, and netdev_priv().

Referenced by hunt_open().

{
        struct efx_nic *efx = netdev_priv(netdev);
        efx_dword_t cmd;

        /* Set interrupt moderation to 0*/
        EFX_POPULATE_DWORD_2(cmd,
                             ERF_DZ_TC_TIMER_MODE, 0,
                             ERF_DZ_TC_TIMER_VAL, 0);
        efx_writel_page(efx, &cmd, 0, ER_DZ_EVQ_TMR);

        /* Ack the eventq */
        if (efx->int_en)
                efx_hunt_evq_read_ack(efx);

        /* Push receive buffers */
        efx_hunt_rxq_fill(efx);

        return 0;
}
void efx_hunt_close ( struct net_device netdev)

Definition at line 486 of file efx_hunt.c.

References efx_tx_queue::buf, efx_rx_queue::buf, efx_hunt_clear_interrupts(), EFX_NUM_RX_DESC, EFX_TXD_SIZE, free_iob(), efx_nic::netdev, netdev_priv(), netdev_tx_complete(), NULL, efx_nic::rxq, and efx_nic::txq.

Referenced by hunt_close(), and hunt_open().

{
        struct efx_nic *efx = netdev_priv(netdev);
        struct efx_rx_queue *rxq = &efx->rxq;
        struct efx_tx_queue *txq = &efx->txq;
        int i;

        /* Complete outstanding descriptors */
        for (i = 0; i < EFX_NUM_RX_DESC; i++) {
                if (rxq->buf[i]) {
                        free_iob(rxq->buf[i]);
                        rxq->buf[i] = NULL;
                }
        }

        for (i = 0; i < EFX_TXD_SIZE; i++) {
                if (txq->buf[i]) {
                        netdev_tx_complete(efx->netdev, txq->buf[i]);
                        txq->buf[i] = NULL;
                }
        }

        /* Clear interrupts */
        efx_hunt_clear_interrupts(efx);
}