freebsd-dev/sys/dev/mgb/if_mgb.h

332 lines
11 KiB
C
Raw Normal View History

/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 The FreeBSD Foundation, Inc.
*
* This driver was written by Gerald ND Aryeetey <gndaryee@uwaterloo.ca>
* under sponsorship from the FreeBSD Foundation.
*
* 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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_MGB_H_
#define _IF_MGB_H_
#define MGB_MICROCHIP_VENDOR_ID 0x1055
#define MGB_LAN7430_DEVICE_ID 0x7430
#define MGB_LAN7431_DEVICE_ID 0x7431
#define MGB_TIMEOUT (500)
/** Control/Status Registers **/
#define MGB_BAR 0 /* PCI Base Address */
/** Reset **/
#define MGB_HW_CFG 0x10 /** H/W Configuration Register **/
#define MGB_LITE_RESET 0x2
/** MAC **/
#define MGB_MAC_CR 0x0100 /** MAC Crontrol Register **/
#define MGB_MAC_ADD_ENBL 0x1000 /* Automatic Duplex Detection */
#define MGB_MAC_ASD_ENBL 0x0800 /* Automatic Speed Detection */
#define MGB_MAC_ADDR_BASE_L 0x11C /** MAC address lower 4 bytes (read) register **/
#define MGB_MAC_ADDR_BASE_H 0x118 /** MAC address upper 2 bytes (read) register **/
#define MGB_MAC_TX 0x0104
#define MGB_MAC_RX 0x0108
#define MGB_MAC_ENBL (1 << 0)
#define MGB_MAC_DSBL (1 << 1)
/** MAC Statistics **/
#define MGB_MAC_STAT_RX_FCS_ERR_CNT 0x1200
#define MGB_MAC_STAT_RX_ALIGN_ERR_CNT 0x1204
#define MGB_MAC_STAT_RX_FRAG_ERR_CNT 0x1208
#define MGB_MAC_STAT_RX_JABBER_ERR_CNT 0x120C
#define MGB_MAC_STAT_RX_UNDER_ERR_CNT 0x1210
#define MGB_MAC_STAT_RX_OVER_ERR_CNT 0x1214
#define MGB_MAC_STAT_RX_DROPPED_CNT 0x1218
#define MGB_MAC_STAT_RX_BROADCAST_CNT1 0x1220
#define MGB_MAC_STAT_RX_BROADCAST_CNT 0x122C
#define MGB_MAC_STAT_RX_FRAME_CNT 0x1254
#define MGB_MAC_STAT_RX_DROPPED_CNT 0x1218
#define MGB_MAC_STAT_RX_BROADCAST_CNT1 0x1220
#define MGB_MAC_STAT_RX_BROADCAST_CNT 0x122C
#define MGB_MAC_STAT_RX_FRAME_CNT 0x1254
/* etc. */
/** Receive Filtering Engine **/
#define MGB_RFE_CTL 0x508
#define MGB_RFE_ALLOW_BROADCAST (1 << 10)
#define MGB_RFE_ALLOW_MULTICAST (1 << 9)
#define MGB_RFE_ALLOW_UNICAST (1 << 8)
#define MGB_RFE_ALLOW_PERFECT_FILTER (1 << 1)
/** PHY Reset (via power management control) **/
#define MGB_PMT_CTL 0x14 /** Power Management Control Register **/
#define MGB_PHY_RESET 0x10
#define MGB_PHY_READY 0x80
/** FIFO Controller **/
#define MGB_FCT_TX_CTL 0xC4
#define MGB_FCT_RX_CTL 0xAC
#define MGB_FCT_ENBL(_channel) (1 << (28 + (_channel)))
#define MGB_FCT_DSBL(_channel) (1 << (24 + (_channel)))
#define MGB_FCT_RESET(_channel) (1 << (20 + (_channel)))
/** DMA Controller **/
#define MGB_DMAC_CMD 0xC0C
#define MGB_DMAC_RESET (1 << 31)
#define MGB_DMAC_TX_START 16
#define MGB_DMAC_RX_START 0
#define MGB_DMAC_CMD_VAL(s, o, ch) (1 << ((s) + (o) + (ch)))
#define MGB_DMAC_CMD_RESET(_s, _ch) MGB_DMAC_CMD_VAL(_s, 8, _ch)
#define MGB_DMAC_CMD_START(_s, _ch) MGB_DMAC_CMD_VAL(_s, 4, _ch)
#define MGB_DMAC_CMD_STOP( _s, _ch) MGB_DMAC_CMD_VAL(_s, 0, _ch)
#define MGB_DMAC_STATE(_start, _stop) \
(((_start) ? 2 : 0) | ((_stop) ? 1 : 0))
#define MGB_DMAC_STATE_INITIAL MGB_DMAC_STATE(0, 0)
#define MGB_DMAC_STATE_STARTED MGB_DMAC_STATE(1, 0)
#define MGB_DMAC_STATE_STOP_PENDING MGB_DMAC_STATE(1, 1)
#define MGB_DMAC_STATE_STOPPED MGB_DMAC_STATE(0, 1)
#define MGB_DMAC_CMD_STATE(sc, _s, _ch) \
(MGB_DMAC_STATE( \
CSR_READ_REG(sc, MGB_DMAC_CMD) & MGB_DMAC_CMD_START(_s, _ch), \
CSR_READ_REG(sc, MGB_DMAC_CMD) & MGB_DMAC_CMD_STOP(_s, _ch)))
#define MGB_DMAC_STATE_IS_INITIAL(sc, _s, _ch) \
(MGB_DMAC_CMD_STATE(sc, _s, _ch) == MGB_DMAC_STATE_INITIAL)
#define MGB_DMAC_INTR_STS 0xC10
#define MGB_DMAC_INTR_ENBL_SET 0xC14
#define MGB_DMAC_INTR_ENBL_CLR 0xC18
#define MGB_DMAC_TX_INTR_ENBL(_ch) (1 << (_ch))
#define MGB_DMAC_RX_INTR_ENBL(_ch) (1 << (16 + (_ch)))
/** DMA Rings **/
/**
* Page size is 256 bytes
*
* Ring size, however, these could be tunable (for RX & TX)
* to be a multiple of 4 (max is 65532)
*
**/
/* In linux driver these numbers are 50 and 65 for tx and rx .... */
#define MGB_DMA_RING_SIZE 16 /* in programming guide, this number is 100 */
#define MGB_DMA_MAXSEGS 32
#define MGB_DMA_REG(reg, _channel) ((reg) | ((_channel) << 6))
#define MGB_DMA_RING_LIST_SIZE \
(sizeof(struct mgb_ring_desc) * MGB_DMA_RING_SIZE)
#define MGB_DMA_RING_INFO_SIZE \
(sizeof(uint32_t) + MGB_DMA_RING_LIST_SIZE)
#define MGB_DMA_TX_CONFIG0(_channel) MGB_DMA_REG(0x0D40, _channel)
#define MGB_DMA_TX_CONFIG1(_channel) MGB_DMA_REG(0x0D44, _channel)
#define MGB_DMA_TX_BASE_H(_channel) MGB_DMA_REG(0x0D48, _channel)
#define MGB_DMA_TX_BASE_L(_channel) MGB_DMA_REG(0x0D4C, _channel)
#define MGB_DMA_TX_HEAD_WB_H(_channel) MGB_DMA_REG(0x0D50, _channel) /* head Writeback */
#define MGB_DMA_TX_HEAD_WB_L(_channel) MGB_DMA_REG(0x0D54, _channel)
#define MGB_DMA_TX_HEAD(_channel) MGB_DMA_REG(0x0D58, _channel)
#define MGB_DMA_TX_TAIL(_channel) MGB_DMA_REG(0x0D5C, _channel)
#define MGB_DMA_RX_CONFIG0(_channel) MGB_DMA_REG(0x0C40, _channel)
#define MGB_DMA_RX_CONFIG1(_channel) MGB_DMA_REG(0x0C44, _channel)
#define MGB_DMA_RX_BASE_H(_channel) MGB_DMA_REG(0x0C48, _channel)
#define MGB_DMA_RX_BASE_L(_channel) MGB_DMA_REG(0x0C4C, _channel)
#define MGB_DMA_RX_HEAD_WB_H(_channel) MGB_DMA_REG(0x0C50, _channel) /* head Writeback */
#define MGB_DMA_RX_HEAD_WB_L(_channel) MGB_DMA_REG(0x0C54, _channel)
#define MGB_DMA_RX_HEAD(_channel) MGB_DMA_REG(0x0C58, _channel)
#define MGB_DMA_RX_TAIL(_channel) MGB_DMA_REG(0x0C5C, _channel)
#define MGB_DMA_RING_LEN_MASK 0xFFFF
#define MGB_DMA_IOC_ENBL 0x10000000
#define MGB_DMA_HEAD_WB_LS_ENBL 0x20000000
#define MGB_DMA_HEAD_WB_ENBL (1 << 5)
#define MGB_DMA_RING_PAD_MASK 0x03000000
#define MGB_DMA_RING_PAD_0 0x00000000
#define MGB_DMA_RING_PAD_2 0x02000000
#define MGB_DESC_CTL_OWN (1 << 15)
#define MGB_DESC_CTL_FCS (1 << 17)
#define MGB_DESC_CTL_IOC (1 << 26)
#define MGB_TX_DESC_CTL_LS (1 << 28)
#define MGB_TX_DESC_CTL_FS (1 << 29)
#define MGB_RX_DESC_CTL_LS (1 << 30)
#define MGB_RX_DESC_CTL_FS (1 << 31)
#define MGB_DESC_CTL_BUFLEN_MASK (0x0000FFFF)
#define MGB_DESC_STS_BUFLEN_MASK (0x00003FFF)
#define MGB_DESC_FRAME_LEN_MASK (0x3FFF0000)
#define MGB_DESC_GET_FRAME_LEN(_desc) \
(((_desc)->ctl & MGB_DESC_FRAME_LEN_MASK) >> 16)
iflib: leave only 1 receive descriptor unused The pidx argument of isc_rxd_flush() indicates which is the last valid receive descriptor to be used by the NIC. However, current code has multiple issues: - Intel drivers write pidx to their RDT register, which means that NICs will only use the descriptors up to pidx-1 (modulo ring size N), and won't actually use the one pointed by pidx. This does not break reception, but it is anyway confusing and suboptimal (the NIC will actually see only N-2 descriptors as available, rather than N-1). Other drivers (if_vmx, if_bnxt, if_mgb) adhere to this semantic). - The semantic used by Intel (RDT is one descriptor past the last valid one) is used by most (if not all) NICs, and it is also used on the TX side (also in iflib). Since iflib is not currently using this semantic for RX, it must decrement fl->ifl_pidx (modulo N) before calling isc_rxd_flush(), and then the per-driver callback implementation must increment the index again (to match the real semantic). This is confusing and suboptimal. - The iflib refill function is also called at initialization. However, in case the ring size is smaller than 128 (e.g. if_mgb), the refill function will actually prepare all the receive descriptors (N), without leaving one unused, as most of NICs assume (e.g. to avoid RDT to overrun RDH). I can speculate that the code looks like this right now because this issue showed up during testing (e.g. with if_mgb), and it was easy to workaround by decrementing pidx before isc_rxd_flush(). The goal of this change is to simplify the code (removing a bunch of instructions from the RX fast path), and to make the semantic of isc_rxd_flush() consistent across drivers. To achieve this, we: - change the semantics of the pidx argument to the usual one (that is the index one past the last valid one), so that both iflib and drivers avoid the decrement/increment dance. - fix the initialization code to prepare at most N-1 descriptors. Reviewed by: markj MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D26191
2020-09-01 20:41:47 +00:00
#define MGB_NEXT_RING_IDX(_idx) (((_idx) == MGB_DMA_RING_SIZE - 1) ? 0 : ((_idx_) + 1))
#define MGB_PREV_RING_IDX(_idx) (((_idx) == 0) ? (MGB_DMA_RING_SIZE - 1) : ((_idx_) - 1))
#define MGB_RING_SPACE(_sc) \
((((_sc)->tx_ring_data.last_head - (_sc)->tx_ring_data.last_tail - 1) \
+ MGB_DMA_RING_SIZE ) % MGB_DMA_RING_SIZE )
/** PHY **/
#define MGB_MII_ACCESS 0x120
#define MGB_MII_DATA 0x124
#define MGB_MII_PHY_ADDR_MASK 0x1F
#define MGB_MII_PHY_ADDR_SHIFT 11
#define MGB_MII_REG_ADDR_MASK 0x1F
#define MGB_MII_REG_ADDR_SHIFT 6
#define MGB_MII_READ 0x0
#define MGB_MII_WRITE 0x2
#define MGB_MII_BUSY 0x1
/** Interrupt registers **/
#define MGB_INTR_STS 0x780
#define MGB_INTR_SET 0x784 /* This triggers a particular interrupt */
#define MGB_INTR_ENBL_SET 0x788
#define MGB_INTR_STS_ANY (0x1)
#define MGB_INTR_STS_RX(_channel) (1 << (24 + (_channel)))
#define MGB_INTR_STS_RX_ANY (0xF << 24)
#define MGB_INTR_STS_TX(_channel) (1 << (16 + (_channel)))
#define MGB_INTR_STS_TX_ANY (0xF << 16)
#define MGB_INTR_STS_TEST (1 << 9)
#define MGB_INTR_ENBL_CLR 0x78C
#define MGB_INTR_VEC_ENBL_SET 0x794
#define MGB_INTR_VEC_ENBL_CLR 0x798
#define MGB_INTR_VEC_ENBL_AUTO_CLR 0x79C
#define MGB_INTR_VEC_RX_MAP 0x7A0
#define MGB_INTR_VEC_TX_MAP 0x7A4
#define MGB_INTR_VEC_OTHER_MAP 0x7A8
#define MGB_INTR_VEC_MAP(_vsts, _ch) ((_vsts) << ((_ch) << 2))
#define MGB_INTR_VEC_STS(_v) (1 << (_v))
#define MGB_INTR_RX_VEC_STS(_qid) MGB_INTR_VEC_STS((_qid) + 1)
#define MGB_STS_OK ( 0 )
#define MGB_STS_TIMEOUT (-1 )
#define CSR_READ_BYTE(sc, reg) \
bus_read_1((sc)->regs, reg)
#define CSR_WRITE_BYTE(sc, reg, val) \
bus_write_1((sc)->regs, reg, val)
#define CSR_UPDATE_BYTE(sc, reg, val) \
CSR_WRITE_BYTE(sc, reg, CSR_READ_BYTE(sc, reg) | (val))
#define CSR_READ_REG(sc, reg) \
bus_read_4((sc)->regs, reg)
#define CSR_WRITE_REG(sc, reg, val) \
bus_write_4((sc)->regs, reg, val)
#define CSR_CLEAR_REG(sc, reg, bits) \
CSR_WRITE_REG(sc, reg, CSR_READ_REG(sc, reg) & ~(bits))
#define CSR_UPDATE_REG(sc, reg, val) \
CSR_WRITE_REG(sc, reg, CSR_READ_REG(sc, reg) | (val))
#define CSR_READ_2_BYTES(sc, reg) \
bus_read_2((sc)->regs, reg)
#define CSR_READ_REG_BYTES(sc, reg, dest, cnt) \
bus_read_region_1((sc)->regs, reg, dest, cnt)
#define CSR_TRANSLATE_ADDR_LOW32(addr) ((uint64_t) (addr) & 0xFFFFFFFF)
#define CSR_TRANSLATE_ADDR_HIGH32(addr) ((uint64_t) (addr) >> 32)
struct mgb_irq {
struct resource *res;
void *handler;
};
enum mgb_dmac_cmd { DMAC_RESET, DMAC_START, DMAC_STOP };
enum mgb_fct_cmd { FCT_RESET, FCT_ENABLE, FCT_DISABLE };
struct mgb_ring_desc_addr {
uint32_t low;
uint32_t high;
} __packed;
/* TODO: With descriptor bit information
* this could be done without masks etc.
* (using bitwise structs like vmx,
* would have to separate rx/tx ring desc
* definitions)
*/
struct mgb_ring_desc {
uint32_t ctl; /* data0 */
struct mgb_ring_desc_addr addr; /* data(1|2) */
uint32_t sts; /* data3 */
} __packed;
#if 0
struct mgb_ring_info {
uint32_t head_wb;
struct mgb_ring_desc *ring;
}
#endif
#define MGB_HEAD_WB_PTR(_ring_info_ptr) \
((uint32_t *)(_ring_info_ptr))
#define MGB_RING_PTR(_ring_info_ptr) \
((struct mgb_ring_desc *)(MGB_HEAD_WB_PTR(_ring_info_ptr) + 1))
struct mgb_ring_data {
uint32_t *head_wb;
struct mgb_ring_desc *ring;
bus_addr_t head_wb_bus_addr;
bus_addr_t ring_bus_addr;
uint32_t last_head;
uint32_t last_tail;
};
struct mgb_softc {
if_ctx_t ctx;
device_t dev;
struct resource *regs;
struct resource *pba;
struct if_irq admin_irq;
struct if_irq rx_irq;
bool isr_test_flag;
device_t miibus;
int link_state;
int baudrate;
int if_flags;
int ethaddr;
int flags;
struct mtx mtx;
struct callout watchdog;
int timer;
bus_dma_tag_t dma_parent_tag;
struct mgb_ring_data rx_ring_data;
struct mgb_ring_data tx_ring_data;
};
#endif /* _IF_MGB_H_ */