73f20bb3a9
This patch introduces processing of the frames up to 9kB by the mvneta driver. Some versions of this NIC limit TX checksum offloading, depending on the frame size, so add appropriate handling of this feature. Submitted by: Kornel Duleba Obtained from: Semihalf Sponsored by: Stormshield Differential Revision: https://reviews.freebsd.org/D23225
330 lines
8.1 KiB
C
330 lines
8.1 KiB
C
/*
|
|
* Copyright (c) 2017 Stormshield.
|
|
* Copyright (c) 2017 Semihalf.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD$
|
|
*
|
|
*/
|
|
|
|
#ifndef _IF_MVNETAVAR_H_
|
|
#define _IF_MVNETAVAR_H_
|
|
#include <net/if.h>
|
|
|
|
#define MVNETA_HWHEADER_SIZE 2 /* Marvell Header */
|
|
#define MVNETA_ETHER_SIZE 22 /* Maximum ether size */
|
|
#define MVNETA_A370_MAX_CSUM_MTU 1600 /* Max frame len for TX csum */
|
|
#define MVNETA_A3700_MAX_CSUM_MTU 9600
|
|
|
|
#define MVNETA_MAX_FRAME (MJUM9BYTES)
|
|
|
|
/*
|
|
* Default limit of queue length
|
|
*
|
|
* queue 0 is lowest priority and queue 7 is highest priority.
|
|
* IP packet is received on queue 7 by default.
|
|
*/
|
|
#define MVNETA_TX_RING_CNT 512
|
|
#define MVNETA_RX_RING_CNT 256
|
|
|
|
#define MVNETA_BUFRING_SIZE 1024
|
|
|
|
#define MVNETA_PACKET_OFFSET 64
|
|
|
|
#define MVNETA_RXTH_COUNT 128
|
|
#define MVNETA_RX_REFILL_COUNT 8
|
|
#define MVNETA_TX_RECLAIM_COUNT 32
|
|
|
|
/*
|
|
* Device Register access
|
|
*/
|
|
#define MVNETA_READ(sc, reg) \
|
|
bus_read_4((sc)->res[0], (reg))
|
|
#define MVNETA_WRITE(sc, reg, val) \
|
|
bus_write_4((sc)->res[0], (reg), (val))
|
|
|
|
#define MVNETA_READ_REGION(sc, reg, val, c) \
|
|
bus_read_region_4((sc)->res[0], (reg), (val), (c))
|
|
#define MVNETA_WRITE_REGION(sc, reg, val, c) \
|
|
bus_write_region_4((sc)->res[0], (reg), (val), (c))
|
|
|
|
#define MVNETA_READ_MIB_4(sc, reg) \
|
|
bus_read_4((sc)->res[0], MVNETA_PORTMIB_BASE + (reg))
|
|
#define MVNETA_READ_MIB_8(sc, reg) \
|
|
bus_read_8((sc)->res[0], MVNETA_PORTMIB_BASE + (reg))
|
|
|
|
#define MVNETA_IS_LINKUP(sc) \
|
|
(MVNETA_READ((sc), MVNETA_PSR) & MVNETA_PSR_LINKUP)
|
|
|
|
#define MVNETA_IS_QUEUE_SET(queues, q) \
|
|
((((queues) >> (q)) & 0x1))
|
|
|
|
/*
|
|
* EEE: Lower Power Idle config
|
|
* Default timer is duration of MTU sized frame transmission.
|
|
* The timer can be negotiated by LLDP protocol, but we have no
|
|
* support.
|
|
*/
|
|
#define MVNETA_LPI_TS (ETHERMTU * 8 / 1000) /* [us] */
|
|
#define MVNETA_LPI_TW (ETHERMTU * 8 / 1000) /* [us] */
|
|
#define MVNETA_LPI_LI (ETHERMTU * 8 / 1000) /* [us] */
|
|
|
|
/*
|
|
* DMA Descriptor
|
|
*
|
|
* the ethernet device has 8 rx/tx DMA queues. each of queue has its own
|
|
* decriptor list. descriptors are simply index by counter inside the device.
|
|
*/
|
|
#define MVNETA_TX_SEGLIMIT 32
|
|
|
|
#define MVNETA_QUEUE_IDLE 1
|
|
#define MVNETA_QUEUE_WORKING 2
|
|
#define MVNETA_QUEUE_DISABLED 3
|
|
|
|
struct mvneta_buf {
|
|
struct mbuf * m; /* pointer to related mbuf */
|
|
bus_dmamap_t dmap;
|
|
};
|
|
|
|
struct mvneta_rx_ring {
|
|
int queue_status;
|
|
/* Real descriptors array. shared by RxDMA */
|
|
struct mvneta_rx_desc *desc;
|
|
bus_dmamap_t desc_map;
|
|
bus_addr_t desc_pa;
|
|
|
|
/* Virtual address of the RX buffer */
|
|
void *rxbuf_virt_addr[MVNETA_RX_RING_CNT];
|
|
|
|
/* Managment entries for each of descritors */
|
|
struct mvneta_buf rxbuf[MVNETA_RX_RING_CNT];
|
|
|
|
/* locks */
|
|
struct mtx ring_mtx;
|
|
|
|
/* Index */
|
|
int dma;
|
|
int cpu;
|
|
|
|
/* Limit */
|
|
int queue_th_received;
|
|
int queue_th_time; /* [Tclk] */
|
|
|
|
/* LRO */
|
|
struct lro_ctrl lro;
|
|
boolean_t lro_enabled;
|
|
/* Is this queue out of mbuf */
|
|
boolean_t needs_refill;
|
|
} __aligned(CACHE_LINE_SIZE);
|
|
|
|
struct mvneta_tx_ring {
|
|
/* Index of this queue */
|
|
int qidx;
|
|
/* IFNET pointer */
|
|
struct ifnet *ifp;
|
|
/* Ring buffer for IFNET */
|
|
struct buf_ring *br;
|
|
/* Real descriptors array. shared by TxDMA */
|
|
struct mvneta_tx_desc *desc;
|
|
bus_dmamap_t desc_map;
|
|
bus_addr_t desc_pa;
|
|
|
|
/* Managment entries for each of descritors */
|
|
struct mvneta_buf txbuf[MVNETA_TX_RING_CNT];
|
|
|
|
/* locks */
|
|
struct mtx ring_mtx;
|
|
|
|
/* Index */
|
|
int used;
|
|
int dma;
|
|
int cpu;
|
|
|
|
/* watchdog */
|
|
#define MVNETA_WATCHDOG_TXCOMP (hz / 10) /* 100ms */
|
|
#define MVNETA_WATCHDOG (10 * hz) /* 10s */
|
|
int watchdog_time;
|
|
int queue_status;
|
|
boolean_t queue_hung;
|
|
|
|
/* Task */
|
|
struct task task;
|
|
struct taskqueue *taskq;
|
|
|
|
/* Stats */
|
|
uint32_t drv_error;
|
|
} __aligned(CACHE_LINE_SIZE);
|
|
|
|
static __inline int
|
|
tx_counter_adv(int ctr, int n)
|
|
{
|
|
|
|
ctr += n;
|
|
while (__predict_false(ctr >= MVNETA_TX_RING_CNT))
|
|
ctr -= MVNETA_TX_RING_CNT;
|
|
|
|
return (ctr);
|
|
}
|
|
|
|
static __inline int
|
|
rx_counter_adv(int ctr, int n)
|
|
{
|
|
|
|
ctr += n;
|
|
while (__predict_false(ctr >= MVNETA_RX_RING_CNT))
|
|
ctr -= MVNETA_RX_RING_CNT;
|
|
|
|
return (ctr);
|
|
}
|
|
|
|
/*
|
|
* Timeout control
|
|
*/
|
|
#define MVNETA_PHY_TIMEOUT 10000 /* msec */
|
|
#define RX_DISABLE_TIMEOUT 0x1000000 /* times */
|
|
#define TX_DISABLE_TIMEOUT 0x1000000 /* times */
|
|
#define TX_FIFO_EMPTY_TIMEOUT 0x1000000 /* times */
|
|
|
|
/*
|
|
* Debug
|
|
*/
|
|
#define KASSERT_SC_MTX(sc) \
|
|
KASSERT(mtx_owned(&(sc)->mtx), ("SC mutex not owned"))
|
|
#define KASSERT_BM_MTX(sc) \
|
|
KASSERT(mtx_owned(&(sc)->bm.bm_mtx), ("BM mutex not owned"))
|
|
#define KASSERT_RX_MTX(sc, q) \
|
|
KASSERT(mtx_owned(&(sc)->rx_ring[(q)].ring_mtx),\
|
|
("RX mutex not owned"))
|
|
#define KASSERT_TX_MTX(sc, q) \
|
|
KASSERT(mtx_owned(&(sc)->tx_ring[(q)].ring_mtx),\
|
|
("TX mutex not owned"))
|
|
|
|
/*
|
|
* sysctl(9) parameters
|
|
*/
|
|
struct mvneta_sysctl_queue {
|
|
struct mvneta_softc *sc;
|
|
int rxtx;
|
|
int queue;
|
|
};
|
|
#define MVNETA_SYSCTL_RX 0
|
|
#define MVNETA_SYSCTL_TX 1
|
|
|
|
struct mvneta_sysctl_mib {
|
|
struct mvneta_softc *sc;
|
|
int index;
|
|
uint64_t counter;
|
|
};
|
|
|
|
enum mvneta_phy_mode {
|
|
MVNETA_PHY_QSGMII,
|
|
MVNETA_PHY_SGMII,
|
|
MVNETA_PHY_RGMII,
|
|
MVNETA_PHY_RGMII_ID
|
|
};
|
|
|
|
/*
|
|
* Ethernet Device main context
|
|
*/
|
|
DECLARE_CLASS(mvneta_driver);
|
|
|
|
struct mvneta_softc {
|
|
device_t dev;
|
|
uint32_t version;
|
|
/*
|
|
* mtx must be held by interface functions to/from
|
|
* other frameworks. interrupt hander, sysctl hander,
|
|
* ioctl hander, and so on.
|
|
*/
|
|
struct mtx mtx;
|
|
struct resource *res[2];
|
|
void *ih_cookie[1];
|
|
|
|
struct ifnet *ifp;
|
|
uint32_t mvneta_if_flags;
|
|
uint32_t mvneta_media;
|
|
uint32_t tx_csum_limit;
|
|
uint32_t rx_frame_size;
|
|
|
|
int phy_attached;
|
|
enum mvneta_phy_mode phy_mode;
|
|
int phy_addr;
|
|
int phy_speed; /* PHY speed */
|
|
boolean_t phy_fdx; /* Full duplex mode */
|
|
boolean_t autoneg; /* Autonegotiation status */
|
|
boolean_t use_inband_status; /* In-band link status */
|
|
|
|
/*
|
|
* Link State control
|
|
*/
|
|
boolean_t linkup;
|
|
device_t miibus;
|
|
struct mii_data *mii;
|
|
uint8_t enaddr[ETHER_ADDR_LEN];
|
|
struct ifmedia mvneta_ifmedia;
|
|
|
|
bus_dma_tag_t rx_dtag;
|
|
bus_dma_tag_t rxbuf_dtag;
|
|
bus_dma_tag_t tx_dtag;
|
|
bus_dma_tag_t txmbuf_dtag;
|
|
struct mvneta_rx_ring rx_ring[MVNETA_RX_QNUM_MAX];
|
|
struct mvneta_tx_ring tx_ring[MVNETA_TX_QNUM_MAX];
|
|
|
|
/*
|
|
* Maintance clock
|
|
*/
|
|
struct callout tick_ch;
|
|
|
|
int cf_lpi;
|
|
int cf_fc;
|
|
int debug;
|
|
|
|
/*
|
|
* Sysctl interfaces
|
|
*/
|
|
struct mvneta_sysctl_queue sysctl_rx_queue[MVNETA_RX_QNUM_MAX];
|
|
struct mvneta_sysctl_queue sysctl_tx_queue[MVNETA_TX_QNUM_MAX];
|
|
|
|
/*
|
|
* MIB counter
|
|
*/
|
|
struct mvneta_sysctl_mib sysctl_mib[MVNETA_PORTMIB_NOCOUNTER];
|
|
uint64_t counter_pdfc;
|
|
uint64_t counter_pofc;
|
|
uint32_t counter_watchdog; /* manual reset when clearing mib */
|
|
uint32_t counter_watchdog_mib; /* reset after each mib update */
|
|
};
|
|
#define MVNETA_RX_RING(sc, q) \
|
|
(&(sc)->rx_ring[(q)])
|
|
#define MVNETA_TX_RING(sc, q) \
|
|
(&(sc)->tx_ring[(q)])
|
|
|
|
int mvneta_attach(device_t);
|
|
|
|
#ifdef FDT
|
|
int mvneta_fdt_mac_address(struct mvneta_softc *, uint8_t *);
|
|
#endif
|
|
|
|
#endif /* _IF_MVNETAVAR_H_ */
|