diff options
Diffstat (limited to 'drivers')
380 files changed, 26392 insertions, 12708 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 737d93ef27c5..35952a94875e 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -97,6 +97,7 @@ config BT_HCIUART_NOKIA depends on BT_HCIUART depends on BT_HCIUART_SERDEV depends on PM + select BT_HCIUART_H4 help Nokia H4+ is serial protocol for communication between Bluetooth device and host. This protocol is required for Bluetooth devices @@ -131,7 +132,7 @@ config BT_HCIUART_ATH3K config BT_HCIUART_LL bool "HCILL protocol support" - depends on BT_HCIUART + depends on BT_HCIUART_SERDEV help HCILL (HCI Low Level) is a serial protocol for communication between Bluetooth device and host. This protocol is required for diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index fce154855718..d32e109bd5cb 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -575,3 +575,5 @@ MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); MODULE_FIRMWARE("intel/ibt-11-5.sfi"); MODULE_FIRMWARE("intel/ibt-11-5.ddc"); +MODULE_FIRMWARE("intel/ibt-12-16.sfi"); +MODULE_FIRMWARE("intel/ibt-12-16.ddc"); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 7fa373b428f8..278e81186150 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -336,6 +336,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW }, { USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL }, + { USB_DEVICE(0x8087, 0x0aaa), .driver_info = BTUSB_INTEL_NEW }, /* Other Intel Bluetooth devices */ { USB_VENDOR_AND_INTERFACE_INFO(0x8087, 0xe0, 0x01, 0x01), @@ -2036,6 +2037,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) switch (ver.hw_variant) { case 0x0b: /* SfP */ case 0x0c: /* WsP */ + case 0x11: /* JfP */ case 0x12: /* ThP */ break; default: @@ -2138,6 +2140,8 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) * Currently the supported hardware variants are: * 11 (0x0b) for iBT3.0 (LnP/SfP) * 12 (0x0c) for iBT3.5 (WsP) + * 17 (0x11) for iBT3.5 (JfP) + * 18 (0x12) for iBT3.5 (ThP) */ snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi", le16_to_cpu(ver.hw_variant), diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c index b6bb58c41df5..85a3978b064f 100644 --- a/drivers/bluetooth/btwilink.c +++ b/drivers/bluetooth/btwilink.c @@ -262,7 +262,6 @@ static int ti_st_send_frame(struct hci_dev *hdev, struct sk_buff *skb) pkt_type = hci_skb_pkt_type(skb); len = hst->st_write(skb); if (len < 0) { - kfree_skb(skb); BT_ERR("ST write failed (%ld)", len); /* Try Again, would only fail if UART has gone bad */ return -EAGAIN; diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 2edd30556956..8397b716fa65 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -114,8 +114,12 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) struct sk_buff *skb = hu->tx_skb; if (!skb) { + read_lock(&hu->proto_lock); + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) skb = hu->proto->dequeue(hu); + + read_unlock(&hu->proto_lock); } else { hu->tx_skb = NULL; } @@ -125,18 +129,23 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) int hci_uart_tx_wakeup(struct hci_uart *hu) { + read_lock(&hu->proto_lock); + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) - return 0; + goto no_schedule; if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); - return 0; + goto no_schedule; } BT_DBG(""); schedule_work(&hu->write_work); +no_schedule: + read_unlock(&hu->proto_lock); + return 0; } EXPORT_SYMBOL_GPL(hci_uart_tx_wakeup); @@ -237,9 +246,13 @@ static int hci_uart_flush(struct hci_dev *hdev) tty_ldisc_flush(tty); tty_driver_flush_buffer(tty); + read_lock(&hu->proto_lock); + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) hu->proto->flush(hu); + read_unlock(&hu->proto_lock); + return 0; } @@ -261,10 +274,15 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s: type %d len %d", hdev->name, hci_skb_pkt_type(skb), skb->len); - if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) + read_lock(&hu->proto_lock); + + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + read_unlock(&hu->proto_lock); return -EUNATCH; + } hu->proto->enqueue(hu, skb); + read_unlock(&hu->proto_lock); hci_uart_tx_wakeup(hu); @@ -460,6 +478,8 @@ static int hci_uart_tty_open(struct tty_struct *tty) INIT_WORK(&hu->init_ready, hci_uart_init_work); INIT_WORK(&hu->write_work, hci_uart_write_work); + rwlock_init(&hu->proto_lock); + /* Flush any pending characters in the driver */ tty_driver_flush_buffer(tty); @@ -475,6 +495,7 @@ static void hci_uart_tty_close(struct tty_struct *tty) { struct hci_uart *hu = tty->disc_data; struct hci_dev *hdev; + unsigned long flags; BT_DBG("tty %p", tty); @@ -490,7 +511,11 @@ static void hci_uart_tty_close(struct tty_struct *tty) cancel_work_sync(&hu->write_work); - if (test_and_clear_bit(HCI_UART_PROTO_READY, &hu->flags)) { + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + write_lock_irqsave(&hu->proto_lock, flags); + clear_bit(HCI_UART_PROTO_READY, &hu->flags); + write_unlock_irqrestore(&hu->proto_lock, flags); + if (hdev) { if (test_bit(HCI_UART_REGISTERED, &hu->flags)) hci_unregister_dev(hdev); @@ -549,13 +574,18 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, if (!hu || tty != hu->tty) return; - if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) + read_lock(&hu->proto_lock); + + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + read_unlock(&hu->proto_lock); return; + } /* It does not need a lock here as it is already protected by a mutex in * tty caller */ hu->proto->recv(hu, data, count); + read_unlock(&hu->proto_lock); if (hu->hdev) hu->hdev->stat.byte_rx += count; diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index adc444f309a3..200288c87fc4 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -624,6 +624,7 @@ static int download_firmware(struct ll_device *lldev) skb = __hci_cmd_sync(lldev->hu.hdev, cmd->opcode, cmd->plen, &cmd->speed, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(lldev->hu.hdev, "send command failed\n"); + err = PTR_ERR(skb); goto out_rel_fw; } kfree_skb(skb); diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 2b05e557fad0..c6e9e1cf63f8 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -87,6 +87,7 @@ struct hci_uart { struct work_struct write_work; const struct hci_uart_proto *proto; + rwlock_t proto_lock; /* Stop work for proto close */ void *priv; struct sk_buff *tx_skb; diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 94c049b62c2f..a384d72ea3cd 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -788,7 +788,7 @@ static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata, *inlen = MLX5_ST_SZ_BYTES(create_cq_in) + MLX5_FLD_SZ_BYTES(create_cq_in, pas[0]) * ncont; - *cqb = mlx5_vzalloc(*inlen); + *cqb = kvzalloc(*inlen, GFP_KERNEL); if (!*cqb) { err = -ENOMEM; goto err_db; @@ -884,7 +884,7 @@ static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, *inlen = MLX5_ST_SZ_BYTES(create_cq_in) + MLX5_FLD_SZ_BYTES(create_cq_in, pas[0]) * cq->buf.buf.npages; - *cqb = mlx5_vzalloc(*inlen); + *cqb = kvzalloc(*inlen, GFP_KERNEL); if (!*cqb) { err = -ENOMEM; goto err_buf; @@ -1314,7 +1314,7 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) inlen = MLX5_ST_SZ_BYTES(modify_cq_in) + MLX5_FLD_SZ_BYTES(modify_cq_in, pas[0]) * npas; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { err = -ENOMEM; goto ex_resize; diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c index f1b56de64871..95db929bdc34 100644 --- a/drivers/infiniband/hw/mlx5/mad.c +++ b/drivers/infiniband/hw/mlx5/mad.c @@ -218,7 +218,7 @@ static int process_pma_cmd(struct ib_device *ibdev, u8 port_num, (struct ib_pma_portcounters_ext *)(out_mad->data + 40); int sz = MLX5_ST_SZ_BYTES(query_vport_counter_out); - out_cnt = mlx5_vzalloc(sz); + out_cnt = kvzalloc(sz, GFP_KERNEL); if (!out_cnt) return IB_MAD_RESULT_FAILURE; @@ -231,7 +231,7 @@ static int process_pma_cmd(struct ib_device *ibdev, u8 port_num, (struct ib_pma_portcounters *)(out_mad->data + 40); int sz = MLX5_ST_SZ_BYTES(ppcnt_reg); - out_cnt = mlx5_vzalloc(sz); + out_cnt = kvzalloc(sz, GFP_KERNEL); if (!out_cnt) return IB_MAD_RESULT_FAILURE; diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 0c79983c8b1a..852a6a75db98 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -60,8 +60,7 @@ #include "cmd.h" #define DRIVER_NAME "mlx5_ib" -#define DRIVER_VERSION "2.2-1" -#define DRIVER_RELDATE "Feb 2014" +#define DRIVER_VERSION "5.0-0" MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>"); MODULE_DESCRIPTION("Mellanox Connect-IB HCA IB driver"); @@ -70,7 +69,7 @@ MODULE_VERSION(DRIVER_VERSION); static char mlx5_version[] = DRIVER_NAME ": Mellanox Connect-IB Infiniband driver v" - DRIVER_VERSION " (" DRIVER_RELDATE ")\n"; + DRIVER_VERSION "\n"; enum { MLX5_ATOMIC_SIZE_QP_8BYTES = 1 << 3, @@ -2263,7 +2262,7 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev, if (!is_valid_attr(dev->mdev, flow_attr)) return ERR_PTR(-EINVAL); - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); handler = kzalloc(sizeof(*handler), GFP_KERNEL); if (!handler || !spec) { err = -ENOMEM; @@ -3468,7 +3467,7 @@ static int mlx5_ib_query_q_counters(struct mlx5_ib_dev *dev, __be32 val; int ret, i; - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -3497,7 +3496,7 @@ static int mlx5_ib_query_cong_counters(struct mlx5_ib_dev *dev, int ret, i; int offset = port->cnts.num_q_counters; - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 366433f71b58..763bb5b36144 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1110,7 +1110,7 @@ static struct mlx5_ib_mr *reg_create(struct ib_mr *ibmr, struct ib_pd *pd, inlen = MLX5_ST_SZ_BYTES(create_mkey_in) + sizeof(*pas) * ((npages + 1) / 2) * 2; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { err = -ENOMEM; goto err_1; diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index ebb6768684de..0889ff367c86 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -823,7 +823,7 @@ static int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd, *inlen = MLX5_ST_SZ_BYTES(create_qp_in) + MLX5_FLD_SZ_BYTES(create_qp_in, pas[0]) * ncont; - *in = mlx5_vzalloc(*inlen); + *in = kvzalloc(*inlen, GFP_KERNEL); if (!*in) { err = -ENOMEM; goto err_umem; @@ -931,7 +931,7 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev, qp->sq.qend = mlx5_get_send_wqe(qp, qp->sq.wqe_cnt); *inlen = MLX5_ST_SZ_BYTES(create_qp_in) + MLX5_FLD_SZ_BYTES(create_qp_in, pas[0]) * qp->buf.npages; - *in = mlx5_vzalloc(*inlen); + *in = kvzalloc(*inlen, GFP_KERNEL); if (!*in) { err = -ENOMEM; goto err_buf; @@ -1060,7 +1060,7 @@ static int create_raw_packet_qp_sq(struct mlx5_ib_dev *dev, return err; inlen = MLX5_ST_SZ_BYTES(create_sq_in) + sizeof(u64) * ncont; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { err = -ENOMEM; goto err_umem; @@ -1140,7 +1140,7 @@ static int create_raw_packet_qp_rq(struct mlx5_ib_dev *dev, u32 rq_pas_size = get_rq_pas_size(qpc); inlen = MLX5_ST_SZ_BYTES(create_rq_in) + rq_pas_size; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -1193,7 +1193,7 @@ static int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev, int err; inlen = MLX5_ST_SZ_BYTES(create_tir_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -1372,7 +1372,7 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, } inlen = MLX5_ST_SZ_BYTES(create_tir_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -1633,7 +1633,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, if (err) return err; } else { - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2164,7 +2164,7 @@ static int modify_raw_packet_eth_prio(struct mlx5_core_dev *dev, int err; inlen = MLX5_ST_SZ_BYTES(modify_tis_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2189,7 +2189,7 @@ static int modify_raw_packet_tx_affinity(struct mlx5_core_dev *dev, int err; inlen = MLX5_ST_SZ_BYTES(modify_tis_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2434,7 +2434,7 @@ static int modify_raw_packet_qp_rq(struct mlx5_ib_dev *dev, int err; inlen = MLX5_ST_SZ_BYTES(modify_rq_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2479,7 +2479,7 @@ static int modify_raw_packet_qp_sq(struct mlx5_core_dev *dev, int err; inlen = MLX5_ST_SZ_BYTES(modify_sq_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -4281,7 +4281,7 @@ static int query_raw_packet_qp_sq_state(struct mlx5_ib_dev *dev, int err; inlen = MLX5_ST_SZ_BYTES(query_sq_out); - out = mlx5_vzalloc(inlen); + out = kvzalloc(inlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -4308,7 +4308,7 @@ static int query_raw_packet_qp_rq_state(struct mlx5_ib_dev *dev, int err; inlen = MLX5_ST_SZ_BYTES(query_rq_out); - out = mlx5_vzalloc(inlen); + out = kvzalloc(inlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -4612,7 +4612,7 @@ static int create_rq(struct mlx5_ib_rwq *rwq, struct ib_pd *pd, dev = to_mdev(pd->device); inlen = MLX5_ST_SZ_BYTES(create_rq_in) + sizeof(u64) * rwq->rq_num_pas; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -4842,7 +4842,7 @@ struct ib_rwq_ind_table *mlx5_ib_create_rwq_ind_table(struct ib_device *device, return ERR_PTR(-ENOMEM); inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * sz; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { err = -ENOMEM; goto err; @@ -4921,7 +4921,7 @@ int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr, return -EOPNOTSUPP; inlen = MLX5_ST_SZ_BYTES(modify_rq_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 7cb145f9a6db..43707b101f47 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -127,7 +127,7 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq, goto err_umem; } - in->pas = mlx5_vzalloc(sizeof(*in->pas) * ncont); + in->pas = kvzalloc(sizeof(*in->pas) * ncont, GFP_KERNEL); if (!in->pas) { err = -ENOMEM; goto err_umem; @@ -189,7 +189,7 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq, } mlx5_ib_dbg(dev, "srq->buf.page_shift = %d\n", srq->buf.page_shift); - in->pas = mlx5_vzalloc(sizeof(*in->pas) * srq->buf.npages); + in->pas = kvzalloc(sizeof(*in->pas) * srq->buf.npages, GFP_KERNEL); if (!in->pas) { err = -ENOMEM; goto err_buf; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2359478b977f..d4484d1a8164 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3488,7 +3488,8 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd case BOND_CHANGE_ACTIVE_OLD: case SIOCBONDCHANGEACTIVE: bond_opt_initstr(&newval, slave_dev->name); - res = __bond_opt_set(bond, BOND_OPT_ACTIVE_SLAVE, &newval); + res = __bond_opt_set_notify(bond, BOND_OPT_ACTIVE_SLAVE, + &newval); break; default: res = -EOPNOTSUPP; diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 1bcbb8913e17..8ca683396fcc 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -673,7 +673,30 @@ int __bond_opt_set(struct bonding *bond, out: if (ret) bond_opt_error_interpret(bond, opt, ret, val); - else if (bond->dev->reg_state == NETREG_REGISTERED) + + return ret; +} +/** + * __bond_opt_set_notify - set a bonding option + * @bond: target bond device + * @option: option to set + * @val: value to set it to + * + * This function is used to change the bond's option value and trigger + * a notification to user sapce. It can be used for both enabling/changing + * an option and for disabling it. RTNL lock must be obtained before calling + * this function. + */ +int __bond_opt_set_notify(struct bonding *bond, + unsigned int option, struct bond_opt_value *val) +{ + int ret = -ENOENT; + + ASSERT_RTNL(); + + ret = __bond_opt_set(bond, option, val); + + if (!ret && (bond->dev->reg_state == NETREG_REGISTERED)) call_netdevice_notifiers(NETDEV_CHANGEINFODATA, bond->dev); return ret; @@ -696,7 +719,7 @@ int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf) if (!rtnl_trylock()) return restart_syscall(); bond_opt_initstr(&optval, buf); - ret = __bond_opt_set(bond, option, &optval); + ret = __bond_opt_set_notify(bond, option, &optval); rtnl_unlock(); return ret; diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index bf8fdaeb955e..f4947a74b65f 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -621,10 +621,8 @@ static int __m_can_get_berr_counter(const struct net_device *dev, return 0; } -static int m_can_get_berr_counter(const struct net_device *dev, - struct can_berr_counter *bec) +static int m_can_clk_start(struct m_can_priv *priv) { - struct m_can_priv *priv = netdev_priv(dev); int err; err = clk_prepare_enable(priv->hclk); @@ -632,15 +630,31 @@ static int m_can_get_berr_counter(const struct net_device *dev, return err; err = clk_prepare_enable(priv->cclk); - if (err) { + if (err) clk_disable_unprepare(priv->hclk); - return err; - } - __m_can_get_berr_counter(dev, bec); + return err; +} +static void m_can_clk_stop(struct m_can_priv *priv) +{ clk_disable_unprepare(priv->cclk); clk_disable_unprepare(priv->hclk); +} + +static int m_can_get_berr_counter(const struct net_device *dev, + struct can_berr_counter *bec) +{ + struct m_can_priv *priv = netdev_priv(dev); + int err; + + err = m_can_clk_start(priv); + if (err) + return err; + + __m_can_get_berr_counter(dev, bec); + + m_can_clk_stop(priv); return 0; } @@ -1276,19 +1290,15 @@ static int m_can_open(struct net_device *dev) struct m_can_priv *priv = netdev_priv(dev); int err; - err = clk_prepare_enable(priv->hclk); + err = m_can_clk_start(priv); if (err) return err; - err = clk_prepare_enable(priv->cclk); - if (err) - goto exit_disable_hclk; - /* open the can device */ err = open_candev(dev); if (err) { netdev_err(dev, "failed to open can device\n"); - goto exit_disable_cclk; + goto exit_disable_clks; } /* register interrupt handler */ @@ -1310,10 +1320,8 @@ static int m_can_open(struct net_device *dev) exit_irq_fail: close_candev(dev); -exit_disable_cclk: - clk_disable_unprepare(priv->cclk); -exit_disable_hclk: - clk_disable_unprepare(priv->hclk); +exit_disable_clks: + m_can_clk_stop(priv); return err; } @@ -1324,9 +1332,6 @@ static void m_can_stop(struct net_device *dev) /* disable all interrupts */ m_can_disable_all_interrupts(priv); - clk_disable_unprepare(priv->hclk); - clk_disable_unprepare(priv->cclk); - /* set the state as STOPPED */ priv->can.state = CAN_STATE_STOPPED; } @@ -1338,6 +1343,7 @@ static int m_can_close(struct net_device *dev) netif_stop_queue(dev); napi_disable(&priv->napi); m_can_stop(dev); + m_can_clk_stop(priv); free_irq(dev->irq, dev); close_candev(dev); can_led_event(dev, CAN_LED_EVENT_STOP); @@ -1489,11 +1495,23 @@ static int register_m_can_dev(struct net_device *dev) return register_candev(dev); } +static void m_can_init_ram(struct m_can_priv *priv) +{ + int end, i, start; + + /* initialize the entire Message RAM in use to avoid possible + * ECC/parity checksum errors when reading an uninitialized buffer + */ + start = priv->mcfg[MRAM_SIDF].off; + end = priv->mcfg[MRAM_TXB].off + + priv->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE; + for (i = start; i < end; i += 4) + writel(0x0, priv->mram_base + i); +} + static void m_can_of_parse_mram(struct m_can_priv *priv, const u32 *mram_config_vals) { - int i, start, end; - priv->mcfg[MRAM_SIDF].off = mram_config_vals[0]; priv->mcfg[MRAM_SIDF].num = mram_config_vals[1]; priv->mcfg[MRAM_XIDF].off = priv->mcfg[MRAM_SIDF].off + @@ -1529,15 +1547,7 @@ static void m_can_of_parse_mram(struct m_can_priv *priv, priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num, priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num); - /* initialize the entire Message RAM in use to avoid possible - * ECC/parity checksum errors when reading an uninitialized buffer - */ - start = priv->mcfg[MRAM_SIDF].off; - end = priv->mcfg[MRAM_TXB].off + - priv->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE; - for (i = start; i < end; i += 4) - writel(0x0, priv->mram_base + i); - + m_can_init_ram(priv); } static int m_can_plat_probe(struct platform_device *pdev) @@ -1658,6 +1668,8 @@ failed_ret: return ret; } +/* TODO: runtime PM with power down or sleep mode */ + static __maybe_unused int m_can_suspend(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); @@ -1666,10 +1678,10 @@ static __maybe_unused int m_can_suspend(struct device *dev) if (netif_running(ndev)) { netif_stop_queue(ndev); netif_device_detach(ndev); + m_can_stop(ndev); + m_can_clk_stop(priv); } - /* TODO: enter low power */ - priv->can.state = CAN_STATE_SLEEPING; return 0; @@ -1680,11 +1692,18 @@ static __maybe_unused int m_can_resume(struct device *dev) struct net_device *ndev = dev_get_drvdata(dev); struct m_can_priv *priv = netdev_priv(ndev); - /* TODO: exit low power */ + m_can_init_ram(priv); priv->can.state = CAN_STATE_ERROR_ACTIVE; if (netif_running(ndev)) { + int ret; + + ret = m_can_clk_start(priv); + if (ret) + return ret; + + m_can_start(ndev); netif_device_attach(ndev); netif_start_queue(ndev); } diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index da020418a652..017f48cdcab9 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -1417,10 +1417,9 @@ static int e100_get_link_ksettings(struct net_device *dev, { struct net_local *np = netdev_priv(dev); u32 supported; - int err; spin_lock_irq(&np->lock); - err = mii_ethtool_get_link_ksettings(&np->mii_if, cmd); + mii_ethtool_get_link_ksettings(&np->mii_if, cmd); spin_unlock_irq(&np->lock); /* The PHY may support 1000baseT, but the Etrax100 does not. */ @@ -1432,7 +1431,7 @@ static int e100_get_link_ksettings(struct net_device *dev, ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, supported); - return err; + return 0; } static int e100_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 862ee22303c2..83a9bc892a3b 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -1,13 +1,7 @@ menu "Distributed Switch Architecture drivers" depends on HAVE_NET_DSA -config NET_DSA_MV88E6060 - tristate "Marvell 88E6060 ethernet switch chip support" - depends on NET_DSA - select NET_DSA_TAG_TRAILER - ---help--- - This enables support for the Marvell 88E6060 ethernet switch - chip. +source "drivers/net/dsa/b53/Kconfig" config NET_DSA_BCM_SF2 tristate "Broadcom Starfighter 2 Ethernet switch support" @@ -21,19 +15,6 @@ config NET_DSA_BCM_SF2 This enables support for the Broadcom Starfighter 2 Ethernet switch chips. -source "drivers/net/dsa/b53/Kconfig" - -source "drivers/net/dsa/mv88e6xxx/Kconfig" - -config NET_DSA_QCA8K - tristate "Qualcomm Atheros QCA8K Ethernet switch family support" - depends on NET_DSA - select NET_DSA_TAG_QCA - select REGMAP - ---help--- - This enables support for the Qualcomm Atheros QCA8K Ethernet - switch chips. - config NET_DSA_LOOP tristate "DSA mock-up Ethernet switch chip support" depends on NET_DSA @@ -50,6 +31,27 @@ config NET_DSA_MT7530 This enables support for the Mediatek MT7530 Ethernet switch chip. +config NET_DSA_MV88E6060 + tristate "Marvell 88E6060 ethernet switch chip support" + depends on NET_DSA + select NET_DSA_TAG_TRAILER + ---help--- + This enables support for the Marvell 88E6060 ethernet switch + chip. + +source "drivers/net/dsa/microchip/Kconfig" + +source "drivers/net/dsa/mv88e6xxx/Kconfig" + +config NET_DSA_QCA8K + tristate "Qualcomm Atheros QCA8K Ethernet switch family support" + depends on NET_DSA + select NET_DSA_TAG_QCA + select REGMAP + ---help--- + This enables support for the Qualcomm Atheros QCA8K Ethernet + switch chips. + config NET_DSA_SMSC_LAN9303 tristate select NET_DSA_TAG_LAN9303 diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index edd630361736..4a5b5bd297ee 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -1,11 +1,12 @@ -obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm-sf2.o bcm-sf2-objs := bcm_sf2.o bcm_sf2_cfp.o -obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o +obj-$(CONFIG_NET_DSA_LOOP) += dsa_loop.o dsa_loop_bdinfo.o obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o +obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o +obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o obj-y += b53/ +obj-y += microchip/ obj-y += mv88e6xxx/ -obj-$(CONFIG_NET_DSA_LOOP) += dsa_loop.o dsa_loop_bdinfo.o diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index fa0eece21eef..e68d368e20ac 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -29,7 +29,6 @@ #include <linux/etherdevice.h> #include <linux/if_bridge.h> #include <net/dsa.h> -#include <net/switchdev.h> #include "b53_regs.h" #include "b53_priv.h" @@ -1056,7 +1055,7 @@ EXPORT_SYMBOL(b53_vlan_del); int b53_vlan_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_vlan *vlan, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct b53_device *dev = ds->priv; u16 vid, vid_start = 0, pvid; @@ -1282,10 +1281,9 @@ static void b53_arl_search_rd(struct b53_device *dev, u8 idx, b53_arl_to_entry(ent, mac_vid, fwd_entry); } -static int b53_fdb_copy(struct net_device *dev, int port, - const struct b53_arl_entry *ent, +static int b53_fdb_copy(int port, const struct b53_arl_entry *ent, struct switchdev_obj_port_fdb *fdb, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { if (!ent->is_valid) return 0; @@ -1302,10 +1300,9 @@ static int b53_fdb_copy(struct net_device *dev, int port, int b53_fdb_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_fdb *fdb, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct b53_device *priv = ds->priv; - struct net_device *dev = ds->ports[port].netdev; struct b53_arl_entry results[2]; unsigned int count = 0; int ret; @@ -1321,13 +1318,13 @@ int b53_fdb_dump(struct dsa_switch *ds, int port, return ret; b53_arl_search_rd(priv, 0, &results[0]); - ret = b53_fdb_copy(dev, port, &results[0], fdb, cb); + ret = b53_fdb_copy(port, &results[0], fdb, cb); if (ret) return ret; if (priv->num_arl_entries > 2) { b53_arl_search_rd(priv, 1, &results[1]); - ret = b53_fdb_copy(dev, port, &results[1], fdb, cb); + ret = b53_fdb_copy(port, &results[1], fdb, cb); if (ret) return ret; @@ -1344,7 +1341,7 @@ EXPORT_SYMBOL(b53_fdb_dump); int b53_br_join(struct dsa_switch *ds, int port, struct net_device *br) { struct b53_device *dev = ds->priv; - s8 cpu_port = ds->dst->cpu_port; + s8 cpu_port = ds->dst->cpu_dp->index; u16 pvlan, reg; unsigned int i; @@ -1390,7 +1387,7 @@ void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *br) { struct b53_device *dev = ds->priv; struct b53_vlan *vl = &dev->vlans[0]; - s8 cpu_port = ds->dst->cpu_port; + s8 cpu_port = ds->dst->cpu_dp->index; unsigned int i; u16 pvlan, reg, pvid; @@ -1992,7 +1989,7 @@ int b53_switch_register(struct b53_device *dev) pr_info("found switch: %s, rev %i\n", dev->name, dev->core_rev); - return dsa_register_switch(dev->ds, dev->ds->dev); + return dsa_register_switch(dev->ds); } EXPORT_SYMBOL(b53_switch_register); diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index a9dc90a01438..155a9c48c317 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -395,7 +395,7 @@ int b53_vlan_del(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan); int b53_vlan_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_vlan *vlan, - int (*cb)(struct switchdev_obj *obj)); + switchdev_obj_dump_cb_t *cb); int b53_fdb_prepare(struct dsa_switch *ds, int port, const struct switchdev_obj_port_fdb *fdb, struct switchdev_trans *trans); @@ -406,7 +406,7 @@ int b53_fdb_del(struct dsa_switch *ds, int port, const struct switchdev_obj_port_fdb *fdb); int b53_fdb_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_fdb *fdb, - int (*cb)(struct switchdev_obj *obj)); + switchdev_obj_dump_cb_t *cb); int b53_mirror_add(struct dsa_switch *ds, int port, struct dsa_mall_mirror_tc_entry *mirror, bool ingress); void b53_mirror_del(struct dsa_switch *ds, int port, diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c index 8a62b6a69703..c37ffd1b6833 100644 --- a/drivers/net/dsa/b53/b53_srab.c +++ b/drivers/net/dsa/b53/b53_srab.c @@ -364,6 +364,7 @@ static const struct of_device_id b53_srab_of_match[] = { { .compatible = "brcm,bcm53018-srab" }, { .compatible = "brcm,bcm53019-srab" }, { .compatible = "brcm,bcm5301x-srab" }, + { .compatible = "brcm,bcm11360-srab", .data = (void *)BCM58XX_DEVICE_ID }, { .compatible = "brcm,bcm58522-srab", .data = (void *)BCM58XX_DEVICE_ID }, { .compatible = "brcm,bcm58525-srab", .data = (void *)BCM58XX_DEVICE_ID }, { .compatible = "brcm,bcm58535-srab", .data = (void *)BCM58XX_DEVICE_ID }, @@ -371,6 +372,7 @@ static const struct of_device_id b53_srab_of_match[] = { { .compatible = "brcm,bcm58623-srab", .data = (void *)BCM58XX_DEVICE_ID }, { .compatible = "brcm,bcm58625-srab", .data = (void *)BCM58XX_DEVICE_ID }, { .compatible = "brcm,bcm88312-srab", .data = (void *)BCM58XX_DEVICE_ID }, + { .compatible = "brcm,cygnus-srab", .data = (void *)BCM58XX_DEVICE_ID }, { .compatible = "brcm,nsp-srab", .data = (void *)BCM58XX_DEVICE_ID }, { /* sentinel */ }, }; diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 2be963252ca5..687a8bae5d73 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -28,7 +28,6 @@ #include <linux/if_bridge.h> #include <linux/brcmphy.h> #include <linux/etherdevice.h> -#include <net/switchdev.h> #include <linux/platform_data/b53.h> #include "bcm_sf2.h" @@ -228,7 +227,7 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, struct phy_device *phy) { struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); - s8 cpu_port = ds->dst[ds->index].cpu_port; + s8 cpu_port = ds->dst->cpu_dp->index; unsigned int i; u32 reg; @@ -832,7 +831,7 @@ static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port, { struct net_device *p = ds->dst[ds->index].master_netdev; struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); - s8 cpu_port = ds->dst[ds->index].cpu_port; + s8 cpu_port = ds->dst->cpu_dp->index; struct ethtool_wolinfo pwol; p->ethtool_ops->get_wol(p, &pwol); diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index a19e1781e9bb..79e62593ff4e 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -17,7 +17,6 @@ #include <linux/workqueue.h> #include <linux/module.h> #include <linux/if_bridge.h> -#include <net/switchdev.h> #include <net/dsa.h> #include "dsa_loop.h" @@ -188,7 +187,7 @@ static int dsa_loop_port_vlan_del(struct dsa_switch *ds, int port, static int dsa_loop_port_vlan_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_vlan *vlan, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct dsa_loop_priv *ps = ds->priv; struct mii_bus *bus = ps->bus; @@ -272,7 +271,7 @@ static int dsa_loop_drv_probe(struct mdio_device *mdiodev) dev_set_drvdata(&mdiodev->dev, ds); - return dsa_register_switch(ds, ds->dev); + return dsa_register_switch(ds); } static void dsa_loop_drv_remove(struct mdio_device *mdiodev) diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c index c8b2423c8ef7..cd76e61f1fca 100644 --- a/drivers/net/dsa/lan9303-core.c +++ b/drivers/net/dsa/lan9303-core.c @@ -802,7 +802,7 @@ static int lan9303_register_switch(struct lan9303 *chip) chip->ds->ops = &lan9303_switch_ops; chip->ds->phys_mii_mask = chip->phy_addr_sel_strap ? 0xe : 0x7; - return dsa_register_switch(chip->ds, chip->dev); + return dsa_register_switch(chip->ds); } static void lan9303_probe_reset_gpio(struct lan9303 *chip, diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig new file mode 100644 index 000000000000..a8b8f59099ce --- /dev/null +++ b/drivers/net/dsa/microchip/Kconfig @@ -0,0 +1,12 @@ +menuconfig MICROCHIP_KSZ + tristate "Microchip KSZ series switch support" + depends on NET_DSA + select NET_DSA_TAG_KSZ + help + This driver adds support for Microchip KSZ switch chips. + +config MICROCHIP_KSZ_SPI_DRIVER + tristate "KSZ series SPI connected switch driver" + depends on MICROCHIP_KSZ && SPI + help + Select to enable support for registering switches configured through SPI. diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile new file mode 100644 index 000000000000..ed335e29fae8 --- /dev/null +++ b/drivers/net/dsa/microchip/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_MICROCHIP_KSZ) += ksz_common.o +obj-$(CONFIG_MICROCHIP_KSZ_SPI_DRIVER) += ksz_spi.o diff --git a/drivers/net/dsa/microchip/ksz_9477_reg.h b/drivers/net/dsa/microchip/ksz_9477_reg.h new file mode 100644 index 000000000000..6aa6752035a1 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz_9477_reg.h @@ -0,0 +1,1676 @@ +/* + * Microchip KSZ9477 register definitions + * + * Copyright (C) 2017 + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __KSZ9477_REGS_H +#define __KSZ9477_REGS_H + +#define KS_PRIO_M 0x7 +#define KS_PRIO_S 4 + +/* 0 - Operation */ +#define REG_CHIP_ID0__1 0x0000 + +#define REG_CHIP_ID1__1 0x0001 + +#define FAMILY_ID 0x95 +#define FAMILY_ID_94 0x94 +#define FAMILY_ID_95 0x95 +#define FAMILY_ID_85 0x85 +#define FAMILY_ID_98 0x98 +#define FAMILY_ID_88 0x88 + +#define REG_CHIP_ID2__1 0x0002 + +#define CHIP_ID_63 0x63 +#define CHIP_ID_66 0x66 +#define CHIP_ID_67 0x67 +#define CHIP_ID_77 0x77 +#define CHIP_ID_93 0x93 +#define CHIP_ID_96 0x96 +#define CHIP_ID_97 0x97 + +#define REG_CHIP_ID3__1 0x0003 + +#define SWITCH_REVISION_M 0x0F +#define SWITCH_REVISION_S 4 +#define SWITCH_RESET 0x01 + +#define REG_SW_PME_CTRL 0x0006 + +#define PME_ENABLE BIT(1) +#define PME_POLARITY BIT(0) + +#define REG_GLOBAL_OPTIONS 0x000F + +#define SW_GIGABIT_ABLE BIT(6) +#define SW_REDUNDANCY_ABLE BIT(5) +#define SW_AVB_ABLE BIT(4) +#define SW_9567_RL_5_2 0xC +#define SW_9477_SL_5_2 0xD + +#define SW_9896_GL_5_1 0xB +#define SW_9896_RL_5_1 0x8 +#define SW_9896_SL_5_1 0x9 + +#define SW_9895_GL_4_1 0x7 +#define SW_9895_RL_4_1 0x4 +#define SW_9895_SL_4_1 0x5 + +#define SW_9896_RL_4_2 0x6 + +#define SW_9893_RL_2_1 0x0 +#define SW_9893_SL_2_1 0x1 +#define SW_9893_GL_2_1 0x3 + +#define SW_QW_ABLE BIT(5) +#define SW_9893_RN_2_1 0xC + +#define REG_SW_INT_STATUS__4 0x0010 +#define REG_SW_INT_MASK__4 0x0014 + +#define LUE_INT BIT(31) +#define TRIG_TS_INT BIT(30) +#define APB_TIMEOUT_INT BIT(29) + +#define SWITCH_INT_MASK (TRIG_TS_INT | APB_TIMEOUT_INT) + +#define REG_SW_PORT_INT_STATUS__4 0x0018 +#define REG_SW_PORT_INT_MASK__4 0x001C +#define REG_SW_PHY_INT_STATUS 0x0020 +#define REG_SW_PHY_INT_ENABLE 0x0024 + +/* 1 - Global */ +#define REG_SW_GLOBAL_SERIAL_CTRL_0 0x0100 +#define SW_SPARE_REG_2 BIT(7) +#define SW_SPARE_REG_1 BIT(6) +#define SW_SPARE_REG_0 BIT(5) +#define SW_BIG_ENDIAN BIT(4) +#define SPI_AUTO_EDGE_DETECTION BIT(1) +#define SPI_CLOCK_OUT_RISING_EDGE BIT(0) + +#define REG_SW_GLOBAL_OUTPUT_CTRL__1 0x0103 +#define SW_ENABLE_REFCLKO BIT(1) +#define SW_REFCLKO_IS_125MHZ BIT(0) + +#define REG_SW_IBA__4 0x0104 + +#define SW_IBA_ENABLE BIT(31) +#define SW_IBA_DA_MATCH BIT(30) +#define SW_IBA_INIT BIT(29) +#define SW_IBA_QID_M 0xF +#define SW_IBA_QID_S 22 +#define SW_IBA_PORT_M 0x2F +#define SW_IBA_PORT_S 16 +#define SW_IBA_FRAME_TPID_M 0xFFFF + +#define REG_SW_APB_TIMEOUT_ADDR__4 0x0108 + +#define APB_TIMEOUT_ACKNOWLEDGE BIT(31) + +#define REG_SW_IBA_SYNC__1 0x010C + +#define REG_SW_IO_STRENGTH__1 0x010D +#define SW_DRIVE_STRENGTH_M 0x7 +#define SW_DRIVE_STRENGTH_2MA 0 +#define SW_DRIVE_STRENGTH_4MA 1 +#define SW_DRIVE_STRENGTH_8MA 2 +#define SW_DRIVE_STRENGTH_12MA 3 +#define SW_DRIVE_STRENGTH_16MA 4 +#define SW_DRIVE_STRENGTH_20MA 5 +#define SW_DRIVE_STRENGTH_24MA 6 +#define SW_DRIVE_STRENGTH_28MA 7 +#define SW_HI_SPEED_DRIVE_STRENGTH_S 4 +#define SW_LO_SPEED_DRIVE_STRENGTH_S 0 + +#define REG_SW_IBA_STATUS__4 0x0110 + +#define SW_IBA_REQ BIT(31) +#define SW_IBA_RESP BIT(30) +#define SW_IBA_DA_MISMATCH BIT(14) +#define SW_IBA_FMT_MISMATCH BIT(13) +#define SW_IBA_CODE_ERROR BIT(12) +#define SW_IBA_CMD_ERROR BIT(11) +#define SW_IBA_CMD_LOC_M (BIT(6) - 1) + +#define REG_SW_IBA_STATES__4 0x0114 + +#define SW_IBA_BUF_STATE_S 30 +#define SW_IBA_CMD_STATE_S 28 +#define SW_IBA_RESP_STATE_S 26 +#define SW_IBA_STATE_M 0x3 +#define SW_IBA_PACKET_SIZE_M 0x7F +#define SW_IBA_PACKET_SIZE_S 16 +#define SW_IBA_FMT_ID_M 0xFFFF + +#define REG_SW_IBA_RESULT__4 0x0118 + +#define SW_IBA_SIZE_S 24 + +#define SW_IBA_RETRY_CNT_M (BIT(5) - 1) + +/* 2 - PHY */ +#define REG_SW_POWER_MANAGEMENT_CTRL 0x0201 + +#define SW_PLL_POWER_DOWN BIT(5) +#define SW_POWER_DOWN_MODE 0x3 +#define SW_ENERGY_DETECTION 1 +#define SW_SOFT_POWER_DOWN 2 +#define SW_POWER_SAVING 3 + +/* 3 - Operation Control */ +#define REG_SW_OPERATION 0x0300 + +#define SW_DOUBLE_TAG BIT(7) +#define SW_RESET BIT(1) +#define SW_START BIT(0) + +#define REG_SW_MAC_ADDR_0 0x0302 +#define REG_SW_MAC_ADDR_1 0x0303 +#define REG_SW_MAC_ADDR_2 0x0304 +#define REG_SW_MAC_ADDR_3 0x0305 +#define REG_SW_MAC_ADDR_4 0x0306 +#define REG_SW_MAC_ADDR_5 0x0307 + +#define REG_SW_MTU__2 0x0308 + +#define REG_SW_ISP_TPID__2 0x030A + +#define REG_SW_HSR_TPID__2 0x030C + +#define REG_AVB_STRATEGY__2 0x030E + +#define SW_SHAPING_CREDIT_ACCT BIT(1) +#define SW_POLICING_CREDIT_ACCT BIT(0) + +#define REG_SW_LUE_CTRL_0 0x0310 + +#define SW_VLAN_ENABLE BIT(7) +#define SW_DROP_INVALID_VID BIT(6) +#define SW_AGE_CNT_M 0x7 +#define SW_AGE_CNT_S 3 +#define SW_RESV_MCAST_ENABLE BIT(2) +#define SW_HASH_OPTION_M 0x03 +#define SW_HASH_OPTION_CRC 1 +#define SW_HASH_OPTION_XOR 2 +#define SW_HASH_OPTION_DIRECT 3 + +#define REG_SW_LUE_CTRL_1 0x0311 + +#define UNICAST_LEARN_DISABLE BIT(7) +#define SW_SRC_ADDR_FILTER BIT(6) +#define SW_FLUSH_STP_TABLE BIT(5) +#define SW_FLUSH_MSTP_TABLE BIT(4) +#define SW_FWD_MCAST_SRC_ADDR BIT(3) +#define SW_AGING_ENABLE BIT(2) +#define SW_FAST_AGING BIT(1) +#define SW_LINK_AUTO_AGING BIT(0) + +#define REG_SW_LUE_CTRL_2 0x0312 + +#define SW_TRAP_DOUBLE_TAG BIT(6) +#define SW_EGRESS_VLAN_FILTER_DYN BIT(5) +#define SW_EGRESS_VLAN_FILTER_STA BIT(4) +#define SW_FLUSH_OPTION_M 0x3 +#define SW_FLUSH_OPTION_S 2 +#define SW_FLUSH_OPTION_DYN_MAC 1 +#define SW_FLUSH_OPTION_STA_MAC 2 +#define SW_FLUSH_OPTION_BOTH 3 +#define SW_PRIO_M 0x3 +#define SW_PRIO_DA 0 +#define SW_PRIO_SA 1 +#define SW_PRIO_HIGHEST_DA_SA 2 +#define SW_PRIO_LOWEST_DA_SA 3 + +#define REG_SW_LUE_CTRL_3 0x0313 + +#define REG_SW_LUE_INT_STATUS 0x0314 +#define REG_SW_LUE_INT_ENABLE 0x0315 + +#define LEARN_FAIL_INT BIT(2) +#define ALMOST_FULL_INT BIT(1) +#define WRITE_FAIL_INT BIT(0) + +#define REG_SW_LUE_INDEX_0__2 0x0316 + +#define ENTRY_INDEX_M 0x0FFF + +#define REG_SW_LUE_INDEX_1__2 0x0318 + +#define FAIL_INDEX_M 0x03FF + +#define REG_SW_LUE_INDEX_2__2 0x031A + +#define REG_SW_LUE_UNK_UCAST_CTRL__4 0x0320 + +#define SW_UNK_UCAST_ENABLE BIT(31) + +#define REG_SW_LUE_UNK_MCAST_CTRL__4 0x0324 + +#define SW_UNK_MCAST_ENABLE BIT(31) + +#define REG_SW_LUE_UNK_VID_CTRL__4 0x0328 + +#define SW_UNK_VID_ENABLE BIT(31) + +#define REG_SW_MAC_CTRL_0 0x0330 + +#define SW_NEW_BACKOFF BIT(7) +#define SW_CHECK_LENGTH BIT(3) +#define SW_PAUSE_UNH_MODE BIT(1) +#define SW_AGGR_BACKOFF BIT(0) + +#define REG_SW_MAC_CTRL_1 0x0331 + +#define MULTICAST_STORM_DISABLE BIT(6) +#define SW_BACK_PRESSURE BIT(5) +#define FAIR_FLOW_CTRL BIT(4) +#define NO_EXC_COLLISION_DROP BIT(3) +#define SW_JUMBO_PACKET BIT(2) +#define SW_LEGAL_PACKET_DISABLE BIT(1) +#define SW_PASS_SHORT_FRAME BIT(0) + +#define REG_SW_MAC_CTRL_2 0x0332 + +#define SW_REPLACE_VID BIT(3) +#define BROADCAST_STORM_RATE_HI 0x07 + +#define REG_SW_MAC_CTRL_3 0x0333 + +#define BROADCAST_STORM_RATE_LO 0xFF +#define BROADCAST_STORM_RATE 0x07FF + +#define REG_SW_MAC_CTRL_4 0x0334 + +#define SW_PASS_PAUSE BIT(3) + +#define REG_SW_MAC_CTRL_5 0x0335 + +#define SW_OUT_RATE_LIMIT_QUEUE_BASED BIT(3) + +#define REG_SW_MAC_CTRL_6 0x0336 + +#define SW_MIB_COUNTER_FLUSH BIT(7) +#define SW_MIB_COUNTER_FREEZE BIT(6) + +#define REG_SW_MAC_802_1P_MAP_0 0x0338 +#define REG_SW_MAC_802_1P_MAP_1 0x0339 +#define REG_SW_MAC_802_1P_MAP_2 0x033A +#define REG_SW_MAC_802_1P_MAP_3 0x033B + +#define SW_802_1P_MAP_M KS_PRIO_M +#define SW_802_1P_MAP_S KS_PRIO_S + +#define REG_SW_MAC_ISP_CTRL 0x033C + +#define REG_SW_MAC_TOS_CTRL 0x033E + +#define SW_TOS_DSCP_REMARK BIT(1) +#define SW_TOS_DSCP_REMAP BIT(0) + +#define REG_SW_MAC_TOS_PRIO_0 0x0340 +#define REG_SW_MAC_TOS_PRIO_1 0x0341 +#define REG_SW_MAC_TOS_PRIO_2 0x0342 +#define REG_SW_MAC_TOS_PRIO_3 0x0343 +#define REG_SW_MAC_TOS_PRIO_4 0x0344 +#define REG_SW_MAC_TOS_PRIO_5 0x0345 +#define REG_SW_MAC_TOS_PRIO_6 0x0346 +#define REG_SW_MAC_TOS_PRIO_7 0x0347 +#define REG_SW_MAC_TOS_PRIO_8 0x0348 +#define REG_SW_MAC_TOS_PRIO_9 0x0349 +#define REG_SW_MAC_TOS_PRIO_10 0x034A +#define REG_SW_MAC_TOS_PRIO_11 0x034B +#define REG_SW_MAC_TOS_PRIO_12 0x034C +#define REG_SW_MAC_TOS_PRIO_13 0x034D +#define REG_SW_MAC_TOS_PRIO_14 0x034E +#define REG_SW_MAC_TOS_PRIO_15 0x034F +#define REG_SW_MAC_TOS_PRIO_16 0x0350 +#define REG_SW_MAC_TOS_PRIO_17 0x0351 +#define REG_SW_MAC_TOS_PRIO_18 0x0352 +#define REG_SW_MAC_TOS_PRIO_19 0x0353 +#define REG_SW_MAC_TOS_PRIO_20 0x0354 +#define REG_SW_MAC_TOS_PRIO_21 0x0355 +#define REG_SW_MAC_TOS_PRIO_22 0x0356 +#define REG_SW_MAC_TOS_PRIO_23 0x0357 +#define REG_SW_MAC_TOS_PRIO_24 0x0358 +#define REG_SW_MAC_TOS_PRIO_25 0x0359 +#define REG_SW_MAC_TOS_PRIO_26 0x035A +#define REG_SW_MAC_TOS_PRIO_27 0x035B +#define REG_SW_MAC_TOS_PRIO_28 0x035C +#define REG_SW_MAC_TOS_PRIO_29 0x035D +#define REG_SW_MAC_TOS_PRIO_30 0x035E +#define REG_SW_MAC_TOS_PRIO_31 0x035F + +#define REG_SW_MRI_CTRL_0 0x0370 + +#define SW_IGMP_SNOOP BIT(6) +#define SW_IPV6_MLD_OPTION BIT(3) +#define SW_IPV6_MLD_SNOOP BIT(2) +#define SW_MIRROR_RX_TX BIT(0) + +#define REG_SW_CLASS_D_IP_CTRL__4 0x0374 + +#define SW_CLASS_D_IP_ENABLE BIT(31) + +#define REG_SW_MRI_CTRL_8 0x0378 + +#define SW_NO_COLOR_S 6 +#define SW_RED_COLOR_S 4 +#define SW_YELLOW_COLOR_S 2 +#define SW_GREEN_COLOR_S 0 +#define SW_COLOR_M 0x3 + +#define REG_SW_QM_CTRL__4 0x0390 + +#define PRIO_SCHEME_SELECT_M KS_PRIO_M +#define PRIO_SCHEME_SELECT_S 6 +#define PRIO_MAP_3_HI 0 +#define PRIO_MAP_2_HI 2 +#define PRIO_MAP_0_LO 3 +#define UNICAST_VLAN_BOUNDARY BIT(1) + +#define REG_SW_EEE_QM_CTRL__2 0x03C0 + +#define REG_SW_EEE_TXQ_WAIT_TIME__2 0x03C2 + +/* 4 - */ +#define REG_SW_VLAN_ENTRY__4 0x0400 + +#define VLAN_VALID BIT(31) +#define VLAN_FORWARD_OPTION BIT(27) +#define VLAN_PRIO_M KS_PRIO_M +#define VLAN_PRIO_S 24 +#define VLAN_MSTP_M 0x7 +#define VLAN_MSTP_S 12 +#define VLAN_FID_M 0x7F + +#define REG_SW_VLAN_ENTRY_UNTAG__4 0x0404 +#define REG_SW_VLAN_ENTRY_PORTS__4 0x0408 + +#define REG_SW_VLAN_ENTRY_INDEX__2 0x040C + +#define VLAN_INDEX_M 0x0FFF + +#define REG_SW_VLAN_CTRL 0x040E + +#define VLAN_START BIT(7) +#define VLAN_ACTION 0x3 +#define VLAN_WRITE 1 +#define VLAN_READ 2 +#define VLAN_CLEAR 3 + +#define REG_SW_ALU_INDEX_0 0x0410 + +#define ALU_FID_INDEX_S 16 +#define ALU_MAC_ADDR_HI 0xFFFF + +#define REG_SW_ALU_INDEX_1 0x0414 + +#define ALU_DIRECT_INDEX_M (BIT(12) - 1) + +#define REG_SW_ALU_CTRL__4 0x0418 + +#define ALU_VALID_CNT_M (BIT(14) - 1) +#define ALU_VALID_CNT_S 16 +#define ALU_START BIT(7) +#define ALU_VALID BIT(6) +#define ALU_DIRECT BIT(2) +#define ALU_ACTION 0x3 +#define ALU_WRITE 1 +#define ALU_READ 2 +#define ALU_SEARCH 3 + +#define REG_SW_ALU_STAT_CTRL__4 0x041C + +#define ALU_STAT_INDEX_M (BIT(4) - 1) +#define ALU_STAT_INDEX_S 16 +#define ALU_RESV_MCAST_INDEX_M (BIT(6) - 1) +#define ALU_STAT_START BIT(7) +#define ALU_RESV_MCAST_ADDR BIT(1) +#define ALU_STAT_READ BIT(0) + +#define REG_SW_ALU_VAL_A 0x0420 + +#define ALU_V_STATIC_VALID BIT(31) +#define ALU_V_SRC_FILTER BIT(30) +#define ALU_V_DST_FILTER BIT(29) +#define ALU_V_PRIO_AGE_CNT_M (BIT(3) - 1) +#define ALU_V_PRIO_AGE_CNT_S 26 +#define ALU_V_MSTP_M 0x7 + +#define REG_SW_ALU_VAL_B 0x0424 + +#define ALU_V_OVERRIDE BIT(31) +#define ALU_V_USE_FID BIT(30) +#define ALU_V_PORT_MAP (BIT(24) - 1) + +#define REG_SW_ALU_VAL_C 0x0428 + +#define ALU_V_FID_M (BIT(16) - 1) +#define ALU_V_FID_S 16 +#define ALU_V_MAC_ADDR_HI 0xFFFF + +#define REG_SW_ALU_VAL_D 0x042C + +#define REG_HSR_ALU_INDEX_0 0x0440 + +#define REG_HSR_ALU_INDEX_1 0x0444 + +#define HSR_DST_MAC_INDEX_LO_S 16 +#define HSR_SRC_MAC_INDEX_HI 0xFFFF + +#define REG_HSR_ALU_INDEX_2 0x0448 + +#define HSR_INDEX_MAX BIT(9) +#define HSR_DIRECT_INDEX_M (HSR_INDEX_MAX - 1) + +#define REG_HSR_ALU_INDEX_3 0x044C + +#define HSR_PATH_INDEX_M (BIT(4) - 1) + +#define REG_HSR_ALU_CTRL__4 0x0450 + +#define HSR_VALID_CNT_M (BIT(14) - 1) +#define HSR_VALID_CNT_S 16 +#define HSR_START BIT(7) +#define HSR_VALID BIT(6) +#define HSR_SEARCH_END BIT(5) +#define HSR_DIRECT BIT(2) +#define HSR_ACTION 0x3 +#define HSR_WRITE 1 +#define HSR_READ 2 +#define HSR_SEARCH 3 + +#define REG_HSR_ALU_VAL_A 0x0454 + +#define HSR_V_STATIC_VALID BIT(31) +#define HSR_V_AGE_CNT_M (BIT(3) - 1) +#define HSR_V_AGE_CNT_S 26 +#define HSR_V_PATH_ID_M (BIT(4) - 1) + +#define REG_HSR_ALU_VAL_B 0x0458 + +#define REG_HSR_ALU_VAL_C 0x045C + +#define HSR_V_DST_MAC_ADDR_LO_S 16 +#define HSR_V_SRC_MAC_ADDR_HI 0xFFFF + +#define REG_HSR_ALU_VAL_D 0x0460 + +#define REG_HSR_ALU_VAL_E 0x0464 + +#define HSR_V_START_SEQ_1_S 16 +#define HSR_V_START_SEQ_2_S 0 + +#define REG_HSR_ALU_VAL_F 0x0468 + +#define HSR_V_EXP_SEQ_1_S 16 +#define HSR_V_EXP_SEQ_2_S 0 + +#define REG_HSR_ALU_VAL_G 0x046C + +#define HSR_V_SEQ_CNT_1_S 16 +#define HSR_V_SEQ_CNT_2_S 0 + +#define HSR_V_SEQ_M (BIT(16) - 1) + +/* 5 - PTP Clock */ +#define REG_PTP_CLK_CTRL 0x0500 + +#define PTP_STEP_ADJ BIT(6) +#define PTP_STEP_DIR BIT(5) +#define PTP_READ_TIME BIT(4) +#define PTP_LOAD_TIME BIT(3) +#define PTP_CLK_ADJ_ENABLE BIT(2) +#define PTP_CLK_ENABLE BIT(1) +#define PTP_CLK_RESET BIT(0) + +#define REG_PTP_RTC_SUB_NANOSEC__2 0x0502 + +#define PTP_RTC_SUB_NANOSEC_M 0x0007 + +#define REG_PTP_RTC_NANOSEC 0x0504 +#define REG_PTP_RTC_NANOSEC_H 0x0504 +#define REG_PTP_RTC_NANOSEC_L 0x0506 + +#define REG_PTP_RTC_SEC 0x0508 +#define REG_PTP_RTC_SEC_H 0x0508 +#define REG_PTP_RTC_SEC_L 0x050A + +#define REG_PTP_SUBNANOSEC_RATE 0x050C +#define REG_PTP_SUBNANOSEC_RATE_H 0x050C + +#define PTP_RATE_DIR BIT(31) +#define PTP_TMP_RATE_ENABLE BIT(30) + +#define REG_PTP_SUBNANOSEC_RATE_L 0x050E + +#define REG_PTP_RATE_DURATION 0x0510 +#define REG_PTP_RATE_DURATION_H 0x0510 +#define REG_PTP_RATE_DURATION_L 0x0512 + +#define REG_PTP_MSG_CONF1 0x0514 + +#define PTP_802_1AS BIT(7) +#define PTP_ENABLE BIT(6) +#define PTP_ETH_ENABLE BIT(5) +#define PTP_IPV4_UDP_ENABLE BIT(4) +#define PTP_IPV6_UDP_ENABLE BIT(3) +#define PTP_TC_P2P BIT(2) +#define PTP_MASTER BIT(1) +#define PTP_1STEP BIT(0) + +#define REG_PTP_MSG_CONF2 0x0516 + +#define PTP_UNICAST_ENABLE BIT(12) +#define PTP_ALTERNATE_MASTER BIT(11) +#define PTP_ALL_HIGH_PRIO BIT(10) +#define PTP_SYNC_CHECK BIT(9) +#define PTP_DELAY_CHECK BIT(8) +#define PTP_PDELAY_CHECK BIT(7) +#define PTP_DROP_SYNC_DELAY_REQ BIT(5) +#define PTP_DOMAIN_CHECK BIT(4) +#define PTP_UDP_CHECKSUM BIT(2) + +#define REG_PTP_DOMAIN_VERSION 0x0518 +#define PTP_VERSION_M 0xFF00 +#define PTP_DOMAIN_M 0x00FF + +#define REG_PTP_UNIT_INDEX__4 0x0520 + +#define PTP_UNIT_M 0xF + +#define PTP_GPIO_INDEX_S 16 +#define PTP_TSI_INDEX_S 8 +#define PTP_TOU_INDEX_S 0 + +#define REG_PTP_TRIG_STATUS__4 0x0524 + +#define TRIG_ERROR_S 16 +#define TRIG_DONE_S 0 + +#define REG_PTP_INT_STATUS__4 0x0528 + +#define TRIG_INT_S 16 +#define TS_INT_S 0 + +#define TRIG_UNIT_M 0x7 +#define TS_UNIT_M 0x3 + +#define REG_PTP_CTRL_STAT__4 0x052C + +#define GPIO_IN BIT(7) +#define GPIO_OUT BIT(6) +#define TS_INT_ENABLE BIT(5) +#define TRIG_ACTIVE BIT(4) +#define TRIG_ENABLE BIT(3) +#define TRIG_RESET BIT(2) +#define TS_ENABLE BIT(1) +#define TS_RESET BIT(0) + +#define GPIO_CTRL_M (GPIO_IN | GPIO_OUT) + +#define TRIG_CTRL_M \ + (TRIG_ACTIVE | TRIG_ENABLE | TRIG_RESET) + +#define TS_CTRL_M \ + (TS_INT_ENABLE | TS_ENABLE | TS_RESET) + +#define REG_TRIG_TARGET_NANOSEC 0x0530 +#define REG_TRIG_TARGET_SEC 0x0534 + +#define REG_TRIG_CTRL__4 0x0538 + +#define TRIG_CASCADE_ENABLE BIT(31) +#define TRIG_CASCADE_TAIL BIT(30) +#define TRIG_CASCADE_UPS_M 0xF +#define TRIG_CASCADE_UPS_S 26 +#define TRIG_NOW BIT(25) +#define TRIG_NOTIFY BIT(24) +#define TRIG_EDGE BIT(23) +#define TRIG_PATTERN_S 20 +#define TRIG_PATTERN_M 0x7 +#define TRIG_NEG_EDGE 0 +#define TRIG_POS_EDGE 1 +#define TRIG_NEG_PULSE 2 +#define TRIG_POS_PULSE 3 +#define TRIG_NEG_PERIOD 4 +#define TRIG_POS_PERIOD 5 +#define TRIG_REG_OUTPUT 6 +#define TRIG_GPO_S 16 +#define TRIG_GPO_M 0xF +#define TRIG_CASCADE_ITERATE_CNT_M 0xFFFF + +#define REG_TRIG_CYCLE_WIDTH 0x053C + +#define REG_TRIG_CYCLE_CNT 0x0540 + +#define TRIG_CYCLE_CNT_M 0xFFFF +#define TRIG_CYCLE_CNT_S 16 +#define TRIG_BIT_PATTERN_M 0xFFFF + +#define REG_TRIG_ITERATE_TIME 0x0544 + +#define REG_TRIG_PULSE_WIDTH__4 0x0548 + +#define TRIG_PULSE_WIDTH_M 0x00FFFFFF + +#define REG_TS_CTRL_STAT__4 0x0550 + +#define TS_EVENT_DETECT_M 0xF +#define TS_EVENT_DETECT_S 17 +#define TS_EVENT_OVERFLOW BIT(16) +#define TS_GPI_M 0xF +#define TS_GPI_S 8 +#define TS_DETECT_RISE BIT(7) +#define TS_DETECT_FALL BIT(6) +#define TS_DETECT_S 6 +#define TS_CASCADE_TAIL BIT(5) +#define TS_CASCADE_UPS_M 0xF +#define TS_CASCADE_UPS_S 1 +#define TS_CASCADE_ENABLE BIT(0) + +#define DETECT_RISE (TS_DETECT_RISE >> TS_DETECT_S) +#define DETECT_FALL (TS_DETECT_FALL >> TS_DETECT_S) + +#define REG_TS_EVENT_0_NANOSEC 0x0554 +#define REG_TS_EVENT_0_SEC 0x0558 +#define REG_TS_EVENT_0_SUB_NANOSEC 0x055C + +#define REG_TS_EVENT_1_NANOSEC 0x0560 +#define REG_TS_EVENT_1_SEC 0x0564 +#define REG_TS_EVENT_1_SUB_NANOSEC 0x0568 + +#define REG_TS_EVENT_2_NANOSEC 0x056C +#define REG_TS_EVENT_2_SEC 0x0570 +#define REG_TS_EVENT_2_SUB_NANOSEC 0x0574 + +#define REG_TS_EVENT_3_NANOSEC 0x0578 +#define REG_TS_EVENT_3_SEC 0x057C +#define REG_TS_EVENT_3_SUB_NANOSEC 0x0580 + +#define REG_TS_EVENT_4_NANOSEC 0x0584 +#define REG_TS_EVENT_4_SEC 0x0588 +#define REG_TS_EVENT_4_SUB_NANOSEC 0x058C + +#define REG_TS_EVENT_5_NANOSEC 0x0590 +#define REG_TS_EVENT_5_SEC 0x0594 +#define REG_TS_EVENT_5_SUB_NANOSEC 0x0598 + +#define REG_TS_EVENT_6_NANOSEC 0x059C +#define REG_TS_EVENT_6_SEC 0x05A0 +#define REG_TS_EVENT_6_SUB_NANOSEC 0x05A4 + +#define REG_TS_EVENT_7_NANOSEC 0x05A8 +#define REG_TS_EVENT_7_SEC 0x05AC +#define REG_TS_EVENT_7_SUB_NANOSEC 0x05B0 + +#define TS_EVENT_EDGE_M 0x1 +#define TS_EVENT_EDGE_S 30 +#define TS_EVENT_NANOSEC_M (BIT(30) - 1) + +#define TS_EVENT_SUB_NANOSEC_M 0x7 + +#define TS_EVENT_SAMPLE \ + (REG_TS_EVENT_1_NANOSEC - REG_TS_EVENT_0_NANOSEC) + +#define PORT_CTRL_ADDR(port, addr) ((addr) | (((port) + 1) << 12)) + +#define REG_GLOBAL_RR_INDEX__1 0x0600 + +/* DLR */ +#define REG_DLR_SRC_PORT__4 0x0604 + +#define DLR_SRC_PORT_UNICAST BIT(31) +#define DLR_SRC_PORT_M 0x3 +#define DLR_SRC_PORT_BOTH 0 +#define DLR_SRC_PORT_EACH 1 + +#define REG_DLR_IP_ADDR__4 0x0608 + +#define REG_DLR_CTRL__1 0x0610 + +#define DLR_RESET_SEQ_ID BIT(3) +#define DLR_BACKUP_AUTO_ON BIT(2) +#define DLR_BEACON_TX_ENABLE BIT(1) +#define DLR_ASSIST_ENABLE BIT(0) + +#define REG_DLR_STATE__1 0x0611 + +#define DLR_NODE_STATE_M 0x3 +#define DLR_NODE_STATE_S 1 +#define DLR_NODE_STATE_IDLE 0 +#define DLR_NODE_STATE_FAULT 1 +#define DLR_NODE_STATE_NORMAL 2 +#define DLR_RING_STATE_FAULT 0 +#define DLR_RING_STATE_NORMAL 1 + +#define REG_DLR_PRECEDENCE__1 0x0612 + +#define REG_DLR_BEACON_INTERVAL__4 0x0614 + +#define REG_DLR_BEACON_TIMEOUT__4 0x0618 + +#define REG_DLR_TIMEOUT_WINDOW__4 0x061C + +#define DLR_TIMEOUT_WINDOW_M (BIT(22) - 1) + +#define REG_DLR_VLAN_ID__2 0x0620 + +#define DLR_VLAN_ID_M (BIT(12) - 1) + +#define REG_DLR_DEST_ADDR_0 0x0622 +#define REG_DLR_DEST_ADDR_1 0x0623 +#define REG_DLR_DEST_ADDR_2 0x0624 +#define REG_DLR_DEST_ADDR_3 0x0625 +#define REG_DLR_DEST_ADDR_4 0x0626 +#define REG_DLR_DEST_ADDR_5 0x0627 + +#define REG_DLR_PORT_MAP__4 0x0628 + +#define REG_DLR_CLASS__1 0x062C + +#define DLR_FRAME_QID_M 0x3 + +/* HSR */ +#define REG_HSR_PORT_MAP__4 0x0640 + +#define REG_HSR_ALU_CTRL_0__1 0x0644 + +#define HSR_DUPLICATE_DISCARD BIT(7) +#define HSR_NODE_UNICAST BIT(6) +#define HSR_AGE_CNT_DEFAULT_M 0x7 +#define HSR_AGE_CNT_DEFAULT_S 3 +#define HSR_LEARN_MCAST_DISABLE BIT(2) +#define HSR_HASH_OPTION_M 0x3 +#define HSR_HASH_DISABLE 0 +#define HSR_HASH_UPPER_BITS 1 +#define HSR_HASH_LOWER_BITS 2 +#define HSR_HASH_XOR_BOTH_BITS 3 + +#define REG_HSR_ALU_CTRL_1__1 0x0645 + +#define HSR_LEARN_UCAST_DISABLE BIT(7) +#define HSR_FLUSH_TABLE BIT(5) +#define HSR_PROC_MCAST_SRC BIT(3) +#define HSR_AGING_ENABLE BIT(2) + +#define REG_HSR_ALU_CTRL_2__2 0x0646 + +#define REG_HSR_ALU_AGE_PERIOD__4 0x0648 + +#define REG_HSR_ALU_INT_STATUS__1 0x064C +#define REG_HSR_ALU_INT_MASK__1 0x064D + +#define HSR_WINDOW_OVERFLOW_INT BIT(3) +#define HSR_LEARN_FAIL_INT BIT(2) +#define HSR_ALMOST_FULL_INT BIT(1) +#define HSR_WRITE_FAIL_INT BIT(0) + +#define REG_HSR_ALU_ENTRY_0__2 0x0650 + +#define HSR_ENTRY_INDEX_M (BIT(10) - 1) +#define HSR_FAIL_INDEX_M (BIT(8) - 1) + +#define REG_HSR_ALU_ENTRY_1__2 0x0652 + +#define HSR_FAIL_LEARN_INDEX_M (BIT(8) - 1) + +#define REG_HSR_ALU_ENTRY_3__2 0x0654 + +#define HSR_CPU_ACCESS_ENTRY_INDEX_M (BIT(8) - 1) + +/* 0 - Operation */ +#define REG_PORT_DEFAULT_VID 0x0000 + +#define REG_PORT_CUSTOM_VID 0x0002 +#define REG_PORT_AVB_SR_1_VID 0x0004 +#define REG_PORT_AVB_SR_2_VID 0x0006 + +#define REG_PORT_AVB_SR_1_TYPE 0x0008 +#define REG_PORT_AVB_SR_2_TYPE 0x000A + +#define REG_PORT_PME_STATUS 0x0013 +#define REG_PORT_PME_CTRL 0x0017 + +#define PME_WOL_MAGICPKT BIT(2) +#define PME_WOL_LINKUP BIT(1) +#define PME_WOL_ENERGY BIT(0) + +#define REG_PORT_INT_STATUS 0x001B +#define REG_PORT_INT_MASK 0x001F + +#define PORT_SGMII_INT BIT(3) +#define PORT_PTP_INT BIT(2) +#define PORT_PHY_INT BIT(1) +#define PORT_ACL_INT BIT(0) + +#define PORT_INT_MASK \ + (PORT_SGMII_INT | PORT_PTP_INT | PORT_PHY_INT | PORT_ACL_INT) + +#define REG_PORT_CTRL_0 0x0020 + +#define PORT_MAC_LOOPBACK BIT(7) +#define PORT_FORCE_TX_FLOW_CTRL BIT(4) +#define PORT_FORCE_RX_FLOW_CTRL BIT(3) +#define PORT_TAIL_TAG_ENABLE BIT(2) +#define PORT_QUEUE_SPLIT_ENABLE 0x3 + +#define REG_PORT_CTRL_1 0x0021 + +#define PORT_SRP_ENABLE 0x3 + +#define REG_PORT_STATUS_0 0x0030 + +#define PORT_INTF_SPEED_M 0x3 +#define PORT_INTF_SPEED_S 3 +#define PORT_INTF_FULL_DUPLEX BIT(2) +#define PORT_TX_FLOW_CTRL BIT(1) +#define PORT_RX_FLOW_CTRL BIT(0) + +#define REG_PORT_STATUS_1 0x0034 + +/* 1 - PHY */ +#define REG_PORT_PHY_CTRL 0x0100 + +#define PORT_PHY_RESET BIT(15) +#define PORT_PHY_LOOPBACK BIT(14) +#define PORT_SPEED_100MBIT BIT(13) +#define PORT_AUTO_NEG_ENABLE BIT(12) +#define PORT_POWER_DOWN BIT(11) +#define PORT_ISOLATE BIT(10) +#define PORT_AUTO_NEG_RESTART BIT(9) +#define PORT_FULL_DUPLEX BIT(8) +#define PORT_COLLISION_TEST BIT(7) +#define PORT_SPEED_1000MBIT BIT(6) + +#define REG_PORT_PHY_STATUS 0x0102 + +#define PORT_100BT4_CAPABLE BIT(15) +#define PORT_100BTX_FD_CAPABLE BIT(14) +#define PORT_100BTX_CAPABLE BIT(13) +#define PORT_10BT_FD_CAPABLE BIT(12) +#define PORT_10BT_CAPABLE BIT(11) +#define PORT_EXTENDED_STATUS BIT(8) +#define PORT_MII_SUPPRESS_CAPABLE BIT(6) +#define PORT_AUTO_NEG_ACKNOWLEDGE BIT(5) +#define PORT_REMOTE_FAULT BIT(4) +#define PORT_AUTO_NEG_CAPABLE BIT(3) +#define PORT_LINK_STATUS BIT(2) +#define PORT_JABBER_DETECT BIT(1) +#define PORT_EXTENDED_CAPABILITY BIT(0) + +#define REG_PORT_PHY_ID_HI 0x0104 +#define REG_PORT_PHY_ID_LO 0x0106 + +#define KSZ9477_ID_HI 0x0022 +#define KSZ9477_ID_LO 0x1622 + +#define REG_PORT_PHY_AUTO_NEGOTIATION 0x0108 + +#define PORT_AUTO_NEG_NEXT_PAGE BIT(15) +#define PORT_AUTO_NEG_REMOTE_FAULT BIT(13) +#define PORT_AUTO_NEG_ASYM_PAUSE BIT(11) +#define PORT_AUTO_NEG_SYM_PAUSE BIT(10) +#define PORT_AUTO_NEG_100BT4 BIT(9) +#define PORT_AUTO_NEG_100BTX_FD BIT(8) +#define PORT_AUTO_NEG_100BTX BIT(7) +#define PORT_AUTO_NEG_10BT_FD BIT(6) +#define PORT_AUTO_NEG_10BT BIT(5) +#define PORT_AUTO_NEG_SELECTOR 0x001F +#define PORT_AUTO_NEG_802_3 0x0001 + +#define PORT_AUTO_NEG_PAUSE \ + (PORT_AUTO_NEG_ASYM_PAUSE | PORT_AUTO_NEG_SYM_PAUSE) + +#define REG_PORT_PHY_REMOTE_CAPABILITY 0x010A + +#define PORT_REMOTE_NEXT_PAGE BIT(15) +#define PORT_REMOTE_ACKNOWLEDGE BIT(14) +#define PORT_REMOTE_REMOTE_FAULT BIT(13) +#define PORT_REMOTE_ASYM_PAUSE BIT(11) +#define PORT_REMOTE_SYM_PAUSE BIT(10) +#define PORT_REMOTE_100BTX_FD BIT(8) +#define PORT_REMOTE_100BTX BIT(7) +#define PORT_REMOTE_10BT_FD BIT(6) +#define PORT_REMOTE_10BT BIT(5) + +#define REG_PORT_PHY_1000_CTRL 0x0112 + +#define PORT_AUTO_NEG_MANUAL BIT(12) +#define PORT_AUTO_NEG_MASTER BIT(11) +#define PORT_AUTO_NEG_MASTER_PREFERRED BIT(10) +#define PORT_AUTO_NEG_1000BT_FD BIT(9) +#define PORT_AUTO_NEG_1000BT BIT(8) + +#define REG_PORT_PHY_1000_STATUS 0x0114 + +#define PORT_MASTER_FAULT BIT(15) +#define PORT_LOCAL_MASTER BIT(14) +#define PORT_LOCAL_RX_OK BIT(13) +#define PORT_REMOTE_RX_OK BIT(12) +#define PORT_REMOTE_1000BT_FD BIT(11) +#define PORT_REMOTE_1000BT BIT(10) +#define PORT_REMOTE_IDLE_CNT_M 0x0F + +#define PORT_PHY_1000_STATIC_STATUS \ + (PORT_LOCAL_RX_OK | \ + PORT_REMOTE_RX_OK | \ + PORT_REMOTE_1000BT_FD | \ + PORT_REMOTE_1000BT) + +#define REG_PORT_PHY_MMD_SETUP 0x011A + +#define PORT_MMD_OP_MODE_M 0x3 +#define PORT_MMD_OP_MODE_S 14 +#define PORT_MMD_OP_INDEX 0 +#define PORT_MMD_OP_DATA_NO_INCR 1 +#define PORT_MMD_OP_DATA_INCR_RW 2 +#define PORT_MMD_OP_DATA_INCR_W 3 +#define PORT_MMD_DEVICE_ID_M 0x1F + +#define MMD_SETUP(mode, dev) \ + (((u16)(mode) << PORT_MMD_OP_MODE_S) | (dev)) + +#define REG_PORT_PHY_MMD_INDEX_DATA 0x011C + +#define MMD_DEVICE_ID_DSP 1 + +#define MMD_DSP_SQI_CHAN_A 0xAC +#define MMD_DSP_SQI_CHAN_B 0xAD +#define MMD_DSP_SQI_CHAN_C 0xAE +#define MMD_DSP_SQI_CHAN_D 0xAF + +#define DSP_SQI_ERR_DETECTED BIT(15) +#define DSP_SQI_AVG_ERR 0x7FFF + +#define MMD_DEVICE_ID_COMMON 2 + +#define MMD_DEVICE_ID_EEE_ADV 7 + +#define MMD_EEE_ADV 0x3C +#define EEE_ADV_100MBIT BIT(1) +#define EEE_ADV_1GBIT BIT(2) + +#define MMD_EEE_LP_ADV 0x3D +#define MMD_EEE_MSG_CODE 0x3F + +#define MMD_DEVICE_ID_AFED 0x1C + +#define REG_PORT_PHY_EXTENDED_STATUS 0x011E + +#define PORT_100BTX_FD_ABLE BIT(15) +#define PORT_100BTX_ABLE BIT(14) +#define PORT_10BT_FD_ABLE BIT(13) +#define PORT_10BT_ABLE BIT(12) + +#define REG_PORT_SGMII_ADDR__4 0x0200 +#define PORT_SGMII_AUTO_INCR BIT(23) +#define PORT_SGMII_DEVICE_ID_M 0x1F +#define PORT_SGMII_DEVICE_ID_S 16 +#define PORT_SGMII_ADDR_M (BIT(21) - 1) + +#define REG_PORT_SGMII_DATA__4 0x0204 +#define PORT_SGMII_DATA_M (BIT(16) - 1) + +#define MMD_DEVICE_ID_PMA 0x01 +#define MMD_DEVICE_ID_PCS 0x03 +#define MMD_DEVICE_ID_PHY_XS 0x04 +#define MMD_DEVICE_ID_DTE_XS 0x05 +#define MMD_DEVICE_ID_AN 0x07 +#define MMD_DEVICE_ID_VENDOR_CTRL 0x1E +#define MMD_DEVICE_ID_VENDOR_MII 0x1F + +#define SR_MII MMD_DEVICE_ID_VENDOR_MII + +#define MMD_SR_MII_CTRL 0x0000 + +#define SR_MII_RESET BIT(15) +#define SR_MII_LOOPBACK BIT(14) +#define SR_MII_SPEED_100MBIT BIT(13) +#define SR_MII_AUTO_NEG_ENABLE BIT(12) +#define SR_MII_POWER_DOWN BIT(11) +#define SR_MII_AUTO_NEG_RESTART BIT(9) +#define SR_MII_FULL_DUPLEX BIT(8) +#define SR_MII_SPEED_1000MBIT BIT(6) + +#define MMD_SR_MII_STATUS 0x0001 +#define MMD_SR_MII_ID_1 0x0002 +#define MMD_SR_MII_ID_2 0x0003 +#define MMD_SR_MII_AUTO_NEGOTIATION 0x0004 + +#define SR_MII_AUTO_NEG_NEXT_PAGE BIT(15) +#define SR_MII_AUTO_NEG_REMOTE_FAULT_M 0x3 +#define SR_MII_AUTO_NEG_REMOTE_FAULT_S 12 +#define SR_MII_AUTO_NEG_NO_ERROR 0 +#define SR_MII_AUTO_NEG_OFFLINE 1 +#define SR_MII_AUTO_NEG_LINK_FAILURE 2 +#define SR_MII_AUTO_NEG_ERROR 3 +#define SR_MII_AUTO_NEG_PAUSE_M 0x3 +#define SR_MII_AUTO_NEG_PAUSE_S 7 +#define SR_MII_AUTO_NEG_NO_PAUSE 0 +#define SR_MII_AUTO_NEG_ASYM_PAUSE_TX 1 +#define SR_MII_AUTO_NEG_SYM_PAUSE 2 +#define SR_MII_AUTO_NEG_ASYM_PAUSE_RX 3 +#define SR_MII_AUTO_NEG_HALF_DUPLEX BIT(6) +#define SR_MII_AUTO_NEG_FULL_DUPLEX BIT(5) + +#define MMD_SR_MII_REMOTE_CAPABILITY 0x0005 +#define MMD_SR_MII_AUTO_NEG_EXP 0x0006 +#define MMD_SR_MII_AUTO_NEG_EXT 0x000F + +#define MMD_SR_MII_DIGITAL_CTRL_1 0x8000 + +#define MMD_SR_MII_AUTO_NEG_CTRL 0x8001 + +#define SR_MII_8_BIT BIT(8) +#define SR_MII_SGMII_LINK_UP BIT(4) +#define SR_MII_TX_CFG_PHY_MASTER BIT(3) +#define SR_MII_PCS_MODE_M 0x3 +#define SR_MII_PCS_MODE_S 1 +#define SR_MII_PCS_SGMII 2 +#define SR_MII_AUTO_NEG_COMPLETE_INTR BIT(0) + +#define MMD_SR_MII_AUTO_NEG_STATUS 0x8002 + +#define SR_MII_STAT_LINK_UP BIT(4) +#define SR_MII_STAT_M 0x3 +#define SR_MII_STAT_S 2 +#define SR_MII_STAT_10_MBPS 0 +#define SR_MII_STAT_100_MBPS 1 +#define SR_MII_STAT_1000_MBPS 2 +#define SR_MII_STAT_FULL_DUPLEX BIT(1) + +#define MMD_SR_MII_PHY_CTRL 0x80A0 + +#define SR_MII_PHY_LANE_SEL_M 0xF +#define SR_MII_PHY_LANE_SEL_S 8 +#define SR_MII_PHY_WRITE BIT(1) +#define SR_MII_PHY_START_BUSY BIT(0) + +#define MMD_SR_MII_PHY_ADDR 0x80A1 + +#define SR_MII_PHY_ADDR_M (BIT(16) - 1) + +#define MMD_SR_MII_PHY_DATA 0x80A2 + +#define SR_MII_PHY_DATA_M (BIT(16) - 1) + +#define SR_MII_PHY_JTAG_CHIP_ID_HI 0x000C +#define SR_MII_PHY_JTAG_CHIP_ID_LO 0x000D + +#define REG_PORT_PHY_REMOTE_LB_LED 0x0122 + +#define PORT_REMOTE_LOOPBACK BIT(8) +#define PORT_LED_SELECT (3 << 6) +#define PORT_LED_CTRL (3 << 4) +#define PORT_LED_CTRL_TEST BIT(3) +#define PORT_10BT_PREAMBLE BIT(2) +#define PORT_LINK_MD_10BT_ENABLE BIT(1) +#define PORT_LINK_MD_PASS BIT(0) + +#define REG_PORT_PHY_LINK_MD 0x0124 + +#define PORT_START_CABLE_DIAG BIT(15) +#define PORT_TX_DISABLE BIT(14) +#define PORT_CABLE_DIAG_PAIR_M 0x3 +#define PORT_CABLE_DIAG_PAIR_S 12 +#define PORT_CABLE_DIAG_SELECT_M 0x3 +#define PORT_CABLE_DIAG_SELECT_S 10 +#define PORT_CABLE_DIAG_RESULT_M 0x3 +#define PORT_CABLE_DIAG_RESULT_S 8 +#define PORT_CABLE_STAT_NORMAL 0 +#define PORT_CABLE_STAT_OPEN 1 +#define PORT_CABLE_STAT_SHORT 2 +#define PORT_CABLE_STAT_FAILED 3 +#define PORT_CABLE_FAULT_COUNTER 0x00FF + +#define REG_PORT_PHY_PMA_STATUS 0x0126 + +#define PORT_1000_LINK_GOOD BIT(1) +#define PORT_100_LINK_GOOD BIT(0) + +#define REG_PORT_PHY_DIGITAL_STATUS 0x0128 + +#define PORT_LINK_DETECT BIT(14) +#define PORT_SIGNAL_DETECT BIT(13) +#define PORT_PHY_STAT_MDI BIT(12) +#define PORT_PHY_STAT_MASTER BIT(11) + +#define REG_PORT_PHY_RXER_COUNTER 0x012A + +#define REG_PORT_PHY_INT_ENABLE 0x0136 +#define REG_PORT_PHY_INT_STATUS 0x0137 + +#define JABBER_INT BIT(7) +#define RX_ERR_INT BIT(6) +#define PAGE_RX_INT BIT(5) +#define PARALLEL_DETECT_FAULT_INT BIT(4) +#define LINK_PARTNER_ACK_INT BIT(3) +#define LINK_DOWN_INT BIT(2) +#define REMOTE_FAULT_INT BIT(1) +#define LINK_UP_INT BIT(0) + +#define REG_PORT_PHY_DIGITAL_DEBUG_1 0x0138 + +#define PORT_REG_CLK_SPEED_25_MHZ BIT(14) +#define PORT_PHY_FORCE_MDI BIT(7) +#define PORT_PHY_AUTO_MDIX_DISABLE BIT(6) + +/* Same as PORT_PHY_LOOPBACK */ +#define PORT_PHY_PCS_LOOPBACK BIT(0) + +#define REG_PORT_PHY_DIGITAL_DEBUG_2 0x013A + +#define REG_PORT_PHY_DIGITAL_DEBUG_3 0x013C + +#define PORT_100BT_FIXED_LATENCY BIT(15) + +#define REG_PORT_PHY_PHY_CTRL 0x013E + +#define PORT_INT_PIN_HIGH BIT(14) +#define PORT_ENABLE_JABBER BIT(9) +#define PORT_STAT_SPEED_1000MBIT BIT(6) +#define PORT_STAT_SPEED_100MBIT BIT(5) +#define PORT_STAT_SPEED_10MBIT BIT(4) +#define PORT_STAT_FULL_DUPLEX BIT(3) + +/* Same as PORT_PHY_STAT_MASTER */ +#define PORT_STAT_MASTER BIT(2) +#define PORT_RESET BIT(1) +#define PORT_LINK_STATUS_FAIL BIT(0) + +/* 3 - xMII */ +#define REG_PORT_XMII_CTRL_0 0x0300 + +#define PORT_SGMII_SEL BIT(7) +#define PORT_MII_FULL_DUPLEX BIT(6) +#define PORT_MII_100MBIT BIT(4) +#define PORT_GRXC_ENABLE BIT(0) + +#define REG_PORT_XMII_CTRL_1 0x0301 + +#define PORT_RMII_CLK_SEL BIT(7) +/* S1 */ +#define PORT_MII_1000MBIT_S1 BIT(6) +/* S2 */ +#define PORT_MII_NOT_1GBIT BIT(6) +#define PORT_MII_SEL_EDGE BIT(5) +#define PORT_RGMII_ID_IG_ENABLE BIT(4) +#define PORT_RGMII_ID_EG_ENABLE BIT(3) +#define PORT_MII_MAC_MODE BIT(2) +#define PORT_MII_SEL_M 0x3 +/* S1 */ +#define PORT_MII_SEL_S1 0x0 +#define PORT_RMII_SEL_S1 0x1 +#define PORT_GMII_SEL_S1 0x2 +#define PORT_RGMII_SEL_S1 0x3 +/* S2 */ +#define PORT_RGMII_SEL 0x0 +#define PORT_RMII_SEL 0x1 +#define PORT_GMII_SEL 0x2 +#define PORT_MII_SEL 0x3 + +/* 4 - MAC */ +#define REG_PORT_MAC_CTRL_0 0x0400 + +#define PORT_BROADCAST_STORM BIT(1) +#define PORT_JUMBO_FRAME BIT(0) + +#define REG_PORT_MAC_CTRL_1 0x0401 + +#define PORT_BACK_PRESSURE BIT(3) +#define PORT_PASS_ALL BIT(0) + +#define REG_PORT_MAC_CTRL_2 0x0402 + +#define PORT_100BT_EEE_DISABLE BIT(7) +#define PORT_1000BT_EEE_DISABLE BIT(6) + +#define REG_PORT_MAC_IN_RATE_LIMIT 0x0403 + +#define PORT_IN_PORT_BASED_S 6 +#define PORT_RATE_PACKET_BASED_S 5 +#define PORT_IN_FLOW_CTRL_S 4 +#define PORT_COUNT_IFG_S 1 +#define PORT_COUNT_PREAMBLE_S 0 +#define PORT_IN_PORT_BASED BIT(6) +#define PORT_IN_PACKET_BASED BIT(5) +#define PORT_IN_FLOW_CTRL BIT(4) +#define PORT_IN_LIMIT_MODE_M 0x3 +#define PORT_IN_LIMIT_MODE_S 2 +#define PORT_IN_ALL 0 +#define PORT_IN_UNICAST 1 +#define PORT_IN_MULTICAST 2 +#define PORT_IN_BROADCAST 3 +#define PORT_COUNT_IFG BIT(1) +#define PORT_COUNT_PREAMBLE BIT(0) + +#define REG_PORT_IN_RATE_0 0x0410 +#define REG_PORT_IN_RATE_1 0x0411 +#define REG_PORT_IN_RATE_2 0x0412 +#define REG_PORT_IN_RATE_3 0x0413 +#define REG_PORT_IN_RATE_4 0x0414 +#define REG_PORT_IN_RATE_5 0x0415 +#define REG_PORT_IN_RATE_6 0x0416 +#define REG_PORT_IN_RATE_7 0x0417 + +#define REG_PORT_OUT_RATE_0 0x0420 +#define REG_PORT_OUT_RATE_1 0x0421 +#define REG_PORT_OUT_RATE_2 0x0422 +#define REG_PORT_OUT_RATE_3 0x0423 + +#define PORT_RATE_LIMIT_M (BIT(7) - 1) + +/* 5 - MIB Counters */ +#define REG_PORT_MIB_CTRL_STAT__4 0x0500 + +#define MIB_COUNTER_OVERFLOW BIT(31) +#define MIB_COUNTER_VALID BIT(30) +#define MIB_COUNTER_READ BIT(25) +#define MIB_COUNTER_FLUSH_FREEZE BIT(24) +#define MIB_COUNTER_INDEX_M (BIT(8) - 1) +#define MIB_COUNTER_INDEX_S 16 +#define MIB_COUNTER_DATA_HI_M 0xF + +#define REG_PORT_MIB_DATA 0x0504 + +/* 6 - ACL */ +#define REG_PORT_ACL_0 0x0600 + +#define ACL_FIRST_RULE_M 0xF + +#define REG_PORT_ACL_1 0x0601 + +#define ACL_MODE_M 0x3 +#define ACL_MODE_S 4 +#define ACL_MODE_DISABLE 0 +#define ACL_MODE_LAYER_2 1 +#define ACL_MODE_LAYER_3 2 +#define ACL_MODE_LAYER_4 3 +#define ACL_ENABLE_M 0x3 +#define ACL_ENABLE_S 2 +#define ACL_ENABLE_2_COUNT 0 +#define ACL_ENABLE_2_TYPE 1 +#define ACL_ENABLE_2_MAC 2 +#define ACL_ENABLE_2_BOTH 3 +#define ACL_ENABLE_3_IP 1 +#define ACL_ENABLE_3_SRC_DST_COMP 2 +#define ACL_ENABLE_4_PROTOCOL 0 +#define ACL_ENABLE_4_TCP_PORT_COMP 1 +#define ACL_ENABLE_4_UDP_PORT_COMP 2 +#define ACL_ENABLE_4_TCP_SEQN_COMP 3 +#define ACL_SRC BIT(1) +#define ACL_EQUAL BIT(0) + +#define REG_PORT_ACL_2 0x0602 +#define REG_PORT_ACL_3 0x0603 + +#define ACL_MAX_PORT 0xFFFF + +#define REG_PORT_ACL_4 0x0604 +#define REG_PORT_ACL_5 0x0605 + +#define ACL_MIN_PORT 0xFFFF +#define ACL_IP_ADDR 0xFFFFFFFF +#define ACL_TCP_SEQNUM 0xFFFFFFFF + +#define REG_PORT_ACL_6 0x0606 + +#define ACL_RESERVED 0xF8 +#define ACL_PORT_MODE_M 0x3 +#define ACL_PORT_MODE_S 1 +#define ACL_PORT_MODE_DISABLE 0 +#define ACL_PORT_MODE_EITHER 1 +#define ACL_PORT_MODE_IN_RANGE 2 +#define ACL_PORT_MODE_OUT_OF_RANGE 3 + +#define REG_PORT_ACL_7 0x0607 + +#define ACL_TCP_FLAG_ENABLE BIT(0) + +#define REG_PORT_ACL_8 0x0608 + +#define ACL_TCP_FLAG_M 0xFF + +#define REG_PORT_ACL_9 0x0609 + +#define ACL_TCP_FLAG 0xFF +#define ACL_ETH_TYPE 0xFFFF +#define ACL_IP_M 0xFFFFFFFF + +#define REG_PORT_ACL_A 0x060A + +#define ACL_PRIO_MODE_M 0x3 +#define ACL_PRIO_MODE_S 6 +#define ACL_PRIO_MODE_DISABLE 0 +#define ACL_PRIO_MODE_HIGHER 1 +#define ACL_PRIO_MODE_LOWER 2 +#define ACL_PRIO_MODE_REPLACE 3 +#define ACL_PRIO_M KS_PRIO_M +#define ACL_PRIO_S 3 +#define ACL_VLAN_PRIO_REPLACE BIT(2) +#define ACL_VLAN_PRIO_M KS_PRIO_M +#define ACL_VLAN_PRIO_HI_M 0x3 + +#define REG_PORT_ACL_B 0x060B + +#define ACL_VLAN_PRIO_LO_M 0x8 +#define ACL_VLAN_PRIO_S 7 +#define ACL_MAP_MODE_M 0x3 +#define ACL_MAP_MODE_S 5 +#define ACL_MAP_MODE_DISABLE 0 +#define ACL_MAP_MODE_OR 1 +#define ACL_MAP_MODE_AND 2 +#define ACL_MAP_MODE_REPLACE 3 + +#define ACL_CNT_M (BIT(11) - 1) +#define ACL_CNT_S 5 + +#define REG_PORT_ACL_C 0x060C + +#define REG_PORT_ACL_D 0x060D +#define ACL_MSEC_UNIT BIT(6) +#define ACL_INTR_MODE BIT(5) +#define ACL_PORT_MAP 0x7F + +#define REG_PORT_ACL_E 0x060E +#define REG_PORT_ACL_F 0x060F + +#define REG_PORT_ACL_BYTE_EN_MSB 0x0610 +#define REG_PORT_ACL_BYTE_EN_LSB 0x0611 + +#define ACL_ACTION_START 0xA +#define ACL_ACTION_LEN 4 +#define ACL_INTR_CNT_START 0xD +#define ACL_RULESET_START 0xE +#define ACL_RULESET_LEN 2 +#define ACL_TABLE_LEN 16 + +#define ACL_ACTION_ENABLE 0x003C +#define ACL_MATCH_ENABLE 0x7FC3 +#define ACL_RULESET_ENABLE 0x8003 +#define ACL_BYTE_ENABLE 0xFFFF + +#define REG_PORT_ACL_CTRL_0 0x0612 + +#define PORT_ACL_WRITE_DONE BIT(6) +#define PORT_ACL_READ_DONE BIT(5) +#define PORT_ACL_WRITE BIT(4) +#define PORT_ACL_INDEX_M 0xF + +#define REG_PORT_ACL_CTRL_1 0x0613 + +/* 8 - Classification and Policing */ +#define REG_PORT_MRI_MIRROR_CTRL 0x0800 + +#define PORT_MIRROR_RX BIT(6) +#define PORT_MIRROR_TX BIT(5) +#define PORT_MIRROR_SNIFFER BIT(1) + +#define REG_PORT_MRI_PRIO_CTRL 0x0801 + +#define PORT_HIGHEST_PRIO BIT(7) +#define PORT_OR_PRIO BIT(6) +#define PORT_MAC_PRIO_ENABLE BIT(4) +#define PORT_VLAN_PRIO_ENABLE BIT(3) +#define PORT_802_1P_PRIO_ENABLE BIT(2) +#define PORT_DIFFSERV_PRIO_ENABLE BIT(1) +#define PORT_ACL_PRIO_ENABLE BIT(0) + +#define REG_PORT_MRI_MAC_CTRL 0x0802 + +#define PORT_USER_PRIO_CEILING BIT(7) +#define PORT_DROP_NON_VLAN BIT(4) +#define PORT_DROP_TAG BIT(3) +#define PORT_BASED_PRIO_M KS_PRIO_M +#define PORT_BASED_PRIO_S 0 + +#define REG_PORT_MRI_AUTHEN_CTRL 0x0803 + +#define PORT_ACL_ENABLE BIT(2) +#define PORT_AUTHEN_MODE 0x3 +#define PORT_AUTHEN_PASS 0 +#define PORT_AUTHEN_BLOCK 1 +#define PORT_AUTHEN_TRAP 2 + +#define REG_PORT_MRI_INDEX__4 0x0804 + +#define MRI_INDEX_P_M 0x7 +#define MRI_INDEX_P_S 16 +#define MRI_INDEX_Q_M 0x3 +#define MRI_INDEX_Q_S 0 + +#define REG_PORT_MRI_TC_MAP__4 0x0808 + +#define PORT_TC_MAP_M 0xf +#define PORT_TC_MAP_S 4 + +#define REG_PORT_MRI_POLICE_CTRL__4 0x080C + +#define POLICE_DROP_ALL BIT(10) +#define POLICE_PACKET_TYPE_M 0x3 +#define POLICE_PACKET_TYPE_S 8 +#define POLICE_PACKET_DROPPED 0 +#define POLICE_PACKET_GREEN 1 +#define POLICE_PACKET_YELLOW 2 +#define POLICE_PACKET_RED 3 +#define PORT_BASED_POLICING BIT(7) +#define NON_DSCP_COLOR_M 0x3 +#define NON_DSCP_COLOR_S 5 +#define COLOR_MARK_ENABLE BIT(4) +#define COLOR_REMAP_ENABLE BIT(3) +#define POLICE_DROP_SRP BIT(2) +#define POLICE_COLOR_NOT_AWARE BIT(1) +#define POLICE_ENABLE BIT(0) + +#define REG_PORT_POLICE_COLOR_0__4 0x0810 +#define REG_PORT_POLICE_COLOR_1__4 0x0814 +#define REG_PORT_POLICE_COLOR_2__4 0x0818 +#define REG_PORT_POLICE_COLOR_3__4 0x081C + +#define POLICE_COLOR_MAP_S 2 +#define POLICE_COLOR_MAP_M (BIT(POLICE_COLOR_MAP_S) - 1) + +#define REG_PORT_POLICE_RATE__4 0x0820 + +#define POLICE_CIR_S 16 +#define POLICE_PIR_S 0 + +#define REG_PORT_POLICE_BURST_SIZE__4 0x0824 + +#define POLICE_BURST_SIZE_M 0x3FFF +#define POLICE_CBS_S 16 +#define POLICE_PBS_S 0 + +#define REG_PORT_WRED_PM_CTRL_0__4 0x0830 + +#define WRED_PM_CTRL_M (BIT(11) - 1) + +#define WRED_PM_MAX_THRESHOLD_S 16 +#define WRED_PM_MIN_THRESHOLD_S 0 + +#define REG_PORT_WRED_PM_CTRL_1__4 0x0834 + +#define WRED_PM_MULTIPLIER_S 16 +#define WRED_PM_AVG_QUEUE_SIZE_S 0 + +#define REG_PORT_WRED_QUEUE_CTRL_0__4 0x0840 +#define REG_PORT_WRED_QUEUE_CTRL_1__4 0x0844 + +#define REG_PORT_WRED_QUEUE_PMON__4 0x0848 + +#define WRED_RANDOM_DROP_ENABLE BIT(31) +#define WRED_PMON_FLUSH BIT(30) +#define WRED_DROP_GYR_DISABLE BIT(29) +#define WRED_DROP_YR_DISABLE BIT(28) +#define WRED_DROP_R_DISABLE BIT(27) +#define WRED_DROP_ALL BIT(26) +#define WRED_PMON_M (BIT(24) - 1) + +/* 9 - Shaping */ + +#define REG_PORT_MTI_QUEUE_INDEX__4 0x0900 + +#define REG_PORT_MTI_QUEUE_CTRL_0__4 0x0904 + +#define MTI_PVID_REPLACE BIT(0) + +#define REG_PORT_MTI_QUEUE_CTRL_0 0x0914 + +#define MTI_SCHEDULE_MODE_M 0x3 +#define MTI_SCHEDULE_MODE_S 6 +#define MTI_SCHEDULE_STRICT_PRIO 0 +#define MTI_SCHEDULE_WRR 2 +#define MTI_SHAPING_M 0x3 +#define MTI_SHAPING_S 4 +#define MTI_SHAPING_OFF 0 +#define MTI_SHAPING_SRP 1 +#define MTI_SHAPING_TIME_AWARE 2 + +#define REG_PORT_MTI_QUEUE_CTRL_1 0x0915 + +#define MTI_TX_RATIO_M (BIT(7) - 1) + +#define REG_PORT_MTI_QUEUE_CTRL_2__2 0x0916 +#define REG_PORT_MTI_HI_WATER_MARK 0x0916 +#define REG_PORT_MTI_QUEUE_CTRL_3__2 0x0918 +#define REG_PORT_MTI_LO_WATER_MARK 0x0918 +#define REG_PORT_MTI_QUEUE_CTRL_4__2 0x091A +#define REG_PORT_MTI_CREDIT_INCREMENT 0x091A + +/* A - QM */ + +#define REG_PORT_QM_CTRL__4 0x0A00 + +#define PORT_QM_DROP_PRIO_M 0x3 + +#define REG_PORT_VLAN_MEMBERSHIP__4 0x0A04 + +#define REG_PORT_QM_QUEUE_INDEX__4 0x0A08 + +#define PORT_QM_QUEUE_INDEX_S 24 +#define PORT_QM_BURST_SIZE_S 16 +#define PORT_QM_MIN_RESV_SPACE_M (BIT(11) - 1) + +#define REG_PORT_QM_WATER_MARK__4 0x0A0C + +#define PORT_QM_HI_WATER_MARK_S 16 +#define PORT_QM_LO_WATER_MARK_S 0 +#define PORT_QM_WATER_MARK_M (BIT(11) - 1) + +#define REG_PORT_QM_TX_CNT_0__4 0x0A10 + +#define PORT_QM_TX_CNT_USED_S 0 +#define PORT_QM_TX_CNT_M (BIT(11) - 1) + +#define REG_PORT_QM_TX_CNT_1__4 0x0A14 + +#define PORT_QM_TX_CNT_CALCULATED_S 16 +#define PORT_QM_TX_CNT_AVAIL_S 0 + +/* B - LUE */ +#define REG_PORT_LUE_CTRL 0x0B00 + +#define PORT_VLAN_LOOKUP_VID_0 BIT(7) +#define PORT_INGRESS_FILTER BIT(6) +#define PORT_DISCARD_NON_VID BIT(5) +#define PORT_MAC_BASED_802_1X BIT(4) +#define PORT_SRC_ADDR_FILTER BIT(3) + +#define REG_PORT_LUE_MSTP_INDEX 0x0B01 + +#define REG_PORT_LUE_MSTP_STATE 0x0B04 + +#define PORT_TX_ENABLE BIT(2) +#define PORT_RX_ENABLE BIT(1) +#define PORT_LEARN_DISABLE BIT(0) + +/* C - PTP */ + +#define REG_PTP_PORT_RX_DELAY__2 0x0C00 +#define REG_PTP_PORT_TX_DELAY__2 0x0C02 +#define REG_PTP_PORT_ASYM_DELAY__2 0x0C04 + +#define REG_PTP_PORT_XDELAY_TS 0x0C08 +#define REG_PTP_PORT_XDELAY_TS_H 0x0C08 +#define REG_PTP_PORT_XDELAY_TS_L 0x0C0A + +#define REG_PTP_PORT_SYNC_TS 0x0C0C +#define REG_PTP_PORT_SYNC_TS_H 0x0C0C +#define REG_PTP_PORT_SYNC_TS_L 0x0C0E + +#define REG_PTP_PORT_PDRESP_TS 0x0C10 +#define REG_PTP_PORT_PDRESP_TS_H 0x0C10 +#define REG_PTP_PORT_PDRESP_TS_L 0x0C12 + +#define REG_PTP_PORT_TX_INT_STATUS__2 0x0C14 +#define REG_PTP_PORT_TX_INT_ENABLE__2 0x0C16 + +#define PTP_PORT_SYNC_INT BIT(15) +#define PTP_PORT_XDELAY_REQ_INT BIT(14) +#define PTP_PORT_PDELAY_RESP_INT BIT(13) + +#define REG_PTP_PORT_LINK_DELAY__4 0x0C18 + +#define PRIO_QUEUES 4 +#define RX_PRIO_QUEUES 8 + +#define KS_PRIO_IN_REG 2 + +#define TOTAL_PORT_NUM 7 + +#define KSZ9477_COUNTER_NUM 0x20 +#define TOTAL_KSZ9477_COUNTER_NUM (KSZ9477_COUNTER_NUM + 2 + 2) + +#define SWITCH_COUNTER_NUM KSZ9477_COUNTER_NUM +#define TOTAL_SWITCH_COUNTER_NUM TOTAL_KSZ9477_COUNTER_NUM + +#define P_BCAST_STORM_CTRL REG_PORT_MAC_CTRL_0 +#define P_PRIO_CTRL REG_PORT_MRI_PRIO_CTRL +#define P_MIRROR_CTRL REG_PORT_MRI_MIRROR_CTRL +#define P_STP_CTRL REG_PORT_LUE_MSTP_STATE +#define P_PHY_CTRL REG_PORT_PHY_CTRL +#define P_NEG_RESTART_CTRL REG_PORT_PHY_CTRL +#define P_LINK_STATUS REG_PORT_PHY_STATUS +#define P_SPEED_STATUS REG_PORT_PHY_PHY_CTRL +#define P_RATE_LIMIT_CTRL REG_PORT_MAC_IN_RATE_LIMIT + +#define S_LINK_AGING_CTRL REG_SW_LUE_CTRL_1 +#define S_MIRROR_CTRL REG_SW_MRI_CTRL_0 +#define S_REPLACE_VID_CTRL REG_SW_MAC_CTRL_2 +#define S_802_1P_PRIO_CTRL REG_SW_MAC_802_1P_MAP_0 +#define S_TOS_PRIO_CTRL REG_SW_MAC_TOS_PRIO_0 +#define S_FLUSH_TABLE_CTRL REG_SW_LUE_CTRL_1 + +#define SW_FLUSH_DYN_MAC_TABLE SW_FLUSH_MSTP_TABLE + +#define MAX_TIMESTAMP_UNIT 2 +#define MAX_TRIG_UNIT 3 +#define MAX_TIMESTAMP_EVENT_UNIT 8 +#define MAX_GPIO 4 + +#define PTP_TRIG_UNIT_M (BIT(MAX_TRIG_UNIT) - 1) +#define PTP_TS_UNIT_M (BIT(MAX_TIMESTAMP_UNIT) - 1) + +/* Driver set switch broadcast storm protection at 10% rate. */ +#define BROADCAST_STORM_PROT_RATE 10 + +/* 148,800 frames * 67 ms / 100 */ +#define BROADCAST_STORM_VALUE 9969 + +#endif /* KSZ9477_REGS_H */ diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c new file mode 100644 index 000000000000..b313ecdf2919 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -0,0 +1,1279 @@ +/* + * Microchip switch driver main logic + * + * Copyright (C) 2017 + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/gpio.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_data/microchip-ksz.h> +#include <linux/phy.h> +#include <linux/etherdevice.h> +#include <linux/if_bridge.h> +#include <net/dsa.h> +#include <net/switchdev.h> + +#include "ksz_priv.h" + +static const struct { + int index; + char string[ETH_GSTRING_LEN]; +} mib_names[TOTAL_SWITCH_COUNTER_NUM] = { + { 0x00, "rx_hi" }, + { 0x01, "rx_undersize" }, + { 0x02, "rx_fragments" }, + { 0x03, "rx_oversize" }, + { 0x04, "rx_jabbers" }, + { 0x05, "rx_symbol_err" }, + { 0x06, "rx_crc_err" }, + { 0x07, "rx_align_err" }, + { 0x08, "rx_mac_ctrl" }, + { 0x09, "rx_pause" }, + { 0x0A, "rx_bcast" }, + { 0x0B, "rx_mcast" }, + { 0x0C, "rx_ucast" }, + { 0x0D, "rx_64_or_less" }, + { 0x0E, "rx_65_127" }, + { 0x0F, "rx_128_255" }, + { 0x10, "rx_256_511" }, + { 0x11, "rx_512_1023" }, + { 0x12, "rx_1024_1522" }, + { 0x13, "rx_1523_2000" }, + { 0x14, "rx_2001" }, + { 0x15, "tx_hi" }, + { 0x16, "tx_late_col" }, + { 0x17, "tx_pause" }, + { 0x18, "tx_bcast" }, + { 0x19, "tx_mcast" }, + { 0x1A, "tx_ucast" }, + { 0x1B, "tx_deferred" }, + { 0x1C, "tx_total_col" }, + { 0x1D, "tx_exc_col" }, + { 0x1E, "tx_single_col" }, + { 0x1F, "tx_mult_col" }, + { 0x80, "rx_total" }, + { 0x81, "tx_total" }, + { 0x82, "rx_discards" }, + { 0x83, "tx_discards" }, +}; + +static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) +{ + u8 data; + + ksz_read8(dev, addr, &data); + if (set) + data |= bits; + else + data &= ~bits; + ksz_write8(dev, addr, data); +} + +static void ksz_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set) +{ + u32 data; + + ksz_read32(dev, addr, &data); + if (set) + data |= bits; + else + data &= ~bits; + ksz_write32(dev, addr, data); +} + +static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, + bool set) +{ + u32 addr; + u8 data; + + addr = PORT_CTRL_ADDR(port, offset); + ksz_read8(dev, addr, &data); + + if (set) + data |= bits; + else + data &= ~bits; + + ksz_write8(dev, addr, data); +} + +static void ksz_port_cfg32(struct ksz_device *dev, int port, int offset, + u32 bits, bool set) +{ + u32 addr; + u32 data; + + addr = PORT_CTRL_ADDR(port, offset); + ksz_read32(dev, addr, &data); + + if (set) + data |= bits; + else + data &= ~bits; + + ksz_write32(dev, addr, data); +} + +static int wait_vlan_ctrl_ready(struct ksz_device *dev, u32 waiton, int timeout) +{ + u8 data; + + do { + ksz_read8(dev, REG_SW_VLAN_CTRL, &data); + if (!(data & waiton)) + break; + usleep_range(1, 10); + } while (timeout-- > 0); + + if (timeout <= 0) + return -ETIMEDOUT; + + return 0; +} + +static int get_vlan_table(struct dsa_switch *ds, u16 vid, u32 *vlan_table) +{ + struct ksz_device *dev = ds->priv; + int ret; + + mutex_lock(&dev->vlan_mutex); + + ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M); + ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_READ | VLAN_START); + + /* wait to be cleared */ + ret = wait_vlan_ctrl_ready(dev, VLAN_START, 1000); + if (ret < 0) { + dev_dbg(dev->dev, "Failed to read vlan table\n"); + goto exit; + } + + ksz_read32(dev, REG_SW_VLAN_ENTRY__4, &vlan_table[0]); + ksz_read32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, &vlan_table[1]); + ksz_read32(dev, REG_SW_VLAN_ENTRY_PORTS__4, &vlan_table[2]); + + ksz_write8(dev, REG_SW_VLAN_CTRL, 0); + +exit: + mutex_unlock(&dev->vlan_mutex); + + return ret; +} + +static int set_vlan_table(struct dsa_switch *ds, u16 vid, u32 *vlan_table) +{ + struct ksz_device *dev = ds->priv; + int ret; + + mutex_lock(&dev->vlan_mutex); + + ksz_write32(dev, REG_SW_VLAN_ENTRY__4, vlan_table[0]); + ksz_write32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, vlan_table[1]); + ksz_write32(dev, REG_SW_VLAN_ENTRY_PORTS__4, vlan_table[2]); + + ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M); + ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_START | VLAN_WRITE); + + /* wait to be cleared */ + ret = wait_vlan_ctrl_ready(dev, VLAN_START, 1000); + if (ret < 0) { + dev_dbg(dev->dev, "Failed to write vlan table\n"); + goto exit; + } + + ksz_write8(dev, REG_SW_VLAN_CTRL, 0); + + /* update vlan cache table */ + dev->vlan_cache[vid].table[0] = vlan_table[0]; + dev->vlan_cache[vid].table[1] = vlan_table[1]; + dev->vlan_cache[vid].table[2] = vlan_table[2]; + +exit: + mutex_unlock(&dev->vlan_mutex); + + return ret; +} + +static void read_table(struct dsa_switch *ds, u32 *table) +{ + struct ksz_device *dev = ds->priv; + + ksz_read32(dev, REG_SW_ALU_VAL_A, &table[0]); + ksz_read32(dev, REG_SW_ALU_VAL_B, &table[1]); + ksz_read32(dev, REG_SW_ALU_VAL_C, &table[2]); + ksz_read32(dev, REG_SW_ALU_VAL_D, &table[3]); +} + +static void write_table(struct dsa_switch *ds, u32 *table) +{ + struct ksz_device *dev = ds->priv; + + ksz_write32(dev, REG_SW_ALU_VAL_A, table[0]); + ksz_write32(dev, REG_SW_ALU_VAL_B, table[1]); + ksz_write32(dev, REG_SW_ALU_VAL_C, table[2]); + ksz_write32(dev, REG_SW_ALU_VAL_D, table[3]); +} + +static int wait_alu_ready(struct ksz_device *dev, u32 waiton, int timeout) +{ + u32 data; + + do { + ksz_read32(dev, REG_SW_ALU_CTRL__4, &data); + if (!(data & waiton)) + break; + usleep_range(1, 10); + } while (timeout-- > 0); + + if (timeout <= 0) + return -ETIMEDOUT; + + return 0; +} + +static int wait_alu_sta_ready(struct ksz_device *dev, u32 waiton, int timeout) +{ + u32 data; + + do { + ksz_read32(dev, REG_SW_ALU_STAT_CTRL__4, &data); + if (!(data & waiton)) + break; + usleep_range(1, 10); + } while (timeout-- > 0); + + if (timeout <= 0) + return -ETIMEDOUT; + + return 0; +} + +static int ksz_reset_switch(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + u8 data8; + u16 data16; + u32 data32; + + /* reset switch */ + ksz_cfg(dev, REG_SW_OPERATION, SW_RESET, true); + + /* turn off SPI DO Edge select */ + ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8); + data8 &= ~SPI_AUTO_EDGE_DETECTION; + ksz_write8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, data8); + + /* default configuration */ + ksz_read8(dev, REG_SW_LUE_CTRL_1, &data8); + data8 = SW_AGING_ENABLE | SW_LINK_AUTO_AGING | + SW_SRC_ADDR_FILTER | SW_FLUSH_STP_TABLE | SW_FLUSH_MSTP_TABLE; + ksz_write8(dev, REG_SW_LUE_CTRL_1, data8); + + /* disable interrupts */ + ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK); + ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0x7F); + ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32); + + /* set broadcast storm protection 10% rate */ + ksz_read16(dev, REG_SW_MAC_CTRL_2, &data16); + data16 &= ~BROADCAST_STORM_RATE; + data16 |= (BROADCAST_STORM_VALUE * BROADCAST_STORM_PROT_RATE) / 100; + ksz_write16(dev, REG_SW_MAC_CTRL_2, data16); + + return 0; +} + +static void port_setup(struct ksz_device *dev, int port, bool cpu_port) +{ + u8 data8; + u16 data16; + + /* enable tag tail for host port */ + if (cpu_port) + ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_TAIL_TAG_ENABLE, + true); + + ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, false); + + /* set back pressure */ + ksz_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE, true); + + /* set flow control */ + ksz_port_cfg(dev, port, REG_PORT_CTRL_0, + PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL, true); + + /* enable broadcast storm limit */ + ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true); + + /* disable DiffServ priority */ + ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_PRIO_ENABLE, false); + + /* replace priority */ + ksz_port_cfg(dev, port, REG_PORT_MRI_MAC_CTRL, PORT_USER_PRIO_CEILING, + false); + ksz_port_cfg32(dev, port, REG_PORT_MTI_QUEUE_CTRL_0__4, + MTI_PVID_REPLACE, false); + + /* enable 802.1p priority */ + ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true); + + /* configure MAC to 1G & RGMII mode */ + ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8); + data8 |= PORT_RGMII_ID_EG_ENABLE; + data8 &= ~PORT_MII_NOT_1GBIT; + data8 &= ~PORT_MII_SEL_M; + data8 |= PORT_RGMII_SEL; + ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, data8); + + /* clear pending interrupts */ + ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16); +} + +static void ksz_config_cpu_port(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + int i; + + ds->num_ports = dev->port_cnt; + + for (i = 0; i < ds->num_ports; i++) { + if (dsa_is_cpu_port(ds, i) && (dev->cpu_ports & (1 << i))) { + dev->cpu_port = i; + + /* enable cpu port */ + port_setup(dev, i, true); + } + } +} + +static int ksz_setup(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + int ret = 0; + + dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table), + dev->num_vlans, GFP_KERNEL); + if (!dev->vlan_cache) + return -ENOMEM; + + ret = ksz_reset_switch(ds); + if (ret) { + dev_err(ds->dev, "failed to reset switch\n"); + return ret; + } + + /* accept packet up to 2000bytes */ + ksz_cfg(dev, REG_SW_MAC_CTRL_1, SW_LEGAL_PACKET_DISABLE, true); + + ksz_config_cpu_port(ds); + + ksz_cfg(dev, REG_SW_MAC_CTRL_1, MULTICAST_STORM_DISABLE, true); + + /* queue based egress rate limit */ + ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true); + + /* start switch */ + ksz_cfg(dev, REG_SW_OPERATION, SW_START, true); + + return 0; +} + +static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds) +{ + return DSA_TAG_PROTO_KSZ; +} + +static int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg) +{ + struct ksz_device *dev = ds->priv; + u16 val = 0; + + ksz_pread16(dev, addr, 0x100 + (reg << 1), &val); + + return val; +} + +static int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) +{ + struct ksz_device *dev = ds->priv; + + ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); + + return 0; +} + +static int ksz_enable_port(struct dsa_switch *ds, int port, + struct phy_device *phy) +{ + struct ksz_device *dev = ds->priv; + + /* setup slave port */ + port_setup(dev, port, false); + + return 0; +} + +static void ksz_disable_port(struct dsa_switch *ds, int port, + struct phy_device *phy) +{ + struct ksz_device *dev = ds->priv; + + /* there is no port disable */ + ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, true); +} + +static int ksz_sset_count(struct dsa_switch *ds) +{ + return TOTAL_SWITCH_COUNTER_NUM; +} + +static void ksz_get_strings(struct dsa_switch *ds, int port, uint8_t *buf) +{ + int i; + + for (i = 0; i < TOTAL_SWITCH_COUNTER_NUM; i++) { + memcpy(buf + i * ETH_GSTRING_LEN, mib_names[i].string, + ETH_GSTRING_LEN); + } +} + +static void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, + uint64_t *buf) +{ + struct ksz_device *dev = ds->priv; + int i; + u32 data; + int timeout; + + mutex_lock(&dev->stats_mutex); + + for (i = 0; i < TOTAL_SWITCH_COUNTER_NUM; i++) { + data = MIB_COUNTER_READ; + data |= ((mib_names[i].index & 0xFF) << MIB_COUNTER_INDEX_S); + ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, data); + + timeout = 1000; + do { + ksz_pread32(dev, port, REG_PORT_MIB_CTRL_STAT__4, + &data); + usleep_range(1, 10); + if (!(data & MIB_COUNTER_READ)) + break; + } while (timeout-- > 0); + + /* failed to read MIB. get out of loop */ + if (!timeout) { + dev_dbg(dev->dev, "Failed to get MIB\n"); + break; + } + + /* count resets upon read */ + ksz_pread32(dev, port, REG_PORT_MIB_DATA, &data); + + dev->mib_value[i] += (uint64_t)data; + buf[i] = dev->mib_value[i]; + } + + mutex_unlock(&dev->stats_mutex); +} + +static void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) +{ + struct ksz_device *dev = ds->priv; + u8 data; + + ksz_pread8(dev, port, P_STP_CTRL, &data); + data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE); + + switch (state) { + case BR_STATE_DISABLED: + data |= PORT_LEARN_DISABLE; + break; + case BR_STATE_LISTENING: + data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE); + break; + case BR_STATE_LEARNING: + data |= PORT_RX_ENABLE; + break; + case BR_STATE_FORWARDING: + data |= (PORT_TX_ENABLE | PORT_RX_ENABLE); + break; + case BR_STATE_BLOCKING: + data |= PORT_LEARN_DISABLE; + break; + default: + dev_err(ds->dev, "invalid STP state: %d\n", state); + return; + } + + ksz_pwrite8(dev, port, P_STP_CTRL, data); +} + +static void ksz_port_fast_age(struct dsa_switch *ds, int port) +{ + struct ksz_device *dev = ds->priv; + u8 data8; + + ksz_read8(dev, REG_SW_LUE_CTRL_1, &data8); + data8 |= SW_FAST_AGING; + ksz_write8(dev, REG_SW_LUE_CTRL_1, data8); + + data8 &= ~SW_FAST_AGING; + ksz_write8(dev, REG_SW_LUE_CTRL_1, data8); +} + +static int ksz_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag) +{ + struct ksz_device *dev = ds->priv; + + if (flag) { + ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, + PORT_VLAN_LOOKUP_VID_0, true); + ksz_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, true); + ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, true); + } else { + ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, false); + ksz_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, false); + ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, + PORT_VLAN_LOOKUP_VID_0, false); + } + + return 0; +} + +static int ksz_port_vlan_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, + struct switchdev_trans *trans) +{ + /* nothing needed */ + + return 0; +} + +static void ksz_port_vlan_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, + struct switchdev_trans *trans) +{ + struct ksz_device *dev = ds->priv; + u32 vlan_table[3]; + u16 vid; + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + if (get_vlan_table(ds, vid, vlan_table)) { + dev_dbg(dev->dev, "Failed to get vlan table\n"); + return; + } + + vlan_table[0] = VLAN_VALID | (vid & VLAN_FID_M); + if (untagged) + vlan_table[1] |= BIT(port); + else + vlan_table[1] &= ~BIT(port); + vlan_table[1] &= ~(BIT(dev->cpu_port)); + + vlan_table[2] |= BIT(port) | BIT(dev->cpu_port); + + if (set_vlan_table(ds, vid, vlan_table)) { + dev_dbg(dev->dev, "Failed to set vlan table\n"); + return; + } + + /* change PVID */ + if (vlan->flags & BRIDGE_VLAN_INFO_PVID) + ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, vid); + } +} + +static int ksz_port_vlan_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) +{ + struct ksz_device *dev = ds->priv; + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + u32 vlan_table[3]; + u16 vid; + u16 pvid; + + ksz_pread16(dev, port, REG_PORT_DEFAULT_VID, &pvid); + pvid = pvid & 0xFFF; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + if (get_vlan_table(ds, vid, vlan_table)) { + dev_dbg(dev->dev, "Failed to get vlan table\n"); + return -ETIMEDOUT; + } + + vlan_table[2] &= ~BIT(port); + + if (pvid == vid) + pvid = 1; + + if (untagged) + vlan_table[1] &= ~BIT(port); + + if (set_vlan_table(ds, vid, vlan_table)) { + dev_dbg(dev->dev, "Failed to set vlan table\n"); + return -ETIMEDOUT; + } + } + + ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, pvid); + + return 0; +} + +static int ksz_port_vlan_dump(struct dsa_switch *ds, int port, + struct switchdev_obj_port_vlan *vlan, + switchdev_obj_dump_cb_t *cb) +{ + struct ksz_device *dev = ds->priv; + u16 vid; + u16 data; + struct vlan_table *vlan_cache; + int err = 0; + + mutex_lock(&dev->vlan_mutex); + + /* use dev->vlan_cache due to lack of searching valid vlan entry */ + for (vid = vlan->vid_begin; vid < dev->num_vlans; vid++) { + vlan_cache = &dev->vlan_cache[vid]; + + if (!(vlan_cache->table[0] & VLAN_VALID)) + continue; + + vlan->vid_begin = vid; + vlan->vid_end = vid; + vlan->flags = 0; + if (vlan_cache->table[2] & BIT(port)) { + if (vlan_cache->table[1] & BIT(port)) + vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; + ksz_pread16(dev, port, REG_PORT_DEFAULT_VID, &data); + if (vid == (data & 0xFFFFF)) + vlan->flags |= BRIDGE_VLAN_INFO_PVID; + + err = cb(&vlan->obj); + if (err) + break; + } + } + + mutex_unlock(&dev->vlan_mutex); + + return err; +} + +static int ksz_port_fdb_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_fdb *fdb, + struct switchdev_trans *trans) +{ + /* nothing needed */ + + return 0; +} + +struct alu_struct { + /* entry 1 */ + u8 is_static:1; + u8 is_src_filter:1; + u8 is_dst_filter:1; + u8 prio_age:3; + u32 _reserv_0_1:23; + u8 mstp:3; + /* entry 2 */ + u8 is_override:1; + u8 is_use_fid:1; + u32 _reserv_1_1:23; + u8 port_forward:7; + /* entry 3 & 4*/ + u32 _reserv_2_1:9; + u8 fid:7; + u8 mac[ETH_ALEN]; +}; + +static void ksz_port_fdb_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_fdb *fdb, + struct switchdev_trans *trans) +{ + struct ksz_device *dev = ds->priv; + u32 alu_table[4]; + u32 data; + + mutex_lock(&dev->alu_mutex); + + /* find any entry with mac & vid */ + data = fdb->vid << ALU_FID_INDEX_S; + data |= ((fdb->addr[0] << 8) | fdb->addr[1]); + ksz_write32(dev, REG_SW_ALU_INDEX_0, data); + + data = ((fdb->addr[2] << 24) | (fdb->addr[3] << 16)); + data |= ((fdb->addr[4] << 8) | fdb->addr[5]); + ksz_write32(dev, REG_SW_ALU_INDEX_1, data); + + /* start read operation */ + ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START); + + /* wait to be finished */ + if (wait_alu_ready(dev, ALU_START, 1000) < 0) { + dev_dbg(dev->dev, "Failed to read ALU\n"); + goto exit; + } + + /* read ALU entry */ + read_table(ds, alu_table); + + /* update ALU entry */ + alu_table[0] = ALU_V_STATIC_VALID; + alu_table[1] |= BIT(port); + if (fdb->vid) + alu_table[1] |= ALU_V_USE_FID; + alu_table[2] = (fdb->vid << ALU_V_FID_S); + alu_table[2] |= ((fdb->addr[0] << 8) | fdb->addr[1]); + alu_table[3] = ((fdb->addr[2] << 24) | (fdb->addr[3] << 16)); + alu_table[3] |= ((fdb->addr[4] << 8) | fdb->addr[5]); + + write_table(ds, alu_table); + + ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START); + + /* wait to be finished */ + if (wait_alu_ready(dev, ALU_START, 1000) < 0) + dev_dbg(dev->dev, "Failed to read ALU\n"); + +exit: + mutex_unlock(&dev->alu_mutex); +} + +static int ksz_port_fdb_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_fdb *fdb) +{ + struct ksz_device *dev = ds->priv; + u32 alu_table[4]; + u32 data; + int ret = 0; + + mutex_lock(&dev->alu_mutex); + + /* read any entry with mac & vid */ + data = fdb->vid << ALU_FID_INDEX_S; + data |= ((fdb->addr[0] << 8) | fdb->addr[1]); + ksz_write32(dev, REG_SW_ALU_INDEX_0, data); + + data = ((fdb->addr[2] << 24) | (fdb->addr[3] << 16)); + data |= ((fdb->addr[4] << 8) | fdb->addr[5]); + ksz_write32(dev, REG_SW_ALU_INDEX_1, data); + + /* start read operation */ + ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START); + + /* wait to be finished */ + ret = wait_alu_ready(dev, ALU_START, 1000); + if (ret < 0) { + dev_dbg(dev->dev, "Failed to read ALU\n"); + goto exit; + } + + ksz_read32(dev, REG_SW_ALU_VAL_A, &alu_table[0]); + if (alu_table[0] & ALU_V_STATIC_VALID) { + ksz_read32(dev, REG_SW_ALU_VAL_B, &alu_table[1]); + ksz_read32(dev, REG_SW_ALU_VAL_C, &alu_table[2]); + ksz_read32(dev, REG_SW_ALU_VAL_D, &alu_table[3]); + + /* clear forwarding port */ + alu_table[2] &= ~BIT(port); + + /* if there is no port to forward, clear table */ + if ((alu_table[2] & ALU_V_PORT_MAP) == 0) { + alu_table[0] = 0; + alu_table[1] = 0; + alu_table[2] = 0; + alu_table[3] = 0; + } + } else { + alu_table[0] = 0; + alu_table[1] = 0; + alu_table[2] = 0; + alu_table[3] = 0; + } + + write_table(ds, alu_table); + + ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START); + + /* wait to be finished */ + ret = wait_alu_ready(dev, ALU_START, 1000); + if (ret < 0) + dev_dbg(dev->dev, "Failed to write ALU\n"); + +exit: + mutex_unlock(&dev->alu_mutex); + + return ret; +} + +static void convert_alu(struct alu_struct *alu, u32 *alu_table) +{ + alu->is_static = !!(alu_table[0] & ALU_V_STATIC_VALID); + alu->is_src_filter = !!(alu_table[0] & ALU_V_SRC_FILTER); + alu->is_dst_filter = !!(alu_table[0] & ALU_V_DST_FILTER); + alu->prio_age = (alu_table[0] >> ALU_V_PRIO_AGE_CNT_S) & + ALU_V_PRIO_AGE_CNT_M; + alu->mstp = alu_table[0] & ALU_V_MSTP_M; + + alu->is_override = !!(alu_table[1] & ALU_V_OVERRIDE); + alu->is_use_fid = !!(alu_table[1] & ALU_V_USE_FID); + alu->port_forward = alu_table[1] & ALU_V_PORT_MAP; + + alu->fid = (alu_table[2] >> ALU_V_FID_S) & ALU_V_FID_M; + + alu->mac[0] = (alu_table[2] >> 8) & 0xFF; + alu->mac[1] = alu_table[2] & 0xFF; + alu->mac[2] = (alu_table[3] >> 24) & 0xFF; + alu->mac[3] = (alu_table[3] >> 16) & 0xFF; + alu->mac[4] = (alu_table[3] >> 8) & 0xFF; + alu->mac[5] = alu_table[3] & 0xFF; +} + +static int ksz_port_fdb_dump(struct dsa_switch *ds, int port, + struct switchdev_obj_port_fdb *fdb, + switchdev_obj_dump_cb_t *cb) +{ + struct ksz_device *dev = ds->priv; + int ret = 0; + u32 data; + u32 alu_table[4]; + struct alu_struct alu; + int timeout; + + mutex_lock(&dev->alu_mutex); + + /* start ALU search */ + ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_START | ALU_SEARCH); + + do { + timeout = 1000; + do { + ksz_read32(dev, REG_SW_ALU_CTRL__4, &data); + if ((data & ALU_VALID) || !(data & ALU_START)) + break; + usleep_range(1, 10); + } while (timeout-- > 0); + + if (!timeout) { + dev_dbg(dev->dev, "Failed to search ALU\n"); + ret = -ETIMEDOUT; + goto exit; + } + + /* read ALU table */ + read_table(ds, alu_table); + + convert_alu(&alu, alu_table); + + if (alu.port_forward & BIT(port)) { + fdb->vid = alu.fid; + if (alu.is_static) + fdb->ndm_state = NUD_NOARP; + else + fdb->ndm_state = NUD_REACHABLE; + ether_addr_copy(fdb->addr, alu.mac); + + ret = cb(&fdb->obj); + if (ret) + goto exit; + } + } while (data & ALU_START); + +exit: + + /* stop ALU search */ + ksz_write32(dev, REG_SW_ALU_CTRL__4, 0); + + mutex_unlock(&dev->alu_mutex); + + return ret; +} + +static int ksz_port_mdb_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb, + struct switchdev_trans *trans) +{ + /* nothing to do */ + return 0; +} + +static void ksz_port_mdb_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb, + struct switchdev_trans *trans) +{ + struct ksz_device *dev = ds->priv; + u32 static_table[4]; + u32 data; + int index; + u32 mac_hi, mac_lo; + + mac_hi = ((mdb->addr[0] << 8) | mdb->addr[1]); + mac_lo = ((mdb->addr[2] << 24) | (mdb->addr[3] << 16)); + mac_lo |= ((mdb->addr[4] << 8) | mdb->addr[5]); + + mutex_lock(&dev->alu_mutex); + + for (index = 0; index < dev->num_statics; index++) { + /* find empty slot first */ + data = (index << ALU_STAT_INDEX_S) | + ALU_STAT_READ | ALU_STAT_START; + ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + + /* wait to be finished */ + if (wait_alu_sta_ready(dev, ALU_STAT_START, 1000) < 0) { + dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); + goto exit; + } + + /* read ALU static table */ + read_table(ds, static_table); + + if (static_table[0] & ALU_V_STATIC_VALID) { + /* check this has same vid & mac address */ + if (((static_table[2] >> ALU_V_FID_S) == (mdb->vid)) && + ((static_table[2] & ALU_V_MAC_ADDR_HI) == mac_hi) && + (static_table[3] == mac_lo)) { + /* found matching one */ + break; + } + } else { + /* found empty one */ + break; + } + } + + /* no available entry */ + if (index == dev->num_statics) + goto exit; + + /* add entry */ + static_table[0] = ALU_V_STATIC_VALID; + static_table[1] |= BIT(port); + if (mdb->vid) + static_table[1] |= ALU_V_USE_FID; + static_table[2] = (mdb->vid << ALU_V_FID_S); + static_table[2] |= mac_hi; + static_table[3] = mac_lo; + + write_table(ds, static_table); + + data = (index << ALU_STAT_INDEX_S) | ALU_STAT_START; + ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + + /* wait to be finished */ + if (wait_alu_sta_ready(dev, ALU_STAT_START, 1000) < 0) + dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); + +exit: + mutex_unlock(&dev->alu_mutex); +} + +static int ksz_port_mdb_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb) +{ + struct ksz_device *dev = ds->priv; + u32 static_table[4]; + u32 data; + int index; + int ret = 0; + u32 mac_hi, mac_lo; + + mac_hi = ((mdb->addr[0] << 8) | mdb->addr[1]); + mac_lo = ((mdb->addr[2] << 24) | (mdb->addr[3] << 16)); + mac_lo |= ((mdb->addr[4] << 8) | mdb->addr[5]); + + mutex_lock(&dev->alu_mutex); + + for (index = 0; index < dev->num_statics; index++) { + /* find empty slot first */ + data = (index << ALU_STAT_INDEX_S) | + ALU_STAT_READ | ALU_STAT_START; + ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + + /* wait to be finished */ + ret = wait_alu_sta_ready(dev, ALU_STAT_START, 1000); + if (ret < 0) { + dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); + goto exit; + } + + /* read ALU static table */ + read_table(ds, static_table); + + if (static_table[0] & ALU_V_STATIC_VALID) { + /* check this has same vid & mac address */ + + if (((static_table[2] >> ALU_V_FID_S) == (mdb->vid)) && + ((static_table[2] & ALU_V_MAC_ADDR_HI) == mac_hi) && + (static_table[3] == mac_lo)) { + /* found matching one */ + break; + } + } + } + + /* no available entry */ + if (index == dev->num_statics) { + ret = -EINVAL; + goto exit; + } + + /* clear port */ + static_table[1] &= ~BIT(port); + + if ((static_table[1] & ALU_V_PORT_MAP) == 0) { + /* delete entry */ + static_table[0] = 0; + static_table[1] = 0; + static_table[2] = 0; + static_table[3] = 0; + } + + write_table(ds, static_table); + + data = (index << ALU_STAT_INDEX_S) | ALU_STAT_START; + ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + + /* wait to be finished */ + ret = wait_alu_sta_ready(dev, ALU_STAT_START, 1000); + if (ret < 0) + dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); + +exit: + mutex_unlock(&dev->alu_mutex); + + return ret; +} + +static int ksz_port_mdb_dump(struct dsa_switch *ds, int port, + struct switchdev_obj_port_mdb *mdb, + switchdev_obj_dump_cb_t *cb) +{ + /* this is not called by switch layer */ + return 0; +} + +static int ksz_port_mirror_add(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror, + bool ingress) +{ + struct ksz_device *dev = ds->priv; + + if (ingress) + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true); + else + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, true); + + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_SNIFFER, false); + + /* configure mirror port */ + ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, + PORT_MIRROR_SNIFFER, true); + + ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false); + + return 0; +} + +static void ksz_port_mirror_del(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror) +{ + struct ksz_device *dev = ds->priv; + u8 data; + + if (mirror->ingress) + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, false); + else + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, false); + + ksz_pread8(dev, port, P_MIRROR_CTRL, &data); + + if (!(data & (PORT_MIRROR_RX | PORT_MIRROR_TX))) + ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, + PORT_MIRROR_SNIFFER, false); +} + +static const struct dsa_switch_ops ksz_switch_ops = { + .get_tag_protocol = ksz_get_tag_protocol, + .setup = ksz_setup, + .phy_read = ksz_phy_read16, + .phy_write = ksz_phy_write16, + .port_enable = ksz_enable_port, + .port_disable = ksz_disable_port, + .get_strings = ksz_get_strings, + .get_ethtool_stats = ksz_get_ethtool_stats, + .get_sset_count = ksz_sset_count, + .port_stp_state_set = ksz_port_stp_state_set, + .port_fast_age = ksz_port_fast_age, + .port_vlan_filtering = ksz_port_vlan_filtering, + .port_vlan_prepare = ksz_port_vlan_prepare, + .port_vlan_add = ksz_port_vlan_add, + .port_vlan_del = ksz_port_vlan_del, + .port_vlan_dump = ksz_port_vlan_dump, + .port_fdb_prepare = ksz_port_fdb_prepare, + .port_fdb_dump = ksz_port_fdb_dump, + .port_fdb_add = ksz_port_fdb_add, + .port_fdb_del = ksz_port_fdb_del, + .port_mdb_prepare = ksz_port_mdb_prepare, + .port_mdb_add = ksz_port_mdb_add, + .port_mdb_del = ksz_port_mdb_del, + .port_mdb_dump = ksz_port_mdb_dump, + .port_mirror_add = ksz_port_mirror_add, + .port_mirror_del = ksz_port_mirror_del, +}; + +struct ksz_chip_data { + u32 chip_id; + const char *dev_name; + int num_vlans; + int num_alus; + int num_statics; + int cpu_ports; + int port_cnt; +}; + +static const struct ksz_chip_data ksz_switch_chips[] = { + { + .chip_id = 0x00947700, + .dev_name = "KSZ9477", + .num_vlans = 4096, + .num_alus = 4096, + .num_statics = 16, + .cpu_ports = 0x7F, /* can be configured as cpu port */ + .port_cnt = 7, /* total physical port count */ + }, +}; + +static int ksz_switch_init(struct ksz_device *dev) +{ + int i; + + mutex_init(&dev->reg_mutex); + mutex_init(&dev->stats_mutex); + mutex_init(&dev->alu_mutex); + mutex_init(&dev->vlan_mutex); + + dev->ds->ops = &ksz_switch_ops; + + for (i = 0; i < ARRAY_SIZE(ksz_switch_chips); i++) { + const struct ksz_chip_data *chip = &ksz_switch_chips[i]; + + if (dev->chip_id == chip->chip_id) { + dev->name = chip->dev_name; + dev->num_vlans = chip->num_vlans; + dev->num_alus = chip->num_alus; + dev->num_statics = chip->num_statics; + dev->port_cnt = chip->port_cnt; + dev->cpu_ports = chip->cpu_ports; + + break; + } + } + + /* no switch found */ + if (!dev->port_cnt) + return -ENODEV; + + return 0; +} + +struct ksz_device *ksz_switch_alloc(struct device *base, + const struct ksz_io_ops *ops, + void *priv) +{ + struct dsa_switch *ds; + struct ksz_device *swdev; + + ds = dsa_switch_alloc(base, DSA_MAX_PORTS); + if (!ds) + return NULL; + + swdev = devm_kzalloc(base, sizeof(*swdev), GFP_KERNEL); + if (!swdev) + return NULL; + + ds->priv = swdev; + swdev->dev = base; + + swdev->ds = ds; + swdev->priv = priv; + swdev->ops = ops; + + return swdev; +} +EXPORT_SYMBOL(ksz_switch_alloc); + +int ksz_switch_detect(struct ksz_device *dev) +{ + u8 data8; + u32 id32; + int ret; + + /* turn off SPI DO Edge select */ + ret = ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8); + if (ret) + return ret; + + data8 &= ~SPI_AUTO_EDGE_DETECTION; + ret = ksz_write8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, data8); + if (ret) + return ret; + + /* read chip id */ + ret = ksz_read32(dev, REG_CHIP_ID0__1, &id32); + if (ret) + return ret; + + dev->chip_id = id32; + + return 0; +} +EXPORT_SYMBOL(ksz_switch_detect); + +int ksz_switch_register(struct ksz_device *dev) +{ + int ret; + + if (dev->pdata) + dev->chip_id = dev->pdata->chip_id; + + if (ksz_switch_detect(dev)) + return -EINVAL; + + ret = ksz_switch_init(dev); + if (ret) + return ret; + + return dsa_register_switch(dev->ds); +} +EXPORT_SYMBOL(ksz_switch_register); + +void ksz_switch_remove(struct ksz_device *dev) +{ + dsa_unregister_switch(dev->ds); +} +EXPORT_SYMBOL(ksz_switch_remove); + +MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>"); +MODULE_DESCRIPTION("Microchip KSZ Series Switch DSA Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/dsa/microchip/ksz_priv.h b/drivers/net/dsa/microchip/ksz_priv.h new file mode 100644 index 000000000000..2a98dbd51456 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz_priv.h @@ -0,0 +1,210 @@ +/* + * Microchip KSZ series switch common definitions + * + * Copyright (C) 2017 + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __KSZ_PRIV_H +#define __KSZ_PRIV_H + +#include <linux/kernel.h> +#include <linux/mutex.h> +#include <linux/phy.h> +#include <linux/etherdevice.h> +#include <net/dsa.h> + +#include "ksz_9477_reg.h" + +struct ksz_io_ops; + +struct vlan_table { + u32 table[3]; +}; + +struct ksz_device { + struct dsa_switch *ds; + struct ksz_platform_data *pdata; + const char *name; + + struct mutex reg_mutex; /* register access */ + struct mutex stats_mutex; /* status access */ + struct mutex alu_mutex; /* ALU access */ + struct mutex vlan_mutex; /* vlan access */ + const struct ksz_io_ops *ops; + + struct device *dev; + + void *priv; + + /* chip specific data */ + u32 chip_id; + int num_vlans; + int num_alus; + int num_statics; + int cpu_port; /* port connected to CPU */ + int cpu_ports; /* port bitmap can be cpu port */ + int port_cnt; + + struct vlan_table *vlan_cache; + + u64 mib_value[TOTAL_SWITCH_COUNTER_NUM]; +}; + +struct ksz_io_ops { + int (*read8)(struct ksz_device *dev, u32 reg, u8 *value); + int (*read16)(struct ksz_device *dev, u32 reg, u16 *value); + int (*read24)(struct ksz_device *dev, u32 reg, u32 *value); + int (*read32)(struct ksz_device *dev, u32 reg, u32 *value); + int (*write8)(struct ksz_device *dev, u32 reg, u8 value); + int (*write16)(struct ksz_device *dev, u32 reg, u16 value); + int (*write24)(struct ksz_device *dev, u32 reg, u32 value); + int (*write32)(struct ksz_device *dev, u32 reg, u32 value); + int (*phy_read16)(struct ksz_device *dev, int addr, int reg, + u16 *value); + int (*phy_write16)(struct ksz_device *dev, int addr, int reg, + u16 value); +}; + +struct ksz_device *ksz_switch_alloc(struct device *base, + const struct ksz_io_ops *ops, void *priv); +int ksz_switch_detect(struct ksz_device *dev); +int ksz_switch_register(struct ksz_device *dev); +void ksz_switch_remove(struct ksz_device *dev); + +static inline int ksz_read8(struct ksz_device *dev, u32 reg, u8 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read8(dev, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int ksz_read16(struct ksz_device *dev, u32 reg, u16 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read16(dev, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int ksz_read24(struct ksz_device *dev, u32 reg, u32 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read24(dev, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int ksz_read32(struct ksz_device *dev, u32 reg, u32 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read32(dev, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int ksz_write8(struct ksz_device *dev, u32 reg, u8 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write8(dev, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int ksz_write16(struct ksz_device *dev, u32 reg, u16 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write16(dev, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int ksz_write24(struct ksz_device *dev, u32 reg, u32 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write24(dev, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write32(dev, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline void ksz_pread8(struct ksz_device *dev, int port, int offset, + u8 *data) +{ + ksz_read8(dev, PORT_CTRL_ADDR(port, offset), data); +} + +static inline void ksz_pread16(struct ksz_device *dev, int port, int offset, + u16 *data) +{ + ksz_read16(dev, PORT_CTRL_ADDR(port, offset), data); +} + +static inline void ksz_pread32(struct ksz_device *dev, int port, int offset, + u32 *data) +{ + ksz_read32(dev, PORT_CTRL_ADDR(port, offset), data); +} + +static inline void ksz_pwrite8(struct ksz_device *dev, int port, int offset, + u8 data) +{ + ksz_write8(dev, PORT_CTRL_ADDR(port, offset), data); +} + +static inline void ksz_pwrite16(struct ksz_device *dev, int port, int offset, + u16 data) +{ + ksz_write16(dev, PORT_CTRL_ADDR(port, offset), data); +} + +static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset, + u32 data) +{ + ksz_write32(dev, PORT_CTRL_ADDR(port, offset), data); +} + +#endif diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c new file mode 100644 index 000000000000..c51946983bed --- /dev/null +++ b/drivers/net/dsa/microchip/ksz_spi.c @@ -0,0 +1,216 @@ +/* + * Microchip KSZ series register access through SPI + * + * Copyright (C) 2017 + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <asm/unaligned.h> + +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/spi/spi.h> + +#include "ksz_priv.h" + +/* SPI frame opcodes */ +#define KS_SPIOP_RD 3 +#define KS_SPIOP_WR 2 + +#define SPI_ADDR_SHIFT 24 +#define SPI_ADDR_MASK (BIT(SPI_ADDR_SHIFT) - 1) +#define SPI_TURNAROUND_SHIFT 5 + +static int ksz_spi_read_reg(struct spi_device *spi, u32 reg, u8 *val, + unsigned int len) +{ + u32 txbuf; + int ret; + + txbuf = reg & SPI_ADDR_MASK; + txbuf |= KS_SPIOP_RD << SPI_ADDR_SHIFT; + txbuf <<= SPI_TURNAROUND_SHIFT; + txbuf = cpu_to_be32(txbuf); + + ret = spi_write_then_read(spi, &txbuf, 4, val, len); + return ret; +} + +static int ksz_spi_read(struct ksz_device *dev, u32 reg, u8 *data, + unsigned int len) +{ + struct spi_device *spi = dev->priv; + + return ksz_spi_read_reg(spi, reg, data, len); +} + +static int ksz_spi_read8(struct ksz_device *dev, u32 reg, u8 *val) +{ + return ksz_spi_read(dev, reg, val, 1); +} + +static int ksz_spi_read16(struct ksz_device *dev, u32 reg, u16 *val) +{ + int ret = ksz_spi_read(dev, reg, (u8 *)val, 2); + + if (!ret) + *val = be16_to_cpu(*val); + + return ret; +} + +static int ksz_spi_read24(struct ksz_device *dev, u32 reg, u32 *val) +{ + int ret; + + *val = 0; + ret = ksz_spi_read(dev, reg, (u8 *)val, 3); + if (!ret) { + *val = be32_to_cpu(*val); + /* convert to 24bit */ + *val >>= 8; + } + + return ret; +} + +static int ksz_spi_read32(struct ksz_device *dev, u32 reg, u32 *val) +{ + int ret = ksz_spi_read(dev, reg, (u8 *)val, 4); + + if (!ret) + *val = be32_to_cpu(*val); + + return ret; +} + +static int ksz_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val, + unsigned int len) +{ + u32 txbuf; + u8 data[12]; + int i; + + txbuf = reg & SPI_ADDR_MASK; + txbuf |= (KS_SPIOP_WR << SPI_ADDR_SHIFT); + txbuf <<= SPI_TURNAROUND_SHIFT; + txbuf = cpu_to_be32(txbuf); + + data[0] = txbuf & 0xFF; + data[1] = (txbuf & 0xFF00) >> 8; + data[2] = (txbuf & 0xFF0000) >> 16; + data[3] = (txbuf & 0xFF000000) >> 24; + for (i = 0; i < len; i++) + data[i + 4] = val[i]; + + return spi_write(spi, &data, 4 + len); +} + +static int ksz_spi_write8(struct ksz_device *dev, u32 reg, u8 value) +{ + struct spi_device *spi = dev->priv; + + return ksz_spi_write_reg(spi, reg, &value, 1); +} + +static int ksz_spi_write16(struct ksz_device *dev, u32 reg, u16 value) +{ + struct spi_device *spi = dev->priv; + + value = cpu_to_be16(value); + return ksz_spi_write_reg(spi, reg, (u8 *)&value, 2); +} + +static int ksz_spi_write24(struct ksz_device *dev, u32 reg, u32 value) +{ + struct spi_device *spi = dev->priv; + + /* make it to big endian 24bit from MSB */ + value <<= 8; + value = cpu_to_be32(value); + return ksz_spi_write_reg(spi, reg, (u8 *)&value, 3); +} + +static int ksz_spi_write32(struct ksz_device *dev, u32 reg, u32 value) +{ + struct spi_device *spi = dev->priv; + + value = cpu_to_be32(value); + return ksz_spi_write_reg(spi, reg, (u8 *)&value, 4); +} + +static const struct ksz_io_ops ksz_spi_ops = { + .read8 = ksz_spi_read8, + .read16 = ksz_spi_read16, + .read24 = ksz_spi_read24, + .read32 = ksz_spi_read32, + .write8 = ksz_spi_write8, + .write16 = ksz_spi_write16, + .write24 = ksz_spi_write24, + .write32 = ksz_spi_write32, +}; + +static int ksz_spi_probe(struct spi_device *spi) +{ + struct ksz_device *dev; + int ret; + + dev = ksz_switch_alloc(&spi->dev, &ksz_spi_ops, spi); + if (!dev) + return -ENOMEM; + + if (spi->dev.platform_data) + dev->pdata = spi->dev.platform_data; + + ret = ksz_switch_register(dev); + if (ret) + return ret; + + spi_set_drvdata(spi, dev); + + return 0; +} + +static int ksz_spi_remove(struct spi_device *spi) +{ + struct ksz_device *dev = spi_get_drvdata(spi); + + if (dev) + ksz_switch_remove(dev); + + return 0; +} + +static const struct of_device_id ksz_dt_ids[] = { + { .compatible = "microchip,ksz9477" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ksz_dt_ids); + +static struct spi_driver ksz_spi_driver = { + .driver = { + .name = "ksz9477-switch", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ksz_dt_ids), + }, + .probe = ksz_spi_probe, + .remove = ksz_spi_remove, +}; + +module_spi_driver(ksz_spi_driver); + +MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>"); +MODULE_DESCRIPTION("Microchip KSZ Series Switch SPI access Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index b070c167e70f..25e00d5e0eec 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -28,7 +28,6 @@ #include <linux/reset.h> #include <linux/gpio/consumer.h> #include <net/dsa.h> -#include <net/switchdev.h> #include "mt7530.h" @@ -854,7 +853,7 @@ mt7530_port_fdb_del(struct dsa_switch *ds, int port, static int mt7530_port_fdb_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_fdb *fdb, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct mt7530_priv *priv = ds->priv; struct mt7530_fdb _fdb = { 0 }; @@ -1081,7 +1080,7 @@ mt7530_probe(struct mdio_device *mdiodev) mutex_init(&priv->reg_mutex); dev_set_drvdata(&mdiodev->dev, priv); - return dsa_register_switch(priv->ds, &mdiodev->dev); + return dsa_register_switch(priv->ds); } static void diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c index 5934b7a4c448..dce7fa57eb55 100644 --- a/drivers/net/dsa/mv88e6060.c +++ b/drivers/net/dsa/mv88e6060.c @@ -176,7 +176,7 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p) ((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) | (dsa_is_cpu_port(ds, p) ? ds->enabled_port_mask : - BIT(ds->dst->cpu_port))); + BIT(ds->dst->cpu_dp->index))); /* Port Association Vector: when learning source addresses * of packets, add the address to the address database using diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile index 6edd869c8d6f..5cd5551461e3 100644 --- a/drivers/net/dsa/mv88e6xxx/Makefile +++ b/drivers/net/dsa/mv88e6xxx/Makefile @@ -4,4 +4,6 @@ mv88e6xxx-objs += global1.o mv88e6xxx-objs += global1_atu.o mv88e6xxx-objs += global1_vtu.o mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2.o +mv88e6xxx-objs += phy.o mv88e6xxx-objs += port.o +mv88e6xxx-objs += serdes.o diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index d034d8cd7d22..117f275e3fb6 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -32,12 +32,13 @@ #include <linux/gpio/consumer.h> #include <linux/phy.h> #include <net/dsa.h> -#include <net/switchdev.h> -#include "mv88e6xxx.h" +#include "chip.h" #include "global1.h" #include "global2.h" +#include "phy.h" #include "port.h" +#include "serdes.h" static void assert_reg_lock(struct mv88e6xxx_chip *chip) { @@ -222,21 +223,7 @@ int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val) return 0; } -static int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, - struct mii_bus *bus, - int addr, int reg, u16 *val) -{ - return mv88e6xxx_read(chip, addr, reg, val); -} - -static int mv88e6165_phy_write(struct mv88e6xxx_chip *chip, - struct mii_bus *bus, - int addr, int reg, u16 val) -{ - return mv88e6xxx_write(chip, addr, reg, val); -} - -static struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) +struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) { struct mv88e6xxx_mdio_bus *mdio_bus; @@ -248,106 +235,6 @@ static struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) return mdio_bus->bus; } -static int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy, - int reg, u16 *val) -{ - int addr = phy; /* PHY devices addresses start at 0x0 */ - struct mii_bus *bus; - - bus = mv88e6xxx_default_mdio_bus(chip); - if (!bus) - return -EOPNOTSUPP; - - if (!chip->info->ops->phy_read) - return -EOPNOTSUPP; - - return chip->info->ops->phy_read(chip, bus, addr, reg, val); -} - -static int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy, - int reg, u16 val) -{ - int addr = phy; /* PHY devices addresses start at 0x0 */ - struct mii_bus *bus; - - bus = mv88e6xxx_default_mdio_bus(chip); - if (!bus) - return -EOPNOTSUPP; - - if (!chip->info->ops->phy_write) - return -EOPNOTSUPP; - - return chip->info->ops->phy_write(chip, bus, addr, reg, val); -} - -static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page) -{ - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_PHY_PAGE)) - return -EOPNOTSUPP; - - return mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page); -} - -static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy) -{ - int err; - - /* Restore PHY page Copper 0x0 for access via the registered MDIO bus */ - err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, PHY_PAGE_COPPER); - if (unlikely(err)) { - dev_err(chip->dev, "failed to restore PHY %d page Copper (%d)\n", - phy, err); - } -} - -static int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy, - u8 page, int reg, u16 *val) -{ - int err; - - /* There is no paging for registers 22 */ - if (reg == PHY_PAGE) - return -EINVAL; - - err = mv88e6xxx_phy_page_get(chip, phy, page); - if (!err) { - err = mv88e6xxx_phy_read(chip, phy, reg, val); - mv88e6xxx_phy_page_put(chip, phy); - } - - return err; -} - -static int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy, - u8 page, int reg, u16 val) -{ - int err; - - /* There is no paging for registers 22 */ - if (reg == PHY_PAGE) - return -EINVAL; - - err = mv88e6xxx_phy_page_get(chip, phy, page); - if (!err) { - err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page); - mv88e6xxx_phy_page_put(chip, phy); - } - - return err; -} - -static int mv88e6xxx_serdes_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) -{ - return mv88e6xxx_phy_page_read(chip, ADDR_SERDES, SERDES_PAGE_FIBER, - reg, val); -} - -static int mv88e6xxx_serdes_write(struct mv88e6xxx_chip *chip, int reg, u16 val) -{ - return mv88e6xxx_phy_page_write(chip, ADDR_SERDES, SERDES_PAGE_FIBER, - reg, val); -} - static void mv88e6xxx_g1_irq_mask(struct irq_data *d) { struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); @@ -561,122 +448,6 @@ int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update) return mv88e6xxx_write(chip, addr, reg, val); } -static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip) -{ - if (!chip->info->ops->ppu_disable) - return 0; - - return chip->info->ops->ppu_disable(chip); -} - -static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip) -{ - if (!chip->info->ops->ppu_enable) - return 0; - - return chip->info->ops->ppu_enable(chip); -} - -static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly) -{ - struct mv88e6xxx_chip *chip; - - chip = container_of(ugly, struct mv88e6xxx_chip, ppu_work); - - mutex_lock(&chip->reg_lock); - - if (mutex_trylock(&chip->ppu_mutex)) { - if (mv88e6xxx_ppu_enable(chip) == 0) - chip->ppu_disabled = 0; - mutex_unlock(&chip->ppu_mutex); - } - - mutex_unlock(&chip->reg_lock); -} - -static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps) -{ - struct mv88e6xxx_chip *chip = (void *)_ps; - - schedule_work(&chip->ppu_work); -} - -static int mv88e6xxx_ppu_access_get(struct mv88e6xxx_chip *chip) -{ - int ret; - - mutex_lock(&chip->ppu_mutex); - - /* If the PHY polling unit is enabled, disable it so that - * we can access the PHY registers. If it was already - * disabled, cancel the timer that is going to re-enable - * it. - */ - if (!chip->ppu_disabled) { - ret = mv88e6xxx_ppu_disable(chip); - if (ret < 0) { - mutex_unlock(&chip->ppu_mutex); - return ret; - } - chip->ppu_disabled = 1; - } else { - del_timer(&chip->ppu_timer); - ret = 0; - } - - return ret; -} - -static void mv88e6xxx_ppu_access_put(struct mv88e6xxx_chip *chip) -{ - /* Schedule a timer to re-enable the PHY polling unit. */ - mod_timer(&chip->ppu_timer, jiffies + msecs_to_jiffies(10)); - mutex_unlock(&chip->ppu_mutex); -} - -static void mv88e6xxx_ppu_state_init(struct mv88e6xxx_chip *chip) -{ - mutex_init(&chip->ppu_mutex); - INIT_WORK(&chip->ppu_work, mv88e6xxx_ppu_reenable_work); - setup_timer(&chip->ppu_timer, mv88e6xxx_ppu_reenable_timer, - (unsigned long)chip); -} - -static void mv88e6xxx_ppu_state_destroy(struct mv88e6xxx_chip *chip) -{ - del_timer_sync(&chip->ppu_timer); -} - -static int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, - struct mii_bus *bus, - int addr, int reg, u16 *val) -{ - int err; - - err = mv88e6xxx_ppu_access_get(chip); - if (!err) { - err = mv88e6xxx_read(chip, addr, reg, val); - mv88e6xxx_ppu_access_put(chip); - } - - return err; -} - -static int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, - struct mii_bus *bus, - int addr, int reg, u16 val) -{ - int err; - - err = mv88e6xxx_ppu_access_get(chip); - if (!err) { - err = mv88e6xxx_write(chip, addr, reg, val); - mv88e6xxx_ppu_access_put(chip); - } - - return err; -} - static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link, int speed, int duplex, phy_interface_t mode) @@ -1269,7 +1040,7 @@ static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_vlan *vlan, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct mv88e6xxx_chip *chip = ds->priv; struct mv88e6xxx_vtu_entry next = { @@ -1700,7 +1471,7 @@ static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, u16 fid, u16 vid, int port, struct switchdev_obj *obj, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct mv88e6xxx_atu_entry addr; int err; @@ -1755,7 +1526,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, struct switchdev_obj *obj, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct mv88e6xxx_vtu_entry vlan = { .vid = chip->info->max_vid, @@ -1792,7 +1563,7 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_fdb *fdb, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct mv88e6xxx_chip *chip = ds->priv; int err; @@ -1951,24 +1722,6 @@ static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip) return mv88e6xxx_software_reset(chip); } -static int mv88e6xxx_serdes_power_on(struct mv88e6xxx_chip *chip) -{ - u16 val; - int err; - - /* Clear Power Down bit */ - err = mv88e6xxx_serdes_read(chip, MII_BMCR, &val); - if (err) - return err; - - if (val & BMCR_PDOWN) { - val &= ~BMCR_PDOWN; - err = mv88e6xxx_serdes_write(chip, MII_BMCR, val); - } - - return err; -} - static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, enum mv88e6xxx_frame_mode frame, u16 egress, u16 etype) @@ -2050,6 +1803,15 @@ static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) return 0; } +static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, + bool on) +{ + if (chip->info->ops->serdes_power) + return chip->info->ops->serdes_power(chip, port, on); + + return 0; +} + static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) { struct dsa_switch *ds = chip->ds; @@ -2100,21 +1862,14 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) if (err) return err; - /* If this port is connected to a SerDes, make sure the SerDes is not - * powered down. + /* Enable the SERDES interface for DSA and CPU ports. Normal + * ports SERDES are enabled when the port is enabled, thus + * saving a bit of power. */ - if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_SERDES)) { - err = mv88e6xxx_port_read(chip, port, PORT_STATUS, ®); + if ((dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) { + err = mv88e6xxx_serdes_power(chip, port, true); if (err) return err; - reg &= PORT_STATUS_CMODE_MASK; - if ((reg == PORT_STATUS_CMODE_100BASE_X) || - (reg == PORT_STATUS_CMODE_1000BASE_X) || - (reg == PORT_STATUS_CMODE_SGMII)) { - err = mv88e6xxx_serdes_power_on(chip); - if (err < 0) - return err; - } } /* Port Control 2: don't force a good FCS, set the maximum frame size to @@ -2217,6 +1972,30 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) return mv88e6xxx_port_write(chip, port, PORT_DEFAULT_VLAN, 0x0000); } +static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phydev) +{ + struct mv88e6xxx_chip *chip = ds->priv; + int err; + + mutex_lock(&chip->reg_lock); + err = mv88e6xxx_serdes_power(chip, port, true); + mutex_unlock(&chip->reg_lock); + + return err; +} + +static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port, + struct phy_device *phydev) +{ + struct mv88e6xxx_chip *chip = ds->priv; + + mutex_lock(&chip->reg_lock); + if (mv88e6xxx_serdes_power(chip, port, false)) + dev_err(chip->dev, "failed to power off SERDES\n"); + mutex_unlock(&chip->reg_lock); +} + static int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) { int err; @@ -2255,13 +2034,6 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) u32 upstream_port = dsa_upstream_port(ds); int err; - /* Enable the PHY Polling Unit if present, don't discard any packets, - * and mask all interrupt sources. - */ - err = mv88e6xxx_ppu_enable(chip); - if (err) - return err; - if (chip->info->ops->g1_set_cpu_port) { err = chip->info->ops->g1_set_cpu_port(chip, upstream_port); if (err) @@ -2361,6 +2133,10 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) goto unlock; } + err = mv88e6xxx_phy_setup(chip); + if (err) + goto unlock; + err = mv88e6xxx_vtu_setup(chip); if (err) goto unlock; @@ -2595,8 +2371,8 @@ static int mv88e6xxx_set_eeprom(struct dsa_switch *ds, static const struct mv88e6xxx_ops mv88e6085_ops = { /* MV88E6XXX_FAMILY_6097 */ .set_switch_mac = mv88e6xxx_g1_set_switch_mac, - .phy_read = mv88e6xxx_phy_ppu_read, - .phy_write = mv88e6xxx_phy_ppu_write, + .phy_read = mv88e6185_phy_ppu_read, + .phy_write = mv88e6185_phy_ppu_write, .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, @@ -2626,8 +2402,8 @@ static const struct mv88e6xxx_ops mv88e6085_ops = { static const struct mv88e6xxx_ops mv88e6095_ops = { /* MV88E6XXX_FAMILY_6095 */ .set_switch_mac = mv88e6xxx_g1_set_switch_mac, - .phy_read = mv88e6xxx_phy_ppu_read, - .phy_write = mv88e6xxx_phy_ppu_write, + .phy_read = mv88e6185_phy_ppu_read, + .phy_write = mv88e6185_phy_ppu_write, .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, @@ -2679,8 +2455,8 @@ static const struct mv88e6xxx_ops mv88e6097_ops = { static const struct mv88e6xxx_ops mv88e6123_ops = { /* MV88E6XXX_FAMILY_6165 */ .set_switch_mac = mv88e6xxx_g2_set_switch_mac, - .phy_read = mv88e6165_phy_read, - .phy_write = mv88e6165_phy_write, + .phy_read = mv88e6xxx_g2_smi_phy_read, + .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, @@ -2688,7 +2464,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = { .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, - .stats_snapshot = mv88e6xxx_g1_stats_snapshot, + .stats_snapshot = mv88e6320_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, @@ -2704,8 +2480,8 @@ static const struct mv88e6xxx_ops mv88e6123_ops = { static const struct mv88e6xxx_ops mv88e6131_ops = { /* MV88E6XXX_FAMILY_6185 */ .set_switch_mac = mv88e6xxx_g1_set_switch_mac, - .phy_read = mv88e6xxx_phy_ppu_read, - .phy_write = mv88e6xxx_phy_ppu_write, + .phy_read = mv88e6185_phy_ppu_read, + .phy_write = mv88e6185_phy_ppu_write, .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, @@ -2768,8 +2544,8 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { static const struct mv88e6xxx_ops mv88e6161_ops = { /* MV88E6XXX_FAMILY_6165 */ .set_switch_mac = mv88e6xxx_g2_set_switch_mac, - .phy_read = mv88e6165_phy_read, - .phy_write = mv88e6165_phy_write, + .phy_read = mv88e6xxx_g2_smi_phy_read, + .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, @@ -2782,7 +2558,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { .port_pause_config = mv88e6097_port_pause_config, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, - .stats_snapshot = mv88e6xxx_g1_stats_snapshot, + .stats_snapshot = mv88e6320_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, @@ -2880,6 +2656,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, + .serdes_power = mv88e6352_serdes_power, }; static const struct mv88e6xxx_ops mv88e6175_ops = { @@ -2944,13 +2721,14 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, + .serdes_power = mv88e6352_serdes_power, }; static const struct mv88e6xxx_ops mv88e6185_ops = { /* MV88E6XXX_FAMILY_6185 */ .set_switch_mac = mv88e6xxx_g1_set_switch_mac, - .phy_read = mv88e6xxx_phy_ppu_read, - .phy_write = mv88e6xxx_phy_ppu_write, + .phy_read = mv88e6185_phy_ppu_read, + .phy_write = mv88e6185_phy_ppu_write, .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, @@ -3003,6 +2781,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .serdes_power = mv88e6390_serdes_power, }; static const struct mv88e6xxx_ops mv88e6190x_ops = { @@ -3035,6 +2814,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .serdes_power = mv88e6390_serdes_power, }; static const struct mv88e6xxx_ops mv88e6191_ops = { @@ -3067,6 +2847,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .serdes_power = mv88e6390_serdes_power, }; static const struct mv88e6xxx_ops mv88e6240_ops = { @@ -3100,6 +2881,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, + .serdes_power = mv88e6352_serdes_power, }; static const struct mv88e6xxx_ops mv88e6290_ops = { @@ -3133,6 +2915,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .serdes_power = mv88e6390_serdes_power, }; static const struct mv88e6xxx_ops mv88e6320_ops = { @@ -3322,6 +3105,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, + .serdes_power = mv88e6352_serdes_power, }; static const struct mv88e6xxx_ops mv88e6390_ops = { @@ -3357,6 +3141,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .serdes_power = mv88e6390_serdes_power, }; static const struct mv88e6xxx_ops mv88e6390x_ops = { @@ -3391,6 +3176,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .serdes_power = mv88e6390_serdes_power, }; static const struct mv88e6xxx_info mv88e6xxx_table[] = { @@ -3915,18 +3701,6 @@ static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) return chip; } -static void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip) -{ - if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable) - mv88e6xxx_ppu_state_init(chip); -} - -static void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip) -{ - if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable) - mv88e6xxx_ppu_state_destroy(chip); -} - static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip, struct mii_bus *bus, int sw_addr) { @@ -4038,7 +3812,7 @@ static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, static int mv88e6xxx_port_mdb_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_mdb *mdb, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct mv88e6xxx_chip *chip = ds->priv; int err; @@ -4059,6 +3833,8 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .get_strings = mv88e6xxx_get_strings, .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, .get_sset_count = mv88e6xxx_get_sset_count, + .port_enable = mv88e6xxx_port_enable, + .port_disable = mv88e6xxx_port_disable, .set_eee = mv88e6xxx_set_eee, .get_eee = mv88e6xxx_get_eee, .get_eeprom_len = mv88e6xxx_get_eeprom_len, @@ -4108,7 +3884,7 @@ static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) dev_set_drvdata(dev, ds); - return dsa_register_switch(ds, dev); + return dsa_register_switch(ds); } static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip) diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h new file mode 100644 index 000000000000..98c24af977fd --- /dev/null +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -0,0 +1,522 @@ +/* + * Marvell 88E6xxx Ethernet switch single-chip definition + * + * Copyright (c) 2008 Marvell Semiconductor + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _MV88E6XXX_CHIP_H +#define _MV88E6XXX_CHIP_H + +#include <linux/if_vlan.h> +#include <linux/irq.h> +#include <linux/gpio/consumer.h> +#include <linux/phy.h> +#include <net/dsa.h> + +#ifndef UINT64_MAX +#define UINT64_MAX (u64)(~((u64)0)) +#endif + +#define SMI_CMD 0x00 +#define SMI_CMD_BUSY BIT(15) +#define SMI_CMD_CLAUSE_22 BIT(12) +#define SMI_CMD_OP_22_WRITE ((1 << 10) | SMI_CMD_BUSY | SMI_CMD_CLAUSE_22) +#define SMI_CMD_OP_22_READ ((2 << 10) | SMI_CMD_BUSY | SMI_CMD_CLAUSE_22) +#define SMI_CMD_OP_45_WRITE_ADDR ((0 << 10) | SMI_CMD_BUSY) +#define SMI_CMD_OP_45_WRITE_DATA ((1 << 10) | SMI_CMD_BUSY) +#define SMI_CMD_OP_45_READ_DATA ((2 << 10) | SMI_CMD_BUSY) +#define SMI_CMD_OP_45_READ_DATA_INC ((3 << 10) | SMI_CMD_BUSY) +#define SMI_DATA 0x01 + +#define MV88E6XXX_N_FID 4096 + +/* PVT limits for 4-bit port and 5-bit switch */ +#define MV88E6XXX_MAX_PVT_SWITCHES 32 +#define MV88E6XXX_MAX_PVT_PORTS 16 + +enum mv88e6xxx_frame_mode { + MV88E6XXX_FRAME_MODE_NORMAL, + MV88E6XXX_FRAME_MODE_DSA, + MV88E6XXX_FRAME_MODE_PROVIDER, + MV88E6XXX_FRAME_MODE_ETHERTYPE, +}; + +/* List of supported models */ +enum mv88e6xxx_model { + MV88E6085, + MV88E6095, + MV88E6097, + MV88E6123, + MV88E6131, + MV88E6141, + MV88E6161, + MV88E6165, + MV88E6171, + MV88E6172, + MV88E6175, + MV88E6176, + MV88E6185, + MV88E6190, + MV88E6190X, + MV88E6191, + MV88E6240, + MV88E6290, + MV88E6320, + MV88E6321, + MV88E6341, + MV88E6350, + MV88E6351, + MV88E6352, + MV88E6390, + MV88E6390X, +}; + +enum mv88e6xxx_family { + MV88E6XXX_FAMILY_NONE, + MV88E6XXX_FAMILY_6065, /* 6031 6035 6061 6065 */ + MV88E6XXX_FAMILY_6095, /* 6092 6095 */ + MV88E6XXX_FAMILY_6097, /* 6046 6085 6096 6097 */ + MV88E6XXX_FAMILY_6165, /* 6123 6161 6165 */ + MV88E6XXX_FAMILY_6185, /* 6108 6121 6122 6131 6152 6155 6182 6185 */ + MV88E6XXX_FAMILY_6320, /* 6320 6321 */ + MV88E6XXX_FAMILY_6341, /* 6141 6341 */ + MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */ + MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */ + MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */ +}; + +enum mv88e6xxx_cap { + /* Energy Efficient Ethernet. + */ + MV88E6XXX_CAP_EEE, + + /* Multi-chip Addressing Mode. + * Some chips respond to only 2 registers of its own SMI device address + * when it is non-zero, and use indirect access to internal registers. + */ + MV88E6XXX_CAP_SMI_CMD, /* (0x00) SMI Command */ + MV88E6XXX_CAP_SMI_DATA, /* (0x01) SMI Data */ + + /* Switch Global (1) Registers. + */ + MV88E6XXX_CAP_G1_ATU_FID, /* (0x01) ATU FID Register */ + MV88E6XXX_CAP_G1_VTU_FID, /* (0x02) VTU FID Register */ + + /* Switch Global 2 Registers. + * The device contains a second set of global 16-bit registers. + */ + MV88E6XXX_CAP_GLOBAL2, + MV88E6XXX_CAP_G2_INT, /* (0x00) Interrupt Status */ + MV88E6XXX_CAP_G2_MGMT_EN_2X, /* (0x02) MGMT Enable Register 2x */ + MV88E6XXX_CAP_G2_MGMT_EN_0X, /* (0x03) MGMT Enable Register 0x */ + MV88E6XXX_CAP_G2_IRL_CMD, /* (0x09) Ingress Rate Command */ + MV88E6XXX_CAP_G2_IRL_DATA, /* (0x0a) Ingress Rate Data */ + MV88E6XXX_CAP_G2_POT, /* (0x0f) Priority Override Table */ + + /* Per VLAN Spanning Tree Unit (STU). + * The Port State database, if present, is accessed through VTU + * operations and dedicated SID registers. See GLOBAL_VTU_SID. + */ + MV88E6XXX_CAP_STU, + + /* VLAN Table Unit. + * The VTU is used to program 802.1Q VLANs. See GLOBAL_VTU_OP. + */ + MV88E6XXX_CAP_VTU, +}; + +/* Bitmask of capabilities */ +#define MV88E6XXX_FLAG_EEE BIT_ULL(MV88E6XXX_CAP_EEE) + +#define MV88E6XXX_FLAG_SMI_CMD BIT_ULL(MV88E6XXX_CAP_SMI_CMD) +#define MV88E6XXX_FLAG_SMI_DATA BIT_ULL(MV88E6XXX_CAP_SMI_DATA) + +#define MV88E6XXX_FLAG_G1_VTU_FID BIT_ULL(MV88E6XXX_CAP_G1_VTU_FID) + +#define MV88E6XXX_FLAG_GLOBAL2 BIT_ULL(MV88E6XXX_CAP_GLOBAL2) +#define MV88E6XXX_FLAG_G2_INT BIT_ULL(MV88E6XXX_CAP_G2_INT) +#define MV88E6XXX_FLAG_G2_MGMT_EN_2X BIT_ULL(MV88E6XXX_CAP_G2_MGMT_EN_2X) +#define MV88E6XXX_FLAG_G2_MGMT_EN_0X BIT_ULL(MV88E6XXX_CAP_G2_MGMT_EN_0X) +#define MV88E6XXX_FLAG_G2_IRL_CMD BIT_ULL(MV88E6XXX_CAP_G2_IRL_CMD) +#define MV88E6XXX_FLAG_G2_IRL_DATA BIT_ULL(MV88E6XXX_CAP_G2_IRL_DATA) +#define MV88E6XXX_FLAG_G2_POT BIT_ULL(MV88E6XXX_CAP_G2_POT) + +/* Ingress Rate Limit unit */ +#define MV88E6XXX_FLAGS_IRL \ + (MV88E6XXX_FLAG_G2_IRL_CMD | \ + MV88E6XXX_FLAG_G2_IRL_DATA) + +/* Multi-chip Addressing Mode */ +#define MV88E6XXX_FLAGS_MULTI_CHIP \ + (MV88E6XXX_FLAG_SMI_CMD | \ + MV88E6XXX_FLAG_SMI_DATA) + +#define MV88E6XXX_FLAGS_FAMILY_6095 \ + (MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6097 \ + (MV88E6XXX_FLAG_G1_VTU_FID | \ + MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_INT | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_POT | \ + MV88E6XXX_FLAGS_IRL | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6165 \ + (MV88E6XXX_FLAG_G1_VTU_FID | \ + MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_INT | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_POT | \ + MV88E6XXX_FLAGS_IRL | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6185 \ + (MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_INT | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6320 \ + (MV88E6XXX_FLAG_EEE | \ + MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_POT | \ + MV88E6XXX_FLAGS_IRL | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6341 \ + (MV88E6XXX_FLAG_EEE | \ + MV88E6XXX_FLAG_G1_VTU_FID | \ + MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_INT | \ + MV88E6XXX_FLAG_G2_POT | \ + MV88E6XXX_FLAGS_IRL | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6351 \ + (MV88E6XXX_FLAG_G1_VTU_FID | \ + MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_INT | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_POT | \ + MV88E6XXX_FLAGS_IRL | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6352 \ + (MV88E6XXX_FLAG_EEE | \ + MV88E6XXX_FLAG_G1_VTU_FID | \ + MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_INT | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_POT | \ + MV88E6XXX_FLAGS_IRL | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6390 \ + (MV88E6XXX_FLAG_EEE | \ + MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_INT | \ + MV88E6XXX_FLAGS_IRL | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +struct mv88e6xxx_ops; + +struct mv88e6xxx_info { + enum mv88e6xxx_family family; + u16 prod_num; + const char *name; + unsigned int num_databases; + unsigned int num_ports; + unsigned int max_vid; + unsigned int port_base_addr; + unsigned int global1_addr; + unsigned int age_time_coeff; + unsigned int g1_irqs; + bool pvt; + enum dsa_tag_protocol tag_protocol; + unsigned long long flags; + + /* Mask for FromPort and ToPort value of PortVec used in ATU Move + * operation. 0 means that the ATU Move operation is not supported. + */ + u8 atu_move_port_mask; + const struct mv88e6xxx_ops *ops; +}; + +struct mv88e6xxx_atu_entry { + u8 state; + bool trunk; + u16 portvec; + u8 mac[ETH_ALEN]; +}; + +struct mv88e6xxx_vtu_entry { + u16 vid; + u16 fid; + u8 sid; + bool valid; + u8 member[DSA_MAX_PORTS]; + u8 state[DSA_MAX_PORTS]; +}; + +struct mv88e6xxx_bus_ops; +struct mv88e6xxx_irq_ops; + +struct mv88e6xxx_irq { + u16 masked; + struct irq_chip chip; + struct irq_domain *domain; + unsigned int nirqs; +}; + +struct mv88e6xxx_chip { + const struct mv88e6xxx_info *info; + + /* The dsa_switch this private structure is related to */ + struct dsa_switch *ds; + + /* The device this structure is associated to */ + struct device *dev; + + /* This mutex protects the access to the switch registers */ + struct mutex reg_lock; + + /* The MII bus and the address on the bus that is used to + * communication with the switch + */ + const struct mv88e6xxx_bus_ops *smi_ops; + struct mii_bus *bus; + int sw_addr; + + /* Handles automatic disabling and re-enabling of the PHY + * polling unit. + */ + const struct mv88e6xxx_bus_ops *phy_ops; + struct mutex ppu_mutex; + int ppu_disabled; + struct work_struct ppu_work; + struct timer_list ppu_timer; + + /* This mutex serialises access to the statistics unit. + * Hold this mutex over snapshot + dump sequences. + */ + struct mutex stats_mutex; + + /* A switch may have a GPIO line tied to its reset pin. Parse + * this from the device tree, and use it before performing + * switch soft reset. + */ + struct gpio_desc *reset; + + /* set to size of eeprom if supported by the switch */ + int eeprom_len; + + /* List of mdio busses */ + struct list_head mdios; + + /* There can be two interrupt controllers, which are chained + * off a GPIO as interrupt source + */ + struct mv88e6xxx_irq g1_irq; + struct mv88e6xxx_irq g2_irq; + int irq; + int device_irq; + int watchdog_irq; +}; + +struct mv88e6xxx_bus_ops { + int (*read)(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val); + int (*write)(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val); +}; + +struct mv88e6xxx_mdio_bus { + struct mii_bus *bus; + struct mv88e6xxx_chip *chip; + struct list_head list; + bool external; +}; + +struct mv88e6xxx_ops { + int (*get_eeprom)(struct mv88e6xxx_chip *chip, + struct ethtool_eeprom *eeprom, u8 *data); + int (*set_eeprom)(struct mv88e6xxx_chip *chip, + struct ethtool_eeprom *eeprom, u8 *data); + + int (*set_switch_mac)(struct mv88e6xxx_chip *chip, u8 *addr); + + int (*phy_read)(struct mv88e6xxx_chip *chip, + struct mii_bus *bus, + int addr, int reg, u16 *val); + int (*phy_write)(struct mv88e6xxx_chip *chip, + struct mii_bus *bus, + int addr, int reg, u16 val); + + /* PHY Polling Unit (PPU) operations */ + int (*ppu_enable)(struct mv88e6xxx_chip *chip); + int (*ppu_disable)(struct mv88e6xxx_chip *chip); + + /* Switch Software Reset */ + int (*reset)(struct mv88e6xxx_chip *chip); + + /* RGMII Receive/Transmit Timing Control + * Add delay on PHY_INTERFACE_MODE_RGMII_*ID, no delay otherwise. + */ + int (*port_set_rgmii_delay)(struct mv88e6xxx_chip *chip, int port, + phy_interface_t mode); + +#define LINK_FORCED_DOWN 0 +#define LINK_FORCED_UP 1 +#define LINK_UNFORCED -2 + + /* Port's MAC link state + * Use LINK_FORCED_UP or LINK_FORCED_DOWN to force link up or down, + * or LINK_UNFORCED for normal link detection. + */ + int (*port_set_link)(struct mv88e6xxx_chip *chip, int port, int link); + +#define DUPLEX_UNFORCED -2 + + /* Port's MAC duplex mode + * + * Use DUPLEX_HALF or DUPLEX_FULL to force half or full duplex, + * or DUPLEX_UNFORCED for normal duplex detection. + */ + int (*port_set_duplex)(struct mv88e6xxx_chip *chip, int port, int dup); + +#define SPEED_MAX INT_MAX +#define SPEED_UNFORCED -2 + + /* Port's MAC speed (in Mbps) + * + * Depending on the chip, 10, 100, 200, 1000, 2500, 10000 are valid. + * Use SPEED_UNFORCED for normal detection, SPEED_MAX for max value. + */ + int (*port_set_speed)(struct mv88e6xxx_chip *chip, int port, int speed); + + int (*port_tag_remap)(struct mv88e6xxx_chip *chip, int port); + + int (*port_set_frame_mode)(struct mv88e6xxx_chip *chip, int port, + enum mv88e6xxx_frame_mode mode); + int (*port_set_egress_floods)(struct mv88e6xxx_chip *chip, int port, + bool unicast, bool multicast); + int (*port_set_ether_type)(struct mv88e6xxx_chip *chip, int port, + u16 etype); + int (*port_jumbo_config)(struct mv88e6xxx_chip *chip, int port); + + int (*port_egress_rate_limiting)(struct mv88e6xxx_chip *chip, int port); + int (*port_pause_config)(struct mv88e6xxx_chip *chip, int port); + int (*port_disable_learn_limit)(struct mv88e6xxx_chip *chip, int port); + int (*port_disable_pri_override)(struct mv88e6xxx_chip *chip, int port); + + /* CMODE control what PHY mode the MAC will use, eg. SGMII, RGMII, etc. + * Some chips allow this to be configured on specific ports. + */ + int (*port_set_cmode)(struct mv88e6xxx_chip *chip, int port, + phy_interface_t mode); + + /* Some devices have a per port register indicating what is + * the upstream port this port should forward to. + */ + int (*port_set_upstream_port)(struct mv88e6xxx_chip *chip, int port, + int upstream_port); + + /* Snapshot the statistics for a port. The statistics can then + * be read back a leisure but still with a consistent view. + */ + int (*stats_snapshot)(struct mv88e6xxx_chip *chip, int port); + + /* Set the histogram mode for statistics, when the control registers + * are separated out of the STATS_OP register. + */ + int (*stats_set_histogram)(struct mv88e6xxx_chip *chip); + + /* Return the number of strings describing statistics */ + int (*stats_get_sset_count)(struct mv88e6xxx_chip *chip); + void (*stats_get_strings)(struct mv88e6xxx_chip *chip, uint8_t *data); + void (*stats_get_stats)(struct mv88e6xxx_chip *chip, int port, + uint64_t *data); + int (*g1_set_cpu_port)(struct mv88e6xxx_chip *chip, int port); + int (*g1_set_egress_port)(struct mv88e6xxx_chip *chip, int port); + const struct mv88e6xxx_irq_ops *watchdog_ops; + + /* Can be either in g1 or g2, so don't use a prefix */ + int (*mgmt_rsvd2cpu)(struct mv88e6xxx_chip *chip); + + /* Power on/off a SERDES interface */ + int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, bool on); + + /* VLAN Translation Unit operations */ + int (*vtu_getnext)(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry); + int (*vtu_loadpurge)(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry); +}; + +struct mv88e6xxx_irq_ops { + /* Action to be performed when the interrupt happens */ + int (*irq_action)(struct mv88e6xxx_chip *chip, int irq); + /* Setup the hardware to generate the interrupt */ + int (*irq_setup)(struct mv88e6xxx_chip *chip); + /* Reset the hardware to stop generating the interrupt */ + void (*irq_free)(struct mv88e6xxx_chip *chip); +}; + +#define STATS_TYPE_PORT BIT(0) +#define STATS_TYPE_BANK0 BIT(1) +#define STATS_TYPE_BANK1 BIT(2) + +struct mv88e6xxx_hw_stat { + char string[ETH_GSTRING_LEN]; + int sizeof_stat; + int reg; + int type; +}; + +static inline bool mv88e6xxx_has(struct mv88e6xxx_chip *chip, + unsigned long flags) +{ + return (chip->info->flags & flags) == flags; +} + +static inline bool mv88e6xxx_has_pvt(struct mv88e6xxx_chip *chip) +{ + return chip->info->pvt; +} + +static inline unsigned int mv88e6xxx_num_databases(struct mv88e6xxx_chip *chip) +{ + return chip->info->num_databases; +} + +static inline unsigned int mv88e6xxx_num_ports(struct mv88e6xxx_chip *chip) +{ + return chip->info->num_ports; +} + +static inline u16 mv88e6xxx_port_mask(struct mv88e6xxx_chip *chip) +{ + return GENMASK(mv88e6xxx_num_ports(chip) - 1, 0); +} + +int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val); +int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val); +int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, + u16 update); +int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask); +struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip); + +#endif /* _MV88E6XXX_CHIP_H */ diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c index 39825837a1c9..4081ff0d38a0 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.c +++ b/drivers/net/dsa/mv88e6xxx/global1.c @@ -12,7 +12,7 @@ * (at your option) any later version. */ -#include "mv88e6xxx.h" +#include "chip.h" #include "global1.h" int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 46a4ea0f8c47..3e2765c53f89 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -15,7 +15,148 @@ #ifndef _MV88E6XXX_GLOBAL1_H #define _MV88E6XXX_GLOBAL1_H -#include "mv88e6xxx.h" +#include "chip.h" + +#define GLOBAL_STATUS 0x00 +#define GLOBAL_STATUS_PPU_STATE BIT(15) /* 6351 and 6171 */ +#define GLOBAL_STATUS_PPU_STATE_MASK (0x3 << 14) /* 6165 6185 */ +#define GLOBAL_STATUS_PPU_STATE_DISABLED_RST (0x0 << 14) +#define GLOBAL_STATUS_PPU_STATE_INITIALIZING (0x1 << 14) +#define GLOBAL_STATUS_PPU_STATE_DISABLED (0x2 << 14) +#define GLOBAL_STATUS_PPU_STATE_POLLING (0x3 << 14) +#define GLOBAL_STATUS_INIT_READY BIT(11) +#define GLOBAL_STATUS_IRQ_AVB 8 +#define GLOBAL_STATUS_IRQ_DEVICE 7 +#define GLOBAL_STATUS_IRQ_STATS 6 +#define GLOBAL_STATUS_IRQ_VTU_PROBLEM 5 +#define GLOBAL_STATUS_IRQ_VTU_DONE 4 +#define GLOBAL_STATUS_IRQ_ATU_PROBLEM 3 +#define GLOBAL_STATUS_IRQ_ATU_DONE 2 +#define GLOBAL_STATUS_IRQ_TCAM_DONE 1 +#define GLOBAL_STATUS_IRQ_EEPROM_DONE 0 +#define GLOBAL_MAC_01 0x01 +#define GLOBAL_MAC_23 0x02 +#define GLOBAL_MAC_45 0x03 +#define GLOBAL_ATU_FID 0x01 +#define GLOBAL_VTU_FID 0x02 +#define GLOBAL_VTU_FID_MASK 0xfff +#define GLOBAL_VTU_SID 0x03 /* 6097 6165 6351 6352 */ +#define GLOBAL_VTU_SID_MASK 0x3f +#define GLOBAL_CONTROL 0x04 +#define GLOBAL_CONTROL_SW_RESET BIT(15) +#define GLOBAL_CONTROL_PPU_ENABLE BIT(14) +#define GLOBAL_CONTROL_DISCARD_EXCESS BIT(13) /* 6352 */ +#define GLOBAL_CONTROL_SCHED_PRIO BIT(11) /* 6152 */ +#define GLOBAL_CONTROL_MAX_FRAME_1632 BIT(10) /* 6152 */ +#define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9) /* 6152 */ +#define GLOBAL_CONTROL_DEVICE_EN BIT(7) +#define GLOBAL_CONTROL_STATS_DONE_EN BIT(6) +#define GLOBAL_CONTROL_VTU_PROBLEM_EN BIT(5) +#define GLOBAL_CONTROL_VTU_DONE_EN BIT(4) +#define GLOBAL_CONTROL_ATU_PROBLEM_EN BIT(3) +#define GLOBAL_CONTROL_ATU_DONE_EN BIT(2) +#define GLOBAL_CONTROL_TCAM_EN BIT(1) +#define GLOBAL_CONTROL_EEPROM_DONE_EN BIT(0) +#define GLOBAL_VTU_OP 0x05 +#define GLOBAL_VTU_OP_BUSY BIT(15) +#define GLOBAL_VTU_OP_FLUSH_ALL ((0x01 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_OP_VTU_LOAD_PURGE ((0x03 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_OP_VTU_GET_NEXT ((0x04 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_OP_STU_LOAD_PURGE ((0x05 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_OP_STU_GET_NEXT ((0x06 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_VID 0x06 +#define GLOBAL_VTU_VID_MASK 0xfff +#define GLOBAL_VTU_VID_PAGE BIT(13) +#define GLOBAL_VTU_VID_VALID BIT(12) +#define GLOBAL_VTU_DATA_0_3 0x07 +#define GLOBAL_VTU_DATA_4_7 0x08 +#define GLOBAL_VTU_DATA_8_11 0x09 +#define GLOBAL_VTU_STU_DATA_MASK 0x03 +#define GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED 0x00 +#define GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED 0x01 +#define GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED 0x02 +#define GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER 0x03 +#define GLOBAL_STU_DATA_PORT_STATE_DISABLED 0x00 +#define GLOBAL_STU_DATA_PORT_STATE_BLOCKING 0x01 +#define GLOBAL_STU_DATA_PORT_STATE_LEARNING 0x02 +#define GLOBAL_STU_DATA_PORT_STATE_FORWARDING 0x03 +#define GLOBAL_ATU_CONTROL 0x0a +#define GLOBAL_ATU_CONTROL_LEARN2ALL BIT(3) +#define GLOBAL_ATU_OP 0x0b +#define GLOBAL_ATU_OP_BUSY BIT(15) +#define GLOBAL_ATU_OP_NOP (0 << 12) +#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL ((1 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC ((2 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_LOAD_DB ((3 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_GET_NEXT_DB ((4 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB ((5 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_GET_CLR_VIOLATION ((7 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_DATA 0x0c +#define GLOBAL_ATU_DATA_TRUNK BIT(15) +#define GLOBAL_ATU_DATA_TRUNK_ID_MASK 0x00f0 +#define GLOBAL_ATU_DATA_TRUNK_ID_SHIFT 4 +#define GLOBAL_ATU_DATA_PORT_VECTOR_MASK 0x3ff0 +#define GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT 4 +#define GLOBAL_ATU_DATA_STATE_MASK 0x0f +#define GLOBAL_ATU_DATA_STATE_UNUSED 0x00 +#define GLOBAL_ATU_DATA_STATE_UC_MGMT 0x0d +#define GLOBAL_ATU_DATA_STATE_UC_STATIC 0x0e +#define GLOBAL_ATU_DATA_STATE_UC_PRIO_OVER 0x0f +#define GLOBAL_ATU_DATA_STATE_MC_NONE_RATE 0x05 +#define GLOBAL_ATU_DATA_STATE_MC_STATIC 0x07 +#define GLOBAL_ATU_DATA_STATE_MC_MGMT 0x0e +#define GLOBAL_ATU_DATA_STATE_MC_PRIO_OVER 0x0f +#define GLOBAL_ATU_MAC_01 0x0d +#define GLOBAL_ATU_MAC_23 0x0e +#define GLOBAL_ATU_MAC_45 0x0f +#define GLOBAL_IP_PRI_0 0x10 +#define GLOBAL_IP_PRI_1 0x11 +#define GLOBAL_IP_PRI_2 0x12 +#define GLOBAL_IP_PRI_3 0x13 +#define GLOBAL_IP_PRI_4 0x14 +#define GLOBAL_IP_PRI_5 0x15 +#define GLOBAL_IP_PRI_6 0x16 +#define GLOBAL_IP_PRI_7 0x17 +#define GLOBAL_IEEE_PRI 0x18 +#define GLOBAL_CORE_TAG_TYPE 0x19 +#define GLOBAL_MONITOR_CONTROL 0x1a +#define GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT 12 +#define GLOBAL_MONITOR_CONTROL_INGRESS_MASK (0xf << 12) +#define GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT 8 +#define GLOBAL_MONITOR_CONTROL_EGRESS_MASK (0xf << 8) +#define GLOBAL_MONITOR_CONTROL_ARP_SHIFT 4 +#define GLOBAL_MONITOR_CONTROL_ARP_MASK (0xf << 4) +#define GLOBAL_MONITOR_CONTROL_MIRROR_SHIFT 0 +#define GLOBAL_MONITOR_CONTROL_ARP_DISABLED (0xf0) +#define GLOBAL_MONITOR_CONTROL_UPDATE BIT(15) +#define GLOBAL_MONITOR_CONTROL_0180C280000000XLO (0x00 << 8) +#define GLOBAL_MONITOR_CONTROL_0180C280000000XHI (0x01 << 8) +#define GLOBAL_MONITOR_CONTROL_0180C280000002XLO (0x02 << 8) +#define GLOBAL_MONITOR_CONTROL_0180C280000002XHI (0x03 << 8) +#define GLOBAL_MONITOR_CONTROL_INGRESS (0x20 << 8) +#define GLOBAL_MONITOR_CONTROL_EGRESS (0x21 << 8) +#define GLOBAL_MONITOR_CONTROL_CPU_DEST (0x30 << 8) +#define GLOBAL_CONTROL_2 0x1c +#define GLOBAL_CONTROL_2_NO_CASCADE 0xe000 +#define GLOBAL_CONTROL_2_MULTIPLE_CASCADE 0xf000 +#define GLOBAL_CONTROL_2_HIST_RX (0x1 << 6) +#define GLOBAL_CONTROL_2_HIST_TX (0x2 << 6) +#define GLOBAL_CONTROL_2_HIST_RX_TX (0x3 << 6) +#define GLOBAL_STATS_OP 0x1d +#define GLOBAL_STATS_OP_BUSY BIT(15) +#define GLOBAL_STATS_OP_NOP (0 << 12) +#define GLOBAL_STATS_OP_FLUSH_ALL ((1 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_FLUSH_PORT ((2 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_READ_CAPTURED ((4 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_CAPTURE_PORT ((5 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_HIST_RX ((1 << 10) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_HIST_TX ((2 << 10) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_HIST_RX_TX ((3 << 10) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_BANK_1_BIT_9 BIT(9) +#define GLOBAL_STATS_OP_BANK_1_BIT_10 BIT(10) +#define GLOBAL_STATS_COUNTER_32 0x1e +#define GLOBAL_STATS_COUNTER_01 0x1f int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val); int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val); diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c index fa7e7db5171b..6b0cf44dc07d 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c @@ -10,7 +10,7 @@ * (at your option) any later version. */ -#include "mv88e6xxx.h" +#include "chip.h" #include "global1.h" /* Offset 0x01: ATU FID Register */ diff --git a/drivers/net/dsa/mv88e6xxx/global1_vtu.c b/drivers/net/dsa/mv88e6xxx/global1_vtu.c index 9aea22d4c9e2..bf593c7aaa9b 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_vtu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_vtu.c @@ -11,7 +11,7 @@ * (at your option) any later version. */ -#include "mv88e6xxx.h" +#include "chip.h" #include "global1.h" /* Offset 0x02: VTU FID Register */ diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index b3fea55071e3..d63af31e7840 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -15,10 +15,10 @@ #include <linux/interrupt.h> #include <linux/irqdomain.h> -#include "mv88e6xxx.h" -#include "global2.h" -#define ADDR_GLOBAL2 0x1c +#include "chip.h" +#include "global1.h" /* for GLOBAL_STATUS_IRQ_DEVICE */ +#include "global2.h" static int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) { diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index 14c0be98e0a4..479d42971706 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -15,7 +15,110 @@ #ifndef _MV88E6XXX_GLOBAL2_H #define _MV88E6XXX_GLOBAL2_H -#include "mv88e6xxx.h" +#include "chip.h" + +#define ADDR_GLOBAL2 0x1c + +#define GLOBAL2_INT_SOURCE 0x00 +#define GLOBAL2_INT_SOURCE_WATCHDOG 15 +#define GLOBAL2_INT_MASK 0x01 +#define GLOBAL2_MGMT_EN_2X 0x02 +#define GLOBAL2_MGMT_EN_0X 0x03 +#define GLOBAL2_FLOW_CONTROL 0x04 +#define GLOBAL2_SWITCH_MGMT 0x05 +#define GLOBAL2_SWITCH_MGMT_USE_DOUBLE_TAG_DATA BIT(15) +#define GLOBAL2_SWITCH_MGMT_PREVENT_LOOPS BIT(14) +#define GLOBAL2_SWITCH_MGMT_FLOW_CONTROL_MSG BIT(13) +#define GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI BIT(7) +#define GLOBAL2_SWITCH_MGMT_RSVD2CPU BIT(3) +#define GLOBAL2_DEVICE_MAPPING 0x06 +#define GLOBAL2_DEVICE_MAPPING_UPDATE BIT(15) +#define GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT 8 +#define GLOBAL2_DEVICE_MAPPING_PORT_MASK 0x0f +#define GLOBAL2_TRUNK_MASK 0x07 +#define GLOBAL2_TRUNK_MASK_UPDATE BIT(15) +#define GLOBAL2_TRUNK_MASK_NUM_SHIFT 12 +#define GLOBAL2_TRUNK_MASK_HASK BIT(11) +#define GLOBAL2_TRUNK_MAPPING 0x08 +#define GLOBAL2_TRUNK_MAPPING_UPDATE BIT(15) +#define GLOBAL2_TRUNK_MAPPING_ID_SHIFT 11 +#define GLOBAL2_IRL_CMD 0x09 +#define GLOBAL2_IRL_CMD_BUSY BIT(15) +#define GLOBAL2_IRL_CMD_OP_INIT_ALL ((0x001 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_CMD_OP_INIT_SEL ((0x010 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_CMD_OP_WRITE_SEL ((0x011 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_CMD_OP_READ_SEL ((0x100 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_DATA 0x0a +#define GLOBAL2_PVT_ADDR 0x0b +#define GLOBAL2_PVT_ADDR_BUSY BIT(15) +#define GLOBAL2_PVT_ADDR_OP_INIT_ONES ((0x01 << 12) | GLOBAL2_PVT_ADDR_BUSY) +#define GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN ((0x03 << 12) | GLOBAL2_PVT_ADDR_BUSY) +#define GLOBAL2_PVT_ADDR_OP_READ ((0x04 << 12) | GLOBAL2_PVT_ADDR_BUSY) +#define GLOBAL2_PVT_DATA 0x0c +#define GLOBAL2_SWITCH_MAC 0x0d +#define GLOBAL2_ATU_STATS 0x0e +#define GLOBAL2_PRIO_OVERRIDE 0x0f +#define GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP BIT(7) +#define GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT 4 +#define GLOBAL2_PRIO_OVERRIDE_FORCE_ARP BIT(3) +#define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT 0 +#define GLOBAL2_EEPROM_CMD 0x14 +#define GLOBAL2_EEPROM_CMD_BUSY BIT(15) +#define GLOBAL2_EEPROM_CMD_OP_WRITE ((0x3 << 12) | GLOBAL2_EEPROM_CMD_BUSY) +#define GLOBAL2_EEPROM_CMD_OP_READ ((0x4 << 12) | GLOBAL2_EEPROM_CMD_BUSY) +#define GLOBAL2_EEPROM_CMD_OP_LOAD ((0x6 << 12) | GLOBAL2_EEPROM_CMD_BUSY) +#define GLOBAL2_EEPROM_CMD_RUNNING BIT(11) +#define GLOBAL2_EEPROM_CMD_WRITE_EN BIT(10) +#define GLOBAL2_EEPROM_CMD_ADDR_MASK 0xff +#define GLOBAL2_EEPROM_DATA 0x15 +#define GLOBAL2_EEPROM_ADDR 0x15 /* 6390, 6341 */ +#define GLOBAL2_PTP_AVB_OP 0x16 +#define GLOBAL2_PTP_AVB_DATA 0x17 +#define GLOBAL2_SMI_PHY_CMD 0x18 +#define GLOBAL2_SMI_PHY_CMD_BUSY BIT(15) +#define GLOBAL2_SMI_PHY_CMD_EXTERNAL BIT(13) +#define GLOBAL2_SMI_PHY_CMD_MODE_22 BIT(12) +#define GLOBAL2_SMI_PHY_CMD_OP_22_WRITE_DATA ((0x1 << 10) | \ + GLOBAL2_SMI_PHY_CMD_MODE_22 | \ + GLOBAL2_SMI_PHY_CMD_BUSY) +#define GLOBAL2_SMI_PHY_CMD_OP_22_READ_DATA ((0x2 << 10) | \ + GLOBAL2_SMI_PHY_CMD_MODE_22 | \ + GLOBAL2_SMI_PHY_CMD_BUSY) +#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_ADDR ((0x0 << 10) | \ + GLOBAL2_SMI_PHY_CMD_BUSY) +#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_DATA ((0x1 << 10) | \ + GLOBAL2_SMI_PHY_CMD_BUSY) +#define GLOBAL2_SMI_PHY_CMD_OP_45_READ_DATA ((0x3 << 10) | \ + GLOBAL2_SMI_PHY_CMD_BUSY) + +#define GLOBAL2_SMI_PHY_DATA 0x19 +#define GLOBAL2_SCRATCH_MISC 0x1a +#define GLOBAL2_SCRATCH_BUSY BIT(15) +#define GLOBAL2_SCRATCH_REGISTER_SHIFT 8 +#define GLOBAL2_SCRATCH_VALUE_MASK 0xff +#define GLOBAL2_WDOG_CONTROL 0x1b +#define GLOBAL2_WDOG_CONTROL_EGRESS_EVENT BIT(7) +#define GLOBAL2_WDOG_CONTROL_RMU_TIMEOUT BIT(6) +#define GLOBAL2_WDOG_CONTROL_QC_ENABLE BIT(5) +#define GLOBAL2_WDOG_CONTROL_EGRESS_HISTORY BIT(4) +#define GLOBAL2_WDOG_CONTROL_EGRESS_ENABLE BIT(3) +#define GLOBAL2_WDOG_CONTROL_FORCE_IRQ BIT(2) +#define GLOBAL2_WDOG_CONTROL_HISTORY BIT(1) +#define GLOBAL2_WDOG_CONTROL_SWRESET BIT(0) +#define GLOBAL2_WDOG_UPDATE BIT(15) +#define GLOBAL2_WDOG_INT_SOURCE (0x00 << 8) +#define GLOBAL2_WDOG_INT_STATUS (0x10 << 8) +#define GLOBAL2_WDOG_INT_ENABLE (0x11 << 8) +#define GLOBAL2_WDOG_EVENT (0x12 << 8) +#define GLOBAL2_WDOG_HISTORY (0x13 << 8) +#define GLOBAL2_WDOG_DATA_MASK 0xff +#define GLOBAL2_WDOG_CUT_THROUGH BIT(3) +#define GLOBAL2_WDOG_QUEUE_CONTROLLER BIT(2) +#define GLOBAL2_WDOG_EGRESS BIT(1) +#define GLOBAL2_WDOG_FORCE_IRQ BIT(0) +#define GLOBAL2_QOS_WEIGHT 0x1c +#define GLOBAL2_MISC 0x1d +#define GLOBAL2_MISC_5_BIT_PORT BIT(14) #ifdef CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h deleted file mode 100644 index 77236cd72df2..000000000000 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ /dev/null @@ -1,946 +0,0 @@ -/* - * Marvell 88e6xxx common definitions - * - * Copyright (c) 2008 Marvell Semiconductor - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __MV88E6XXX_H -#define __MV88E6XXX_H - -#include <linux/if_vlan.h> -#include <linux/irq.h> -#include <linux/gpio/consumer.h> -#include <linux/phy.h> -#include <net/dsa.h> - -#ifndef UINT64_MAX -#define UINT64_MAX (u64)(~((u64)0)) -#endif - -#define SMI_CMD 0x00 -#define SMI_CMD_BUSY BIT(15) -#define SMI_CMD_CLAUSE_22 BIT(12) -#define SMI_CMD_OP_22_WRITE ((1 << 10) | SMI_CMD_BUSY | SMI_CMD_CLAUSE_22) -#define SMI_CMD_OP_22_READ ((2 << 10) | SMI_CMD_BUSY | SMI_CMD_CLAUSE_22) -#define SMI_CMD_OP_45_WRITE_ADDR ((0 << 10) | SMI_CMD_BUSY) -#define SMI_CMD_OP_45_WRITE_DATA ((1 << 10) | SMI_CMD_BUSY) -#define SMI_CMD_OP_45_READ_DATA ((2 << 10) | SMI_CMD_BUSY) -#define SMI_CMD_OP_45_READ_DATA_INC ((3 << 10) | SMI_CMD_BUSY) -#define SMI_DATA 0x01 - -/* PHY Registers */ -#define PHY_PAGE 0x16 -#define PHY_PAGE_COPPER 0x00 - -#define ADDR_SERDES 0x0f -#define SERDES_PAGE_FIBER 0x01 - -#define PORT_STATUS 0x00 -#define PORT_STATUS_PAUSE_EN BIT(15) -#define PORT_STATUS_MY_PAUSE BIT(14) -#define PORT_STATUS_HD_FLOW BIT(13) -#define PORT_STATUS_PHY_DETECT BIT(12) -#define PORT_STATUS_LINK BIT(11) -#define PORT_STATUS_DUPLEX BIT(10) -#define PORT_STATUS_SPEED_MASK 0x0300 -#define PORT_STATUS_SPEED_10 0x0000 -#define PORT_STATUS_SPEED_100 0x0100 -#define PORT_STATUS_SPEED_1000 0x0200 -#define PORT_STATUS_EEE BIT(6) /* 6352 */ -#define PORT_STATUS_AM_DIS BIT(6) /* 6165 */ -#define PORT_STATUS_MGMII BIT(6) /* 6185 */ -#define PORT_STATUS_TX_PAUSED BIT(5) -#define PORT_STATUS_FLOW_CTRL BIT(4) -#define PORT_STATUS_CMODE_MASK 0x0f -#define PORT_STATUS_CMODE_100BASE_X 0x8 -#define PORT_STATUS_CMODE_1000BASE_X 0x9 -#define PORT_STATUS_CMODE_SGMII 0xa -#define PORT_STATUS_CMODE_2500BASEX 0xb -#define PORT_STATUS_CMODE_XAUI 0xc -#define PORT_STATUS_CMODE_RXAUI 0xd -#define PORT_PCS_CTRL 0x01 -#define PORT_PCS_CTRL_RGMII_DELAY_RXCLK BIT(15) -#define PORT_PCS_CTRL_RGMII_DELAY_TXCLK BIT(14) -#define PORT_PCS_CTRL_FORCE_SPEED BIT(13) /* 6390 */ -#define PORT_PCS_CTRL_ALTSPEED BIT(12) /* 6390 */ -#define PORT_PCS_CTRL_200BASE BIT(12) /* 6352 */ -#define PORT_PCS_CTRL_FC BIT(7) -#define PORT_PCS_CTRL_FORCE_FC BIT(6) -#define PORT_PCS_CTRL_LINK_UP BIT(5) -#define PORT_PCS_CTRL_FORCE_LINK BIT(4) -#define PORT_PCS_CTRL_DUPLEX_FULL BIT(3) -#define PORT_PCS_CTRL_FORCE_DUPLEX BIT(2) -#define PORT_PCS_CTRL_SPEED_MASK (0x03) -#define PORT_PCS_CTRL_SPEED_10 (0x00) -#define PORT_PCS_CTRL_SPEED_100 (0x01) -#define PORT_PCS_CTRL_SPEED_200 (0x02) /* 6065 and non Gb chips */ -#define PORT_PCS_CTRL_SPEED_1000 (0x02) -#define PORT_PCS_CTRL_SPEED_10000 (0x03) /* 6390X */ -#define PORT_PCS_CTRL_SPEED_UNFORCED (0x03) -#define PORT_PAUSE_CTRL 0x02 -#define PORT_FLOW_CTRL_LIMIT_IN ((0x00 << 8) | BIT(15)) -#define PORT_FLOW_CTRL_LIMIT_OUT ((0x01 << 8) | BIT(15)) -#define PORT_SWITCH_ID 0x03 -#define PORT_SWITCH_ID_PROD_NUM_6085 0x04a -#define PORT_SWITCH_ID_PROD_NUM_6095 0x095 -#define PORT_SWITCH_ID_PROD_NUM_6097 0x099 -#define PORT_SWITCH_ID_PROD_NUM_6131 0x106 -#define PORT_SWITCH_ID_PROD_NUM_6320 0x115 -#define PORT_SWITCH_ID_PROD_NUM_6123 0x121 -#define PORT_SWITCH_ID_PROD_NUM_6141 0x340 -#define PORT_SWITCH_ID_PROD_NUM_6161 0x161 -#define PORT_SWITCH_ID_PROD_NUM_6165 0x165 -#define PORT_SWITCH_ID_PROD_NUM_6171 0x171 -#define PORT_SWITCH_ID_PROD_NUM_6172 0x172 -#define PORT_SWITCH_ID_PROD_NUM_6175 0x175 -#define PORT_SWITCH_ID_PROD_NUM_6176 0x176 -#define PORT_SWITCH_ID_PROD_NUM_6185 0x1a7 -#define PORT_SWITCH_ID_PROD_NUM_6190 0x190 -#define PORT_SWITCH_ID_PROD_NUM_6190X 0x0a0 -#define PORT_SWITCH_ID_PROD_NUM_6191 0x191 -#define PORT_SWITCH_ID_PROD_NUM_6240 0x240 -#define PORT_SWITCH_ID_PROD_NUM_6290 0x290 -#define PORT_SWITCH_ID_PROD_NUM_6321 0x310 -#define PORT_SWITCH_ID_PROD_NUM_6341 0x341 -#define PORT_SWITCH_ID_PROD_NUM_6352 0x352 -#define PORT_SWITCH_ID_PROD_NUM_6350 0x371 -#define PORT_SWITCH_ID_PROD_NUM_6351 0x375 -#define PORT_SWITCH_ID_PROD_NUM_6390 0x390 -#define PORT_SWITCH_ID_PROD_NUM_6390X 0x0a1 -#define PORT_CONTROL 0x04 -#define PORT_CONTROL_USE_CORE_TAG BIT(15) -#define PORT_CONTROL_DROP_ON_LOCK BIT(14) -#define PORT_CONTROL_EGRESS_UNMODIFIED (0x0 << 12) -#define PORT_CONTROL_EGRESS_UNTAGGED (0x1 << 12) -#define PORT_CONTROL_EGRESS_TAGGED (0x2 << 12) -#define PORT_CONTROL_EGRESS_ADD_TAG (0x3 << 12) -#define PORT_CONTROL_EGRESS_MASK (0x3 << 12) -#define PORT_CONTROL_HEADER BIT(11) -#define PORT_CONTROL_IGMP_MLD_SNOOP BIT(10) -#define PORT_CONTROL_DOUBLE_TAG BIT(9) -#define PORT_CONTROL_FRAME_MODE_NORMAL (0x0 << 8) -#define PORT_CONTROL_FRAME_MODE_DSA (0x1 << 8) -#define PORT_CONTROL_FRAME_MODE_PROVIDER (0x2 << 8) -#define PORT_CONTROL_FRAME_ETHER_TYPE_DSA (0x3 << 8) -#define PORT_CONTROL_FRAME_MASK (0x3 << 8) -#define PORT_CONTROL_DSA_TAG BIT(8) -#define PORT_CONTROL_VLAN_TUNNEL BIT(7) -#define PORT_CONTROL_TAG_IF_BOTH BIT(6) -#define PORT_CONTROL_USE_IP BIT(5) -#define PORT_CONTROL_USE_TAG BIT(4) -#define PORT_CONTROL_FORWARD_UNKNOWN BIT(2) -#define PORT_CONTROL_EGRESS_FLOODS_MASK (0x3 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_DA (0x0 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_MC_DA (0x1 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_UC_DA (0x2 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_ALL_UNKNOWN_DA (0x3 << 2) -#define PORT_CONTROL_STATE_MASK 0x03 -#define PORT_CONTROL_STATE_DISABLED 0x00 -#define PORT_CONTROL_STATE_BLOCKING 0x01 -#define PORT_CONTROL_STATE_LEARNING 0x02 -#define PORT_CONTROL_STATE_FORWARDING 0x03 -#define PORT_CONTROL_1 0x05 -#define PORT_CONTROL_1_MESSAGE_PORT BIT(15) -#define PORT_CONTROL_1_FID_11_4_MASK (0xff << 0) -#define PORT_BASE_VLAN 0x06 -#define PORT_BASE_VLAN_FID_3_0_MASK (0xf << 12) -#define PORT_DEFAULT_VLAN 0x07 -#define PORT_DEFAULT_VLAN_MASK 0xfff -#define PORT_CONTROL_2 0x08 -#define PORT_CONTROL_2_IGNORE_FCS BIT(15) -#define PORT_CONTROL_2_VTU_PRI_OVERRIDE BIT(14) -#define PORT_CONTROL_2_SA_PRIO_OVERRIDE BIT(13) -#define PORT_CONTROL_2_DA_PRIO_OVERRIDE BIT(12) -#define PORT_CONTROL_2_JUMBO_1522 (0x00 << 12) -#define PORT_CONTROL_2_JUMBO_2048 (0x01 << 12) -#define PORT_CONTROL_2_JUMBO_10240 (0x02 << 12) -#define PORT_CONTROL_2_8021Q_MASK (0x03 << 10) -#define PORT_CONTROL_2_8021Q_DISABLED (0x00 << 10) -#define PORT_CONTROL_2_8021Q_FALLBACK (0x01 << 10) -#define PORT_CONTROL_2_8021Q_CHECK (0x02 << 10) -#define PORT_CONTROL_2_8021Q_SECURE (0x03 << 10) -#define PORT_CONTROL_2_DISCARD_TAGGED BIT(9) -#define PORT_CONTROL_2_DISCARD_UNTAGGED BIT(8) -#define PORT_CONTROL_2_MAP_DA BIT(7) -#define PORT_CONTROL_2_DEFAULT_FORWARD BIT(6) -#define PORT_CONTROL_2_EGRESS_MONITOR BIT(5) -#define PORT_CONTROL_2_INGRESS_MONITOR BIT(4) -#define PORT_CONTROL_2_UPSTREAM_MASK 0x0f -#define PORT_RATE_CONTROL 0x09 -#define PORT_RATE_CONTROL_2 0x0a -#define PORT_ASSOC_VECTOR 0x0b -#define PORT_ASSOC_VECTOR_HOLD_AT_1 BIT(15) -#define PORT_ASSOC_VECTOR_INT_AGE_OUT BIT(14) -#define PORT_ASSOC_VECTOR_LOCKED_PORT BIT(13) -#define PORT_ASSOC_VECTOR_IGNORE_WRONG BIT(12) -#define PORT_ASSOC_VECTOR_REFRESH_LOCKED BIT(11) -#define PORT_ATU_CONTROL 0x0c -#define PORT_PRI_OVERRIDE 0x0d -#define PORT_ETH_TYPE 0x0f -#define PORT_ETH_TYPE_DEFAULT 0x9100 -#define PORT_IN_DISCARD_LO 0x10 -#define PORT_IN_DISCARD_HI 0x11 -#define PORT_IN_FILTERED 0x12 -#define PORT_OUT_FILTERED 0x13 -#define PORT_TAG_REGMAP_0123 0x18 -#define PORT_TAG_REGMAP_4567 0x19 -#define PORT_IEEE_PRIO_MAP_TABLE 0x18 /* 6390 */ -#define PORT_IEEE_PRIO_MAP_TABLE_UPDATE BIT(15) -#define PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP (0x0 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP (0x1 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP (0x2 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP (0x3 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_DSCP (0x5 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_DSCP (0x6 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_DSCP (0x7 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT 9 - -#define GLOBAL_STATUS 0x00 -#define GLOBAL_STATUS_PPU_STATE BIT(15) /* 6351 and 6171 */ -#define GLOBAL_STATUS_PPU_STATE_MASK (0x3 << 14) /* 6165 6185 */ -#define GLOBAL_STATUS_PPU_STATE_DISABLED_RST (0x0 << 14) -#define GLOBAL_STATUS_PPU_STATE_INITIALIZING (0x1 << 14) -#define GLOBAL_STATUS_PPU_STATE_DISABLED (0x2 << 14) -#define GLOBAL_STATUS_PPU_STATE_POLLING (0x3 << 14) -#define GLOBAL_STATUS_INIT_READY BIT(11) -#define GLOBAL_STATUS_IRQ_AVB 8 -#define GLOBAL_STATUS_IRQ_DEVICE 7 -#define GLOBAL_STATUS_IRQ_STATS 6 -#define GLOBAL_STATUS_IRQ_VTU_PROBLEM 5 -#define GLOBAL_STATUS_IRQ_VTU_DONE 4 -#define GLOBAL_STATUS_IRQ_ATU_PROBLEM 3 -#define GLOBAL_STATUS_IRQ_ATU_DONE 2 -#define GLOBAL_STATUS_IRQ_TCAM_DONE 1 -#define GLOBAL_STATUS_IRQ_EEPROM_DONE 0 -#define GLOBAL_MAC_01 0x01 -#define GLOBAL_MAC_23 0x02 -#define GLOBAL_MAC_45 0x03 -#define GLOBAL_ATU_FID 0x01 -#define GLOBAL_VTU_FID 0x02 -#define GLOBAL_VTU_FID_MASK 0xfff -#define GLOBAL_VTU_SID 0x03 /* 6097 6165 6351 6352 */ -#define GLOBAL_VTU_SID_MASK 0x3f -#define GLOBAL_CONTROL 0x04 -#define GLOBAL_CONTROL_SW_RESET BIT(15) -#define GLOBAL_CONTROL_PPU_ENABLE BIT(14) -#define GLOBAL_CONTROL_DISCARD_EXCESS BIT(13) /* 6352 */ -#define GLOBAL_CONTROL_SCHED_PRIO BIT(11) /* 6152 */ -#define GLOBAL_CONTROL_MAX_FRAME_1632 BIT(10) /* 6152 */ -#define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9) /* 6152 */ -#define GLOBAL_CONTROL_DEVICE_EN BIT(7) -#define GLOBAL_CONTROL_STATS_DONE_EN BIT(6) -#define GLOBAL_CONTROL_VTU_PROBLEM_EN BIT(5) -#define GLOBAL_CONTROL_VTU_DONE_EN BIT(4) -#define GLOBAL_CONTROL_ATU_PROBLEM_EN BIT(3) -#define GLOBAL_CONTROL_ATU_DONE_EN BIT(2) -#define GLOBAL_CONTROL_TCAM_EN BIT(1) -#define GLOBAL_CONTROL_EEPROM_DONE_EN BIT(0) -#define GLOBAL_VTU_OP 0x05 -#define GLOBAL_VTU_OP_BUSY BIT(15) -#define GLOBAL_VTU_OP_FLUSH_ALL ((0x01 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_VTU_LOAD_PURGE ((0x03 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_VTU_GET_NEXT ((0x04 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_STU_LOAD_PURGE ((0x05 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_STU_GET_NEXT ((0x06 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_VID 0x06 -#define GLOBAL_VTU_VID_MASK 0xfff -#define GLOBAL_VTU_VID_PAGE BIT(13) -#define GLOBAL_VTU_VID_VALID BIT(12) -#define GLOBAL_VTU_DATA_0_3 0x07 -#define GLOBAL_VTU_DATA_4_7 0x08 -#define GLOBAL_VTU_DATA_8_11 0x09 -#define GLOBAL_VTU_STU_DATA_MASK 0x03 -#define GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED 0x00 -#define GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED 0x01 -#define GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED 0x02 -#define GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER 0x03 -#define GLOBAL_STU_DATA_PORT_STATE_DISABLED 0x00 -#define GLOBAL_STU_DATA_PORT_STATE_BLOCKING 0x01 -#define GLOBAL_STU_DATA_PORT_STATE_LEARNING 0x02 -#define GLOBAL_STU_DATA_PORT_STATE_FORWARDING 0x03 -#define GLOBAL_ATU_CONTROL 0x0a -#define GLOBAL_ATU_CONTROL_LEARN2ALL BIT(3) -#define GLOBAL_ATU_OP 0x0b -#define GLOBAL_ATU_OP_BUSY BIT(15) -#define GLOBAL_ATU_OP_NOP (0 << 12) -#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL ((1 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC ((2 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_LOAD_DB ((3 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_GET_NEXT_DB ((4 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB ((5 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_GET_CLR_VIOLATION ((7 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_DATA 0x0c -#define GLOBAL_ATU_DATA_TRUNK BIT(15) -#define GLOBAL_ATU_DATA_TRUNK_ID_MASK 0x00f0 -#define GLOBAL_ATU_DATA_TRUNK_ID_SHIFT 4 -#define GLOBAL_ATU_DATA_PORT_VECTOR_MASK 0x3ff0 -#define GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT 4 -#define GLOBAL_ATU_DATA_STATE_MASK 0x0f -#define GLOBAL_ATU_DATA_STATE_UNUSED 0x00 -#define GLOBAL_ATU_DATA_STATE_UC_MGMT 0x0d -#define GLOBAL_ATU_DATA_STATE_UC_STATIC 0x0e -#define GLOBAL_ATU_DATA_STATE_UC_PRIO_OVER 0x0f -#define GLOBAL_ATU_DATA_STATE_MC_NONE_RATE 0x05 -#define GLOBAL_ATU_DATA_STATE_MC_STATIC 0x07 -#define GLOBAL_ATU_DATA_STATE_MC_MGMT 0x0e -#define GLOBAL_ATU_DATA_STATE_MC_PRIO_OVER 0x0f -#define GLOBAL_ATU_MAC_01 0x0d -#define GLOBAL_ATU_MAC_23 0x0e -#define GLOBAL_ATU_MAC_45 0x0f -#define GLOBAL_IP_PRI_0 0x10 -#define GLOBAL_IP_PRI_1 0x11 -#define GLOBAL_IP_PRI_2 0x12 -#define GLOBAL_IP_PRI_3 0x13 -#define GLOBAL_IP_PRI_4 0x14 -#define GLOBAL_IP_PRI_5 0x15 -#define GLOBAL_IP_PRI_6 0x16 -#define GLOBAL_IP_PRI_7 0x17 -#define GLOBAL_IEEE_PRI 0x18 -#define GLOBAL_CORE_TAG_TYPE 0x19 -#define GLOBAL_MONITOR_CONTROL 0x1a -#define GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT 12 -#define GLOBAL_MONITOR_CONTROL_INGRESS_MASK (0xf << 12) -#define GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT 8 -#define GLOBAL_MONITOR_CONTROL_EGRESS_MASK (0xf << 8) -#define GLOBAL_MONITOR_CONTROL_ARP_SHIFT 4 -#define GLOBAL_MONITOR_CONTROL_ARP_MASK (0xf << 4) -#define GLOBAL_MONITOR_CONTROL_MIRROR_SHIFT 0 -#define GLOBAL_MONITOR_CONTROL_ARP_DISABLED (0xf0) -#define GLOBAL_MONITOR_CONTROL_UPDATE BIT(15) -#define GLOBAL_MONITOR_CONTROL_0180C280000000XLO (0x00 << 8) -#define GLOBAL_MONITOR_CONTROL_0180C280000000XHI (0x01 << 8) -#define GLOBAL_MONITOR_CONTROL_0180C280000002XLO (0x02 << 8) -#define GLOBAL_MONITOR_CONTROL_0180C280000002XHI (0x03 << 8) -#define GLOBAL_MONITOR_CONTROL_INGRESS (0x20 << 8) -#define GLOBAL_MONITOR_CONTROL_EGRESS (0x21 << 8) -#define GLOBAL_MONITOR_CONTROL_CPU_DEST (0x30 << 8) -#define GLOBAL_CONTROL_2 0x1c -#define GLOBAL_CONTROL_2_NO_CASCADE 0xe000 -#define GLOBAL_CONTROL_2_MULTIPLE_CASCADE 0xf000 -#define GLOBAL_CONTROL_2_HIST_RX (0x1 << 6) -#define GLOBAL_CONTROL_2_HIST_TX (0x2 << 6) -#define GLOBAL_CONTROL_2_HIST_RX_TX (0x3 << 6) -#define GLOBAL_STATS_OP 0x1d -#define GLOBAL_STATS_OP_BUSY BIT(15) -#define GLOBAL_STATS_OP_NOP (0 << 12) -#define GLOBAL_STATS_OP_FLUSH_ALL ((1 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_FLUSH_PORT ((2 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_READ_CAPTURED ((4 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_CAPTURE_PORT ((5 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_HIST_RX ((1 << 10) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_HIST_TX ((2 << 10) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_HIST_RX_TX ((3 << 10) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_BANK_1_BIT_9 BIT(9) -#define GLOBAL_STATS_OP_BANK_1_BIT_10 BIT(10) -#define GLOBAL_STATS_COUNTER_32 0x1e -#define GLOBAL_STATS_COUNTER_01 0x1f - -#define GLOBAL2_INT_SOURCE 0x00 -#define GLOBAL2_INT_SOURCE_WATCHDOG 15 -#define GLOBAL2_INT_MASK 0x01 -#define GLOBAL2_MGMT_EN_2X 0x02 -#define GLOBAL2_MGMT_EN_0X 0x03 -#define GLOBAL2_FLOW_CONTROL 0x04 -#define GLOBAL2_SWITCH_MGMT 0x05 -#define GLOBAL2_SWITCH_MGMT_USE_DOUBLE_TAG_DATA BIT(15) -#define GLOBAL2_SWITCH_MGMT_PREVENT_LOOPS BIT(14) -#define GLOBAL2_SWITCH_MGMT_FLOW_CONTROL_MSG BIT(13) -#define GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI BIT(7) -#define GLOBAL2_SWITCH_MGMT_RSVD2CPU BIT(3) -#define GLOBAL2_DEVICE_MAPPING 0x06 -#define GLOBAL2_DEVICE_MAPPING_UPDATE BIT(15) -#define GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT 8 -#define GLOBAL2_DEVICE_MAPPING_PORT_MASK 0x0f -#define GLOBAL2_TRUNK_MASK 0x07 -#define GLOBAL2_TRUNK_MASK_UPDATE BIT(15) -#define GLOBAL2_TRUNK_MASK_NUM_SHIFT 12 -#define GLOBAL2_TRUNK_MASK_HASK BIT(11) -#define GLOBAL2_TRUNK_MAPPING 0x08 -#define GLOBAL2_TRUNK_MAPPING_UPDATE BIT(15) -#define GLOBAL2_TRUNK_MAPPING_ID_SHIFT 11 -#define GLOBAL2_IRL_CMD 0x09 -#define GLOBAL2_IRL_CMD_BUSY BIT(15) -#define GLOBAL2_IRL_CMD_OP_INIT_ALL ((0x001 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_CMD_OP_INIT_SEL ((0x010 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_CMD_OP_WRITE_SEL ((0x011 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_CMD_OP_READ_SEL ((0x100 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_DATA 0x0a -#define GLOBAL2_PVT_ADDR 0x0b -#define GLOBAL2_PVT_ADDR_BUSY BIT(15) -#define GLOBAL2_PVT_ADDR_OP_INIT_ONES ((0x01 << 12) | GLOBAL2_PVT_ADDR_BUSY) -#define GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN ((0x03 << 12) | GLOBAL2_PVT_ADDR_BUSY) -#define GLOBAL2_PVT_ADDR_OP_READ ((0x04 << 12) | GLOBAL2_PVT_ADDR_BUSY) -#define GLOBAL2_PVT_DATA 0x0c -#define GLOBAL2_SWITCH_MAC 0x0d -#define GLOBAL2_ATU_STATS 0x0e -#define GLOBAL2_PRIO_OVERRIDE 0x0f -#define GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP BIT(7) -#define GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT 4 -#define GLOBAL2_PRIO_OVERRIDE_FORCE_ARP BIT(3) -#define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT 0 -#define GLOBAL2_EEPROM_CMD 0x14 -#define GLOBAL2_EEPROM_CMD_BUSY BIT(15) -#define GLOBAL2_EEPROM_CMD_OP_WRITE ((0x3 << 12) | GLOBAL2_EEPROM_CMD_BUSY) -#define GLOBAL2_EEPROM_CMD_OP_READ ((0x4 << 12) | GLOBAL2_EEPROM_CMD_BUSY) -#define GLOBAL2_EEPROM_CMD_OP_LOAD ((0x6 << 12) | GLOBAL2_EEPROM_CMD_BUSY) -#define GLOBAL2_EEPROM_CMD_RUNNING BIT(11) -#define GLOBAL2_EEPROM_CMD_WRITE_EN BIT(10) -#define GLOBAL2_EEPROM_CMD_ADDR_MASK 0xff -#define GLOBAL2_EEPROM_DATA 0x15 -#define GLOBAL2_EEPROM_ADDR 0x15 /* 6390, 6341 */ -#define GLOBAL2_PTP_AVB_OP 0x16 -#define GLOBAL2_PTP_AVB_DATA 0x17 -#define GLOBAL2_SMI_PHY_CMD 0x18 -#define GLOBAL2_SMI_PHY_CMD_BUSY BIT(15) -#define GLOBAL2_SMI_PHY_CMD_EXTERNAL BIT(13) -#define GLOBAL2_SMI_PHY_CMD_MODE_22 BIT(12) -#define GLOBAL2_SMI_PHY_CMD_OP_22_WRITE_DATA ((0x1 << 10) | \ - GLOBAL2_SMI_PHY_CMD_MODE_22 | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_22_READ_DATA ((0x2 << 10) | \ - GLOBAL2_SMI_PHY_CMD_MODE_22 | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_ADDR ((0x0 << 10) | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_DATA ((0x1 << 10) | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_45_READ_DATA ((0x3 << 10) | \ - GLOBAL2_SMI_PHY_CMD_BUSY) - -#define GLOBAL2_SMI_PHY_DATA 0x19 -#define GLOBAL2_SCRATCH_MISC 0x1a -#define GLOBAL2_SCRATCH_BUSY BIT(15) -#define GLOBAL2_SCRATCH_REGISTER_SHIFT 8 -#define GLOBAL2_SCRATCH_VALUE_MASK 0xff -#define GLOBAL2_WDOG_CONTROL 0x1b -#define GLOBAL2_WDOG_CONTROL_EGRESS_EVENT BIT(7) -#define GLOBAL2_WDOG_CONTROL_RMU_TIMEOUT BIT(6) -#define GLOBAL2_WDOG_CONTROL_QC_ENABLE BIT(5) -#define GLOBAL2_WDOG_CONTROL_EGRESS_HISTORY BIT(4) -#define GLOBAL2_WDOG_CONTROL_EGRESS_ENABLE BIT(3) -#define GLOBAL2_WDOG_CONTROL_FORCE_IRQ BIT(2) -#define GLOBAL2_WDOG_CONTROL_HISTORY BIT(1) -#define GLOBAL2_WDOG_CONTROL_SWRESET BIT(0) -#define GLOBAL2_WDOG_UPDATE BIT(15) -#define GLOBAL2_WDOG_INT_SOURCE (0x00 << 8) -#define GLOBAL2_WDOG_INT_STATUS (0x10 << 8) -#define GLOBAL2_WDOG_INT_ENABLE (0x11 << 8) -#define GLOBAL2_WDOG_EVENT (0x12 << 8) -#define GLOBAL2_WDOG_HISTORY (0x13 << 8) -#define GLOBAL2_WDOG_DATA_MASK 0xff -#define GLOBAL2_WDOG_CUT_THROUGH BIT(3) -#define GLOBAL2_WDOG_QUEUE_CONTROLLER BIT(2) -#define GLOBAL2_WDOG_EGRESS BIT(1) -#define GLOBAL2_WDOG_FORCE_IRQ BIT(0) -#define GLOBAL2_QOS_WEIGHT 0x1c -#define GLOBAL2_MISC 0x1d -#define GLOBAL2_MISC_5_BIT_PORT BIT(14) - -#define MV88E6XXX_N_FID 4096 - -/* PVT limits for 4-bit port and 5-bit switch */ -#define MV88E6XXX_MAX_PVT_SWITCHES 32 -#define MV88E6XXX_MAX_PVT_PORTS 16 - -enum mv88e6xxx_frame_mode { - MV88E6XXX_FRAME_MODE_NORMAL, - MV88E6XXX_FRAME_MODE_DSA, - MV88E6XXX_FRAME_MODE_PROVIDER, - MV88E6XXX_FRAME_MODE_ETHERTYPE, -}; - -/* List of supported models */ -enum mv88e6xxx_model { - MV88E6085, - MV88E6095, - MV88E6097, - MV88E6123, - MV88E6131, - MV88E6141, - MV88E6161, - MV88E6165, - MV88E6171, - MV88E6172, - MV88E6175, - MV88E6176, - MV88E6185, - MV88E6190, - MV88E6190X, - MV88E6191, - MV88E6240, - MV88E6290, - MV88E6320, - MV88E6321, - MV88E6341, - MV88E6350, - MV88E6351, - MV88E6352, - MV88E6390, - MV88E6390X, -}; - -enum mv88e6xxx_family { - MV88E6XXX_FAMILY_NONE, - MV88E6XXX_FAMILY_6065, /* 6031 6035 6061 6065 */ - MV88E6XXX_FAMILY_6095, /* 6092 6095 */ - MV88E6XXX_FAMILY_6097, /* 6046 6085 6096 6097 */ - MV88E6XXX_FAMILY_6165, /* 6123 6161 6165 */ - MV88E6XXX_FAMILY_6185, /* 6108 6121 6122 6131 6152 6155 6182 6185 */ - MV88E6XXX_FAMILY_6320, /* 6320 6321 */ - MV88E6XXX_FAMILY_6341, /* 6141 6341 */ - MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */ - MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */ - MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */ -}; - -enum mv88e6xxx_cap { - /* Energy Efficient Ethernet. - */ - MV88E6XXX_CAP_EEE, - - /* Multi-chip Addressing Mode. - * Some chips respond to only 2 registers of its own SMI device address - * when it is non-zero, and use indirect access to internal registers. - */ - MV88E6XXX_CAP_SMI_CMD, /* (0x00) SMI Command */ - MV88E6XXX_CAP_SMI_DATA, /* (0x01) SMI Data */ - - /* PHY Registers. - */ - MV88E6XXX_CAP_PHY_PAGE, /* (0x16) Page Register */ - - /* Fiber/SERDES Registers (SMI address F). - */ - MV88E6XXX_CAP_SERDES, - - /* Switch Global (1) Registers. - */ - MV88E6XXX_CAP_G1_ATU_FID, /* (0x01) ATU FID Register */ - MV88E6XXX_CAP_G1_VTU_FID, /* (0x02) VTU FID Register */ - - /* Switch Global 2 Registers. - * The device contains a second set of global 16-bit registers. - */ - MV88E6XXX_CAP_GLOBAL2, - MV88E6XXX_CAP_G2_INT, /* (0x00) Interrupt Status */ - MV88E6XXX_CAP_G2_MGMT_EN_2X, /* (0x02) MGMT Enable Register 2x */ - MV88E6XXX_CAP_G2_MGMT_EN_0X, /* (0x03) MGMT Enable Register 0x */ - MV88E6XXX_CAP_G2_IRL_CMD, /* (0x09) Ingress Rate Command */ - MV88E6XXX_CAP_G2_IRL_DATA, /* (0x0a) Ingress Rate Data */ - MV88E6XXX_CAP_G2_POT, /* (0x0f) Priority Override Table */ - - /* Per VLAN Spanning Tree Unit (STU). - * The Port State database, if present, is accessed through VTU - * operations and dedicated SID registers. See GLOBAL_VTU_SID. - */ - MV88E6XXX_CAP_STU, - - /* VLAN Table Unit. - * The VTU is used to program 802.1Q VLANs. See GLOBAL_VTU_OP. - */ - MV88E6XXX_CAP_VTU, -}; - -/* Bitmask of capabilities */ -#define MV88E6XXX_FLAG_EEE BIT_ULL(MV88E6XXX_CAP_EEE) - -#define MV88E6XXX_FLAG_SMI_CMD BIT_ULL(MV88E6XXX_CAP_SMI_CMD) -#define MV88E6XXX_FLAG_SMI_DATA BIT_ULL(MV88E6XXX_CAP_SMI_DATA) - -#define MV88E6XXX_FLAG_PHY_PAGE BIT_ULL(MV88E6XXX_CAP_PHY_PAGE) - -#define MV88E6XXX_FLAG_SERDES BIT_ULL(MV88E6XXX_CAP_SERDES) - -#define MV88E6XXX_FLAG_G1_VTU_FID BIT_ULL(MV88E6XXX_CAP_G1_VTU_FID) - -#define MV88E6XXX_FLAG_GLOBAL2 BIT_ULL(MV88E6XXX_CAP_GLOBAL2) -#define MV88E6XXX_FLAG_G2_INT BIT_ULL(MV88E6XXX_CAP_G2_INT) -#define MV88E6XXX_FLAG_G2_MGMT_EN_2X BIT_ULL(MV88E6XXX_CAP_G2_MGMT_EN_2X) -#define MV88E6XXX_FLAG_G2_MGMT_EN_0X BIT_ULL(MV88E6XXX_CAP_G2_MGMT_EN_0X) -#define MV88E6XXX_FLAG_G2_IRL_CMD BIT_ULL(MV88E6XXX_CAP_G2_IRL_CMD) -#define MV88E6XXX_FLAG_G2_IRL_DATA BIT_ULL(MV88E6XXX_CAP_G2_IRL_DATA) -#define MV88E6XXX_FLAG_G2_POT BIT_ULL(MV88E6XXX_CAP_G2_POT) - -/* Ingress Rate Limit unit */ -#define MV88E6XXX_FLAGS_IRL \ - (MV88E6XXX_FLAG_G2_IRL_CMD | \ - MV88E6XXX_FLAG_G2_IRL_DATA) - -/* Multi-chip Addressing Mode */ -#define MV88E6XXX_FLAGS_MULTI_CHIP \ - (MV88E6XXX_FLAG_SMI_CMD | \ - MV88E6XXX_FLAG_SMI_DATA) - -/* Fiber/SERDES Registers at SMI address F, page 1 */ -#define MV88E6XXX_FLAGS_SERDES \ - (MV88E6XXX_FLAG_PHY_PAGE | \ - MV88E6XXX_FLAG_SERDES) - -#define MV88E6XXX_FLAGS_FAMILY_6095 \ - (MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -#define MV88E6XXX_FLAGS_FAMILY_6097 \ - (MV88E6XXX_FLAG_G1_VTU_FID | \ - MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ - MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -#define MV88E6XXX_FLAGS_FAMILY_6165 \ - (MV88E6XXX_FLAG_G1_VTU_FID | \ - MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ - MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -#define MV88E6XXX_FLAGS_FAMILY_6185 \ - (MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -#define MV88E6XXX_FLAGS_FAMILY_6320 \ - (MV88E6XXX_FLAG_EEE | \ - MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ - MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -#define MV88E6XXX_FLAGS_FAMILY_6341 \ - (MV88E6XXX_FLAG_EEE | \ - MV88E6XXX_FLAG_G1_VTU_FID | \ - MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP | \ - MV88E6XXX_FLAGS_SERDES) - -#define MV88E6XXX_FLAGS_FAMILY_6351 \ - (MV88E6XXX_FLAG_G1_VTU_FID | \ - MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ - MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -#define MV88E6XXX_FLAGS_FAMILY_6352 \ - (MV88E6XXX_FLAG_EEE | \ - MV88E6XXX_FLAG_G1_VTU_FID | \ - MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ - MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP | \ - MV88E6XXX_FLAGS_SERDES) - -#define MV88E6XXX_FLAGS_FAMILY_6390 \ - (MV88E6XXX_FLAG_EEE | \ - MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -struct mv88e6xxx_ops; - -struct mv88e6xxx_info { - enum mv88e6xxx_family family; - u16 prod_num; - const char *name; - unsigned int num_databases; - unsigned int num_ports; - unsigned int max_vid; - unsigned int port_base_addr; - unsigned int global1_addr; - unsigned int age_time_coeff; - unsigned int g1_irqs; - bool pvt; - enum dsa_tag_protocol tag_protocol; - unsigned long long flags; - - /* Mask for FromPort and ToPort value of PortVec used in ATU Move - * operation. 0 means that the ATU Move operation is not supported. - */ - u8 atu_move_port_mask; - const struct mv88e6xxx_ops *ops; -}; - -struct mv88e6xxx_atu_entry { - u8 state; - bool trunk; - u16 portvec; - u8 mac[ETH_ALEN]; -}; - -struct mv88e6xxx_vtu_entry { - u16 vid; - u16 fid; - u8 sid; - bool valid; - u8 member[DSA_MAX_PORTS]; - u8 state[DSA_MAX_PORTS]; -}; - -struct mv88e6xxx_bus_ops; -struct mv88e6xxx_irq_ops; - -struct mv88e6xxx_irq { - u16 masked; - struct irq_chip chip; - struct irq_domain *domain; - unsigned int nirqs; -}; - -struct mv88e6xxx_chip { - const struct mv88e6xxx_info *info; - - /* The dsa_switch this private structure is related to */ - struct dsa_switch *ds; - - /* The device this structure is associated to */ - struct device *dev; - - /* This mutex protects the access to the switch registers */ - struct mutex reg_lock; - - /* The MII bus and the address on the bus that is used to - * communication with the switch - */ - const struct mv88e6xxx_bus_ops *smi_ops; - struct mii_bus *bus; - int sw_addr; - - /* Handles automatic disabling and re-enabling of the PHY - * polling unit. - */ - const struct mv88e6xxx_bus_ops *phy_ops; - struct mutex ppu_mutex; - int ppu_disabled; - struct work_struct ppu_work; - struct timer_list ppu_timer; - - /* This mutex serialises access to the statistics unit. - * Hold this mutex over snapshot + dump sequences. - */ - struct mutex stats_mutex; - - /* A switch may have a GPIO line tied to its reset pin. Parse - * this from the device tree, and use it before performing - * switch soft reset. - */ - struct gpio_desc *reset; - - /* set to size of eeprom if supported by the switch */ - int eeprom_len; - - /* List of mdio busses */ - struct list_head mdios; - - /* There can be two interrupt controllers, which are chained - * off a GPIO as interrupt source - */ - struct mv88e6xxx_irq g1_irq; - struct mv88e6xxx_irq g2_irq; - int irq; - int device_irq; - int watchdog_irq; -}; - -struct mv88e6xxx_bus_ops { - int (*read)(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val); - int (*write)(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val); -}; - -struct mv88e6xxx_mdio_bus { - struct mii_bus *bus; - struct mv88e6xxx_chip *chip; - struct list_head list; - bool external; -}; - -struct mv88e6xxx_ops { - int (*get_eeprom)(struct mv88e6xxx_chip *chip, - struct ethtool_eeprom *eeprom, u8 *data); - int (*set_eeprom)(struct mv88e6xxx_chip *chip, - struct ethtool_eeprom *eeprom, u8 *data); - - int (*set_switch_mac)(struct mv88e6xxx_chip *chip, u8 *addr); - - int (*phy_read)(struct mv88e6xxx_chip *chip, - struct mii_bus *bus, - int addr, int reg, u16 *val); - int (*phy_write)(struct mv88e6xxx_chip *chip, - struct mii_bus *bus, - int addr, int reg, u16 val); - - /* PHY Polling Unit (PPU) operations */ - int (*ppu_enable)(struct mv88e6xxx_chip *chip); - int (*ppu_disable)(struct mv88e6xxx_chip *chip); - - /* Switch Software Reset */ - int (*reset)(struct mv88e6xxx_chip *chip); - - /* RGMII Receive/Transmit Timing Control - * Add delay on PHY_INTERFACE_MODE_RGMII_*ID, no delay otherwise. - */ - int (*port_set_rgmii_delay)(struct mv88e6xxx_chip *chip, int port, - phy_interface_t mode); - -#define LINK_FORCED_DOWN 0 -#define LINK_FORCED_UP 1 -#define LINK_UNFORCED -2 - - /* Port's MAC link state - * Use LINK_FORCED_UP or LINK_FORCED_DOWN to force link up or down, - * or LINK_UNFORCED for normal link detection. - */ - int (*port_set_link)(struct mv88e6xxx_chip *chip, int port, int link); - -#define DUPLEX_UNFORCED -2 - - /* Port's MAC duplex mode - * - * Use DUPLEX_HALF or DUPLEX_FULL to force half or full duplex, - * or DUPLEX_UNFORCED for normal duplex detection. - */ - int (*port_set_duplex)(struct mv88e6xxx_chip *chip, int port, int dup); - -#define SPEED_MAX INT_MAX -#define SPEED_UNFORCED -2 - - /* Port's MAC speed (in Mbps) - * - * Depending on the chip, 10, 100, 200, 1000, 2500, 10000 are valid. - * Use SPEED_UNFORCED for normal detection, SPEED_MAX for max value. - */ - int (*port_set_speed)(struct mv88e6xxx_chip *chip, int port, int speed); - - int (*port_tag_remap)(struct mv88e6xxx_chip *chip, int port); - - int (*port_set_frame_mode)(struct mv88e6xxx_chip *chip, int port, - enum mv88e6xxx_frame_mode mode); - int (*port_set_egress_floods)(struct mv88e6xxx_chip *chip, int port, - bool unicast, bool multicast); - int (*port_set_ether_type)(struct mv88e6xxx_chip *chip, int port, - u16 etype); - int (*port_jumbo_config)(struct mv88e6xxx_chip *chip, int port); - - int (*port_egress_rate_limiting)(struct mv88e6xxx_chip *chip, int port); - int (*port_pause_config)(struct mv88e6xxx_chip *chip, int port); - int (*port_disable_learn_limit)(struct mv88e6xxx_chip *chip, int port); - int (*port_disable_pri_override)(struct mv88e6xxx_chip *chip, int port); - - /* CMODE control what PHY mode the MAC will use, eg. SGMII, RGMII, etc. - * Some chips allow this to be configured on specific ports. - */ - int (*port_set_cmode)(struct mv88e6xxx_chip *chip, int port, - phy_interface_t mode); - - /* Some devices have a per port register indicating what is - * the upstream port this port should forward to. - */ - int (*port_set_upstream_port)(struct mv88e6xxx_chip *chip, int port, - int upstream_port); - - /* Snapshot the statistics for a port. The statistics can then - * be read back a leisure but still with a consistent view. - */ - int (*stats_snapshot)(struct mv88e6xxx_chip *chip, int port); - - /* Set the histogram mode for statistics, when the control registers - * are separated out of the STATS_OP register. - */ - int (*stats_set_histogram)(struct mv88e6xxx_chip *chip); - - /* Return the number of strings describing statistics */ - int (*stats_get_sset_count)(struct mv88e6xxx_chip *chip); - void (*stats_get_strings)(struct mv88e6xxx_chip *chip, uint8_t *data); - void (*stats_get_stats)(struct mv88e6xxx_chip *chip, int port, - uint64_t *data); - int (*g1_set_cpu_port)(struct mv88e6xxx_chip *chip, int port); - int (*g1_set_egress_port)(struct mv88e6xxx_chip *chip, int port); - const struct mv88e6xxx_irq_ops *watchdog_ops; - - /* Can be either in g1 or g2, so don't use a prefix */ - int (*mgmt_rsvd2cpu)(struct mv88e6xxx_chip *chip); - - /* VLAN Translation Unit operations */ - int (*vtu_getnext)(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry); - int (*vtu_loadpurge)(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry); -}; - -struct mv88e6xxx_irq_ops { - /* Action to be performed when the interrupt happens */ - int (*irq_action)(struct mv88e6xxx_chip *chip, int irq); - /* Setup the hardware to generate the interrupt */ - int (*irq_setup)(struct mv88e6xxx_chip *chip); - /* Reset the hardware to stop generating the interrupt */ - void (*irq_free)(struct mv88e6xxx_chip *chip); -}; - -#define STATS_TYPE_PORT BIT(0) -#define STATS_TYPE_BANK0 BIT(1) -#define STATS_TYPE_BANK1 BIT(2) - -struct mv88e6xxx_hw_stat { - char string[ETH_GSTRING_LEN]; - int sizeof_stat; - int reg; - int type; -}; - -static inline bool mv88e6xxx_has(struct mv88e6xxx_chip *chip, - unsigned long flags) -{ - return (chip->info->flags & flags) == flags; -} - -static inline bool mv88e6xxx_has_pvt(struct mv88e6xxx_chip *chip) -{ - return chip->info->pvt; -} - -static inline unsigned int mv88e6xxx_num_databases(struct mv88e6xxx_chip *chip) -{ - return chip->info->num_databases; -} - -static inline unsigned int mv88e6xxx_num_ports(struct mv88e6xxx_chip *chip) -{ - return chip->info->num_ports; -} - -static inline u16 mv88e6xxx_port_mask(struct mv88e6xxx_chip *chip) -{ - return GENMASK(mv88e6xxx_num_ports(chip) - 1, 0); -} - -int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val); -int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val); -int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, - u16 update); -int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask); - -#endif diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c new file mode 100644 index 000000000000..0db624f0993c --- /dev/null +++ b/drivers/net/dsa/mv88e6xxx/phy.c @@ -0,0 +1,248 @@ +/* + * Marvell 88e6xxx Ethernet switch PHY and PPU support + * + * Copyright (c) 2008 Marvell Semiconductor + * + * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/mdio.h> +#include <linux/module.h> +#include <net/dsa.h> + +#include "chip.h" +#include "phy.h" + +int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 *val) +{ + return mv88e6xxx_read(chip, addr, reg, val); +} + +int mv88e6165_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 val) +{ + return mv88e6xxx_write(chip, addr, reg, val); +} + +int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy, int reg, u16 *val) +{ + int addr = phy; /* PHY devices addresses start at 0x0 */ + struct mii_bus *bus; + + bus = mv88e6xxx_default_mdio_bus(chip); + if (!bus) + return -EOPNOTSUPP; + + if (!chip->info->ops->phy_read) + return -EOPNOTSUPP; + + return chip->info->ops->phy_read(chip, bus, addr, reg, val); +} + +int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy, int reg, u16 val) +{ + int addr = phy; /* PHY devices addresses start at 0x0 */ + struct mii_bus *bus; + + bus = mv88e6xxx_default_mdio_bus(chip); + if (!bus) + return -EOPNOTSUPP; + + if (!chip->info->ops->phy_write) + return -EOPNOTSUPP; + + return chip->info->ops->phy_write(chip, bus, addr, reg, val); +} + +static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page) +{ + return mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page); +} + +static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy) +{ + int err; + + /* Restore PHY page Copper 0x0 for access via the registered + * MDIO bus + */ + err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, PHY_PAGE_COPPER); + if (unlikely(err)) { + dev_err(chip->dev, + "failed to restore PHY %d page Copper (%d)\n", + phy, err); + } +} + +int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy, + u8 page, int reg, u16 *val) +{ + int err; + + /* There is no paging for registers 22 */ + if (reg == PHY_PAGE) + return -EINVAL; + + err = mv88e6xxx_phy_page_get(chip, phy, page); + if (!err) { + err = mv88e6xxx_phy_read(chip, phy, reg, val); + mv88e6xxx_phy_page_put(chip, phy); + } + + return err; +} + +int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy, + u8 page, int reg, u16 val) +{ + int err; + + /* There is no paging for registers 22 */ + if (reg == PHY_PAGE) + return -EINVAL; + + err = mv88e6xxx_phy_page_get(chip, phy, page); + if (!err) { + err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page); + mv88e6xxx_phy_page_put(chip, phy); + } + + return err; +} + +static int mv88e6xxx_phy_ppu_disable(struct mv88e6xxx_chip *chip) +{ + if (!chip->info->ops->ppu_disable) + return 0; + + return chip->info->ops->ppu_disable(chip); +} + +static int mv88e6xxx_phy_ppu_enable(struct mv88e6xxx_chip *chip) +{ + if (!chip->info->ops->ppu_enable) + return 0; + + return chip->info->ops->ppu_enable(chip); +} + +static void mv88e6xxx_phy_ppu_reenable_work(struct work_struct *ugly) +{ + struct mv88e6xxx_chip *chip; + + chip = container_of(ugly, struct mv88e6xxx_chip, ppu_work); + + mutex_lock(&chip->reg_lock); + + if (mutex_trylock(&chip->ppu_mutex)) { + if (mv88e6xxx_phy_ppu_enable(chip) == 0) + chip->ppu_disabled = 0; + mutex_unlock(&chip->ppu_mutex); + } + + mutex_unlock(&chip->reg_lock); +} + +static void mv88e6xxx_phy_ppu_reenable_timer(unsigned long _ps) +{ + struct mv88e6xxx_chip *chip = (void *)_ps; + + schedule_work(&chip->ppu_work); +} + +static int mv88e6xxx_phy_ppu_access_get(struct mv88e6xxx_chip *chip) +{ + int ret; + + mutex_lock(&chip->ppu_mutex); + + /* If the PHY polling unit is enabled, disable it so that + * we can access the PHY registers. If it was already + * disabled, cancel the timer that is going to re-enable + * it. + */ + if (!chip->ppu_disabled) { + ret = mv88e6xxx_phy_ppu_disable(chip); + if (ret < 0) { + mutex_unlock(&chip->ppu_mutex); + return ret; + } + chip->ppu_disabled = 1; + } else { + del_timer(&chip->ppu_timer); + ret = 0; + } + + return ret; +} + +static void mv88e6xxx_phy_ppu_access_put(struct mv88e6xxx_chip *chip) +{ + /* Schedule a timer to re-enable the PHY polling unit. */ + mod_timer(&chip->ppu_timer, jiffies + msecs_to_jiffies(10)); + mutex_unlock(&chip->ppu_mutex); +} + +static void mv88e6xxx_phy_ppu_state_init(struct mv88e6xxx_chip *chip) +{ + mutex_init(&chip->ppu_mutex); + INIT_WORK(&chip->ppu_work, mv88e6xxx_phy_ppu_reenable_work); + setup_timer(&chip->ppu_timer, mv88e6xxx_phy_ppu_reenable_timer, + (unsigned long)chip); +} + +static void mv88e6xxx_phy_ppu_state_destroy(struct mv88e6xxx_chip *chip) +{ + del_timer_sync(&chip->ppu_timer); +} + +int mv88e6185_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 *val) +{ + int err; + + err = mv88e6xxx_phy_ppu_access_get(chip); + if (!err) { + err = mv88e6xxx_read(chip, addr, reg, val); + mv88e6xxx_phy_ppu_access_put(chip); + } + + return err; +} + +int mv88e6185_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 val) +{ + int err; + + err = mv88e6xxx_phy_ppu_access_get(chip); + if (!err) { + err = mv88e6xxx_write(chip, addr, reg, val); + mv88e6xxx_phy_ppu_access_put(chip); + } + + return err; +} + +void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip) +{ + if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable) + mv88e6xxx_phy_ppu_state_init(chip); +} + +void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip) +{ + if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable) + mv88e6xxx_phy_ppu_state_destroy(chip); +} + +int mv88e6xxx_phy_setup(struct mv88e6xxx_chip *chip) +{ + return mv88e6xxx_phy_ppu_enable(chip); +} diff --git a/drivers/net/dsa/mv88e6xxx/phy.h b/drivers/net/dsa/mv88e6xxx/phy.h new file mode 100644 index 000000000000..4131a4e8206a --- /dev/null +++ b/drivers/net/dsa/mv88e6xxx/phy.h @@ -0,0 +1,43 @@ +/* + * Marvell 88E6xxx PHY access + * + * Copyright (c) 2008 Marvell Semiconductor + * + * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _MV88E6XXX_PHY_H +#define _MV88E6XXX_PHY_H + +#define PHY_PAGE 0x16 +#define PHY_PAGE_COPPER 0x00 + +/* PHY Registers accesses implementations */ +int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 *val); +int mv88e6165_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 val); +int mv88e6185_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 *val); +int mv88e6185_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 val); + +/* Generic PHY operations */ +int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy, + int reg, u16 *val); +int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy, + int reg, u16 val); +int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy, + u8 page, int reg, u16 *val); +int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy, + u8 page, int reg, u16 val); +void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip); +void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip); +int mv88e6xxx_phy_setup(struct mv88e6xxx_chip *chip); + +#endif /*_MV88E6XXX_PHY_H */ diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 548a956637ee..3719ece60c61 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -13,7 +13,8 @@ */ #include <linux/phy.h> -#include "mv88e6xxx.h" + +#include "chip.h" #include "port.h" int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg, @@ -450,7 +451,7 @@ int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, if (err) return err; - reg &= ~PORT_CONTROL_FRAME_MODE_DSA; + reg &= ~PORT_CONTROL_FRAME_MASK; switch (mode) { case MV88E6XXX_FRAME_MODE_NORMAL: diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 86f40887b6d2..4f5e1ccfadc6 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -15,7 +15,167 @@ #ifndef _MV88E6XXX_PORT_H #define _MV88E6XXX_PORT_H -#include "mv88e6xxx.h" +#include "chip.h" + +#define PORT_STATUS 0x00 +#define PORT_STATUS_PAUSE_EN BIT(15) +#define PORT_STATUS_MY_PAUSE BIT(14) +#define PORT_STATUS_HD_FLOW BIT(13) +#define PORT_STATUS_PHY_DETECT BIT(12) +#define PORT_STATUS_LINK BIT(11) +#define PORT_STATUS_DUPLEX BIT(10) +#define PORT_STATUS_SPEED_MASK 0x0300 +#define PORT_STATUS_SPEED_10 0x0000 +#define PORT_STATUS_SPEED_100 0x0100 +#define PORT_STATUS_SPEED_1000 0x0200 +#define PORT_STATUS_EEE BIT(6) /* 6352 */ +#define PORT_STATUS_AM_DIS BIT(6) /* 6165 */ +#define PORT_STATUS_MGMII BIT(6) /* 6185 */ +#define PORT_STATUS_TX_PAUSED BIT(5) +#define PORT_STATUS_FLOW_CTRL BIT(4) +#define PORT_STATUS_CMODE_MASK 0x0f +#define PORT_STATUS_CMODE_100BASE_X 0x8 +#define PORT_STATUS_CMODE_1000BASE_X 0x9 +#define PORT_STATUS_CMODE_SGMII 0xa +#define PORT_STATUS_CMODE_2500BASEX 0xb +#define PORT_STATUS_CMODE_XAUI 0xc +#define PORT_STATUS_CMODE_RXAUI 0xd +#define PORT_PCS_CTRL 0x01 +#define PORT_PCS_CTRL_RGMII_DELAY_RXCLK BIT(15) +#define PORT_PCS_CTRL_RGMII_DELAY_TXCLK BIT(14) +#define PORT_PCS_CTRL_FORCE_SPEED BIT(13) /* 6390 */ +#define PORT_PCS_CTRL_ALTSPEED BIT(12) /* 6390 */ +#define PORT_PCS_CTRL_200BASE BIT(12) /* 6352 */ +#define PORT_PCS_CTRL_FC BIT(7) +#define PORT_PCS_CTRL_FORCE_FC BIT(6) +#define PORT_PCS_CTRL_LINK_UP BIT(5) +#define PORT_PCS_CTRL_FORCE_LINK BIT(4) +#define PORT_PCS_CTRL_DUPLEX_FULL BIT(3) +#define PORT_PCS_CTRL_FORCE_DUPLEX BIT(2) +#define PORT_PCS_CTRL_SPEED_MASK (0x03) +#define PORT_PCS_CTRL_SPEED_10 (0x00) +#define PORT_PCS_CTRL_SPEED_100 (0x01) +#define PORT_PCS_CTRL_SPEED_200 (0x02) /* 6065 and non Gb chips */ +#define PORT_PCS_CTRL_SPEED_1000 (0x02) +#define PORT_PCS_CTRL_SPEED_10000 (0x03) /* 6390X */ +#define PORT_PCS_CTRL_SPEED_UNFORCED (0x03) +#define PORT_PAUSE_CTRL 0x02 +#define PORT_FLOW_CTRL_LIMIT_IN ((0x00 << 8) | BIT(15)) +#define PORT_FLOW_CTRL_LIMIT_OUT ((0x01 << 8) | BIT(15)) +#define PORT_SWITCH_ID 0x03 +#define PORT_SWITCH_ID_PROD_NUM_6085 0x04a +#define PORT_SWITCH_ID_PROD_NUM_6095 0x095 +#define PORT_SWITCH_ID_PROD_NUM_6097 0x099 +#define PORT_SWITCH_ID_PROD_NUM_6131 0x106 +#define PORT_SWITCH_ID_PROD_NUM_6320 0x115 +#define PORT_SWITCH_ID_PROD_NUM_6123 0x121 +#define PORT_SWITCH_ID_PROD_NUM_6141 0x340 +#define PORT_SWITCH_ID_PROD_NUM_6161 0x161 +#define PORT_SWITCH_ID_PROD_NUM_6165 0x165 +#define PORT_SWITCH_ID_PROD_NUM_6171 0x171 +#define PORT_SWITCH_ID_PROD_NUM_6172 0x172 +#define PORT_SWITCH_ID_PROD_NUM_6175 0x175 +#define PORT_SWITCH_ID_PROD_NUM_6176 0x176 +#define PORT_SWITCH_ID_PROD_NUM_6185 0x1a7 +#define PORT_SWITCH_ID_PROD_NUM_6190 0x190 +#define PORT_SWITCH_ID_PROD_NUM_6190X 0x0a0 +#define PORT_SWITCH_ID_PROD_NUM_6191 0x191 +#define PORT_SWITCH_ID_PROD_NUM_6240 0x240 +#define PORT_SWITCH_ID_PROD_NUM_6290 0x290 +#define PORT_SWITCH_ID_PROD_NUM_6321 0x310 +#define PORT_SWITCH_ID_PROD_NUM_6341 0x341 +#define PORT_SWITCH_ID_PROD_NUM_6352 0x352 +#define PORT_SWITCH_ID_PROD_NUM_6350 0x371 +#define PORT_SWITCH_ID_PROD_NUM_6351 0x375 +#define PORT_SWITCH_ID_PROD_NUM_6390 0x390 +#define PORT_SWITCH_ID_PROD_NUM_6390X 0x0a1 +#define PORT_CONTROL 0x04 +#define PORT_CONTROL_USE_CORE_TAG BIT(15) +#define PORT_CONTROL_DROP_ON_LOCK BIT(14) +#define PORT_CONTROL_EGRESS_UNMODIFIED (0x0 << 12) +#define PORT_CONTROL_EGRESS_UNTAGGED (0x1 << 12) +#define PORT_CONTROL_EGRESS_TAGGED (0x2 << 12) +#define PORT_CONTROL_EGRESS_ADD_TAG (0x3 << 12) +#define PORT_CONTROL_EGRESS_MASK (0x3 << 12) +#define PORT_CONTROL_HEADER BIT(11) +#define PORT_CONTROL_IGMP_MLD_SNOOP BIT(10) +#define PORT_CONTROL_DOUBLE_TAG BIT(9) +#define PORT_CONTROL_FRAME_MODE_NORMAL (0x0 << 8) +#define PORT_CONTROL_FRAME_MODE_DSA (0x1 << 8) +#define PORT_CONTROL_FRAME_MODE_PROVIDER (0x2 << 8) +#define PORT_CONTROL_FRAME_ETHER_TYPE_DSA (0x3 << 8) +#define PORT_CONTROL_FRAME_MASK (0x3 << 8) +#define PORT_CONTROL_DSA_TAG BIT(8) +#define PORT_CONTROL_VLAN_TUNNEL BIT(7) +#define PORT_CONTROL_TAG_IF_BOTH BIT(6) +#define PORT_CONTROL_USE_IP BIT(5) +#define PORT_CONTROL_USE_TAG BIT(4) +#define PORT_CONTROL_FORWARD_UNKNOWN BIT(2) +#define PORT_CONTROL_EGRESS_FLOODS_MASK (0x3 << 2) +#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_DA (0x0 << 2) +#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_MC_DA (0x1 << 2) +#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_UC_DA (0x2 << 2) +#define PORT_CONTROL_EGRESS_FLOODS_ALL_UNKNOWN_DA (0x3 << 2) +#define PORT_CONTROL_STATE_MASK 0x03 +#define PORT_CONTROL_STATE_DISABLED 0x00 +#define PORT_CONTROL_STATE_BLOCKING 0x01 +#define PORT_CONTROL_STATE_LEARNING 0x02 +#define PORT_CONTROL_STATE_FORWARDING 0x03 +#define PORT_CONTROL_1 0x05 +#define PORT_CONTROL_1_MESSAGE_PORT BIT(15) +#define PORT_CONTROL_1_FID_11_4_MASK (0xff << 0) +#define PORT_BASE_VLAN 0x06 +#define PORT_BASE_VLAN_FID_3_0_MASK (0xf << 12) +#define PORT_DEFAULT_VLAN 0x07 +#define PORT_DEFAULT_VLAN_MASK 0xfff +#define PORT_CONTROL_2 0x08 +#define PORT_CONTROL_2_IGNORE_FCS BIT(15) +#define PORT_CONTROL_2_VTU_PRI_OVERRIDE BIT(14) +#define PORT_CONTROL_2_SA_PRIO_OVERRIDE BIT(13) +#define PORT_CONTROL_2_DA_PRIO_OVERRIDE BIT(12) +#define PORT_CONTROL_2_JUMBO_1522 (0x00 << 12) +#define PORT_CONTROL_2_JUMBO_2048 (0x01 << 12) +#define PORT_CONTROL_2_JUMBO_10240 (0x02 << 12) +#define PORT_CONTROL_2_8021Q_MASK (0x03 << 10) +#define PORT_CONTROL_2_8021Q_DISABLED (0x00 << 10) +#define PORT_CONTROL_2_8021Q_FALLBACK (0x01 << 10) +#define PORT_CONTROL_2_8021Q_CHECK (0x02 << 10) +#define PORT_CONTROL_2_8021Q_SECURE (0x03 << 10) +#define PORT_CONTROL_2_DISCARD_TAGGED BIT(9) +#define PORT_CONTROL_2_DISCARD_UNTAGGED BIT(8) +#define PORT_CONTROL_2_MAP_DA BIT(7) +#define PORT_CONTROL_2_DEFAULT_FORWARD BIT(6) +#define PORT_CONTROL_2_EGRESS_MONITOR BIT(5) +#define PORT_CONTROL_2_INGRESS_MONITOR BIT(4) +#define PORT_CONTROL_2_UPSTREAM_MASK 0x0f +#define PORT_RATE_CONTROL 0x09 +#define PORT_RATE_CONTROL_2 0x0a +#define PORT_ASSOC_VECTOR 0x0b +#define PORT_ASSOC_VECTOR_HOLD_AT_1 BIT(15) +#define PORT_ASSOC_VECTOR_INT_AGE_OUT BIT(14) +#define PORT_ASSOC_VECTOR_LOCKED_PORT BIT(13) +#define PORT_ASSOC_VECTOR_IGNORE_WRONG BIT(12) +#define PORT_ASSOC_VECTOR_REFRESH_LOCKED BIT(11) +#define PORT_ATU_CONTROL 0x0c +#define PORT_PRI_OVERRIDE 0x0d +#define PORT_ETH_TYPE 0x0f +#define PORT_ETH_TYPE_DEFAULT 0x9100 +#define PORT_IN_DISCARD_LO 0x10 +#define PORT_IN_DISCARD_HI 0x11 +#define PORT_IN_FILTERED 0x12 +#define PORT_OUT_FILTERED 0x13 +#define PORT_TAG_REGMAP_0123 0x18 +#define PORT_TAG_REGMAP_4567 0x19 +#define PORT_IEEE_PRIO_MAP_TABLE 0x18 /* 6390 */ +#define PORT_IEEE_PRIO_MAP_TABLE_UPDATE BIT(15) +#define PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP (0x0 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP (0x1 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP (0x2 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP (0x3 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_DSCP (0x5 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_DSCP (0x6 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_DSCP (0x7 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT 9 int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg, u16 *val); diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c new file mode 100644 index 000000000000..78f5b1eb44ea --- /dev/null +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -0,0 +1,229 @@ +/* + * Marvell 88E6xxx SERDES manipulation, via SMI bus + * + * Copyright (c) 2008 Marvell Semiconductor + * + * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/mii.h> + +#include "chip.h" +#include "global2.h" +#include "phy.h" +#include "port.h" +#include "serdes.h" + +static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg, + u16 *val) +{ + return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES, + MV88E6352_SERDES_PAGE_FIBER, + reg, val); +} + +static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg, + u16 val) +{ + return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES, + MV88E6352_SERDES_PAGE_FIBER, + reg, val); +} + +static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on) +{ + u16 val, new_val; + int err; + + err = mv88e6352_serdes_read(chip, MII_BMCR, &val); + if (err) + return err; + + if (on) + new_val = val & ~BMCR_PDOWN; + else + new_val = val | BMCR_PDOWN; + + if (val != new_val) + err = mv88e6352_serdes_write(chip, MII_BMCR, new_val); + + return err; +} + +int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) +{ + int err; + u8 cmode; + + err = mv88e6xxx_port_get_cmode(chip, port, &cmode); + if (err) + return err; + + if ((cmode == PORT_STATUS_CMODE_100BASE_X) || + (cmode == PORT_STATUS_CMODE_1000BASE_X) || + (cmode == PORT_STATUS_CMODE_SGMII)) { + err = mv88e6352_serdes_power_set(chip, on); + if (err < 0) + return err; + } + + return 0; +} + +/* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */ +static int mv88e6390_serdes_10g(struct mv88e6xxx_chip *chip, int addr, bool on) +{ + u16 val, new_val; + int reg_c45; + int err; + + reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE | + MV88E6390_PCS_CONTROL_1; + err = mv88e6xxx_phy_read(chip, addr, reg_c45, &val); + if (err) + return err; + + if (on) + new_val = val & ~(MV88E6390_PCS_CONTROL_1_RESET | + MV88E6390_PCS_CONTROL_1_LOOPBACK | + MV88E6390_PCS_CONTROL_1_PDOWN); + else + new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN; + + if (val != new_val) + err = mv88e6xxx_phy_write(chip, addr, reg_c45, new_val); + + return err; +} + +/* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */ +static int mv88e6390_serdes_sgmii(struct mv88e6xxx_chip *chip, int addr, + bool on) +{ + u16 val, new_val; + int reg_c45; + int err; + + reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE | + MV88E6390_SGMII_CONTROL; + err = mv88e6xxx_phy_read(chip, addr, reg_c45, &val); + if (err) + return err; + + if (on) + new_val = val & ~(MV88E6390_SGMII_CONTROL_RESET | + MV88E6390_SGMII_CONTROL_LOOPBACK | + MV88E6390_SGMII_CONTROL_PDOWN); + else + new_val = val | MV88E6390_SGMII_CONTROL_PDOWN; + + if (val != new_val) + err = mv88e6xxx_phy_write(chip, addr, reg_c45, new_val); + + return err; +} + +static int mv88e6390_serdes_lower(struct mv88e6xxx_chip *chip, u8 cmode, + int port_donor, int lane, bool rxaui, bool on) +{ + int err; + u8 cmode_donor; + + err = mv88e6xxx_port_get_cmode(chip, port_donor, &cmode_donor); + if (err) + return err; + + switch (cmode_donor) { + case PORT_STATUS_CMODE_RXAUI: + if (!rxaui) + break; + /* Fall through */ + case PORT_STATUS_CMODE_1000BASE_X: + case PORT_STATUS_CMODE_SGMII: + case PORT_STATUS_CMODE_2500BASEX: + if (cmode == PORT_STATUS_CMODE_1000BASE_X || + cmode == PORT_STATUS_CMODE_SGMII) + return mv88e6390_serdes_sgmii(chip, lane, on); + } + return 0; +} + +static int mv88e6390_serdes_port9(struct mv88e6xxx_chip *chip, u8 cmode, + bool on) +{ + switch (cmode) { + case PORT_STATUS_CMODE_1000BASE_X: + case PORT_STATUS_CMODE_SGMII: + return mv88e6390_serdes_sgmii(chip, MV88E6390_PORT9_LANE0, on); + case PORT_STATUS_CMODE_XAUI: + case PORT_STATUS_CMODE_RXAUI: + case PORT_STATUS_CMODE_2500BASEX: + return mv88e6390_serdes_10g(chip, MV88E6390_PORT9_LANE0, on); + } + + return 0; +} + +static int mv88e6390_serdes_port10(struct mv88e6xxx_chip *chip, u8 cmode, + bool on) +{ + switch (cmode) { + case PORT_STATUS_CMODE_SGMII: + return mv88e6390_serdes_sgmii(chip, MV88E6390_PORT10_LANE0, on); + case PORT_STATUS_CMODE_XAUI: + case PORT_STATUS_CMODE_RXAUI: + case PORT_STATUS_CMODE_1000BASE_X: + case PORT_STATUS_CMODE_2500BASEX: + return mv88e6390_serdes_10g(chip, MV88E6390_PORT10_LANE0, on); + } + + return 0; +} + +int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) +{ + u8 cmode; + int err; + + err = mv88e6xxx_port_get_cmode(chip, port, &cmode); + if (err) + return cmode; + + switch (port) { + case 2: + return mv88e6390_serdes_lower(chip, cmode, 9, + MV88E6390_PORT9_LANE1, + false, on); + case 3: + return mv88e6390_serdes_lower(chip, cmode, 9, + MV88E6390_PORT9_LANE2, + true, on); + case 4: + return mv88e6390_serdes_lower(chip, cmode, 9, + MV88E6390_PORT9_LANE3, + true, on); + case 5: + return mv88e6390_serdes_lower(chip, cmode, 10, + MV88E6390_PORT10_LANE1, + false, on); + case 6: + return mv88e6390_serdes_lower(chip, cmode, 10, + MV88E6390_PORT10_LANE2, + true, on); + case 7: + return mv88e6390_serdes_lower(chip, cmode, 10, + MV88E6390_PORT10_LANE3, + true, on); + case 9: + return mv88e6390_serdes_port9(chip, cmode, on); + case 10: + return mv88e6390_serdes_port10(chip, cmode, on); + } + + return 0; +} diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h new file mode 100644 index 000000000000..5c1cd6d8e9a5 --- /dev/null +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -0,0 +1,48 @@ +/* + * Marvell 88E6xxx SERDES manipulation, via SMI bus + * + * Copyright (c) 2008 Marvell Semiconductor + * + * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _MV88E6XXX_SERDES_H +#define _MV88E6XXX_SERDES_H + +#include "chip.h" + +#define MV88E6352_ADDR_SERDES 0x0f +#define MV88E6352_SERDES_PAGE_FIBER 0x01 + +#define MV88E6390_PORT9_LANE0 0x09 +#define MV88E6390_PORT9_LANE1 0x12 +#define MV88E6390_PORT9_LANE2 0x13 +#define MV88E6390_PORT9_LANE3 0x14 +#define MV88E6390_PORT10_LANE0 0x0a +#define MV88E6390_PORT10_LANE1 0x15 +#define MV88E6390_PORT10_LANE2 0x16 +#define MV88E6390_PORT10_LANE3 0x17 +#define MV88E6390_SERDES_DEVICE (4 << 16) + +/* 10GBASE-R and 10GBASE-X4/X2 */ +#define MV88E6390_PCS_CONTROL_1 0x1000 +#define MV88E6390_PCS_CONTROL_1_RESET BIT(15) +#define MV88E6390_PCS_CONTROL_1_LOOPBACK BIT(14) +#define MV88E6390_PCS_CONTROL_1_SPEED BIT(13) +#define MV88E6390_PCS_CONTROL_1_PDOWN BIT(11) + +/* 1000BASE-X and SGMII */ +#define MV88E6390_SGMII_CONTROL 0x2000 +#define MV88E6390_SGMII_CONTROL_RESET BIT(15) +#define MV88E6390_SGMII_CONTROL_LOOPBACK BIT(14) +#define MV88E6390_SGMII_CONTROL_PDOWN BIT(11) + +int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on); +int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on); + +#endif diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index a4fd4ccf7b67..b3bee7eab45f 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -18,7 +18,6 @@ #include <linux/phy.h> #include <linux/netdevice.h> #include <net/dsa.h> -#include <net/switchdev.h> #include <linux/of_net.h> #include <linux/of_platform.h> #include <linux/if_bridge.h> @@ -507,7 +506,7 @@ qca8k_setup(struct dsa_switch *ds) pr_warn("regmap initialization failed"); /* Initialize CPU port pad mode (xMII type, delays...) */ - phy_mode = of_get_phy_mode(ds->ports[ds->dst->cpu_port].dn); + phy_mode = of_get_phy_mode(ds->dst->cpu_dp->dn); if (phy_mode < 0) { pr_err("Can't find phy-mode for master device\n"); return phy_mode; @@ -873,7 +872,7 @@ qca8k_port_fdb_del(struct dsa_switch *ds, int port, static int qca8k_port_fdb_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_fdb *fdb, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; struct qca8k_fdb _fdb = { 0 }; @@ -959,7 +958,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev) mutex_init(&priv->reg_mutex); dev_set_drvdata(&mdiodev->dev, priv); - return dsa_register_switch(priv->ds, &mdiodev->dev); + return dsa_register_switch(priv->ds); } static void diff --git a/drivers/net/ethernet/3com/3c509.c b/drivers/net/ethernet/3com/3c509.c index db8592d412ab..f66c9710cb81 100644 --- a/drivers/net/ethernet/3com/3c509.c +++ b/drivers/net/ethernet/3com/3c509.c @@ -1039,7 +1039,7 @@ el3_link_ok(struct net_device *dev) return tmp & (1<<11); } -static int +static void el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_link_ksettings *cmd) { u16 tmp; @@ -1082,7 +1082,6 @@ el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_link_ksettings *cmd) supported); cmd->base.speed = SPEED_10; EL3WINDOW(1); - return 0; } static int @@ -1151,12 +1150,11 @@ static int el3_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct el3_private *lp = netdev_priv(dev); - int ret; spin_lock_irq(&lp->lock); - ret = el3_netdev_get_ecmd(dev, cmd); + el3_netdev_get_ecmd(dev, cmd); spin_unlock_irq(&lp->lock); - return ret; + return 0; } static int el3_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index e41245a54f8b..14cff6017756 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -2912,7 +2912,9 @@ static int vortex_get_link_ksettings(struct net_device *dev, { struct vortex_private *vp = netdev_priv(dev); - return mii_ethtool_get_link_ksettings(&vp->mii, cmd); + mii_ethtool_get_link_ksettings(&vp->mii, cmd); + + return 0; } static int vortex_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index db02bc2fb4b2..05d9d3e2e92e 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -723,6 +723,12 @@ static int ax_init_dev(struct net_device *dev) ax->plat->mac_addr) memcpy(dev->dev_addr, ax->plat->mac_addr, ETH_ALEN); + if (!is_valid_ether_addr(dev->dev_addr)) { + eth_hw_addr_random(dev); + dev_info(&dev->dev, "Using random MAC address: %pM\n", + dev->dev_addr); + } + ax_reset_8390(dev); ei_local->name = "AX88796"; diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c index 86369d7c9a0f..7f60d17819ce 100644 --- a/drivers/net/ethernet/amd/pcnet32.c +++ b/drivers/net/ethernet/amd/pcnet32.c @@ -731,12 +731,10 @@ static int pcnet32_get_link_ksettings(struct net_device *dev, { struct pcnet32_private *lp = netdev_priv(dev); unsigned long flags; - int r = -EOPNOTSUPP; spin_lock_irqsave(&lp->lock, flags); if (lp->mii) { mii_ethtool_get_link_ksettings(&lp->mii_if, cmd); - r = 0; } else if (lp->chip_version == PCNET32_79C970A) { if (lp->autoneg) { cmd->base.autoneg = AUTONEG_ENABLE; @@ -753,10 +751,9 @@ static int pcnet32_get_link_ksettings(struct net_device *dev, ethtool_convert_legacy_u32_to_link_mode( cmd->link_modes.supported, SUPPORTED_TP | SUPPORTED_AUI); - r = 0; } spin_unlock_irqrestore(&lp->lock, flags); - return r; + return 0; } static int pcnet32_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index c772420fa41c..5a2ad9c5faab 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1268,6 +1268,7 @@ static int xgbe_set_hwtstamp_settings(struct xgbe_prv_data *pdata, case HWTSTAMP_FILTER_NONE: break; + case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENALL, 1); XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); @@ -1390,8 +1391,7 @@ static void xgbe_prep_tx_tstamp(struct xgbe_prv_data *pdata, spin_unlock_irqrestore(&pdata->tstamp_lock, flags); } - if (!XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, PTP)) - skb_tx_timestamp(skb); + skb_tx_timestamp(skb); } static void xgbe_prep_vlan(struct sk_buff *skb, struct xgbe_packet_data *packet) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c index 28fdedc30b74..559963b1aa32 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c @@ -23,9 +23,17 @@ struct xgene_gstrings_stats { char name[ETH_GSTRING_LEN]; int offset; + u32 addr; + u32 mask; }; -#define XGENE_STAT(m) { #m, offsetof(struct xgene_enet_pdata, stats.m) } +#define XGENE_STAT(m) { #m, offsetof(struct rtnl_link_stats64, m) } +#define XGENE_EXTD_STAT(s, a, m) \ + { \ + .name = #s, \ + .addr = a ## _ADDR, \ + .mask = m \ + } static const struct xgene_gstrings_stats gstrings_stats[] = { XGENE_STAT(rx_packets), @@ -40,7 +48,65 @@ static const struct xgene_gstrings_stats gstrings_stats[] = { XGENE_STAT(rx_fifo_errors) }; +static const struct xgene_gstrings_stats gstrings_extd_stats[] = { + XGENE_EXTD_STAT(tx_rx_64b_frame_cntr, TR64, 31), + XGENE_EXTD_STAT(tx_rx_127b_frame_cntr, TR127, 31), + XGENE_EXTD_STAT(tx_rx_255b_frame_cntr, TR255, 31), + XGENE_EXTD_STAT(tx_rx_511b_frame_cntr, TR511, 31), + XGENE_EXTD_STAT(tx_rx_1023b_frame_cntr, TR1K, 31), + XGENE_EXTD_STAT(tx_rx_1518b_frame_cntr, TRMAX, 31), + XGENE_EXTD_STAT(tx_rx_1522b_frame_cntr, TRMGV, 31), + XGENE_EXTD_STAT(rx_fcs_error_cntr, RFCS, 16), + XGENE_EXTD_STAT(rx_multicast_pkt_cntr, RMCA, 31), + XGENE_EXTD_STAT(rx_broadcast_pkt_cntr, RBCA, 31), + XGENE_EXTD_STAT(rx_ctrl_frame_pkt_cntr, RXCF, 16), + XGENE_EXTD_STAT(rx_pause_frame_pkt_cntr, RXPF, 16), + XGENE_EXTD_STAT(rx_unk_opcode_cntr, RXUO, 16), + XGENE_EXTD_STAT(rx_align_err_cntr, RALN, 16), + XGENE_EXTD_STAT(rx_frame_len_err_cntr, RFLR, 16), + XGENE_EXTD_STAT(rx_frame_len_err_recov_cntr, DUMP, 0), + XGENE_EXTD_STAT(rx_code_err_cntr, RCDE, 16), + XGENE_EXTD_STAT(rx_carrier_sense_err_cntr, RCSE, 16), + XGENE_EXTD_STAT(rx_undersize_pkt_cntr, RUND, 16), + XGENE_EXTD_STAT(rx_oversize_pkt_cntr, ROVR, 16), + XGENE_EXTD_STAT(rx_fragments_cntr, RFRG, 16), + XGENE_EXTD_STAT(rx_jabber_cntr, RJBR, 16), + XGENE_EXTD_STAT(rx_jabber_recov_cntr, DUMP, 0), + XGENE_EXTD_STAT(rx_dropped_pkt_cntr, RDRP, 16), + XGENE_EXTD_STAT(rx_overrun_cntr, DUMP, 0), + XGENE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA, 31), + XGENE_EXTD_STAT(tx_broadcast_pkt_cntr, TBCA, 31), + XGENE_EXTD_STAT(tx_pause_ctrl_frame_cntr, TXPF, 16), + XGENE_EXTD_STAT(tx_defer_pkt_cntr, TDFR, 31), + XGENE_EXTD_STAT(tx_excv_defer_pkt_cntr, TEDF, 31), + XGENE_EXTD_STAT(tx_single_col_pkt_cntr, TSCL, 31), + XGENE_EXTD_STAT(tx_multi_col_pkt_cntr, TMCL, 31), + XGENE_EXTD_STAT(tx_late_col_pkt_cntr, TLCL, 31), + XGENE_EXTD_STAT(tx_excv_col_pkt_cntr, TXCL, 31), + XGENE_EXTD_STAT(tx_total_col_cntr, TNCL, 31), + XGENE_EXTD_STAT(tx_pause_frames_hnrd_cntr, TPFH, 16), + XGENE_EXTD_STAT(tx_drop_frame_cntr, TDRP, 16), + XGENE_EXTD_STAT(tx_jabber_frame_cntr, TJBR, 12), + XGENE_EXTD_STAT(tx_fcs_error_cntr, TFCS, 12), + XGENE_EXTD_STAT(tx_ctrl_frame_cntr, TXCF, 12), + XGENE_EXTD_STAT(tx_oversize_frame_cntr, TOVR, 12), + XGENE_EXTD_STAT(tx_undersize_frame_cntr, TUND, 12), + XGENE_EXTD_STAT(tx_fragments_cntr, TFRG, 12), + XGENE_EXTD_STAT(tx_underrun_cntr, DUMP, 0) +}; + #define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats) +#define XGENE_EXTD_STATS_LEN ARRAY_SIZE(gstrings_extd_stats) +#define RFCS_IDX 7 +#define RALN_IDX 13 +#define RFLR_IDX 14 +#define FALSE_RFLR_IDX 15 +#define RUND_IDX 18 +#define FALSE_RJBR_IDX 22 +#define RX_OVERRUN_IDX 24 +#define TFCS_IDX 38 +#define TFRG_IDX 42 +#define TX_UNDERRUN_IDX 43 static void xgene_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) @@ -61,7 +127,7 @@ static int xgene_get_link_ksettings(struct net_device *ndev, struct phy_device *phydev = ndev->phydev; u32 supported; - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { + if (phy_interface_mode_is_rgmii(pdata->phy_mode)) { if (phydev == NULL) return -ENODEV; @@ -111,7 +177,7 @@ static int xgene_set_link_ksettings(struct net_device *ndev, struct xgene_enet_pdata *pdata = netdev_priv(ndev); struct phy_device *phydev = ndev->phydev; - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { + if (phy_interface_mode_is_rgmii(pdata->phy_mode)) { if (!phydev) return -ENODEV; @@ -142,6 +208,11 @@ static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data) memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } + + for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) { + memcpy(p, gstrings_extd_stats[i].name, ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } } static int xgene_get_sset_count(struct net_device *ndev, int sset) @@ -149,18 +220,71 @@ static int xgene_get_sset_count(struct net_device *ndev, int sset) if (sset != ETH_SS_STATS) return -EINVAL; - return XGENE_STATS_LEN; + return XGENE_STATS_LEN + XGENE_EXTD_STATS_LEN; +} + +static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata) +{ + u32 rx_drop, tx_drop; + u32 mask, tmp; + int i; + + for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) { + tmp = xgene_enet_rd_stat(pdata, gstrings_extd_stats[i].addr); + if (gstrings_extd_stats[i].mask) { + mask = GENMASK(gstrings_extd_stats[i].mask - 1, 0); + pdata->extd_stats[i] += (tmp & mask); + } + } + + if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) { + /* Errata 10GE_10 - SW should intepret RALN as 0 */ + pdata->extd_stats[RALN_IDX] = 0; + } else { + /* Errata ENET_15 - Fixes RFCS, RFLR, TFCS counter */ + pdata->extd_stats[RFCS_IDX] -= pdata->extd_stats[RALN_IDX]; + pdata->extd_stats[RFLR_IDX] -= pdata->extd_stats[RUND_IDX]; + pdata->extd_stats[TFCS_IDX] -= pdata->extd_stats[TFRG_IDX]; + } + + pdata->mac_ops->get_drop_cnt(pdata, &rx_drop, &tx_drop); + pdata->extd_stats[RX_OVERRUN_IDX] += rx_drop; + pdata->extd_stats[TX_UNDERRUN_IDX] += tx_drop; + + /* Errata 10GE_8 - Update Frame recovered from Errata 10GE_8/ENET_11 */ + pdata->extd_stats[FALSE_RFLR_IDX] = pdata->false_rflr; + /* Errata ENET_15 - Jabber Frame recov'ed from Errata 10GE_10/ENET_15 */ + pdata->extd_stats[FALSE_RJBR_IDX] = pdata->vlan_rjbr; +} + +int xgene_extd_stats_init(struct xgene_enet_pdata *pdata) +{ + pdata->extd_stats = devm_kmalloc_array(&pdata->pdev->dev, + XGENE_EXTD_STATS_LEN, sizeof(u64), GFP_KERNEL); + if (!pdata->extd_stats) + return -ENOMEM; + + xgene_get_extd_stats(pdata); + memset(pdata->extd_stats, 0, XGENE_EXTD_STATS_LEN * sizeof(u64)); + + return 0; } static void xgene_get_ethtool_stats(struct net_device *ndev, struct ethtool_stats *dummy, u64 *data) { - void *pdata = netdev_priv(ndev); + struct xgene_enet_pdata *pdata = netdev_priv(ndev); + struct rtnl_link_stats64 stats; int i; + dev_get_stats(ndev, &stats); for (i = 0; i < XGENE_STATS_LEN; i++) - *data++ = *(u64 *)(pdata + gstrings_stats[i].offset); + data[i] = *(u64 *)((char *)&stats + gstrings_stats[i].offset); + + xgene_get_extd_stats(pdata); + for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) + data[i + XGENE_STATS_LEN] = pdata->extd_stats[i]; } static void xgene_get_pauseparam(struct net_device *ndev, @@ -180,7 +304,7 @@ static int xgene_set_pauseparam(struct net_device *ndev, struct phy_device *phydev = ndev->phydev; u32 oldadv, newadv; - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII || + if (phy_interface_mode_is_rgmii(pdata->phy_mode) || pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { if (!phydev) return -EINVAL; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 2a835e07adfb..e45b587c2994 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -205,30 +205,24 @@ static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring) } void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring, - struct xgene_enet_pdata *pdata, enum xgene_enet_err_code status) { switch (status) { case INGRESS_CRC: ring->rx_crc_errors++; - ring->rx_dropped++; break; case INGRESS_CHECKSUM: case INGRESS_CHECKSUM_COMPUTE: ring->rx_errors++; - ring->rx_dropped++; break; case INGRESS_TRUNC_FRAME: ring->rx_frame_errors++; - ring->rx_dropped++; break; case INGRESS_PKT_LEN: ring->rx_length_errors++; - ring->rx_dropped++; break; case INGRESS_PKT_UNDER: ring->rx_frame_errors++; - ring->rx_dropped++; break; case INGRESS_FIFO_OVERRUN: ring->rx_fifo_errors++; @@ -270,42 +264,39 @@ static void xgene_enet_wr_mcx_csr(struct xgene_enet_pdata *pdata, iowrite32(val, addr); } -static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr, - void __iomem *cmd, void __iomem *cmd_done, - u32 wr_addr, u32 wr_data) +void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, u32 wr_addr, u32 wr_data) { - u32 done; + void __iomem *addr, *wr, *cmd, *cmd_done; + struct net_device *ndev = pdata->ndev; u8 wait = 10; + u32 done; + + if (pdata->mdio_driver && ndev->phydev && + phy_interface_mode_is_rgmii(pdata->phy_mode)) { + struct mii_bus *bus = ndev->phydev->mdio.bus; + + return xgene_mdio_wr_mac(bus->priv, wr_addr, wr_data); + } + + addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; + wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET; + cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; + cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; + spin_lock(&pdata->mac_lock); iowrite32(wr_addr, addr); iowrite32(wr_data, wr); iowrite32(XGENE_ENET_WR_CMD, cmd); - /* wait for write command to complete */ while (!(done = ioread32(cmd_done)) && wait--) udelay(1); if (!done) - return false; + netdev_err(ndev, "mac write failed, addr: %04x data: %08x\n", + wr_addr, wr_data); iowrite32(0, cmd); - - return true; -} - -static void xgene_enet_wr_mcx_mac(struct xgene_enet_pdata *pdata, - u32 wr_addr, u32 wr_data) -{ - void __iomem *addr, *wr, *cmd, *cmd_done; - - addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; - wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET; - cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; - cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; - - if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data)) - netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n", - wr_addr); + spin_unlock(&pdata->mac_lock); } static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata, @@ -332,42 +323,69 @@ static void xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *pdata, *val = ioread32(addr); } -static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd, - void __iomem *cmd, void __iomem *cmd_done, - u32 rd_addr, u32 *rd_data) +u32 xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, u32 rd_addr) { - u32 done; + void __iomem *addr, *rd, *cmd, *cmd_done; + struct net_device *ndev = pdata->ndev; + u32 done, rd_data; u8 wait = 10; + if (pdata->mdio_driver && ndev->phydev && + phy_interface_mode_is_rgmii(pdata->phy_mode)) { + struct mii_bus *bus = ndev->phydev->mdio.bus; + + return xgene_mdio_rd_mac(bus->priv, rd_addr); + } + + addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; + rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET; + cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; + cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; + + spin_lock(&pdata->mac_lock); iowrite32(rd_addr, addr); iowrite32(XGENE_ENET_RD_CMD, cmd); - /* wait for read command to complete */ while (!(done = ioread32(cmd_done)) && wait--) udelay(1); if (!done) - return false; + netdev_err(ndev, "mac read failed, addr: %04x\n", rd_addr); - *rd_data = ioread32(rd); + rd_data = ioread32(rd); iowrite32(0, cmd); + spin_unlock(&pdata->mac_lock); - return true; + return rd_data; } -static void xgene_enet_rd_mcx_mac(struct xgene_enet_pdata *pdata, - u32 rd_addr, u32 *rd_data) +u32 xgene_enet_rd_stat(struct xgene_enet_pdata *pdata, u32 rd_addr) { void __iomem *addr, *rd, *cmd, *cmd_done; + u32 done, rd_data; + u8 wait = 10; - addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; - rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET; - cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; - cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; + addr = pdata->mcx_stats_addr + STAT_ADDR_REG_OFFSET; + rd = pdata->mcx_stats_addr + STAT_READ_REG_OFFSET; + cmd = pdata->mcx_stats_addr + STAT_COMMAND_REG_OFFSET; + cmd_done = pdata->mcx_stats_addr + STAT_COMMAND_DONE_REG_OFFSET; + + spin_lock(&pdata->stats_lock); + iowrite32(rd_addr, addr); + iowrite32(XGENE_ENET_RD_CMD, cmd); - if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data)) - netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n", + while (!(done = ioread32(cmd_done)) && wait--) + udelay(1); + + if (!done) + netdev_err(pdata->ndev, "mac stats read failed, addr: %04x\n", rd_addr); + + rd_data = ioread32(rd); + iowrite32(0, cmd); + spin_unlock(&pdata->stats_lock); + + return rd_data; } static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) @@ -379,8 +397,8 @@ static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) (dev_addr[1] << 8) | dev_addr[0]; addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16); - xgene_enet_wr_mcx_mac(pdata, STATION_ADDR0_ADDR, addr0); - xgene_enet_wr_mcx_mac(pdata, STATION_ADDR1_ADDR, addr1); + xgene_enet_wr_mac(pdata, STATION_ADDR0_ADDR, addr0); + xgene_enet_wr_mac(pdata, STATION_ADDR1_ADDR, addr1); } static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata) @@ -405,8 +423,8 @@ static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata) static void xgene_gmac_reset(struct xgene_enet_pdata *pdata) { - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET1); - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, 0); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET1); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, 0); } static void xgene_enet_configure_clock(struct xgene_enet_pdata *pdata) @@ -456,8 +474,8 @@ static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata) xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, &icm0); xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, &icm2); - xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_2_ADDR, &mc2); - xgene_enet_rd_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, &intf_ctl); + mc2 = xgene_enet_rd_mac(pdata, MAC_CONFIG_2_ADDR); + intf_ctl = xgene_enet_rd_mac(pdata, INTERFACE_CONTROL_ADDR); xgene_enet_rd_csr(pdata, RGMII_REG_0_ADDR, &rgmii); switch (pdata->phy_speed) { @@ -495,8 +513,8 @@ static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata) } mc2 |= FULL_DUPLEX2 | PAD_CRC | LENGTH_CHK; - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2); - xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl); + xgene_enet_wr_mac(pdata, MAC_CONFIG_2_ADDR, mc2); + xgene_enet_wr_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl); xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii); xgene_enet_configure_clock(pdata); @@ -506,7 +524,7 @@ static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata) static void xgene_enet_set_frame_size(struct xgene_enet_pdata *pdata, int size) { - xgene_enet_wr_mcx_mac(pdata, MAX_FRAME_LEN_ADDR, size); + xgene_enet_wr_mac(pdata, MAX_FRAME_LEN_ADDR, size); } static void xgene_gmac_enable_tx_pause(struct xgene_enet_pdata *pdata, @@ -528,14 +546,14 @@ static void xgene_gmac_flowctl_tx(struct xgene_enet_pdata *pdata, bool enable) { u32 data; - xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); + data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR); if (enable) data |= TX_FLOW_EN; else data &= ~TX_FLOW_EN; - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data); pdata->mac_ops->enable_tx_pause(pdata, enable); } @@ -544,14 +562,14 @@ static void xgene_gmac_flowctl_rx(struct xgene_enet_pdata *pdata, bool enable) { u32 data; - xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); + data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR); if (enable) data |= RX_FLOW_EN; else data &= ~RX_FLOW_EN; - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data); } static void xgene_gmac_init(struct xgene_enet_pdata *pdata) @@ -565,9 +583,9 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) xgene_gmac_set_mac_addr(pdata); /* Adjust MDC clock frequency */ - xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &value); + value = xgene_enet_rd_mac(pdata, MII_MGMT_CONFIG_ADDR); MGMT_CLOCK_SEL_SET(&value, 7); - xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, value); + xgene_enet_wr_mac(pdata, MII_MGMT_CONFIG_ADDR, value); /* Enable drop if bufpool not available */ xgene_enet_rd_csr(pdata, RSIF_CONFIG_REG_ADDR, &value); @@ -600,6 +618,18 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) xgene_enet_wr_csr(pdata, CFG_BYPASS_ADDR, RESUME_TX); } +static void xgene_gmac_get_drop_cnt(struct xgene_enet_pdata *pdata, + u32 *rx, u32 *tx) +{ + u32 count; + + xgene_enet_rd_mcx_csr(pdata, ICM_ECM_DROP_COUNT_REG0_ADDR, &count); + *rx = ICM_DROP_COUNT(count); + *tx = ECM_DROP_COUNT(count); + /* Errata: 10GE_4 - Fix ICM_ECM_DROP_COUNT not clear-on-read */ + xgene_enet_rd_mcx_csr(pdata, ECM_CONFIG0_REG_0_ADDR, &count); +} + static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata) { u32 val = 0xffffffff; @@ -637,32 +667,32 @@ static void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | RX_EN); + data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data | RX_EN); } static void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | TX_EN); + data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data | TX_EN); } static void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~RX_EN); + data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data & ~RX_EN); } static void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~TX_EN); + data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data & ~TX_EN); } bool xgene_ring_mgr_init(struct xgene_enet_pdata *p) @@ -733,27 +763,6 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata, static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) { struct device *dev = &pdata->pdev->dev; - struct xgene_enet_desc_ring *ring; - u32 pb; - int i; - - pb = 0; - for (i = 0; i < pdata->rxq_cnt; i++) { - ring = pdata->rx_ring[i]->buf_pool; - pb |= BIT(xgene_enet_get_fpsel(ring->id)); - ring = pdata->rx_ring[i]->page_pool; - if (ring) - pb |= BIT(xgene_enet_get_fpsel(ring->id)); - - } - xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPRESET_ADDR, pb); - - pb = 0; - for (i = 0; i < pdata->txq_cnt; i++) { - ring = pdata->tx_ring[i]; - pb |= BIT(xgene_enet_ring_bufnum(ring->id)); - } - xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb); if (dev->of_node) { if (!IS_ERR(pdata->clk)) @@ -1009,6 +1018,7 @@ const struct xgene_mac_ops xgene_gmac_ops = { .tx_enable = xgene_gmac_tx_enable, .rx_disable = xgene_gmac_rx_disable, .tx_disable = xgene_gmac_tx_disable, + .get_drop_cnt = xgene_gmac_get_drop_cnt, .set_speed = xgene_gmac_set_speed, .set_mac_addr = xgene_gmac_set_mac_addr, .set_framesize = xgene_enet_set_frame_size, diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index d250bfe94d24..5d3e18d3c94c 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -115,6 +115,7 @@ enum xgene_enet_rm { #define BLOCK_ETH_CLKRST_CSR_OFFSET 0xc000 #define BLOCK_ETH_DIAG_CSR_OFFSET 0xD000 #define BLOCK_ETH_MAC_OFFSET 0x0000 +#define BLOCK_ETH_STATS_OFFSET 0x0000 #define BLOCK_ETH_MAC_CSR_OFFSET 0x2800 #define CLKEN_ADDR 0xc208 @@ -126,6 +127,12 @@ enum xgene_enet_rm { #define MAC_READ_REG_OFFSET 0x0c #define MAC_COMMAND_DONE_REG_OFFSET 0x10 +#define STAT_ADDR_REG_OFFSET 0x14 +#define STAT_COMMAND_REG_OFFSET 0x18 +#define STAT_WRITE_REG_OFFSET 0x1c +#define STAT_READ_REG_OFFSET 0x20 +#define STAT_COMMAND_DONE_REG_OFFSET 0x24 + #define PCS_ADDR_REG_OFFSET 0x00 #define PCS_COMMAND_REG_OFFSET 0x04 #define PCS_WRITE_REG_OFFSET 0x08 @@ -185,6 +192,10 @@ enum xgene_enet_rm { #define CFG_CLE_NXTFPSEL0(val) (((val) << 20) & GENMASK(23, 20)) #define ICM_CONFIG0_REG_0_ADDR 0x0400 #define ICM_CONFIG2_REG_0_ADDR 0x0410 +#define ECM_CONFIG0_REG_0_ADDR 0x0500 +#define ECM_CONFIG0_REG_1_ADDR 0x0504 +#define ICM_ECM_DROP_COUNT_REG0_ADDR 0x0508 +#define ICM_ECM_DROP_COUNT_REG1_ADDR 0x050c #define RX_DV_GATE_REG_0_ADDR 0x05fc #define TX_DV_GATE_EN0 BIT(2) #define RX_DV_GATE_EN0 BIT(1) @@ -217,12 +228,53 @@ enum xgene_enet_rm { #define FULL_DUPLEX2 BIT(0) #define PAD_CRC BIT(2) #define LENGTH_CHK BIT(4) -#define SCAN_AUTO_INCR BIT(5) -#define TBYT_ADDR 0x38 -#define TPKT_ADDR 0x39 -#define TDRP_ADDR 0x45 -#define TFCS_ADDR 0x47 -#define TUND_ADDR 0x4a + +#define TR64_ADDR 0x20 +#define TR127_ADDR 0x21 +#define TR255_ADDR 0x22 +#define TR511_ADDR 0x23 +#define TR1K_ADDR 0x24 +#define TRMAX_ADDR 0x25 +#define TRMGV_ADDR 0x26 + +#define RFCS_ADDR 0x29 +#define RMCA_ADDR 0x2a +#define RBCA_ADDR 0x2b +#define RXCF_ADDR 0x2c +#define RXPF_ADDR 0x2d +#define RXUO_ADDR 0x2e +#define RALN_ADDR 0x2f +#define RFLR_ADDR 0x30 +#define RCDE_ADDR 0x31 +#define RCSE_ADDR 0x32 +#define RUND_ADDR 0x33 +#define ROVR_ADDR 0x34 +#define RFRG_ADDR 0x35 +#define RJBR_ADDR 0x36 +#define RDRP_ADDR 0x37 + +#define TMCA_ADDR 0x3a +#define TBCA_ADDR 0x3b +#define TXPF_ADDR 0x3c +#define TDFR_ADDR 0x3d +#define TEDF_ADDR 0x3e +#define TSCL_ADDR 0x3f +#define TMCL_ADDR 0x40 +#define TLCL_ADDR 0x41 +#define TXCL_ADDR 0x42 +#define TNCL_ADDR 0x43 +#define TPFH_ADDR 0x44 +#define TDRP_ADDR 0x45 +#define TJBR_ADDR 0x46 +#define TFCS_ADDR 0x47 +#define TXCF_ADDR 0x48 +#define TOVR_ADDR 0x49 +#define TUND_ADDR 0x4a +#define TFRG_ADDR 0x4b +#define DUMP_ADDR 0x27 + +#define ECM_DROP_COUNT(src) xgene_get_bits(src, 0, 15) +#define ICM_DROP_COUNT(src) xgene_get_bits(src, 16, 31) #define TSO_IPPROTO_TCP 1 @@ -380,14 +432,16 @@ static inline u16 xgene_enet_get_numslots(u16 id, u32 size) } void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring, - struct xgene_enet_pdata *pdata, enum xgene_enet_err_code status); - int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata); void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata); bool xgene_ring_mgr_init(struct xgene_enet_pdata *p); int xgene_enet_phy_connect(struct net_device *ndev); void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata); +u32 xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, u32 rd_addr); +void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, u32 wr_addr, + u32 wr_data); +u32 xgene_enet_rd_stat(struct xgene_enet_pdata *pdata, u32 rd_addr); extern const struct xgene_mac_ops xgene_gmac_ops; extern const struct xgene_port_ops xgene_gport_ops; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 5f37ed3506d5..d3906f6b01bd 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -246,9 +246,9 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring, skb_frag_t *frag; dma_addr_t *frag_dma_addr; u16 skb_index; - u8 status; - int i, ret = 0; u8 mss_index; + u8 status; + int i; skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); skb = cp_ring->cp_skb[skb_index]; @@ -275,19 +275,17 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring, /* Checking for error */ status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0)); if (unlikely(status > 2)) { - xgene_enet_parse_error(cp_ring, netdev_priv(cp_ring->ndev), - status); - ret = -EIO; + cp_ring->tx_dropped++; + cp_ring->tx_errors++; } if (likely(skb)) { dev_kfree_skb_any(skb); } else { netdev_err(cp_ring->ndev, "completion skb is NULL\n"); - ret = -EIO; } - return ret; + return 0; } static int xgene_enet_setup_mss(struct net_device *ndev, u32 mss) @@ -658,6 +656,18 @@ static void xgene_enet_free_pagepool(struct xgene_enet_desc_ring *buf_pool, buf_pool->head = head; } +/* Errata 10GE_10 and ENET_15 - Fix duplicated HW statistic counters */ +static bool xgene_enet_errata_10GE_10(struct sk_buff *skb, u32 len, u8 status) +{ + if (status == INGRESS_CRC && + len >= (ETHER_STD_PACKET + 1) && + len <= (ETHER_STD_PACKET + 4) && + skb->protocol == htons(ETH_P_8021Q)) + return true; + + return false; +} + /* Errata 10GE_8 and ENET_11 - allow packet with length <=64B */ static bool xgene_enet_errata_10GE_8(struct sk_buff *skb, u32 len, u8 status) { @@ -708,10 +718,15 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) | GET_VAL(LERR, le64_to_cpu(raw_desc->m0)); if (unlikely(status)) { - if (!xgene_enet_errata_10GE_8(skb, datalen, status)) { + if (xgene_enet_errata_10GE_8(skb, datalen, status)) { + pdata->false_rflr++; + } else if (xgene_enet_errata_10GE_10(skb, datalen, status)) { + pdata->vlan_rjbr++; + } else { dev_kfree_skb_any(skb); xgene_enet_free_pagepool(page_pool, raw_desc, exp_desc); - xgene_enet_parse_error(rx_ring, pdata, status); + xgene_enet_parse_error(rx_ring, status); + rx_ring->rx_dropped++; goto out; } } @@ -1466,10 +1481,9 @@ err: static void xgene_enet_get_stats64( struct net_device *ndev, - struct rtnl_link_stats64 *storage) + struct rtnl_link_stats64 *stats) { struct xgene_enet_pdata *pdata = netdev_priv(ndev); - struct rtnl_link_stats64 *stats = &pdata->stats; struct xgene_enet_desc_ring *ring; int i; @@ -1478,6 +1492,8 @@ static void xgene_enet_get_stats64( if (ring) { stats->tx_packets += ring->tx_packets; stats->tx_bytes += ring->tx_bytes; + stats->tx_dropped += ring->tx_dropped; + stats->tx_errors += ring->tx_errors; } } @@ -1486,14 +1502,18 @@ static void xgene_enet_get_stats64( if (ring) { stats->rx_packets += ring->rx_packets; stats->rx_bytes += ring->rx_bytes; - stats->rx_errors += ring->rx_length_errors + + stats->rx_dropped += ring->rx_dropped; + stats->rx_errors += ring->rx_errors + + ring->rx_length_errors + ring->rx_crc_errors + ring->rx_frame_errors + ring->rx_fifo_errors; - stats->rx_dropped += ring->rx_dropped; + stats->rx_length_errors += ring->rx_length_errors; + stats->rx_crc_errors += ring->rx_crc_errors; + stats->rx_frame_errors += ring->rx_frame_errors; + stats->rx_fifo_errors += ring->rx_fifo_errors; } } - memcpy(storage, stats, sizeof(struct rtnl_link_stats64)); } static int xgene_enet_set_mac_address(struct net_device *ndev, void *addr) @@ -1614,7 +1634,7 @@ static int xgene_enet_get_irqs(struct xgene_enet_pdata *pdata) struct device *dev = &pdev->dev; int i, ret, max_irqs; - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + if (phy_interface_mode_is_rgmii(pdata->phy_mode)) max_irqs = 1; else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) max_irqs = 2; @@ -1740,7 +1760,7 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) dev_err(dev, "Unable to get phy-connection-type\n"); return pdata->phy_mode; } - if (pdata->phy_mode != PHY_INTERFACE_MODE_RGMII && + if (!phy_interface_mode_is_rgmii(pdata->phy_mode) && pdata->phy_mode != PHY_INTERFACE_MODE_SGMII && pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { dev_err(dev, "Incorrect phy-connection-type specified\n"); @@ -1785,15 +1805,18 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) pdata->cle.base = base_addr + BLOCK_ETH_CLE_CSR_OFFSET; pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET; pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET; - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII || + if (phy_interface_mode_is_rgmii(pdata->phy_mode) || pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { pdata->mcx_mac_addr = pdata->base_addr + BLOCK_ETH_MAC_OFFSET; + pdata->mcx_stats_addr = + pdata->base_addr + BLOCK_ETH_STATS_OFFSET; offset = (pdata->enet_id == XGENE_ENET1) ? BLOCK_ETH_MAC_CSR_OFFSET : X2_BLOCK_ETH_MAC_CSR_OFFSET; pdata->mcx_mac_csr_addr = base_addr + offset; } else { pdata->mcx_mac_addr = base_addr + BLOCK_AXG_MAC_OFFSET; + pdata->mcx_stats_addr = base_addr + BLOCK_AXG_STATS_OFFSET; pdata->mcx_mac_csr_addr = base_addr + BLOCK_AXG_MAC_CSR_OFFSET; pdata->pcs_addr = base_addr + BLOCK_PCS_OFFSET; } @@ -1881,6 +1904,9 @@ static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata) { switch (pdata->phy_mode) { case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: pdata->mac_ops = &xgene_gmac_ops; pdata->port_ops = &xgene_gport_ops; pdata->rm = RM3; @@ -2055,6 +2081,7 @@ static int xgene_enet_probe(struct platform_device *pdev) goto err; xgene_enet_setup_ops(pdata); + spin_lock_init(&pdata->mac_lock); if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) { ndev->features |= NETIF_F_TSO | NETIF_F_RXCSUM; @@ -2076,7 +2103,7 @@ static int xgene_enet_probe(struct platform_device *pdev) if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) { INIT_DELAYED_WORK(&pdata->link_work, link_state); } else if (!pdata->mdio_driver) { - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + if (phy_interface_mode_is_rgmii(pdata->phy_mode)) ret = xgene_enet_mdio_config(pdata); else INIT_DELAYED_WORK(&pdata->link_work, link_state); @@ -2085,6 +2112,11 @@ static int xgene_enet_probe(struct platform_device *pdev) goto err1; } + spin_lock_init(&pdata->stats_lock); + ret = xgene_extd_stats_init(pdata); + if (ret) + goto err2; + xgene_enet_napi_add(pdata); ret = register_netdev(ndev); if (ret) { @@ -2102,7 +2134,7 @@ err2: if (pdata->mdio_driver) xgene_enet_phy_disconnect(pdata); - else if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + else if (phy_interface_mode_is_rgmii(pdata->phy_mode)) xgene_enet_mdio_remove(pdata); err1: xgene_enet_delete_desc_rings(pdata); @@ -2126,12 +2158,12 @@ static int xgene_enet_remove(struct platform_device *pdev) if (pdata->mdio_driver) xgene_enet_phy_disconnect(pdata); - else if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + else if (phy_interface_mode_is_rgmii(pdata->phy_mode)) xgene_enet_mdio_remove(pdata); unregister_netdev(ndev); - pdata->port_ops->shutdown(pdata); xgene_enet_delete_desc_rings(pdata); + pdata->port_ops->shutdown(pdata); free_netdev(ndev); return 0; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 0d4be2425ebc..985768596900 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -42,6 +42,7 @@ #define XGENE_DRV_VERSION "v1.0" #define ETHER_MIN_PACKET 64 +#define ETHER_STD_PACKET 1518 #define XGENE_ENET_STD_MTU 1536 #define XGENE_ENET_MAX_MTU 9600 #define SKB_BUFFER_SIZE (XGENE_ENET_STD_MTU - NET_IP_ALIGN) @@ -138,6 +139,8 @@ struct xgene_enet_desc_ring { __le64 *exp_bufs; u64 tx_packets; u64 tx_bytes; + u64 tx_dropped; + u64 tx_errors; u64 rx_packets; u64 rx_bytes; u64 rx_dropped; @@ -155,6 +158,7 @@ struct xgene_mac_ops { void (*rx_enable)(struct xgene_enet_pdata *pdata); void (*tx_disable)(struct xgene_enet_pdata *pdata); void (*rx_disable)(struct xgene_enet_pdata *pdata); + void (*get_drop_cnt)(struct xgene_enet_pdata *pdata, u32 *rx, u32 *tx); void (*set_speed)(struct xgene_enet_pdata *pdata); void (*set_mac_addr)(struct xgene_enet_pdata *pdata); void (*set_framesize)(struct xgene_enet_pdata *pdata, int framesize); @@ -212,6 +216,7 @@ struct xgene_enet_pdata { void __iomem *eth_diag_csr_addr; void __iomem *mcx_mac_addr; void __iomem *mcx_mac_csr_addr; + void __iomem *mcx_stats_addr; void __iomem *base_addr; void __iomem *pcs_addr; void __iomem *ring_csr_addr; @@ -219,8 +224,12 @@ struct xgene_enet_pdata { int phy_mode; enum xgene_enet_rm rm; struct xgene_enet_cle cle; - struct rtnl_link_stats64 stats; + u64 *extd_stats; + u64 false_rflr; + u64 vlan_rjbr; + spinlock_t stats_lock; /* statistics lock */ const struct xgene_mac_ops *mac_ops; + spinlock_t mac_lock; /* mac lock */ const struct xgene_port_ops *port_ops; struct xgene_ring_ops *ring_ops; const struct xgene_cle_ops *cle_ops; @@ -263,5 +272,6 @@ static inline u16 xgene_enet_dst_ring_num(struct xgene_enet_desc_ring *ring) } void xgene_enet_set_ethtool_ops(struct net_device *netdev); +int xgene_extd_stats_init(struct xgene_enet_pdata *pdata); #endif /* __XGENE_ENET_MAIN_H__ */ diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c index a8e063bdee3b..b1a83fdbefb8 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c @@ -54,41 +54,6 @@ static void xgene_enet_wr_mcx_csr(struct xgene_enet_pdata *pdata, iowrite32(val, addr); } -static bool xgene_enet_wr_indirect(struct xgene_indirect_ctl *ctl, - u32 wr_addr, u32 wr_data) -{ - int i; - - iowrite32(wr_addr, ctl->addr); - iowrite32(wr_data, ctl->ctl); - iowrite32(XGENE_ENET_WR_CMD, ctl->cmd); - - /* wait for write command to complete */ - for (i = 0; i < 10; i++) { - if (ioread32(ctl->cmd_done)) { - iowrite32(0, ctl->cmd); - return true; - } - udelay(1); - } - - return false; -} - -static void xgene_enet_wr_mac(struct xgene_enet_pdata *p, - u32 wr_addr, u32 wr_data) -{ - struct xgene_indirect_ctl ctl = { - .addr = p->mcx_mac_addr + MAC_ADDR_REG_OFFSET, - .ctl = p->mcx_mac_addr + MAC_WRITE_REG_OFFSET, - .cmd = p->mcx_mac_addr + MAC_COMMAND_REG_OFFSET, - .cmd_done = p->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET - }; - - if (!xgene_enet_wr_indirect(&ctl, wr_addr, wr_data)) - netdev_err(p->ndev, "mac write failed, addr: %04x\n", wr_addr); -} - static u32 xgene_enet_rd_csr(struct xgene_enet_pdata *p, u32 offset) { return ioread32(p->eth_csr_addr + offset); @@ -104,42 +69,6 @@ static u32 xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *p, u32 offset) return ioread32(p->mcx_mac_csr_addr + offset); } -static u32 xgene_enet_rd_indirect(struct xgene_indirect_ctl *ctl, u32 rd_addr) -{ - u32 rd_data; - int i; - - iowrite32(rd_addr, ctl->addr); - iowrite32(XGENE_ENET_RD_CMD, ctl->cmd); - - /* wait for read command to complete */ - for (i = 0; i < 10; i++) { - if (ioread32(ctl->cmd_done)) { - rd_data = ioread32(ctl->ctl); - iowrite32(0, ctl->cmd); - - return rd_data; - } - udelay(1); - } - - pr_err("%s: mac read failed, addr: %04x\n", __func__, rd_addr); - - return 0; -} - -static u32 xgene_enet_rd_mac(struct xgene_enet_pdata *p, u32 rd_addr) -{ - struct xgene_indirect_ctl ctl = { - .addr = p->mcx_mac_addr + MAC_ADDR_REG_OFFSET, - .ctl = p->mcx_mac_addr + MAC_READ_REG_OFFSET, - .cmd = p->mcx_mac_addr + MAC_COMMAND_REG_OFFSET, - .cmd_done = p->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET - }; - - return xgene_enet_rd_indirect(&ctl, rd_addr); -} - static int xgene_enet_ecc_init(struct xgene_enet_pdata *p) { struct net_device *ndev = p->ndev; @@ -166,6 +95,24 @@ static int xgene_enet_ecc_init(struct xgene_enet_pdata *p) return -ENODEV; } +static void xgene_sgmac_get_drop_cnt(struct xgene_enet_pdata *pdata, + u32 *rx, u32 *tx) +{ + u32 addr, count; + + addr = (pdata->enet_id != XGENE_ENET1) ? + XG_MCX_ICM_ECM_DROP_COUNT_REG0_ADDR : + ICM_ECM_DROP_COUNT_REG0_ADDR + pdata->port_id * OFFSET_4; + count = xgene_enet_rd_mcx_csr(pdata, addr); + *rx = ICM_DROP_COUNT(count); + *tx = ECM_DROP_COUNT(count); + /* Errata: 10GE_4 - ICM_ECM_DROP_COUNT not clear-on-read */ + addr = (pdata->enet_id != XGENE_ENET1) ? + XG_MCX_ECM_CONFIG0_REG_0_ADDR : + ECM_CONFIG0_REG_0_ADDR + pdata->port_id * OFFSET_4; + xgene_enet_rd_mcx_csr(pdata, addr); +} + static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *p) { u32 val; @@ -587,26 +534,6 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata, static void xgene_enet_shutdown(struct xgene_enet_pdata *p) { struct device *dev = &p->pdev->dev; - struct xgene_enet_desc_ring *ring; - u32 pb; - int i; - - pb = 0; - for (i = 0; i < p->rxq_cnt; i++) { - ring = p->rx_ring[i]->buf_pool; - pb |= BIT(xgene_enet_get_fpsel(ring->id)); - ring = p->rx_ring[i]->page_pool; - if (ring) - pb |= BIT(xgene_enet_get_fpsel(ring->id)); - } - xgene_enet_wr_ring_if(p, ENET_CFGSSQMIFPRESET_ADDR, pb); - - pb = 0; - for (i = 0; i < p->txq_cnt; i++) { - ring = p->tx_ring[i]; - pb |= BIT(xgene_enet_ring_bufnum(ring->id)); - } - xgene_enet_wr_ring_if(p, ENET_CFGSSQMIWQRESET_ADDR, pb); if (dev->of_node) { if (!IS_ERR(p->clk)) @@ -671,6 +598,7 @@ const struct xgene_mac_ops xgene_sgmac_ops = { .tx_enable = xgene_sgmac_tx_enable, .rx_disable = xgene_sgmac_rx_disable, .tx_disable = xgene_sgmac_tx_disable, + .get_drop_cnt = xgene_sgmac_get_drop_cnt, .set_speed = xgene_sgmac_set_speed, .set_mac_addr = xgene_sgmac_set_mac_addr, .set_framesize = xgene_sgmac_set_frame_size, diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c index 423240c97d39..b7d75d067c7a 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c @@ -71,21 +71,6 @@ static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr, return true; } -static void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, - u32 wr_addr, u32 wr_data) -{ - void __iomem *addr, *wr, *cmd, *cmd_done; - - addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; - wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET; - cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; - cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; - - if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data)) - netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n", - wr_addr); -} - static void xgene_enet_wr_pcs(struct xgene_enet_pdata *pdata, u32 wr_addr, u32 wr_data) { @@ -148,21 +133,6 @@ static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd, return true; } -static void xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, - u32 rd_addr, u32 *rd_data) -{ - void __iomem *addr, *rd, *cmd, *cmd_done; - - addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; - rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET; - cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; - cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; - - if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data)) - netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n", - rd_addr); -} - static bool xgene_enet_rd_pcs(struct xgene_enet_pdata *pdata, u32 rd_addr, u32 *rd_data) { @@ -210,6 +180,18 @@ static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata) return 0; } +static void xgene_xgmac_get_drop_cnt(struct xgene_enet_pdata *pdata, + u32 *rx, u32 *tx) +{ + u32 count; + + xgene_enet_rd_axg_csr(pdata, XGENET_ICM_ECM_DROP_COUNT_REG0, &count); + *rx = ICM_DROP_COUNT(count); + *tx = ECM_DROP_COUNT(count); + /* Errata: 10GE_4 - ICM_ECM_DROP_COUNT not clear-on-read */ + xgene_enet_rd_axg_csr(pdata, XGENET_ECM_CONFIG0_REG_0, &count); +} + static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata) { xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQASSOC_ADDR, 0); @@ -300,7 +282,7 @@ static void xgene_xgmac_flowctl_tx(struct xgene_enet_pdata *pdata, bool enable) { u32 data; - xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1); if (enable) data |= HSTTCTLEN; @@ -316,7 +298,7 @@ static void xgene_xgmac_flowctl_rx(struct xgene_enet_pdata *pdata, bool enable) { u32 data; - xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1); if (enable) data |= HSTRCTLEN; @@ -332,7 +314,7 @@ static void xgene_xgmac_init(struct xgene_enet_pdata *pdata) xgene_xgmac_reset(pdata); - xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1); data |= HSTPPEN; data &= ~HSTLENCHK; xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data); @@ -379,7 +361,7 @@ static void xgene_xgmac_rx_enable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1); xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTRFEN); } @@ -387,7 +369,7 @@ static void xgene_xgmac_tx_enable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1); xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTTFEN); } @@ -395,7 +377,7 @@ static void xgene_xgmac_rx_disable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1); xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTRFEN); } @@ -403,7 +385,7 @@ static void xgene_xgmac_tx_disable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1); xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTTFEN); } @@ -464,26 +446,6 @@ static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata, static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata) { struct device *dev = &pdata->pdev->dev; - struct xgene_enet_desc_ring *ring; - u32 pb; - int i; - - pb = 0; - for (i = 0; i < pdata->rxq_cnt; i++) { - ring = pdata->rx_ring[i]->buf_pool; - pb |= BIT(xgene_enet_get_fpsel(ring->id)); - ring = pdata->rx_ring[i]->page_pool; - if (ring) - pb |= BIT(xgene_enet_get_fpsel(ring->id)); - } - xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPRESET_ADDR, pb); - - pb = 0; - for (i = 0; i < pdata->txq_cnt; i++) { - ring = pdata->tx_ring[i]; - pb |= BIT(xgene_enet_ring_bufnum(ring->id)); - } - xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb); if (dev->of_node) { if (!IS_ERR(pdata->clk)) @@ -567,6 +529,7 @@ const struct xgene_mac_ops xgene_xgmac_ops = { .set_mac_addr = xgene_xgmac_set_mac_addr, .set_framesize = xgene_xgmac_set_frame_size, .set_mss = xgene_xgmac_set_mss, + .get_drop_cnt = xgene_xgmac_get_drop_cnt, .link_state = xgene_enet_link_state, .enable_tx_pause = xgene_xgmac_enable_tx_pause, .flowctl_rx = xgene_xgmac_flowctl_rx, diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h index e644a429ebf4..a3b45517df45 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h @@ -23,6 +23,7 @@ #define X2_BLOCK_ETH_MAC_CSR_OFFSET 0x3000 #define BLOCK_AXG_MAC_OFFSET 0x0800 +#define BLOCK_AXG_STATS_OFFSET 0x0800 #define BLOCK_AXG_MAC_CSR_OFFSET 0x2000 #define BLOCK_PCS_OFFSET 0x3800 @@ -70,6 +71,8 @@ #define XG_RSIF_CONFIG1_REG_ADDR 0x00b8 #define XG_RSIF_PLC_CLE_BUFF_THRESH 0x1 #define RSIF_PLC_CLE_BUFF_THRESH_SET(dst, val) xgene_set_bits(dst, val, 0, 2) +#define XG_MCX_ECM_CONFIG0_REG_0_ADDR 0x0070 +#define XG_MCX_ICM_ECM_DROP_COUNT_REG0_ADDR 0x0124 #define XCLE_BYPASS_REG0_ADDR 0x0160 #define XCLE_BYPASS_REG1_ADDR 0x0164 #define XG_CFG_BYPASS_ADDR 0x0204 @@ -80,6 +83,8 @@ #define XG_ENET_SPARE_CFG_REG_ADDR 0x040c #define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410 #define XGENET_RX_DV_GATE_REG_0_ADDR 0x0804 +#define XGENET_ECM_CONFIG0_REG_0 0x0870 +#define XGENET_ICM_ECM_DROP_COUNT_REG0 0x0924 #define XGENET_CSR_ECM_CFG_0_ADDR 0x0880 #define XGENET_CSR_MULTI_DPF0_ADDR 0x0888 #define XGENET_CSR_MULTI_DPF1_ADDR 0x088c diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index 3a8a4aa13687..9a0817938eca 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -223,7 +223,7 @@ int aq_ring_rx_clean(struct aq_ring_s *self, int *work_done, int budget) skb->protocol = eth_type_trans(skb, ndev); if (unlikely(buff->is_cso_err)) { ++self->stats.rx.errors; - __skb_mark_checksum_bad(skb); + skb->ip_summed = CHECKSUM_NONE; } else { if (buff->is_ip_cso) { __skb_incr_checksum_unnecessary(skb); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index a851f95c307a..14c236e5bdb1 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -10303,7 +10303,7 @@ sp_rtnl_not_reset: } if (test_and_clear_bit(BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN, &bp->sp_rtnl_state)){ - if (!test_bit(__LINK_STATE_NOCARRIER, &bp->dev->state)) { + if (netif_carrier_ok(bp->dev)) { bnx2x_tx_disable(bp); BNX2X_ERR("PF indicated channel is not servicable anymore. This means this VF device is no longer operational\n"); } @@ -15351,6 +15351,7 @@ int bnx2x_configure_ptp_filters(struct bnx2x *bp) break; case HWTSTAMP_FILTER_ALL: case HWTSTAMP_FILTER_SOME: + case HWTSTAMP_FILTER_NTP_ALL: bp->rx_filter = HWTSTAMP_FILTER_NONE; break; case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 03f55daecb20..c1cd72a5eccf 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -175,6 +175,8 @@ static const struct pci_device_id bnxt_pci_tbl[] = { { PCI_VDEVICE(BROADCOM, 0x16f1), .driver_data = BCM57452 }, { PCI_VDEVICE(BROADCOM, 0x1614), .driver_data = BCM57454 }, #ifdef CONFIG_BNXT_SRIOV + { PCI_VDEVICE(BROADCOM, 0x1606), .driver_data = NETXTREME_E_VF }, + { PCI_VDEVICE(BROADCOM, 0x1609), .driver_data = NETXTREME_E_VF }, { PCI_VDEVICE(BROADCOM, 0x16c1), .driver_data = NETXTREME_E_VF }, { PCI_VDEVICE(BROADCOM, 0x16cb), .driver_data = NETXTREME_C_VF }, { PCI_VDEVICE(BROADCOM, 0x16d3), .driver_data = NETXTREME_E_VF }, @@ -461,14 +463,17 @@ normal_tx: prod = NEXT_TX(prod); txr->tx_prod = prod; - writel(DB_KEY_TX | prod, txr->tx_doorbell); - writel(DB_KEY_TX | prod, txr->tx_doorbell); + if (!skb->xmit_more || netif_xmit_stopped(txq)) + bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | prod); tx_done: mmiowb(); if (unlikely(bnxt_tx_avail(bp, txr) <= MAX_SKB_FRAGS + 1)) { + if (skb->xmit_more && !tx_buf->is_push) + bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | prod); + netif_tx_stop_queue(txq); /* netif_tx_stop_queue() must be done before checking @@ -582,7 +587,8 @@ static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping, if (!page) return NULL; - *mapping = dma_map_page(dev, page, 0, PAGE_SIZE, bp->rx_dir); + *mapping = dma_map_page_attrs(dev, page, 0, PAGE_SIZE, bp->rx_dir, + DMA_ATTR_WEAK_ORDERING); if (dma_mapping_error(dev, *mapping)) { __free_page(page); return NULL; @@ -601,8 +607,9 @@ static inline u8 *__bnxt_alloc_rx_data(struct bnxt *bp, dma_addr_t *mapping, if (!data) return NULL; - *mapping = dma_map_single(&pdev->dev, data + bp->rx_dma_offset, - bp->rx_buf_use_size, bp->rx_dir); + *mapping = dma_map_single_attrs(&pdev->dev, data + bp->rx_dma_offset, + bp->rx_buf_use_size, bp->rx_dir, + DMA_ATTR_WEAK_ORDERING); if (dma_mapping_error(&pdev->dev, *mapping)) { kfree(data); @@ -705,8 +712,9 @@ static inline int bnxt_alloc_rx_page(struct bnxt *bp, return -ENOMEM; } - mapping = dma_map_page(&pdev->dev, page, offset, BNXT_RX_PAGE_SIZE, - PCI_DMA_FROMDEVICE); + mapping = dma_map_page_attrs(&pdev->dev, page, offset, + BNXT_RX_PAGE_SIZE, PCI_DMA_FROMDEVICE, + DMA_ATTR_WEAK_ORDERING); if (dma_mapping_error(&pdev->dev, mapping)) { __free_page(page); return -EIO; @@ -799,7 +807,8 @@ static struct sk_buff *bnxt_rx_page_skb(struct bnxt *bp, return NULL; } dma_addr -= bp->rx_dma_offset; - dma_unmap_page(&bp->pdev->dev, dma_addr, PAGE_SIZE, bp->rx_dir); + dma_unmap_page_attrs(&bp->pdev->dev, dma_addr, PAGE_SIZE, bp->rx_dir, + DMA_ATTR_WEAK_ORDERING); if (unlikely(!payload)) payload = eth_get_headlen(data_ptr, len); @@ -841,8 +850,8 @@ static struct sk_buff *bnxt_rx_skb(struct bnxt *bp, } skb = build_skb(data, 0); - dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size, - bp->rx_dir); + dma_unmap_single_attrs(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size, + bp->rx_dir, DMA_ATTR_WEAK_ORDERING); if (!skb) { kfree(data); return NULL; @@ -909,8 +918,9 @@ static struct sk_buff *bnxt_rx_pages(struct bnxt *bp, struct bnxt_napi *bnapi, return NULL; } - dma_unmap_page(&pdev->dev, mapping, BNXT_RX_PAGE_SIZE, - PCI_DMA_FROMDEVICE); + dma_unmap_page_attrs(&pdev->dev, mapping, BNXT_RX_PAGE_SIZE, + PCI_DMA_FROMDEVICE, + DMA_ATTR_WEAK_ORDERING); skb->data_len += frag_len; skb->len += frag_len; @@ -1329,8 +1339,9 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, tpa_info->mapping = new_mapping; skb = build_skb(data, 0); - dma_unmap_single(&bp->pdev->dev, mapping, bp->rx_buf_use_size, - bp->rx_dir); + dma_unmap_single_attrs(&bp->pdev->dev, mapping, + bp->rx_buf_use_size, bp->rx_dir, + DMA_ATTR_WEAK_ORDERING); if (!skb) { kfree(data); @@ -1771,8 +1782,7 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) /* Sync BD data before updating doorbell */ wmb(); - writel(DB_KEY_TX | prod, db); - writel(DB_KEY_TX | prod, db); + bnxt_db_write(bp, db, DB_KEY_TX | prod); } cpr->cp_raw_cons = raw_cons; @@ -1788,14 +1798,10 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) if (event & BNXT_RX_EVENT) { struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; - writel(DB_KEY_RX | rxr->rx_prod, rxr->rx_doorbell); - writel(DB_KEY_RX | rxr->rx_prod, rxr->rx_doorbell); - if (event & BNXT_AGG_EVENT) { - writel(DB_KEY_RX | rxr->rx_agg_prod, - rxr->rx_agg_doorbell); - writel(DB_KEY_RX | rxr->rx_agg_prod, - rxr->rx_agg_doorbell); - } + bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rxr->rx_prod); + if (event & BNXT_AGG_EVENT) + bnxt_db_write(bp, rxr->rx_agg_doorbell, + DB_KEY_RX | rxr->rx_agg_prod); } return rx_pkts; } @@ -1855,13 +1861,11 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget) cpr->cp_raw_cons = raw_cons; BNXT_CP_DB(cpr->cp_doorbell, cpr->cp_raw_cons); - writel(DB_KEY_RX | rxr->rx_prod, rxr->rx_doorbell); - writel(DB_KEY_RX | rxr->rx_prod, rxr->rx_doorbell); + bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rxr->rx_prod); - if (event & BNXT_AGG_EVENT) { - writel(DB_KEY_RX | rxr->rx_agg_prod, rxr->rx_agg_doorbell); - writel(DB_KEY_RX | rxr->rx_agg_prod, rxr->rx_agg_doorbell); - } + if (event & BNXT_AGG_EVENT) + bnxt_db_write(bp, rxr->rx_agg_doorbell, + DB_KEY_RX | rxr->rx_agg_prod); if (!bnxt_has_work(bp, cpr) && rx_pkts < budget) { napi_complete_done(napi, rx_pkts); @@ -1971,9 +1975,11 @@ static void bnxt_free_rx_skbs(struct bnxt *bp) if (!data) continue; - dma_unmap_single(&pdev->dev, tpa_info->mapping, - bp->rx_buf_use_size, - bp->rx_dir); + dma_unmap_single_attrs(&pdev->dev, + tpa_info->mapping, + bp->rx_buf_use_size, + bp->rx_dir, + DMA_ATTR_WEAK_ORDERING); tpa_info->data = NULL; @@ -1993,13 +1999,15 @@ static void bnxt_free_rx_skbs(struct bnxt *bp) if (BNXT_RX_PAGE_MODE(bp)) { mapping -= bp->rx_dma_offset; - dma_unmap_page(&pdev->dev, mapping, - PAGE_SIZE, bp->rx_dir); + dma_unmap_page_attrs(&pdev->dev, mapping, + PAGE_SIZE, bp->rx_dir, + DMA_ATTR_WEAK_ORDERING); __free_page(data); } else { - dma_unmap_single(&pdev->dev, mapping, - bp->rx_buf_use_size, - bp->rx_dir); + dma_unmap_single_attrs(&pdev->dev, mapping, + bp->rx_buf_use_size, + bp->rx_dir, + DMA_ATTR_WEAK_ORDERING); kfree(data); } } @@ -2012,8 +2020,10 @@ static void bnxt_free_rx_skbs(struct bnxt *bp) if (!page) continue; - dma_unmap_page(&pdev->dev, rx_agg_buf->mapping, - BNXT_RX_PAGE_SIZE, PCI_DMA_FROMDEVICE); + dma_unmap_page_attrs(&pdev->dev, rx_agg_buf->mapping, + BNXT_RX_PAGE_SIZE, + PCI_DMA_FROMDEVICE, + DMA_ATTR_WEAK_ORDERING); rx_agg_buf->page = NULL; __clear_bit(j, rxr->rx_agg_bmap); @@ -2856,6 +2866,32 @@ static int bnxt_alloc_hwrm_resources(struct bnxt *bp) return 0; } +static void bnxt_free_hwrm_short_cmd_req(struct bnxt *bp) +{ + if (bp->hwrm_short_cmd_req_addr) { + struct pci_dev *pdev = bp->pdev; + + dma_free_coherent(&pdev->dev, BNXT_HWRM_MAX_REQ_LEN, + bp->hwrm_short_cmd_req_addr, + bp->hwrm_short_cmd_req_dma_addr); + bp->hwrm_short_cmd_req_addr = NULL; + } +} + +static int bnxt_alloc_hwrm_short_cmd_req(struct bnxt *bp) +{ + struct pci_dev *pdev = bp->pdev; + + bp->hwrm_short_cmd_req_addr = + dma_alloc_coherent(&pdev->dev, BNXT_HWRM_MAX_REQ_LEN, + &bp->hwrm_short_cmd_req_dma_addr, + GFP_KERNEL); + if (!bp->hwrm_short_cmd_req_addr) + return -ENOMEM; + + return 0; +} + static void bnxt_free_stats(struct bnxt *bp) { u32 size, i; @@ -3203,16 +3239,41 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len, __le32 *resp_len, *valid; u16 cp_ring_id, len = 0; struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr; + u16 max_req_len = BNXT_HWRM_MAX_REQ_LEN; req->seq_id = cpu_to_le16(bp->hwrm_cmd_seq++); memset(resp, 0, PAGE_SIZE); cp_ring_id = le16_to_cpu(req->cmpl_ring); intr_process = (cp_ring_id == INVALID_HW_RING_ID) ? 0 : 1; + if (bp->flags & BNXT_FLAG_SHORT_CMD) { + void *short_cmd_req = bp->hwrm_short_cmd_req_addr; + struct hwrm_short_input short_input = {0}; + + memcpy(short_cmd_req, req, msg_len); + memset(short_cmd_req + msg_len, 0, BNXT_HWRM_MAX_REQ_LEN - + msg_len); + + short_input.req_type = req->req_type; + short_input.signature = + cpu_to_le16(SHORT_REQ_SIGNATURE_SHORT_CMD); + short_input.size = cpu_to_le16(msg_len); + short_input.req_addr = + cpu_to_le64(bp->hwrm_short_cmd_req_dma_addr); + + data = (u32 *)&short_input; + msg_len = sizeof(short_input); + + /* Sync memory write before updating doorbell */ + wmb(); + + max_req_len = BNXT_HWRM_SHORT_REQ_LEN; + } + /* Write request msg to hwrm channel */ __iowrite32_copy(bp->bar0, data, msg_len / 4); - for (i = msg_len; i < BNXT_HWRM_MAX_REQ_LEN; i += 4) + for (i = msg_len; i < max_req_len; i += 4) writel(0, bp->bar0 + i); /* currently supports only one outstanding message */ @@ -4650,6 +4711,7 @@ static int bnxt_hwrm_ver_get(struct bnxt *bp) int rc; struct hwrm_ver_get_input req = {0}; struct hwrm_ver_get_output *resp = bp->hwrm_cmd_resp_addr; + u32 dev_caps_cfg; bp->hwrm_max_req_len = HWRM_MAX_REQ_LEN; bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VER_GET, -1, -1); @@ -4687,6 +4749,11 @@ static int bnxt_hwrm_ver_get(struct bnxt *bp) !resp->chip_metal) bp->flags |= BNXT_FLAG_CHIP_NITRO_A0; + dev_caps_cfg = le32_to_cpu(resp->dev_caps_cfg); + if ((dev_caps_cfg & VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_SUPPORTED) && + (dev_caps_cfg & VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_REQUIRED)) + bp->flags |= BNXT_FLAG_SHORT_CMD; + hwrm_ver_get_exit: mutex_unlock(&bp->hwrm_cmd_lock); return rc; @@ -7345,6 +7412,7 @@ static void bnxt_remove_one(struct pci_dev *pdev) bnxt_clear_int_mode(bp); bnxt_hwrm_func_drv_unrgtr(bp); bnxt_free_hwrm_resources(bp); + bnxt_free_hwrm_short_cmd_req(bp); bnxt_ethtool_free(bp); bnxt_dcb_free(bp); kfree(bp->edev); @@ -7499,10 +7567,9 @@ static int bnxt_get_dflt_rings(struct bnxt *bp, int *max_rx, int *max_tx, return rc; } -static int bnxt_set_dflt_rings(struct bnxt *bp) +static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh) { int dflt_rings, max_rx_rings, max_tx_rings, rc; - bool sh = true; if (sh) bp->flags |= BNXT_FLAG_SHARED_RINGS; @@ -7595,6 +7662,12 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto init_err_pci_clean; + if (bp->flags & BNXT_FLAG_SHORT_CMD) { + rc = bnxt_alloc_hwrm_short_cmd_req(bp); + if (rc) + goto init_err_pci_clean; + } + rc = bnxt_hwrm_func_reset(bp); if (rc) goto init_err_pci_clean; @@ -7634,8 +7707,10 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) init_waitqueue_head(&bp->sriov_cfg_wait); #endif bp->gro_func = bnxt_gro_func_5730x; - if (BNXT_CHIP_NUM_57X1X(bp->chip_num)) + if (BNXT_CHIP_P4_PLUS(bp)) bp->gro_func = bnxt_gro_func_5731x; + else + bp->flags |= BNXT_FLAG_DOUBLE_DB; rc = bnxt_hwrm_func_drv_rgtr(bp); if (rc) @@ -7673,7 +7748,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) bnxt_set_tpa_flags(bp); bnxt_set_ring_params(bp); bnxt_set_max_func_irqs(bp, max_irqs); - rc = bnxt_set_dflt_rings(bp); + rc = bnxt_set_dflt_rings(bp, true); if (rc) { netdev_err(bp->dev, "Not enough rings available.\n"); rc = -ENOMEM; @@ -7685,9 +7760,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4 | VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 | VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; - if (!BNXT_CHIP_NUM_57X0X(bp->chip_num) && - !BNXT_CHIP_TYPE_NITRO_A0(bp) && - bp->hwrm_spec_code >= 0x10501) { + if (BNXT_CHIP_P4_PLUS(bp) && bp->hwrm_spec_code >= 0x10501) { bp->flags |= BNXT_FLAG_UDP_RSS_CAP; bp->rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4 | VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; @@ -7759,6 +7832,7 @@ static void bnxt_shutdown(struct pci_dev *pdev) dev_close(dev); if (system_state == SYSTEM_POWER_OFF) { + bnxt_ulp_shutdown(bp); bnxt_clear_int_mode(bp); pci_wake_from_d3(pdev, bp->wol); pci_set_power_state(pdev, PCI_D3hot); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 3ef42dbc6327..5984423499e6 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -500,6 +500,7 @@ struct rx_tpa_end_cmp_ext { #define NEXT_CMP(idx) RING_CMP(ADV_RAW_CMP(idx, 1)) #define BNXT_HWRM_MAX_REQ_LEN (bp->hwrm_max_req_len) +#define BNXT_HWRM_SHORT_REQ_LEN sizeof(struct hwrm_short_input) #define DFLT_HWRM_CMD_TIMEOUT 500 #define HWRM_CMD_TIMEOUT (bp->hwrm_cmd_timeout) #define HWRM_RESET_TIMEOUT ((HWRM_CMD_TIMEOUT) * 4) @@ -937,31 +938,45 @@ struct bnxt { #define CHIP_NUM_57402 0x16d0 #define CHIP_NUM_57404 0x16d1 #define CHIP_NUM_57406 0x16d2 +#define CHIP_NUM_57407 0x16d5 #define CHIP_NUM_57311 0x16ce #define CHIP_NUM_57312 0x16cf #define CHIP_NUM_57314 0x16df +#define CHIP_NUM_57317 0x16e0 #define CHIP_NUM_57412 0x16d6 #define CHIP_NUM_57414 0x16d7 #define CHIP_NUM_57416 0x16d8 #define CHIP_NUM_57417 0x16d9 +#define CHIP_NUM_57412L 0x16da +#define CHIP_NUM_57414L 0x16db + +#define CHIP_NUM_5745X 0xd730 #define BNXT_CHIP_NUM_5730X(chip_num) \ ((chip_num) >= CHIP_NUM_57301 && \ (chip_num) <= CHIP_NUM_57304) #define BNXT_CHIP_NUM_5740X(chip_num) \ - ((chip_num) >= CHIP_NUM_57402 && \ - (chip_num) <= CHIP_NUM_57406) + (((chip_num) >= CHIP_NUM_57402 && \ + (chip_num) <= CHIP_NUM_57406) || \ + (chip_num) == CHIP_NUM_57407) #define BNXT_CHIP_NUM_5731X(chip_num) \ ((chip_num) == CHIP_NUM_57311 || \ (chip_num) == CHIP_NUM_57312 || \ - (chip_num) == CHIP_NUM_57314) + (chip_num) == CHIP_NUM_57314 || \ + (chip_num) == CHIP_NUM_57317) #define BNXT_CHIP_NUM_5741X(chip_num) \ ((chip_num) >= CHIP_NUM_57412 && \ - (chip_num) <= CHIP_NUM_57417) + (chip_num) <= CHIP_NUM_57414L) + +#define BNXT_CHIP_NUM_58700(chip_num) \ + ((chip_num) == CHIP_NUM_58700) + +#define BNXT_CHIP_NUM_5745X(chip_num) \ + ((chip_num) == CHIP_NUM_5745X) #define BNXT_CHIP_NUM_57X0X(chip_num) \ (BNXT_CHIP_NUM_5730X(chip_num) || BNXT_CHIP_NUM_5740X(chip_num)) @@ -1006,6 +1021,8 @@ struct bnxt { #define BNXT_FLAG_RX_PAGE_MODE 0x40000 #define BNXT_FLAG_FW_LLDP_AGENT 0x80000 #define BNXT_FLAG_MULTI_HOST 0x100000 + #define BNXT_FLAG_SHORT_CMD 0x200000 + #define BNXT_FLAG_DOUBLE_DB 0x400000 #define BNXT_FLAG_CHIP_NITRO_A0 0x1000000 #define BNXT_FLAG_ALL_CONFIG_FEATS (BNXT_FLAG_TPA | \ @@ -1020,6 +1037,13 @@ struct bnxt { #define BNXT_CHIP_TYPE_NITRO_A0(bp) ((bp)->flags & BNXT_FLAG_CHIP_NITRO_A0) #define BNXT_RX_PAGE_MODE(bp) ((bp)->flags & BNXT_FLAG_RX_PAGE_MODE) +/* Chip class phase 4 and later */ +#define BNXT_CHIP_P4_PLUS(bp) \ + (BNXT_CHIP_NUM_57X1X((bp)->chip_num) || \ + BNXT_CHIP_NUM_5745X((bp)->chip_num) || \ + (BNXT_CHIP_NUM_58700((bp)->chip_num) && \ + !BNXT_CHIP_TYPE_NITRO_A0(bp))) + struct bnxt_en_dev *edev; struct bnxt_en_dev * (*ulp_probe)(struct net_device *); @@ -1106,6 +1130,8 @@ struct bnxt { u32 hwrm_spec_code; u16 hwrm_cmd_seq; u32 hwrm_intr_seq_id; + void *hwrm_short_cmd_req_addr; + dma_addr_t hwrm_short_cmd_req_dma_addr; void *hwrm_cmd_resp_addr; dma_addr_t hwrm_cmd_resp_dma_addr; void *hwrm_dbg_resp_addr; @@ -1229,6 +1255,14 @@ static inline u32 bnxt_tx_avail(struct bnxt *bp, struct bnxt_tx_ring_info *txr) ((txr->tx_prod - txr->tx_cons) & bp->tx_ring_mask); } +/* For TX and RX ring doorbells */ +static inline void bnxt_db_write(struct bnxt *bp, void __iomem *db, u32 val) +{ + writel(val, db); + if (bp->flags & BNXT_FLAG_DOUBLE_DB) + writel(val, db); +} + extern const u16 bnxt_lhint_arr[]; int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 11ddf0adc6e1..fd1181510b65 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2376,8 +2376,7 @@ static int bnxt_run_loopback(struct bnxt *bp) /* Sync BD data before updating doorbell */ wmb(); - writel(DB_KEY_TX | txr->tx_prod, txr->tx_doorbell); - writel(DB_KEY_TX | txr->tx_prod, txr->tx_doorbell); + bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | txr->tx_prod); rc = bnxt_poll_loopback(bp, pkt_size); dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c index 8b7464b76501..77da75a55c02 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c @@ -266,6 +266,25 @@ void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs) } } +void bnxt_ulp_shutdown(struct bnxt *bp) +{ + struct bnxt_en_dev *edev = bp->edev; + struct bnxt_ulp_ops *ops; + int i; + + if (!edev) + return; + + for (i = 0; i < BNXT_MAX_ULP; i++) { + struct bnxt_ulp *ulp = &edev->ulp_tbl[i]; + + ops = rtnl_dereference(ulp->ulp_ops); + if (!ops || !ops->ulp_shutdown) + continue; + ops->ulp_shutdown(ulp->handle); + } +} + void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl) { u16 event_id = le16_to_cpu(cmpl->event_id); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h index 74f816e46a33..d2471067dc37 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h @@ -26,6 +26,7 @@ struct bnxt_ulp_ops { void (*ulp_stop)(void *); void (*ulp_start)(void *); void (*ulp_sriov_config)(void *, int); + void (*ulp_shutdown)(void *); }; struct bnxt_msix_entry { @@ -87,6 +88,7 @@ void bnxt_subtract_ulp_resources(struct bnxt *bp, int ulp_id); void bnxt_ulp_stop(struct bnxt *bp); void bnxt_ulp_start(struct bnxt *bp); void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs); +void bnxt_ulp_shutdown(struct bnxt *bp); void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl); struct bnxt_en_dev *bnxt_ulp_probe(struct net_device *dev); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 9dae32756767..8ce793a0d030 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -63,7 +63,7 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts) tx_buf = &txr->tx_buf_ring[last_tx_cons]; rx_prod = tx_buf->rx_prod; } - writel(DB_KEY_RX | rx_prod, rxr->rx_doorbell); + bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rx_prod); } /* returns the following: diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c index b6117b6a1de2..20f3d2adf0c2 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c @@ -431,11 +431,6 @@ int cn23xx_octeon_pfvf_handshake(struct octeon_device *oct) mbox_cmd.fn = (octeon_mbox_callback_t)octeon_pfvf_hs_callback; mbox_cmd.fn_arg = &status; - /* Interrupts are not enabled at this point. - * Enable them with default oq ticks - */ - oct->fn_list.enable_interrupt(oct, OCTEON_ALL_INTR); - octeon_mbox_write(oct, &mbox_cmd); atomic_set(&status, 0); @@ -444,11 +439,6 @@ int cn23xx_octeon_pfvf_handshake(struct octeon_device *oct) schedule_timeout_uninterruptible(1); } while ((!atomic_read(&status)) && (count++ < 100000)); - /* Disable the interrupt so that the interrupsts will be reenabled - * with the oq ticks received from the PF - */ - oct->fn_list.disable_interrupt(oct, OCTEON_ALL_INTR); - ret = atomic_read(&status); if (!ret) { dev_err(&oct->pci_dev->dev, "octeon_pfvf_handshake timeout\n"); diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c index 579dc7336f58..2e253061460b 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c @@ -984,11 +984,11 @@ lio_get_ethtool_stats(struct net_device *netdev, data[i++] = CVM_CAST64(oct_dev->instr_queue[j]->stats.instr_posted); /*# of instructions processed */ - data[i++] = CVM_CAST64(oct_dev->instr_queue[j]-> - stats.instr_processed); + data[i++] = CVM_CAST64( + oct_dev->instr_queue[j]->stats.instr_processed); /*# of instructions could not be processed */ - data[i++] = CVM_CAST64(oct_dev->instr_queue[j]-> - stats.instr_dropped); + data[i++] = CVM_CAST64( + oct_dev->instr_queue[j]->stats.instr_dropped); /*bytes sent through the queue */ data[i++] = CVM_CAST64(oct_dev->instr_queue[j]->stats.bytes_sent); diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 927617cbf6a9..ba012427edd6 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -1421,7 +1421,7 @@ static bool fw_type_is_none(void) */ static void octeon_destroy_resources(struct octeon_device *oct) { - int i; + int i, refcount; struct msix_entry *msix_entries; struct octeon_device_priv *oct_priv = (struct octeon_device_priv *)oct->priv; @@ -1556,10 +1556,14 @@ static void octeon_destroy_resources(struct octeon_device *oct) /* fallthrough */ case OCT_DEV_PCI_MAP_DONE: + refcount = octeon_deregister_device(oct); + if (!fw_type_is_none()) { - /* Soft reset the octeon device before exiting */ - if (!OCTEON_CN23XX_PF(oct) || - (OCTEON_CN23XX_PF(oct) && !oct->octeon_id)) + /* Soft reset the octeon device before exiting. + * Implementation note: here, we reset the device + * if it is a CN6XXX OR the last CN23XX device. + */ + if (OCTEON_CN6XXX(oct) || !refcount) oct->fn_list.soft_reset(oct); } @@ -3020,6 +3024,7 @@ static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: conf.rx_filter = HWTSTAMP_FILTER_ALL; break; default: @@ -3694,6 +3699,9 @@ static int liquidio_set_vf_mac(struct net_device *netdev, int vfidx, u8 *mac) struct octeon_device *oct = lio->oct_dev; int retval; + if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) + return -EINVAL; + retval = __liquidio_set_vf_mac(netdev, vfidx, mac, true); if (!retval) cn23xx_tell_vf_its_macaddr_changed(oct, vfidx, mac); @@ -4511,6 +4519,15 @@ static int octeon_device_init(struct octeon_device *octeon_dev) atomic_set(&octeon_dev->status, OCT_DEV_PCI_MAP_DONE); + /* Only add a reference after setting status 'OCT_DEV_PCI_MAP_DONE', + * since that is what is required for the reference to be removed + * during de-initialization (see 'octeon_destroy_resources'). + */ + octeon_register_device(octeon_dev, octeon_dev->pci_dev->bus->number, + PCI_SLOT(octeon_dev->pci_dev->devfn), + PCI_FUNC(octeon_dev->pci_dev->devfn), + true); + octeon_dev->app_mode = CVM_DRV_INVALID_APP; if (OCTEON_CN23XX_PF(octeon_dev)) { diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index 34c77821fad9..07124096db48 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -879,8 +879,6 @@ liquidio_vf_probe(struct pci_dev *pdev, */ static void octeon_pci_flr(struct octeon_device *oct) { - u16 status; - pci_save_state(oct->pci_dev); pci_cfg_access_lock(oct->pci_dev); @@ -889,20 +887,7 @@ static void octeon_pci_flr(struct octeon_device *oct) pci_write_config_word(oct->pci_dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); - /* Wait for Transaction Pending bit clean */ - msleep(100); - pcie_capability_read_word(oct->pci_dev, PCI_EXP_DEVSTA, &status); - if (status & PCI_EXP_DEVSTA_TRPND) { - dev_info(&oct->pci_dev->dev, "Function reset incomplete after 100ms, sleeping for 5 seconds\n"); - ssleep(5); - pcie_capability_read_word(oct->pci_dev, PCI_EXP_DEVSTA, - &status); - if (status & PCI_EXP_DEVSTA_TRPND) - dev_info(&oct->pci_dev->dev, "Function reset still incomplete after 5s, reset anyway\n"); - } - pcie_capability_set_word(oct->pci_dev, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_BCR_FLR); - mdelay(100); + pcie_flr(oct->pci_dev); pci_cfg_access_unlock(oct->pci_dev); @@ -2100,6 +2085,7 @@ static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: conf.rx_filter = HWTSTAMP_FILTER_ALL; break; default: @@ -3202,13 +3188,28 @@ static int octeon_device_init(struct octeon_device *oct) if (octeon_setup_interrupt(oct)) return 1; + atomic_set(&oct->status, OCT_DEV_INTR_SET_DONE); + + /* *************************************************************** + * The interrupts need to be enabled for the PF<-->VF handshake. + * They are [re]-enabled after the PF<-->VF handshake so that the + * correct OQ tick value is used (i.e. the value retrieved from + * the PF as part of the handshake). + */ + + /* Enable Octeon device interrupts */ + oct->fn_list.enable_interrupt(oct, OCTEON_ALL_INTR); + if (cn23xx_octeon_pfvf_handshake(oct)) return 1; + /* Here we [re]-enable the interrupts so that the correct OQ tick value + * is used (i.e. the value that was retrieved during the handshake) + */ + /* Enable Octeon device interrupts */ oct->fn_list.enable_interrupt(oct, OCTEON_ALL_INTR); - - atomic_set(&oct->status, OCT_DEV_INTR_SET_DONE); + /* *************************************************************** */ /* Enable the input and output queues for this Octeon device */ if (oct->fn_list.enable_io_queues(oct)) { diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.c b/drivers/net/ethernet/cavium/liquidio/octeon_device.c index e21b477d0159..3b7cc9320deb 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.c @@ -543,7 +543,11 @@ static char oct_dev_app_str[CVM_DRV_APP_COUNT + 1][32] = { "BASE", "NIC", "UNKNOWN"}; static struct octeon_device *octeon_device[MAX_OCTEON_DEVICES]; +static atomic_t adapter_refcounts[MAX_OCTEON_DEVICES]; + static u32 octeon_device_count; +/* locks device array (i.e. octeon_device[]) */ +static spinlock_t octeon_devices_lock; static struct octeon_core_setup core_setup[MAX_OCTEON_DEVICES]; @@ -561,6 +565,7 @@ void octeon_init_device_list(int conf_type) memset(octeon_device, 0, (sizeof(void *) * MAX_OCTEON_DEVICES)); for (i = 0; i < MAX_OCTEON_DEVICES; i++) oct_set_config_info(i, conf_type); + spin_lock_init(&octeon_devices_lock); } static void *__retrieve_octeon_config_info(struct octeon_device *oct, @@ -720,23 +725,27 @@ struct octeon_device *octeon_allocate_device(u32 pci_id, u32 oct_idx = 0; struct octeon_device *oct = NULL; + spin_lock(&octeon_devices_lock); + for (oct_idx = 0; oct_idx < MAX_OCTEON_DEVICES; oct_idx++) if (!octeon_device[oct_idx]) break; - if (oct_idx == MAX_OCTEON_DEVICES) - return NULL; + if (oct_idx < MAX_OCTEON_DEVICES) { + oct = octeon_allocate_device_mem(pci_id, priv_size); + if (oct) { + octeon_device_count++; + octeon_device[oct_idx] = oct; + } + } - oct = octeon_allocate_device_mem(pci_id, priv_size); + spin_unlock(&octeon_devices_lock); if (!oct) return NULL; spin_lock_init(&oct->pci_win_lock); spin_lock_init(&oct->mem_access_lock); - octeon_device_count++; - octeon_device[oct_idx] = oct; - oct->octeon_id = oct_idx; snprintf(oct->device_name, sizeof(oct->device_name), "LiquidIO%d", (oct->octeon_id)); @@ -744,6 +753,72 @@ struct octeon_device *octeon_allocate_device(u32 pci_id, return oct; } +/** Register a device's bus location at initialization time. + * @param octeon_dev - pointer to the octeon device structure. + * @param bus - PCIe bus # + * @param dev - PCIe device # + * @param func - PCIe function # + * @param is_pf - TRUE for PF, FALSE for VF + * @return reference count of device's adapter + */ +int octeon_register_device(struct octeon_device *oct, + int bus, int dev, int func, int is_pf) +{ + int idx, refcount; + + oct->loc.bus = bus; + oct->loc.dev = dev; + oct->loc.func = func; + + oct->adapter_refcount = &adapter_refcounts[oct->octeon_id]; + atomic_set(oct->adapter_refcount, 0); + + spin_lock(&octeon_devices_lock); + for (idx = (int)oct->octeon_id - 1; idx >= 0; idx--) { + if (!octeon_device[idx]) { + dev_err(&oct->pci_dev->dev, + "%s: Internal driver error, missing dev", + __func__); + spin_unlock(&octeon_devices_lock); + atomic_inc(oct->adapter_refcount); + return 1; /* here, refcount is guaranteed to be 1 */ + } + /* if another device is at same bus/dev, use its refcounter */ + if ((octeon_device[idx]->loc.bus == bus) && + (octeon_device[idx]->loc.dev == dev)) { + oct->adapter_refcount = + octeon_device[idx]->adapter_refcount; + break; + } + } + spin_unlock(&octeon_devices_lock); + + atomic_inc(oct->adapter_refcount); + refcount = atomic_read(oct->adapter_refcount); + + dev_dbg(&oct->pci_dev->dev, "%s: %02x:%02x:%d refcount %u", __func__, + oct->loc.bus, oct->loc.dev, oct->loc.func, refcount); + + return refcount; +} + +/** Deregister a device at de-initialization time. + * @param octeon_dev - pointer to the octeon device structure. + * @return reference count of device's adapter + */ +int octeon_deregister_device(struct octeon_device *oct) +{ + int refcount; + + atomic_dec(oct->adapter_refcount); + refcount = atomic_read(oct->adapter_refcount); + + dev_dbg(&oct->pci_dev->dev, "%s: %04d:%02d:%d refcount %u", __func__, + oct->loc.bus, oct->loc.dev, oct->loc.func, refcount); + + return refcount; +} + int octeon_allocate_ioq_vector(struct octeon_device *oct) { @@ -1354,13 +1429,15 @@ int lio_get_device_id(void *dev) void lio_enable_irq(struct octeon_droq *droq, struct octeon_instr_queue *iq) { u64 instr_cnt; + u32 pkts_pend; struct octeon_device *oct = NULL; /* the whole thing needs to be atomic, ideally */ if (droq) { + pkts_pend = (u32)atomic_read(&droq->pkts_pending); spin_lock_bh(&droq->lock); - writel(droq->pkt_count, droq->pkts_sent_reg); - droq->pkt_count = 0; + writel(droq->pkt_count - pkts_pend, droq->pkts_sent_reg); + droq->pkt_count = pkts_pend; /* this write needs to be flushed before we release the lock */ mmiowb(); spin_unlock_bh(&droq->lock); diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.h b/drivers/net/ethernet/cavium/liquidio/octeon_device.h index 92f67de111aa..c90ed48ae8ab 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.h @@ -544,6 +544,14 @@ struct octeon_device { u32 tx_max_coalesced_frames; bool cores_crashed; + + struct { + int bus; + int dev; + int func; + } loc; + + atomic_t *adapter_refcount; /* reference count of adapter */ }; #define OCT_DRV_ONLINE 1 @@ -572,6 +580,23 @@ void octeon_free_device_mem(struct octeon_device *oct); struct octeon_device *octeon_allocate_device(u32 pci_id, u32 priv_size); +/** Register a device's bus location at initialization time. + * @param octeon_dev - pointer to the octeon device structure. + * @param bus - PCIe bus # + * @param dev - PCIe device # + * @param func - PCIe function # + * @param is_pf - TRUE for PF, FALSE for VF + * @return reference count of device's adapter + */ +int octeon_register_device(struct octeon_device *oct, + int bus, int dev, int func, int is_pf); + +/** Deregister a device at de-initialization time. + * @param octeon_dev - pointer to the octeon device structure. + * @return reference count of device's adapter + */ +int octeon_deregister_device(struct octeon_device *oct); + /** Initialize the driver's dispatch list which is a mix of a hash table * and a linked list. This is done at driver load time. * @param octeon_dev - pointer to the octeon device structure. diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c index 286be5539cef..d3a6a1c28053 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c @@ -425,8 +425,7 @@ octeon_droq_refill_pullup_descs(struct octeon_droq *droq, droq->max_count); desc_refilled++; droq->refill_count--; - } while (droq->recv_buf_list[droq->refill_idx]. - buffer); + } while (droq->recv_buf_list[droq->refill_idx].buffer); } refill_index = incr_index(refill_index, 1, droq->max_count); } /* while */ @@ -490,8 +489,8 @@ octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq) droq->recv_buf_list[droq->refill_idx].data = data; desc_ring[droq->refill_idx].buffer_ptr = - lio_map_ring(droq->recv_buf_list[droq-> - refill_idx].buffer); + lio_map_ring(droq->recv_buf_list[ + droq->refill_idx].buffer); /* Reset any previous values in the length field. */ droq->info_list[droq->refill_idx].length = 0; @@ -690,8 +689,8 @@ octeon_droq_fast_process_packets(struct octeon_device *oct, nicbuf, cpy_len, idx); - buf = droq->recv_buf_list[idx]. - buffer; + buf = droq->recv_buf_list[ + idx].buffer; recv_buffer_fast_free(buf); droq->recv_buf_list[idx].buffer = NULL; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h index 5063a12613e5..5c3c8da976f7 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h @@ -251,7 +251,7 @@ union octeon_instr_64B { /** The size of each buffer in soft command buffer pool */ -#define SOFT_COMMAND_BUFFER_SIZE 1536 +#define SOFT_COMMAND_BUFFER_SIZE 2048 struct octeon_soft_command { /** Soft command buffer info. */ diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c index 5cca73b8880b..57af7df74ced 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c @@ -178,7 +178,10 @@ int octeon_mbox_write(struct octeon_device *oct, break; } } - writeq(mbox_cmd->data[i], mbox->mbox_write_reg); + if (ret == OCTEON_MBOX_STATUS_SUCCESS) + writeq(mbox_cmd->data[i], mbox->mbox_write_reg); + else + break; } } diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.h b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.h index c9376fe075bc..1def22afeff1 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.h @@ -20,16 +20,16 @@ /* Macros for Mail Box Communication */ -#define OCTEON_MBOX_DATA_MAX 32 +#define OCTEON_MBOX_DATA_MAX 32 #define OCTEON_VF_ACTIVE 0x1 #define OCTEON_VF_FLR_REQUEST 0x2 #define OCTEON_PF_CHANGED_VF_MACADDR 0x4 /*Macro for Read acknowldgement*/ -#define OCTEON_PFVFACK 0xffffffffffffffff -#define OCTEON_PFVFSIG 0x1122334455667788 -#define OCTEON_PFVFERR 0xDEADDEADDEADDEAD +#define OCTEON_PFVFACK 0xffffffffffffffffULL +#define OCTEON_PFVFSIG 0x1122334455667788ULL +#define OCTEON_PFVFERR 0xDEADDEADDEADDEADULL #define LIO_MBOX_WRITE_WAIT_CNT 1000 #define LIO_MBOX_WRITE_WAIT_TIME msecs_to_jiffies(1) @@ -74,8 +74,8 @@ enum octeon_mbox_state { OCTEON_MBOX_STATE_REQUEST_RECEIVED = 4, OCTEON_MBOX_STATE_RESPONSE_PENDING = 8, OCTEON_MBOX_STATE_RESPONSE_RECEIVING = 16, - OCTEON_MBOX_STATE_RESPONSE_RECEIVED = 16, - OCTEON_MBOX_STATE_ERROR = 32 + OCTEON_MBOX_STATE_RESPONSE_RECEIVED = 32, + OCTEON_MBOX_STATE_ERROR = 64 }; struct octeon_mbox { diff --git a/drivers/net/ethernet/cavium/liquidio/request_manager.c b/drivers/net/ethernet/cavium/liquidio/request_manager.c index 261f448f9de2..7b297f1f6dbe 100644 --- a/drivers/net/ethernet/cavium/liquidio/request_manager.c +++ b/drivers/net/ethernet/cavium/liquidio/request_manager.c @@ -252,8 +252,7 @@ int lio_wait_for_instr_fetch(struct octeon_device *oct) if (!(oct->io_qmask.iq & BIT_ULL(i))) continue; pending = - atomic_read(&oct-> - instr_queue[i]->instr_pending); + atomic_read(&oct->instr_queue[i]->instr_pending); if (pending) __check_db_timeout(oct, i); instr_cnt += pending; diff --git a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c index a2138686c605..2887bcaf6af5 100644 --- a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c +++ b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c @@ -755,6 +755,7 @@ static int octeon_mgmt_ioctl_hwtstamp(struct net_device *netdev, case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: p->has_rx_tstamp = have_hw_timestamps; config.rx_filter = HWTSTAMP_FILTER_ALL; if (p->has_rx_tstamp) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index e88c1808e46f..b7a92ebab3cf 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -777,6 +777,7 @@ struct uld_msix_info { struct vf_info { unsigned char vf_mac_addr[ETH_ALEN]; + unsigned int tx_rate; bool pf_set_mac; }; @@ -1551,6 +1552,7 @@ int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int eqid); int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox); void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl); +int t4_update_port_info(struct port_info *pi); int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl); void t4_db_full(struct adapter *adapter); void t4_db_dropped(struct adapter *adapter); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c index 0ba7866c8259..e9bab72253bb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c @@ -500,7 +500,11 @@ static int from_fw_port_mod_type(enum fw_port_type port_type, } else if (port_type == FW_PORT_TYPE_SFP || port_type == FW_PORT_TYPE_QSFP_10G || port_type == FW_PORT_TYPE_QSA || - port_type == FW_PORT_TYPE_QSFP) { + port_type == FW_PORT_TYPE_QSFP || + port_type == FW_PORT_TYPE_CR4_QSFP || + port_type == FW_PORT_TYPE_CR_QSFP || + port_type == FW_PORT_TYPE_CR2_QSFP || + port_type == FW_PORT_TYPE_SFP28) { if (mod_type == FW_PORT_MOD_TYPE_LR || mod_type == FW_PORT_MOD_TYPE_SR || mod_type == FW_PORT_MOD_TYPE_ER || @@ -511,6 +515,9 @@ static int from_fw_port_mod_type(enum fw_port_type port_type, return PORT_DA; else return PORT_OTHER; + } else if (port_type == FW_PORT_TYPE_KR4_100G || + port_type == FW_PORT_TYPE_KR_SFP28) { + return PORT_NONE; } return PORT_OTHER; @@ -618,7 +625,21 @@ static void fw_caps_to_lmm(enum fw_port_type port_type, case FW_PORT_TYPE_CR_QSFP: case FW_PORT_TYPE_SFP28: SET_LMM(FIBRE); - SET_LMM(25000baseCR_Full); + FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); + FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full); + FW_CAPS_TO_LMM(SPEED_25G, 25000baseCR_Full); + break; + + case FW_PORT_TYPE_KR_SFP28: + SET_LMM(Backplane); + FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); + FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); + FW_CAPS_TO_LMM(SPEED_25G, 25000baseKR_Full); + break; + + case FW_PORT_TYPE_CR2_QSFP: + SET_LMM(FIBRE); + SET_LMM(50000baseSR2_Full); break; case FW_PORT_TYPE_KR4_100G: @@ -674,13 +695,20 @@ static unsigned int lmm_to_fw_caps(const unsigned long *link_mode_mask) static int get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *link_ksettings) { - const struct port_info *pi = netdev_priv(dev); + struct port_info *pi = netdev_priv(dev); struct ethtool_link_settings *base = &link_ksettings->base; ethtool_link_ksettings_zero_link_mode(link_ksettings, supported); ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); ethtool_link_ksettings_zero_link_mode(link_ksettings, lp_advertising); + /* For the nonce, the Firmware doesn't send up Port State changes + * when the Virtual Interface attached to the Port is down. So + * if it's down, let's grab any changes. + */ + if (!netif_running(dev)) + (void)t4_update_port_info(pi); + base->port = from_fw_port_mod_type(pi->port_type, pi->mod_type); if (pi->mdio_addr >= 0) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 77ed2f628f9c..6c463703e072 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -891,7 +891,7 @@ static u16 cxgb_select_queue(struct net_device *dev, struct sk_buff *skb, * The skb's priority is determined via the VLAN Tag Priority Code * Point field. */ - if (cxgb4_dcb_enabled(dev)) { + if (cxgb4_dcb_enabled(dev) && !is_kdump_kernel()) { u16 vlan_tci; int err; @@ -2249,6 +2249,13 @@ static int cxgb_open(struct net_device *dev) return err; } + /* It's possible that the basic port information could have + * changed since we first read it. + */ + err = t4_update_port_info(pi); + if (err < 0) + return err; + err = link_start(dev); if (!err) netif_tx_start_all_queues(dev); @@ -2560,6 +2567,8 @@ static int cxgb_get_vf_config(struct net_device *dev, if (vf >= adap->num_vfs) return -EINVAL; ivi->vf = vf; + ivi->max_tx_rate = adap->vfinfo[vf].tx_rate; + ivi->min_tx_rate = 0; ether_addr_copy(ivi->mac, adap->vfinfo[vf].vf_mac_addr); return 0; } @@ -2576,6 +2585,109 @@ static int cxgb_get_phys_port_id(struct net_device *dev, return 0; } +static int cxgb_set_vf_rate(struct net_device *dev, int vf, int min_tx_rate, + int max_tx_rate) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + struct fw_port_cmd port_cmd, port_rpl; + u32 link_status, speed = 0; + u32 fw_pfvf, fw_class; + int class_id = vf; + int link_ok, ret; + u16 pktsize; + + if (vf >= adap->num_vfs) + return -EINVAL; + + if (min_tx_rate) { + dev_err(adap->pdev_dev, + "Min tx rate (%d) (> 0) for VF %d is Invalid.\n", + min_tx_rate, vf); + return -EINVAL; + } + /* Retrieve link details for VF port */ + memset(&port_cmd, 0, sizeof(port_cmd)); + port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_READ_F | + FW_PORT_CMD_PORTID_V(pi->port_id)); + port_cmd.action_to_len16 = + cpu_to_be32(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_GET_PORT_INFO) | + FW_LEN16(port_cmd)); + ret = t4_wr_mbox(adap, adap->mbox, &port_cmd, sizeof(port_cmd), + &port_rpl); + if (ret != FW_SUCCESS) { + dev_err(adap->pdev_dev, + "Failed to get link status for VF %d\n", vf); + return -EINVAL; + } + link_status = be32_to_cpu(port_rpl.u.info.lstatus_to_modtype); + link_ok = (link_status & FW_PORT_CMD_LSTATUS_F) != 0; + if (!link_ok) { + dev_err(adap->pdev_dev, "Link down for VF %d\n", vf); + return -EINVAL; + } + /* Determine link speed */ + if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M)) + speed = 100; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G)) + speed = 1000; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G)) + speed = 10000; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G)) + speed = 25000; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G)) + speed = 40000; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G)) + speed = 100000; + + if (max_tx_rate > speed) { + dev_err(adap->pdev_dev, + "Max tx rate %d for VF %d can't be > link-speed %u", + max_tx_rate, vf, speed); + return -EINVAL; + } + pktsize = be16_to_cpu(port_rpl.u.info.mtu); + /* subtract ethhdr size and 4 bytes crc since, f/w appends it */ + pktsize = pktsize - sizeof(struct ethhdr) - 4; + /* subtract ipv4 hdr size, tcp hdr size to get typical IPv4 MSS size */ + pktsize = pktsize - sizeof(struct iphdr) - sizeof(struct tcphdr); + /* configure Traffic Class for rate-limiting */ + ret = t4_sched_params(adap, SCHED_CLASS_TYPE_PACKET, + SCHED_CLASS_LEVEL_CL_RL, + SCHED_CLASS_MODE_CLASS, + SCHED_CLASS_RATEUNIT_BITS, + SCHED_CLASS_RATEMODE_ABS, + pi->port_id, class_id, 0, + max_tx_rate * 1000, 0, pktsize); + if (ret) { + dev_err(adap->pdev_dev, "Err %d for Traffic Class config\n", + ret); + return -EINVAL; + } + dev_info(adap->pdev_dev, + "Class %d with MSS %u configured with rate %u\n", + class_id, pktsize, max_tx_rate); + + /* bind VF to configured Traffic Class */ + fw_pfvf = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH)); + fw_class = class_id; + ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1, &fw_pfvf, + &fw_class); + if (ret) { + dev_err(adap->pdev_dev, + "Err %d in binding VF %d to Traffic Class %d\n", + ret, vf, class_id); + return -EINVAL; + } + dev_info(adap->pdev_dev, "PF %d VF %d is bound to Class %d\n", + adap->pf, vf, class_id); + adap->vfinfo[vf].tx_rate = max_tx_rate; + return 0; +} + #endif static int cxgb_set_mac_addr(struct net_device *dev, void *p) @@ -2724,6 +2836,16 @@ static int cxgb_setup_tc(struct net_device *dev, u32 handle, __be16 proto, return -EOPNOTSUPP; } +static netdev_features_t cxgb_fix_features(struct net_device *dev, + netdev_features_t features) +{ + /* Disable GRO, if RX_CSUM is disabled */ + if (!(features & NETIF_F_RXCSUM)) + features &= ~NETIF_F_GRO; + + return features; +} + static const struct net_device_ops cxgb4_netdev_ops = { .ndo_open = cxgb_open, .ndo_stop = cxgb_close, @@ -2745,6 +2867,7 @@ static const struct net_device_ops cxgb4_netdev_ops = { #endif /* CONFIG_CHELSIO_T4_FCOE */ .ndo_set_tx_maxrate = cxgb_set_tx_maxrate, .ndo_setup_tc = cxgb_setup_tc, + .ndo_fix_features = cxgb_fix_features, }; #ifdef CONFIG_PCI_IOV @@ -2752,6 +2875,7 @@ static const struct net_device_ops cxgb4_mgmt_netdev_ops = { .ndo_open = dummy_open, .ndo_set_vf_mac = cxgb_set_vf_mac, .ndo_get_vf_config = cxgb_get_vf_config, + .ndo_set_vf_rate = cxgb_set_vf_rate, .ndo_get_phys_port_id = cxgb_get_phys_port_id, }; #endif @@ -4016,10 +4140,7 @@ static void cfg_queues(struct adapter *adap) /* Reduce memory usage in kdump environment, disable all offload. */ - if (is_kdump_kernel()) { - adap->params.offload = 0; - adap->params.crypto = 0; - } else if (is_uld(adap) && t4_uld_mem_alloc(adap)) { + if (is_kdump_kernel() || (is_uld(adap) && t4_uld_mem_alloc(adap))) { adap->params.offload = 0; adap->params.crypto = 0; } @@ -4040,7 +4161,7 @@ static void cfg_queues(struct adapter *adap) struct port_info *pi = adap2pinfo(adap, i); pi->first_qset = qidx; - pi->nqsets = 8; + pi->nqsets = is_kdump_kernel() ? 1 : 8; qidx += pi->nqsets; } #else /* !CONFIG_CHELSIO_T4_DCB */ @@ -4053,6 +4174,9 @@ static void cfg_queues(struct adapter *adap) if (q10g > netif_get_num_default_rss_queues()) q10g = netif_get_num_default_rss_queues(); + if (is_kdump_kernel()) + q10g = 1; + for_each_port(adap, i) { struct port_info *pi = adap2pinfo(adap, i); @@ -4958,6 +5082,8 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netif_set_real_num_tx_queues(adapter->port[i], pi->nqsets); netif_set_real_num_rx_queues(adapter->port[i], pi->nqsets); + netif_carrier_off(adapter->port[i]); + err = register_netdev(adapter->port[i]); if (err) break; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 3a34aa629f7d..4618185d6bc2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -6293,13 +6293,18 @@ int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, if (!t4_fw_matches_chip(adap, fw_hdr)) return -EINVAL; + /* Disable FW_OK flag so that mbox commands with FW_OK flag set + * wont be sent when we are flashing FW. + */ + adap->flags &= ~FW_OK; + ret = t4_fw_halt(adap, mbox, force); if (ret < 0 && !force) - return ret; + goto out; ret = t4_load_fw(adap, fw_data, size); if (ret < 0) - return ret; + goto out; /* * Older versions of the firmware don't understand the new @@ -6310,7 +6315,17 @@ int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, * its header flags to see if it advertises the capability. */ reset = ((be32_to_cpu(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0); - return t4_fw_restart(adap, mbox, reset); + ret = t4_fw_restart(adap, mbox, reset); + + /* Grab potentially new Firmware Device Log parameters so we can see + * how healthy the new Firmware is. It's okay to contact the new + * Firmware for these parameters even though, as far as it's + * concerned, we've never said "HELLO" to it ... + */ + (void)t4_init_devlog_params(adap); +out: + adap->flags |= FW_OK; + return ret; } /** @@ -7360,11 +7375,41 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl) lc->fc = fc; lc->supported = be16_to_cpu(p->u.info.pcap); lc->lp_advertising = be16_to_cpu(p->u.info.lpacap); + t4_os_link_changed(adap, pi->port_id, link_ok); } } /** + * t4_update_port_info - retrieve and update port information if changed + * @pi: the port_info + * + * We issue a Get Port Information Command to the Firmware and, if + * successful, we check to see if anything is different from what we + * last recorded and update things accordingly. + */ +int t4_update_port_info(struct port_info *pi) +{ + struct fw_port_cmd port_cmd; + int ret; + + memset(&port_cmd, 0, sizeof(port_cmd)); + port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | + FW_CMD_REQUEST_F | FW_CMD_READ_F | + FW_PORT_CMD_PORTID_V(pi->port_id)); + port_cmd.action_to_len16 = cpu_to_be32( + FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_GET_PORT_INFO) | + FW_LEN16(port_cmd)); + ret = t4_wr_mbox(pi->adapter, pi->adapter->mbox, + &port_cmd, sizeof(port_cmd), &port_cmd); + if (ret) + return ret; + + t4_handle_get_port_info(pi, (__be64 *)&port_cmd); + return 0; +} + +/** * t4_handle_fw_rpl - process a FW reply message * @adap: the adapter * @rpl: start of the FW message @@ -8272,7 +8317,16 @@ int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr) ret = t4_cim_read(adap, UP_UP_DBG_LA_DATA_A, 1, &la_buf[i]); if (ret) break; - idx = (idx + 1) & UPDBGLARDPTR_M; + + /* Bits 0-3 of UpDbgLaRdPtr can be between 0000 to 1001 to + * identify the 32-bit portion of the full 312-bit data + */ + if (is_t6(adap->params.chip) && (idx & 0xf) >= 9) + idx = (idx & 0xff0) + 0x10; + else + idx++; + /* address can't exceed 0xfff */ + idx &= UPDBGLARDPTR_M; } restart: if (cfg & UPDBGLAEN_F) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h index a323185507ec..be7041f6cf71 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h @@ -172,6 +172,8 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN CH_PCI_ID_TABLE_FENTRY(0x509e), /* Custom T520-CR */ CH_PCI_ID_TABLE_FENTRY(0x509f), /* Custom T540-CR */ CH_PCI_ID_TABLE_FENTRY(0x50a0), /* Custom T540-CR */ + CH_PCI_ID_TABLE_FENTRY(0x50a1), /* Custom T540-CR */ + CH_PCI_ID_TABLE_FENTRY(0x50a2), /* Custom T540-KR4 */ /* T6 adapters: */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 251a35e9795c..c65c33c03bcb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -2572,6 +2572,7 @@ enum fw_port_type { FW_PORT_TYPE_CR_QSFP, FW_PORT_TYPE_CR2_QSFP, FW_PORT_TYPE_SFP28, + FW_PORT_TYPE_KR_SFP28, FW_PORT_TYPE_NONE = FW_PORT_CMD_PTYPE_M }; diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c index 7a7c02f1f8b9..e2a702996db4 100644 --- a/drivers/net/ethernet/cirrus/ep93xx_eth.c +++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c @@ -702,7 +702,10 @@ static int ep93xx_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct ep93xx_priv *ep = netdev_priv(dev); - return mii_ethtool_get_link_ksettings(&ep->mii, cmd); + + mii_ethtool_get_link_ksettings(&ep->mii, cmd); + + return 0; } static int ep93xx_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 4b87beeabce1..6a9c8878aca0 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1537,13 +1537,12 @@ static int enic_poll(struct napi_struct *napi, int budget) */ enic_calc_int_moderation(enic, &enic->rq[0]); - if (rq_work_done < rq_work_to_do) { + if ((rq_work_done < budget) && napi_complete_done(napi, rq_work_done)) { /* Some work done, but not enough to stay in polling, * exit polling */ - napi_complete_done(napi, rq_work_done); if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) enic_set_int_moderation(enic, &enic->rq[0]); vnic_intr_unmask(&enic->intr[intr]); @@ -1663,13 +1662,12 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget) */ enic_calc_int_moderation(enic, &enic->rq[rq]); - if (work_done < work_to_do) { + if ((work_done < budget) && napi_complete_done(napi, work_done)) { /* Some work done, but not enough to stay in polling, * exit polling */ - napi_complete_done(napi, work_done); if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) enic_set_int_moderation(enic, &enic->rq[rq]); vnic_intr_unmask(&enic->intr[intr]); diff --git a/drivers/net/ethernet/dec/tulip/de2104x.c b/drivers/net/ethernet/dec/tulip/de2104x.c index 91b8f6f5a765..c87b8cc42963 100644 --- a/drivers/net/ethernet/dec/tulip/de2104x.c +++ b/drivers/net/ethernet/dec/tulip/de2104x.c @@ -1483,8 +1483,8 @@ static void __de_get_regs(struct de_private *de, u8 *buf) de_rx_missed(de, rbuf[8]); } -static int __de_get_link_ksettings(struct de_private *de, - struct ethtool_link_ksettings *cmd) +static void __de_get_link_ksettings(struct de_private *de, + struct ethtool_link_ksettings *cmd) { ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, de->media_supported); @@ -1517,8 +1517,6 @@ static int __de_get_link_ksettings(struct de_private *de, cmd->base.autoneg = AUTONEG_ENABLE; /* ignore maxtxpkt, maxrxpkt for now */ - - return 0; } static int __de_set_link_ksettings(struct de_private *de, @@ -1615,13 +1613,12 @@ static int de_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct de_private *de = netdev_priv(dev); - int rc; spin_lock_irq(&de->lock); - rc = __de_get_link_ksettings(de, cmd); + __de_get_link_ksettings(de, cmd); spin_unlock_irq(&de->lock); - return rc; + return 0; } static int de_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c index d1f2f3cc7cfa..32d7229544fa 100644 --- a/drivers/net/ethernet/dec/tulip/winbond-840.c +++ b/drivers/net/ethernet/dec/tulip/winbond-840.c @@ -1395,13 +1395,12 @@ static int netdev_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct netdev_private *np = netdev_priv(dev); - int rc; spin_lock_irq(&np->lock); - rc = mii_ethtool_get_link_ksettings(&np->mii_if, cmd); + mii_ethtool_get_link_ksettings(&np->mii_if, cmd); spin_unlock_irq(&np->lock); - return rc; + return 0; } static int netdev_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 50566243e6fa..674cf9d13b98 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -37,7 +37,7 @@ #include "be_hw.h" #include "be_roce.h" -#define DRV_VER "11.1.0.0" +#define DRV_VER "11.4.0.0" #define DRV_NAME "be2net" #define BE_NAME "Emulex BladeEngine2" #define BE3_NAME "Emulex BladeEngine3" diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h index 36e4232ed6b8..c967f45705d9 100644 --- a/drivers/net/ethernet/emulex/benet/be_hw.h +++ b/drivers/net/ethernet/emulex/benet/be_hw.h @@ -49,6 +49,9 @@ #define POST_STAGE_BE_RESET 0x3 /* Host wants to reset chip */ #define POST_STAGE_ARMFW_RDY 0xc000 /* FW is done with POST */ #define POST_STAGE_RECOVERABLE_ERR 0xE000 /* Recoverable err detected */ +/* FW has detected a UE and is dumping FAT log data */ +#define POST_STAGE_FAT_LOG_START 0x0D00 +#define POST_STAGE_ARMFW_UE 0xF000 /*FW has asserted an UE*/ /* Lancer SLIPORT registers */ #define SLIPORT_STATUS_OFFSET 0x404 diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 4eee18ce9be4..319eee36649b 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3241,8 +3241,9 @@ void be_detect_error(struct be_adapter *adapter) { u32 ue_lo = 0, ue_hi = 0, ue_lo_mask = 0, ue_hi_mask = 0; u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; - u32 i; struct device *dev = &adapter->pdev->dev; + u16 val; + u32 i; if (be_check_error(adapter, BE_ERROR_HW)) return; @@ -3280,15 +3281,25 @@ void be_detect_error(struct be_adapter *adapter) ue_lo = (ue_lo & ~ue_lo_mask); ue_hi = (ue_hi & ~ue_hi_mask); - /* On certain platforms BE hardware can indicate spurious UEs. - * Allow HW to stop working completely in case of a real UE. - * Hence not setting the hw_error for UE detection. - */ - if (ue_lo || ue_hi) { + /* On certain platforms BE3 hardware can indicate + * spurious UEs. In case of a UE in the chip, + * the POST register correctly reports either a + * FAT_LOG_START state (FW is currently dumping + * FAT log data) or a ARMFW_UE state. Check for the + * above states to ascertain if the UE is valid or not. + */ + if (BE3_chip(adapter)) { + val = be_POST_stage_get(adapter); + if ((val & POST_STAGE_FAT_LOG_START) + != POST_STAGE_FAT_LOG_START && + (val & POST_STAGE_ARMFW_UE) + != POST_STAGE_ARMFW_UE) + return; + } + dev_err(dev, "Error detected in the adapter"); - if (skyhawk_chip(adapter)) - be_set_error(adapter, BE_ERROR_UE); + be_set_error(adapter, BE_ERROR_UE); for (i = 0; ue_lo; ue_lo >>= 1, i++) { if (ue_lo & 1) diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c index 1536356e2ea8..66928a922824 100644 --- a/drivers/net/ethernet/faraday/ftmac100.c +++ b/drivers/net/ethernet/faraday/ftmac100.c @@ -829,7 +829,10 @@ static int ftmac100_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { struct ftmac100 *priv = netdev_priv(netdev); - return mii_ethtool_get_link_ksettings(&priv->mii, cmd); + + mii_ethtool_get_link_ksettings(&priv->mii, cmd); + + return 0; } static int ftmac100_set_link_ksettings(struct net_device *netdev, diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c index 766636a7c25e..610f9c07c21d 100644 --- a/drivers/net/ethernet/fealnx.c +++ b/drivers/net/ethernet/fealnx.c @@ -1821,13 +1821,12 @@ static int netdev_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct netdev_private *np = netdev_priv(dev); - int rc; spin_lock_irq(&np->lock); - rc = mii_ethtool_get_link_ksettings(&np->mii, cmd); + mii_ethtool_get_link_ksettings(&np->mii, cmd); spin_unlock_irq(&np->lock); - return rc; + return 0; } static int netdev_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 72ab7b6bf20b..9a74c4e2e193 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -46,6 +46,8 @@ #include <asm/vio.h> #include <asm/iommu.h> #include <asm/firmware.h> +#include <net/tcp.h> +#include <net/ip6_checksum.h> #include "ibmveth.h" @@ -808,8 +810,7 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data) ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr); - if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) && - !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) && + if (ret == H_SUCCESS && (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) { ret4 = h_illan_attributes(adapter->vdev->unit_address, clr_attr, set_attr, &ret_attr); @@ -1040,6 +1041,15 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, dma_addr_t dma_addr; unsigned long mss = 0; + /* veth doesn't handle frag_list, so linearize the skb. + * When GRO is enabled SKB's can have frag_list. + */ + if (adapter->is_active_trunk && + skb_has_frag_list(skb) && __skb_linearize(skb)) { + netdev->stats.tx_dropped++; + goto out; + } + /* * veth handles a maximum of 6 segments including the header, so * we have to linearize the skb if there are more than this. @@ -1064,9 +1074,6 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, desc_flags = IBMVETH_BUF_VALID; - if (skb_is_gso(skb) && adapter->fw_large_send_support) - desc_flags |= IBMVETH_BUF_LRG_SND; - if (skb->ip_summed == CHECKSUM_PARTIAL) { unsigned char *buf = skb_transport_header(skb) + skb->csum_offset; @@ -1076,6 +1083,9 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, /* Need to zero out the checksum */ buf[0] = 0; buf[1] = 0; + + if (skb_is_gso(skb) && adapter->fw_large_send_support) + desc_flags |= IBMVETH_BUF_LRG_SND; } retry_bounce: @@ -1128,7 +1138,7 @@ retry_bounce: descs[i+1].fields.address = dma_addr; } - if (skb_is_gso(skb)) { + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_is_gso(skb)) { if (adapter->fw_large_send_support) { mss = (unsigned long)skb_shinfo(skb)->gso_size; adapter->tx_large_packets++; @@ -1232,6 +1242,71 @@ static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt) } } +static void ibmveth_rx_csum_helper(struct sk_buff *skb, + struct ibmveth_adapter *adapter) +{ + struct iphdr *iph = NULL; + struct ipv6hdr *iph6 = NULL; + __be16 skb_proto = 0; + u16 iphlen = 0; + u16 iph_proto = 0; + u16 tcphdrlen = 0; + + skb_proto = be16_to_cpu(skb->protocol); + + if (skb_proto == ETH_P_IP) { + iph = (struct iphdr *)skb->data; + + /* If the IP checksum is not offloaded and if the packet + * is large send, the checksum must be rebuilt. + */ + if (iph->check == 0xffff) { + iph->check = 0; + iph->check = ip_fast_csum((unsigned char *)iph, + iph->ihl); + } + + iphlen = iph->ihl * 4; + iph_proto = iph->protocol; + } else if (skb_proto == ETH_P_IPV6) { + iph6 = (struct ipv6hdr *)skb->data; + iphlen = sizeof(struct ipv6hdr); + iph_proto = iph6->nexthdr; + } + + /* In OVS environment, when a flow is not cached, specifically for a + * new TCP connection, the first packet information is passed up + * the user space for finding a flow. During this process, OVS computes + * checksum on the first packet when CHECKSUM_PARTIAL flag is set. + * + * Given that we zeroed out TCP checksum field in transmit path + * (refer ibmveth_start_xmit routine) as we set "no checksum bit", + * OVS computed checksum will be incorrect w/o TCP pseudo checksum + * in the packet. This leads to OVS dropping the packet and hence + * TCP retransmissions are seen. + * + * So, re-compute TCP pseudo header checksum. + */ + if (iph_proto == IPPROTO_TCP && adapter->is_active_trunk) { + struct tcphdr *tcph = (struct tcphdr *)(skb->data + iphlen); + + tcphdrlen = skb->len - iphlen; + + /* Recompute TCP pseudo header checksum */ + if (skb_proto == ETH_P_IP) + tcph->check = ~csum_tcpudp_magic(iph->saddr, + iph->daddr, tcphdrlen, iph_proto, 0); + else if (skb_proto == ETH_P_IPV6) + tcph->check = ~csum_ipv6_magic(&iph6->saddr, + &iph6->daddr, tcphdrlen, iph_proto, 0); + + /* Setup SKB fields for checksum offload */ + skb_partial_csum_set(skb, iphlen, + offsetof(struct tcphdr, check)); + skb_reset_network_header(skb); + } +} + static int ibmveth_poll(struct napi_struct *napi, int budget) { struct ibmveth_adapter *adapter = @@ -1239,7 +1314,6 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) struct net_device *netdev = adapter->netdev; int frames_processed = 0; unsigned long lpar_rc; - struct iphdr *iph; u16 mss = 0; restart_poll: @@ -1297,17 +1371,7 @@ restart_poll: if (csum_good) { skb->ip_summed = CHECKSUM_UNNECESSARY; - if (be16_to_cpu(skb->protocol) == ETH_P_IP) { - iph = (struct iphdr *)skb->data; - - /* If the IP checksum is not offloaded and if the packet - * is large send, the checksum must be rebuilt. - */ - if (iph->check == 0xffff) { - iph->check = 0; - iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); - } - } + ibmveth_rx_csum_helper(skb, adapter); } if (length > netdev->mtu + ETH_HLEN) { @@ -1626,6 +1690,13 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) netdev->hw_features |= NETIF_F_TSO; } + adapter->is_active_trunk = false; + if (ret == H_SUCCESS && (ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK)) { + adapter->is_active_trunk = true; + netdev->hw_features |= NETIF_F_FRAGLIST; + netdev->features |= NETIF_F_FRAGLIST; + } + netdev->min_mtu = IBMVETH_MIN_MTU; netdev->max_mtu = ETH_MAX_MTU; diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h index ed8780cca982..01c587fc02c7 100644 --- a/drivers/net/ethernet/ibm/ibmveth.h +++ b/drivers/net/ethernet/ibm/ibmveth.h @@ -156,6 +156,7 @@ struct ibmveth_adapter { int pool_config; int rx_csum; int large_send; + bool is_active_trunk; void *bounce_buffer; dma_addr_t bounce_buffer_dma; diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index a93757c255f7..7d84e20b4887 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -163,6 +163,16 @@ static long h_reg_sub_crq(unsigned long unit_address, unsigned long token, return rc; } +static void reset_long_term_buff(struct ibmvnic_adapter *adapter, + struct ibmvnic_long_term_buff *ltb) +{ + memset(ltb->buff, 0, ltb->size); + + init_completion(&adapter->fw_done); + send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); + wait_for_completion(&adapter->fw_done); +} + static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, struct ibmvnic_long_term_buff *ltb, int size) { @@ -200,6 +210,15 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter, dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); } +static void deactivate_rx_pools(struct ibmvnic_adapter *adapter) +{ + int i; + + for (i = 0; i < be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); + i++) + adapter->rx_pool[i].active = 0; +} + static void replenish_rx_pool(struct ibmvnic_adapter *adapter, struct ibmvnic_rx_pool *pool) { @@ -217,6 +236,9 @@ static void replenish_rx_pool(struct ibmvnic_adapter *adapter, int index; int i; + if (!pool->active) + return; + handle_array = (u64 *)((u8 *)(adapter->login_rsp_buf) + be32_to_cpu(adapter->login_rsp_buf-> off_rxadd_subcrqs)); @@ -287,6 +309,15 @@ failure: dev_kfree_skb_any(skb); adapter->replenish_add_buff_failure++; atomic_add(buffers_added, &pool->available); + + if (lpar_rc == H_CLOSED) { + /* Disable buffer pool replenishment and report carrier off if + * queue is closed. Firmware guarantees that a signal will + * be sent to the driver, triggering a reset. + */ + deactivate_rx_pools(adapter); + netif_carrier_off(adapter->netdev); + } } static void replenish_pools(struct ibmvnic_adapter *adapter) @@ -331,6 +362,32 @@ static int init_stats_token(struct ibmvnic_adapter *adapter) return 0; } +static int reset_rx_pools(struct ibmvnic_adapter *adapter) +{ + struct ibmvnic_rx_pool *rx_pool; + int rx_scrqs; + int i, j; + + rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); + for (i = 0; i < rx_scrqs; i++) { + rx_pool = &adapter->rx_pool[i]; + + reset_long_term_buff(adapter, &rx_pool->long_term_buff); + + for (j = 0; j < rx_pool->size; j++) + rx_pool->free_map[j] = j; + + memset(rx_pool->rx_buff, 0, + rx_pool->size * sizeof(struct ibmvnic_rx_buff)); + + atomic_set(&rx_pool->available, 0); + rx_pool->next_alloc = 0; + rx_pool->next_free = 0; + } + + return 0; +} + static void release_rx_pools(struct ibmvnic_adapter *adapter) { struct ibmvnic_rx_pool *rx_pool; @@ -432,6 +489,32 @@ static int init_rx_pools(struct net_device *netdev) return 0; } +static int reset_tx_pools(struct ibmvnic_adapter *adapter) +{ + struct ibmvnic_tx_pool *tx_pool; + int tx_scrqs; + int i, j; + + tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs); + for (i = 0; i < tx_scrqs; i++) { + tx_pool = &adapter->tx_pool[i]; + + reset_long_term_buff(adapter, &tx_pool->long_term_buff); + + memset(tx_pool->tx_buff, 0, + adapter->req_tx_entries_per_subcrq * + sizeof(struct ibmvnic_tx_buff)); + + for (j = 0; j < adapter->req_tx_entries_per_subcrq; j++) + tx_pool->free_map[j] = j; + + tx_pool->consumer_index = 0; + tx_pool->producer_index = 0; + } + + return 0; +} + static void release_tx_pools(struct ibmvnic_adapter *adapter) { struct ibmvnic_tx_pool *tx_pool; @@ -518,6 +601,32 @@ static void release_error_buffers(struct ibmvnic_adapter *adapter) spin_unlock_irqrestore(&adapter->error_list_lock, flags); } +static void ibmvnic_napi_enable(struct ibmvnic_adapter *adapter) +{ + int i; + + if (adapter->napi_enabled) + return; + + for (i = 0; i < adapter->req_rx_queues; i++) + napi_enable(&adapter->napi[i]); + + adapter->napi_enabled = true; +} + +static void ibmvnic_napi_disable(struct ibmvnic_adapter *adapter) +{ + int i; + + if (!adapter->napi_enabled) + return; + + for (i = 0; i < adapter->req_rx_queues; i++) + napi_disable(&adapter->napi[i]); + + adapter->napi_enabled = false; +} + static int ibmvnic_login(struct net_device *netdev) { struct ibmvnic_adapter *adapter = netdev_priv(netdev); @@ -674,9 +783,7 @@ static int __ibmvnic_open(struct net_device *netdev) adapter->state = VNIC_OPENING; replenish_pools(adapter); - - for (i = 0; i < adapter->req_rx_queues; i++) - napi_enable(&adapter->napi[i]); + ibmvnic_napi_enable(adapter); /* We're ready to receive frames, enable the sub-crq interrupts and * set the logical link state to up @@ -779,13 +886,7 @@ static int __ibmvnic_close(struct net_device *netdev) adapter->state = VNIC_CLOSING; netif_tx_stop_all_queues(netdev); - - if (adapter->napi) { - for (i = 0; i < adapter->req_rx_queues; i++) - napi_disable(&adapter->napi[i]); - } - - clean_tx_pools(adapter); + ibmvnic_napi_disable(adapter); if (adapter->tx_scrq) { for (i = 0; i < adapter->req_tx_queues; i++) @@ -814,6 +915,7 @@ static int __ibmvnic_close(struct net_device *netdev) } } + clean_tx_pools(adapter); adapter->state = VNIC_CLOSED; return rc; } @@ -1092,8 +1194,14 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb_any(skb); tx_buff->skb = NULL; - if (lpar_rc == H_CLOSED) - netif_stop_subqueue(netdev, queue_num); + if (lpar_rc == H_CLOSED) { + /* Disable TX and report carrier off if queue is closed. + * Firmware guarantees that a signal will be sent to the + * driver, triggering a reset or some other action. + */ + netif_tx_stop_all_queues(netdev); + netif_carrier_off(netdev); + } tx_send_failed++; tx_dropped++; @@ -1206,37 +1314,39 @@ static int do_reset(struct ibmvnic_adapter *adapter, if (rc) return rc; - /* remove the closed state so when we call open it appears - * we are coming from the probed state. - */ - adapter->state = VNIC_PROBED; + if (adapter->reset_reason != VNIC_RESET_NON_FATAL) { + /* remove the closed state so when we call open it appears + * we are coming from the probed state. + */ + adapter->state = VNIC_PROBED; - release_resources(adapter); - release_sub_crqs(adapter); - release_crq_queue(adapter); + rc = ibmvnic_init(adapter); + if (rc) + return 0; - rc = ibmvnic_init(adapter); - if (rc) - return 0; + /* If the adapter was in PROBE state prior to the reset, + * exit here. + */ + if (reset_state == VNIC_PROBED) + return 0; - /* If the adapter was in PROBE state prior to the reset, exit here. */ - if (reset_state == VNIC_PROBED) - return 0; + rc = ibmvnic_login(netdev); + if (rc) { + adapter->state = VNIC_PROBED; + return 0; + } - rc = ibmvnic_login(netdev); - if (rc) { - adapter->state = VNIC_PROBED; - return 0; - } + rc = reset_tx_pools(adapter); + if (rc) + return rc; - rtnl_lock(); - rc = init_resources(adapter); - rtnl_unlock(); - if (rc) - return rc; + rc = reset_rx_pools(adapter); + if (rc) + return rc; - if (reset_state == VNIC_CLOSED) - return 0; + if (reset_state == VNIC_CLOSED) + return 0; + } rc = __ibmvnic_open(netdev); if (rc) { @@ -1254,6 +1364,7 @@ static int do_reset(struct ibmvnic_adapter *adapter, for (i = 0; i < adapter->req_rx_queues; i++) napi_schedule(&adapter->napi[i]); + netdev_notify_peers(netdev); return 0; } @@ -1313,6 +1424,7 @@ static void __ibmvnic_reset(struct work_struct *work) if (rc) { free_all_rwi(adapter); + mutex_unlock(&adapter->reset_lock); return; } @@ -1383,6 +1495,10 @@ static int ibmvnic_poll(struct napi_struct *napi, int budget) struct ibmvnic_adapter *adapter = netdev_priv(netdev); int scrq_num = (int)(napi - adapter->napi); int frames_processed = 0; + + if (adapter->resetting) + return 0; + restart_poll: while (frames_processed < budget) { struct sk_buff *skb; @@ -1441,7 +1557,9 @@ restart_poll: netdev->stats.rx_bytes += length; frames_processed++; } - replenish_rx_pool(adapter, &adapter->rx_pool[scrq_num]); + + if (adapter->state != VNIC_CLOSING) + replenish_rx_pool(adapter, &adapter->rx_pool[scrq_num]); if (frames_processed < budget) { enable_scrq_irq(adapter, adapter->rx_scrq[scrq_num]); @@ -1608,6 +1726,45 @@ static const struct ethtool_ops ibmvnic_ethtool_ops = { /* Routines for managing CRQs/sCRQs */ +static int reset_one_sub_crq_queue(struct ibmvnic_adapter *adapter, + struct ibmvnic_sub_crq_queue *scrq) +{ + int rc; + + if (scrq->irq) { + free_irq(scrq->irq, scrq); + irq_dispose_mapping(scrq->irq); + scrq->irq = 0; + } + + memset(scrq->msgs, 0, 2 * PAGE_SIZE); + scrq->cur = 0; + + rc = h_reg_sub_crq(adapter->vdev->unit_address, scrq->msg_token, + 4 * PAGE_SIZE, &scrq->crq_num, &scrq->hw_irq); + return rc; +} + +static int reset_sub_crq_queues(struct ibmvnic_adapter *adapter) +{ + int i, rc; + + for (i = 0; i < adapter->req_tx_queues; i++) { + rc = reset_one_sub_crq_queue(adapter, adapter->tx_scrq[i]); + if (rc) + return rc; + } + + for (i = 0; i < adapter->req_rx_queues; i++) { + rc = reset_one_sub_crq_queue(adapter, adapter->rx_scrq[i]); + if (rc) + return rc; + } + + rc = init_sub_crq_irqs(adapter); + return rc; +} + static void release_sub_crq_queue(struct ibmvnic_adapter *adapter, struct ibmvnic_sub_crq_queue *scrq) { @@ -2742,6 +2899,8 @@ static void handle_error_indication(union ibmvnic_crq *crq, if (crq->error_indication.flags & IBMVNIC_FATAL_ERROR) ibmvnic_reset(adapter, VNIC_RESET_FATAL); + else + ibmvnic_reset(adapter, VNIC_RESET_NON_FATAL); } static void handle_change_mac_rsp(union ibmvnic_crq *crq, @@ -3147,6 +3306,8 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq, switch (gen_crq->cmd) { case IBMVNIC_CRQ_INIT: dev_info(dev, "Partner initialized\n"); + adapter->from_passive_init = true; + complete(&adapter->init_done); break; case IBMVNIC_CRQ_INIT_COMPLETE: dev_info(dev, "Partner initialization complete\n"); @@ -3455,21 +3616,38 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) unsigned long timeout = msecs_to_jiffies(30000); int rc; - rc = init_crq_queue(adapter); + if (adapter->resetting) { + rc = ibmvnic_reset_crq(adapter); + if (!rc) + rc = vio_enable_interrupts(adapter->vdev); + } else { + rc = init_crq_queue(adapter); + } + if (rc) { dev_err(dev, "Couldn't initialize crq. rc=%d\n", rc); return rc; } + adapter->from_passive_init = false; + init_completion(&adapter->init_done); ibmvnic_send_crq_init(adapter); if (!wait_for_completion_timeout(&adapter->init_done, timeout)) { dev_err(dev, "Initialization sequence timed out\n"); - release_crq_queue(adapter); return -1; } - rc = init_sub_crqs(adapter); + if (adapter->from_passive_init) { + adapter->state = VNIC_OPEN; + adapter->from_passive_init = false; + return -1; + } + + if (adapter->resetting) + rc = reset_sub_crq_queues(adapter); + else + rc = init_sub_crqs(adapter); if (rc) { dev_err(dev, "Initialization of sub crqs failed\n"); release_crq_queue(adapter); diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 4702b48cfa44..7e2300e64a47 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -925,6 +925,7 @@ enum vnic_state {VNIC_PROBING = 1, enum ibmvnic_reset_reason {VNIC_RESET_FAILOVER = 1, VNIC_RESET_MOBILITY, VNIC_RESET_FATAL, + VNIC_RESET_NON_FATAL, VNIC_RESET_TIMEOUT}; struct ibmvnic_rwi { @@ -1031,4 +1032,5 @@ struct ibmvnic_adapter { struct list_head rwi_list; struct work_struct ibmvnic_reset; bool resetting; + bool napi_enabled, from_passive_init; }; diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 1542a2158e96..1feb54b6d92e 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -236,12 +236,14 @@ config I40E_DCB If unsure, say N. config I40EVF - tristate "Intel(R) XL710 X710 Virtual Function Ethernet support" + tristate "Intel(R) Ethernet Adaptive Virtual Function support" depends on PCI_MSI ---help--- - This driver supports Intel(R) XL710 and X710 virtual functions. - For more information on how to identify your adapter, go to the - Adapter & Driver ID Guide that can be located at: + This driver supports virtual functions for Intel XL710, + X710, X722, and all devices advertising support for Intel + Ethernet Adaptive Virtual Function devices. For more + information on how to identify your adapter, go to the Adapter + & Driver ID Guide that can be located at: <http://support.intel.com> diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c index 2b7323d392dc..4d10270ddf8f 100644 --- a/drivers/net/ethernet/intel/e100.c +++ b/drivers/net/ethernet/intel/e100.c @@ -2430,7 +2430,10 @@ static int e100_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { struct nic *nic = netdev_priv(netdev); - return mii_ethtool_get_link_ksettings(&nic->mii, cmd); + + mii_ethtool_get_link_ksettings(&nic->mii, cmd); + + return 0; } static int e100_set_link_ksettings(struct net_device *netdev, diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index c7c994eb410e..98e68888abb1 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -268,6 +268,7 @@ struct e1000_adapter { u32 tx_fifo_size; u32 tx_dma_failed; u32 tx_hwtstamp_timeouts; + u32 tx_hwtstamp_skipped; /* Rx */ bool (*clean_rx)(struct e1000_ring *ring, int *work_done, diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index e23dbd9190d6..003cbd605799 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -105,6 +105,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = { E1000_STAT("uncorr_ecc_errors", uncorr_errors), E1000_STAT("corr_ecc_errors", corr_errors), E1000_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), + E1000_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped), }; #define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats) @@ -2072,7 +2073,7 @@ static void e1000_get_ethtool_stats(struct net_device *netdev, pm_runtime_get_sync(netdev->dev.parent); - e1000e_get_stats64(netdev, &net_stats); + dev_get_stats(netdev, &net_stats); pm_runtime_put_sync(netdev->dev.parent); diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index b3679728caac..e1d46c11cb61 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1183,6 +1183,7 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work) struct e1000_hw *hw = &adapter->hw; if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) { + struct sk_buff *skb = adapter->tx_hwtstamp_skb; struct skb_shared_hwtstamps shhwtstamps; u64 txstmp; @@ -1191,9 +1192,14 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work) e1000e_systim_to_hwtstamp(adapter, &shhwtstamps, txstmp); - skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps); - dev_kfree_skb_any(adapter->tx_hwtstamp_skb); + /* Clear the global tx_hwtstamp_skb pointer and force writes + * prior to notifying the stack of a Tx timestamp. + */ adapter->tx_hwtstamp_skb = NULL; + wmb(); /* force write prior to skb_tstamp_tx */ + + skb_tstamp_tx(skb, &shhwtstamps); + dev_kfree_skb_any(skb); } else if (time_after(jiffies, adapter->tx_hwtstamp_start + adapter->tx_timeout_factor * HZ)) { dev_kfree_skb_any(adapter->tx_hwtstamp_skb); @@ -3680,6 +3686,7 @@ static int e1000e_config_hwtstamp(struct e1000_adapter *adapter, * Delay Request messages but not both so fall-through to * time stamp all packets. */ + case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: is_l2 = true; is_l4 = true; @@ -5860,17 +5867,20 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, nr_frags); if (count) { if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && - (adapter->flags & FLAG_HAS_HW_TIMESTAMP) && - !adapter->tx_hwtstamp_skb) { - skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - tx_flags |= E1000_TX_FLAGS_HWTSTAMP; - adapter->tx_hwtstamp_skb = skb_get(skb); - adapter->tx_hwtstamp_start = jiffies; - schedule_work(&adapter->tx_hwtstamp_work); - } else { - skb_tx_timestamp(skb); + (adapter->flags & FLAG_HAS_HW_TIMESTAMP)) { + if (!adapter->tx_hwtstamp_skb) { + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + tx_flags |= E1000_TX_FLAGS_HWTSTAMP; + adapter->tx_hwtstamp_skb = skb_get(skb); + adapter->tx_hwtstamp_start = jiffies; + schedule_work(&adapter->tx_hwtstamp_work); + } else { + adapter->tx_hwtstamp_skipped++; + } } + skb_tx_timestamp(skb); + netdev_sent_queue(netdev, skb->len); e1000_tx_queue(tx_ring, tx_flags, count); /* Make sure there is space in the ring for the next send. */ @@ -6733,20 +6743,20 @@ static irqreturn_t e1000_intr_msix(int __always_unused irq, void *data) vector = 0; msix_irq = adapter->msix_entries[vector].vector; - disable_irq(msix_irq); - e1000_intr_msix_rx(msix_irq, netdev); + if (disable_hardirq(msix_irq)) + e1000_intr_msix_rx(msix_irq, netdev); enable_irq(msix_irq); vector++; msix_irq = adapter->msix_entries[vector].vector; - disable_irq(msix_irq); - e1000_intr_msix_tx(msix_irq, netdev); + if (disable_hardirq(msix_irq)) + e1000_intr_msix_tx(msix_irq, netdev); enable_irq(msix_irq); vector++; msix_irq = adapter->msix_entries[vector].vector; - disable_irq(msix_irq); - e1000_msix_other(msix_irq, netdev); + if (disable_hardirq(msix_irq)) + e1000_msix_other(msix_irq, netdev); enable_irq(msix_irq); } diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index cdde3cc28fb5..60dc9b2c19ff 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -57,7 +57,7 @@ #include "i40e_type.h" #include "i40e_prototype.h" #include "i40e_client.h" -#include "i40e_virtchnl.h" +#include <linux/avf/virtchnl.h> #include "i40e_virtchnl_pf.h" #include "i40e_txrx.h" #include "i40e_dcb.h" @@ -502,10 +502,12 @@ struct i40e_pf { struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_caps; struct sk_buff *ptp_tx_skb; + unsigned long ptp_tx_start; struct hwtstamp_config tstamp_config; struct mutex tmreg_lock; /* Used to protect the SYSTIME registers. */ u64 ptp_base_adj; u32 tx_hwtstamp_timeouts; + u32 tx_hwtstamp_skipped; u32 rx_hwtstamp_cleared; u32 latch_event_flags; spinlock_t ptp_rx_lock; /* Used to protect Rx timestamp registers. */ @@ -955,7 +957,8 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf, struct i40e_dcbx_config *old_cfg, struct i40e_dcbx_config *new_cfg); #endif /* CONFIG_I40E_DCB */ -void i40e_ptp_rx_hang(struct i40e_vsi *vsi); +void i40e_ptp_rx_hang(struct i40e_pf *pf); +void i40e_ptp_tx_hang(struct i40e_pf *pf); void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf); void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index); void i40e_ptp_set_increment(struct i40e_pf *pf); diff --git a/drivers/net/ethernet/intel/i40e/i40e_client.c b/drivers/net/ethernet/intel/i40e/i40e_client.c index c3b81a97558e..36f694ccdc09 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_client.c +++ b/drivers/net/ethernet/intel/i40e/i40e_client.c @@ -565,7 +565,7 @@ static int i40e_client_virtchnl_send(struct i40e_info *ldev, struct i40e_hw *hw = &pf->hw; i40e_status err; - err = i40e_aq_send_msg_to_vf(hw, vf_id, I40E_VIRTCHNL_OP_IWARP, + err = i40e_aq_send_msg_to_vf(hw, vf_id, VIRTCHNL_OP_IWARP, 0, msg, len, NULL); if (err) dev_err(&pf->pdev->dev, "Unable to send iWarp message to VF, error %d, aq status %d\n", @@ -595,6 +595,8 @@ static int i40e_client_setup_qvlist(struct i40e_info *ldev, size = sizeof(struct i40e_qvlist_info) + (sizeof(struct i40e_qv_info) * (qvlist_info->num_vectors - 1)); ldev->qvlist_info = kzalloc(size, GFP_KERNEL); + if (!ldev->qvlist_info) + return -ENOMEM; ldev->qvlist_info->num_vectors = qvlist_info->num_vectors; for (i = 0; i < qvlist_info->num_vectors; i++) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 24f020655291..cbad4eba7ae7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -27,7 +27,7 @@ #include "i40e_type.h" #include "i40e_adminq.h" #include "i40e_prototype.h" -#include "i40e_virtchnl.h" +#include <linux/avf/virtchnl.h> /** * i40e_set_mac_type - Sets MAC type diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 7a8eb486b9ea..35a246f05520 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -147,6 +147,7 @@ static const struct i40e_stats i40e_gstrings_stats[] = { I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests), I40E_PF_STAT("arq_overflows", arq_overflows), I40E_PF_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared), + I40E_PF_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped), I40E_PF_STAT("fdir_flush_cnt", fd_flush_cnt), I40E_PF_STAT("fdir_atr_match", stats.fd_atr_match), I40E_PF_STAT("fdir_atr_tunnel_match", stats.fd_atr_tunnel_match), diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 150caf6ca2b4..5fef27ebfa52 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6372,7 +6372,8 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf) i40e_update_veb_stats(pf->veb[i]); } - i40e_ptp_rx_hang(pf->vsi[pf->lan_vsi]); + i40e_ptp_rx_hang(pf); + i40e_ptp_tx_hang(pf); } /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index c56d976cf85a..df613ea40313 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -29,7 +29,7 @@ #include "i40e_type.h" #include "i40e_alloc.h" -#include "i40e_virtchnl.h" +#include <linux/avf/virtchnl.h> /* Prototypes for shared code functions that are not in * the standard function pointer structures. These are @@ -333,10 +333,10 @@ static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) /* i40e_common for VF drivers*/ void i40e_vf_parse_hw_config(struct i40e_hw *hw, - struct i40e_virtchnl_vf_resource *msg); + struct virtchnl_vf_resource *msg); i40e_status i40e_vf_reset(struct i40e_hw *hw); i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, - enum i40e_virtchnl_ops v_opcode, + enum virtchnl_ops v_opcode, i40e_status v_retval, u8 *msg, u16 msglen, struct i40e_asq_cmd_details *cmd_details); diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 18c1cc08da97..1a0be835fa06 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -269,6 +269,7 @@ static u32 i40e_ptp_get_rx_events(struct i40e_pf *pf) /** * i40e_ptp_rx_hang - Detect error case when Rx timestamp registers are hung + * @pf: The PF private data structure * @vsi: The VSI with the rings relevant to 1588 * * This watchdog task is scheduled to detect error case where hardware has @@ -276,9 +277,8 @@ static u32 i40e_ptp_get_rx_events(struct i40e_pf *pf) * particular error is rare but leaves the device in a state unable to timestamp * any future packets. **/ -void i40e_ptp_rx_hang(struct i40e_vsi *vsi) +void i40e_ptp_rx_hang(struct i40e_pf *pf) { - struct i40e_pf *pf = vsi->back; struct i40e_hw *hw = &pf->hw; unsigned int i, cleared = 0; @@ -328,6 +328,36 @@ void i40e_ptp_rx_hang(struct i40e_vsi *vsi) } /** + * i40e_ptp_tx_hang - Detect error case when Tx timestamp register is hung + * @pf: The PF private data structure + * + * This watchdog task is run periodically to make sure that we clear the Tx + * timestamp logic if we don't obtain a timestamp in a reasonable amount of + * time. It is unexpected in the normal case but if it occurs it results in + * permanently prevent timestamps of future packets + **/ +void i40e_ptp_tx_hang(struct i40e_pf *pf) +{ + if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx) + return; + + /* Nothing to do if we're not already waiting for a timestamp */ + if (!test_bit(__I40E_PTP_TX_IN_PROGRESS, pf->state)) + return; + + /* We already have a handler routine which is run when we are notified + * of a Tx timestamp in the hardware. If we don't get an interrupt + * within a second it is reasonable to assume that we never will. + */ + if (time_is_before_jiffies(pf->ptp_tx_start + HZ)) { + dev_kfree_skb_any(pf->ptp_tx_skb); + pf->ptp_tx_skb = NULL; + clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, pf->state); + pf->tx_hwtstamp_timeouts++; + } +} + +/** * i40e_ptp_tx_hwtstamp - Utility function which returns the Tx timestamp * @pf: Board private structure * @@ -338,6 +368,7 @@ void i40e_ptp_rx_hang(struct i40e_vsi *vsi) void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf) { struct skb_shared_hwtstamps shhwtstamps; + struct sk_buff *skb = pf->ptp_tx_skb; struct i40e_hw *hw = &pf->hw; u32 hi, lo; u64 ns; @@ -353,12 +384,19 @@ void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf) hi = rd32(hw, I40E_PRTTSYN_TXTIME_H); ns = (((u64)hi) << 32) | lo; - i40e_ptp_convert_to_hwtstamp(&shhwtstamps, ns); - skb_tstamp_tx(pf->ptp_tx_skb, &shhwtstamps); - dev_kfree_skb_any(pf->ptp_tx_skb); + + /* Clear the bit lock as soon as possible after reading the register, + * and prior to notifying the stack via skb_tstamp_tx(). Otherwise + * applications might wake up and attempt to request another transmit + * timestamp prior to the bit lock being cleared. + */ pf->ptp_tx_skb = NULL; clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, pf->state); + + /* Notify the stack and free the skb after we've unlocked */ + skb_tstamp_tx(skb, &shhwtstamps); + dev_kfree_skb_any(skb); } /** @@ -562,6 +600,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; } break; + case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: default: return -ERANGE; diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index cd894f4023b1..ddf885084c77 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2629,8 +2629,10 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb, if (pf->ptp_tx && !test_and_set_bit_lock(__I40E_PTP_TX_IN_PROGRESS, pf->state)) { skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + pf->ptp_tx_start = jiffies; pf->ptp_tx_skb = skb_get(skb); } else { + pf->tx_hwtstamp_skipped++; return 0; } @@ -2933,10 +2935,12 @@ bool __i40e_chk_linearize(struct sk_buff *skb) * @hdr_len: size of the packet header * @td_cmd: the command field in the descriptor * @td_offset: offset for checksum or crc + * + * Returns 0 on success, -1 on failure to DMA **/ -static inline void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, - struct i40e_tx_buffer *first, u32 tx_flags, - const u8 hdr_len, u32 td_cmd, u32 td_offset) +static inline int i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, + struct i40e_tx_buffer *first, u32 tx_flags, + const u8 hdr_len, u32 td_cmd, u32 td_offset) { unsigned int data_len = skb->data_len; unsigned int size = skb_headlen(skb); @@ -3094,7 +3098,7 @@ do_rs: mmiowb(); } - return; + return 0; dma_error: dev_info(tx_ring->dev, "TX DMA map failed\n"); @@ -3111,6 +3115,8 @@ dma_error: } tx_ring->next_to_use = i; + + return -1; } /** @@ -3211,8 +3217,9 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, */ i40e_atr(tx_ring, skb, tx_flags); - i40e_tx_map(tx_ring, skb, first, tx_flags, hdr_len, - td_cmd, td_offset); + if (i40e_tx_map(tx_ring, skb, first, tx_flags, hdr_len, + td_cmd, td_offset)) + goto cleanup_tx_tstamp; return NETDEV_TX_OK; @@ -3220,6 +3227,15 @@ out_drop: i40e_trace(xmit_frame_ring_drop, first->skb, tx_ring); dev_kfree_skb_any(first->skb); first->skb = NULL; +cleanup_tx_tstamp: + if (unlikely(tx_flags & I40E_TX_FLAGS_TSYN)) { + struct i40e_pf *pf = i40e_netdev_to_pf(tx_ring->netdev); + + dev_kfree_skb_any(pf->ptp_tx_skb); + pf->ptp_tx_skb = NULL; + clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, pf->state); + } + return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h deleted file mode 100644 index 8552192a5bde..000000000000 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h +++ /dev/null @@ -1,449 +0,0 @@ -/******************************************************************************* - * - * Intel Ethernet Controller XL710 Family Linux Driver - * Copyright(c) 2013 - 2014 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - ******************************************************************************/ - -#ifndef _I40E_VIRTCHNL_H_ -#define _I40E_VIRTCHNL_H_ - -#include "i40e_type.h" - -/* Description: - * This header file describes the VF-PF communication protocol used - * by the various i40e drivers. - * - * Admin queue buffer usage: - * desc->opcode is always i40e_aqc_opc_send_msg_to_pf - * flags, retval, datalen, and data addr are all used normally. - * Firmware copies the cookie fields when sending messages between the PF and - * VF, but uses all other fields internally. Due to this limitation, we - * must send all messages as "indirect", i.e. using an external buffer. - * - * All the vsi indexes are relative to the VF. Each VF can have maximum of - * three VSIs. All the queue indexes are relative to the VSI. Each VF can - * have a maximum of sixteen queues for all of its VSIs. - * - * The PF is required to return a status code in v_retval for all messages - * except RESET_VF, which does not require any response. The return value is of - * i40e_status_code type, defined in the i40e_type.h. - * - * In general, VF driver initialization should roughly follow the order of these - * opcodes. The VF driver must first validate the API version of the PF driver, - * then request a reset, then get resources, then configure queues and - * interrupts. After these operations are complete, the VF driver may start - * its queues, optionally add MAC and VLAN filters, and process traffic. - */ - -/* Opcodes for VF-PF communication. These are placed in the v_opcode field - * of the virtchnl_msg structure. - */ -enum i40e_virtchnl_ops { -/* The PF sends status change events to VFs using - * the I40E_VIRTCHNL_OP_EVENT opcode. - * VFs send requests to the PF using the other ops. - */ - I40E_VIRTCHNL_OP_UNKNOWN = 0, - I40E_VIRTCHNL_OP_VERSION = 1, /* must ALWAYS be 1 */ - I40E_VIRTCHNL_OP_RESET_VF = 2, - I40E_VIRTCHNL_OP_GET_VF_RESOURCES = 3, - I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE = 4, - I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE = 5, - I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES = 6, - I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP = 7, - I40E_VIRTCHNL_OP_ENABLE_QUEUES = 8, - I40E_VIRTCHNL_OP_DISABLE_QUEUES = 9, - I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS = 10, - I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS = 11, - I40E_VIRTCHNL_OP_ADD_VLAN = 12, - I40E_VIRTCHNL_OP_DEL_VLAN = 13, - I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE = 14, - I40E_VIRTCHNL_OP_GET_STATS = 15, - I40E_VIRTCHNL_OP_FCOE = 16, - I40E_VIRTCHNL_OP_EVENT = 17, /* must ALWAYS be 17 */ - I40E_VIRTCHNL_OP_IWARP = 20, - I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP = 21, - I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP = 22, - I40E_VIRTCHNL_OP_CONFIG_RSS_KEY = 23, - I40E_VIRTCHNL_OP_CONFIG_RSS_LUT = 24, - I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS = 25, - I40E_VIRTCHNL_OP_SET_RSS_HENA = 26, - -}; - -/* Virtual channel message descriptor. This overlays the admin queue - * descriptor. All other data is passed in external buffers. - */ - -struct i40e_virtchnl_msg { - u8 pad[8]; /* AQ flags/opcode/len/retval fields */ - enum i40e_virtchnl_ops v_opcode; /* avoid confusion with desc->opcode */ - i40e_status v_retval; /* ditto for desc->retval */ - u32 vfid; /* used by PF when sending to VF */ -}; - -/* Message descriptions and data structures.*/ - -/* I40E_VIRTCHNL_OP_VERSION - * VF posts its version number to the PF. PF responds with its version number - * in the same format, along with a return code. - * Reply from PF has its major/minor versions also in param0 and param1. - * If there is a major version mismatch, then the VF cannot operate. - * If there is a minor version mismatch, then the VF can operate but should - * add a warning to the system log. - * - * This enum element MUST always be specified as == 1, regardless of other - * changes in the API. The PF must always respond to this message without - * error regardless of version mismatch. - */ -#define I40E_VIRTCHNL_VERSION_MAJOR 1 -#define I40E_VIRTCHNL_VERSION_MINOR 1 -#define I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS 0 - -struct i40e_virtchnl_version_info { - u32 major; - u32 minor; -}; - -/* I40E_VIRTCHNL_OP_RESET_VF - * VF sends this request to PF with no parameters - * PF does NOT respond! VF driver must delay then poll VFGEN_RSTAT register - * until reset completion is indicated. The admin queue must be reinitialized - * after this operation. - * - * When reset is complete, PF must ensure that all queues in all VSIs associated - * with the VF are stopped, all queue configurations in the HMC are set to 0, - * and all MAC and VLAN filters (except the default MAC address) on all VSIs - * are cleared. - */ - -/* I40E_VIRTCHNL_OP_GET_VF_RESOURCES - * Version 1.0 VF sends this request to PF with no parameters - * Version 1.1 VF sends this request to PF with u32 bitmap of its capabilities - * PF responds with an indirect message containing - * i40e_virtchnl_vf_resource and one or more - * i40e_virtchnl_vsi_resource structures. - */ - -struct i40e_virtchnl_vsi_resource { - u16 vsi_id; - u16 num_queue_pairs; - enum i40e_vsi_type vsi_type; - u16 qset_handle; - u8 default_mac_addr[ETH_ALEN]; -}; -/* VF offload flags */ -#define I40E_VIRTCHNL_VF_OFFLOAD_L2 0x00000001 -#define I40E_VIRTCHNL_VF_OFFLOAD_IWARP 0x00000002 -#define I40E_VIRTCHNL_VF_OFFLOAD_FCOE 0x00000004 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ 0x00000008 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG 0x00000010 -#define I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR 0x00000020 -#define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000 -#define I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING 0x00020000 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 0x00040000 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF 0X00080000 -#define I40E_VIRTCHNL_VF_OFFLOAD_ENCAP 0X00100000 -#define I40E_VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM 0X00200000 - -#define I40E_VF_BASE_MODE_OFFLOADS (I40E_VIRTCHNL_VF_OFFLOAD_L2 | \ - I40E_VIRTCHNL_VF_OFFLOAD_VLAN | \ - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF) - -struct i40e_virtchnl_vf_resource { - u16 num_vsis; - u16 num_queue_pairs; - u16 max_vectors; - u16 max_mtu; - - u32 vf_offload_flags; - u32 rss_key_size; - u32 rss_lut_size; - - struct i40e_virtchnl_vsi_resource vsi_res[1]; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE - * VF sends this message to set up parameters for one TX queue. - * External data buffer contains one instance of i40e_virtchnl_txq_info. - * PF configures requested queue and returns a status code. - */ - -/* Tx queue config info */ -struct i40e_virtchnl_txq_info { - u16 vsi_id; - u16 queue_id; - u16 ring_len; /* number of descriptors, multiple of 8 */ - u16 headwb_enabled; - u64 dma_ring_addr; - u64 dma_headwb_addr; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE - * VF sends this message to set up parameters for one RX queue. - * External data buffer contains one instance of i40e_virtchnl_rxq_info. - * PF configures requested queue and returns a status code. - */ - -/* Rx queue config info */ -struct i40e_virtchnl_rxq_info { - u16 vsi_id; - u16 queue_id; - u32 ring_len; /* number of descriptors, multiple of 32 */ - u16 hdr_size; - u16 splithdr_enabled; - u32 databuffer_size; - u32 max_pkt_size; - u64 dma_ring_addr; - enum i40e_hmc_obj_rx_hsplit_0 rx_split_pos; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES - * VF sends this message to set parameters for all active TX and RX queues - * associated with the specified VSI. - * PF configures queues and returns status. - * If the number of queues specified is greater than the number of queues - * associated with the VSI, an error is returned and no queues are configured. - */ -struct i40e_virtchnl_queue_pair_info { - /* NOTE: vsi_id and queue_id should be identical for both queues. */ - struct i40e_virtchnl_txq_info txq; - struct i40e_virtchnl_rxq_info rxq; -}; - -struct i40e_virtchnl_vsi_queue_config_info { - u16 vsi_id; - u16 num_queue_pairs; - struct i40e_virtchnl_queue_pair_info qpair[1]; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP - * VF uses this message to map vectors to queues. - * The rxq_map and txq_map fields are bitmaps used to indicate which queues - * are to be associated with the specified vector. - * The "other" causes are always mapped to vector 0. - * PF configures interrupt mapping and returns status. - */ -struct i40e_virtchnl_vector_map { - u16 vsi_id; - u16 vector_id; - u16 rxq_map; - u16 txq_map; - u16 rxitr_idx; - u16 txitr_idx; -}; - -struct i40e_virtchnl_irq_map_info { - u16 num_vectors; - struct i40e_virtchnl_vector_map vecmap[1]; -}; - -/* I40E_VIRTCHNL_OP_ENABLE_QUEUES - * I40E_VIRTCHNL_OP_DISABLE_QUEUES - * VF sends these message to enable or disable TX/RX queue pairs. - * The queues fields are bitmaps indicating which queues to act upon. - * (Currently, we only support 16 queues per VF, but we make the field - * u32 to allow for expansion.) - * PF performs requested action and returns status. - */ -struct i40e_virtchnl_queue_select { - u16 vsi_id; - u16 pad; - u32 rx_queues; - u32 tx_queues; -}; - -/* I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS - * VF sends this message in order to add one or more unicast or multicast - * address filters for the specified VSI. - * PF adds the filters and returns status. - */ - -/* I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS - * VF sends this message in order to remove one or more unicast or multicast - * filters for the specified VSI. - * PF removes the filters and returns status. - */ - -struct i40e_virtchnl_ether_addr { - u8 addr[ETH_ALEN]; - u8 pad[2]; -}; - -struct i40e_virtchnl_ether_addr_list { - u16 vsi_id; - u16 num_elements; - struct i40e_virtchnl_ether_addr list[1]; -}; - -/* I40E_VIRTCHNL_OP_ADD_VLAN - * VF sends this message to add one or more VLAN tag filters for receives. - * PF adds the filters and returns status. - * If a port VLAN is configured by the PF, this operation will return an - * error to the VF. - */ - -/* I40E_VIRTCHNL_OP_DEL_VLAN - * VF sends this message to remove one or more VLAN tag filters for receives. - * PF removes the filters and returns status. - * If a port VLAN is configured by the PF, this operation will return an - * error to the VF. - */ - -struct i40e_virtchnl_vlan_filter_list { - u16 vsi_id; - u16 num_elements; - u16 vlan_id[1]; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE - * VF sends VSI id and flags. - * PF returns status code in retval. - * Note: we assume that broadcast accept mode is always enabled. - */ -struct i40e_virtchnl_promisc_info { - u16 vsi_id; - u16 flags; -}; - -#define I40E_FLAG_VF_UNICAST_PROMISC 0x00000001 -#define I40E_FLAG_VF_MULTICAST_PROMISC 0x00000002 - -/* I40E_VIRTCHNL_OP_GET_STATS - * VF sends this message to request stats for the selected VSI. VF uses - * the i40e_virtchnl_queue_select struct to specify the VSI. The queue_id - * field is ignored by the PF. - * - * PF replies with struct i40e_eth_stats in an external buffer. - */ - -/* I40E_VIRTCHNL_OP_CONFIG_RSS_KEY - * I40E_VIRTCHNL_OP_CONFIG_RSS_LUT - * VF sends these messages to configure RSS. Only supported if both PF - * and VF drivers set the I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF bit during - * configuration negotiation. If this is the case, then the RSS fields in - * the VF resource struct are valid. - * Both the key and LUT are initialized to 0 by the PF, meaning that - * RSS is effectively disabled until set up by the VF. - */ -struct i40e_virtchnl_rss_key { - u16 vsi_id; - u16 key_len; - u8 key[1]; /* RSS hash key, packed bytes */ -}; - -struct i40e_virtchnl_rss_lut { - u16 vsi_id; - u16 lut_entries; - u8 lut[1]; /* RSS lookup table*/ -}; - -/* I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS - * I40E_VIRTCHNL_OP_SET_RSS_HENA - * VF sends these messages to get and set the hash filter enable bits for RSS. - * By default, the PF sets these to all possible traffic types that the - * hardware supports. The VF can query this value if it wants to change the - * traffic types that are hashed by the hardware. - * Traffic types are defined in the i40e_filter_pctype enum in i40e_type.h - */ -struct i40e_virtchnl_rss_hena { - u64 hena; -}; - -/* I40E_VIRTCHNL_OP_EVENT - * PF sends this message to inform the VF driver of events that may affect it. - * No direct response is expected from the VF, though it may generate other - * messages in response to this one. - */ -enum i40e_virtchnl_event_codes { - I40E_VIRTCHNL_EVENT_UNKNOWN = 0, - I40E_VIRTCHNL_EVENT_LINK_CHANGE, - I40E_VIRTCHNL_EVENT_RESET_IMPENDING, - I40E_VIRTCHNL_EVENT_PF_DRIVER_CLOSE, -}; -#define I40E_PF_EVENT_SEVERITY_INFO 0 -#define I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM 255 - -struct i40e_virtchnl_pf_event { - enum i40e_virtchnl_event_codes event; - union { - struct { - enum i40e_aq_link_speed link_speed; - bool link_status; - } link_event; - } event_data; - - int severity; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP - * VF uses this message to request PF to map IWARP vectors to IWARP queues. - * The request for this originates from the VF IWARP driver through - * a client interface between VF LAN and VF IWARP driver. - * A vector could have an AEQ and CEQ attached to it although - * there is a single AEQ per VF IWARP instance in which case - * most vectors will have an INVALID_IDX for aeq and valid idx for ceq. - * There will never be a case where there will be multiple CEQs attached - * to a single vector. - * PF configures interrupt mapping and returns status. - */ - -/* HW does not define a type value for AEQ; only for RX/TX and CEQ. - * In order for us to keep the interface simple, SW will define a - * unique type value for AEQ. -*/ -#define I40E_QUEUE_TYPE_PE_AEQ 0x80 -#define I40E_QUEUE_INVALID_IDX 0xFFFF - -struct i40e_virtchnl_iwarp_qv_info { - u32 v_idx; /* msix_vector */ - u16 ceq_idx; - u16 aeq_idx; - u8 itr_idx; -}; - -struct i40e_virtchnl_iwarp_qvlist_info { - u32 num_vectors; - struct i40e_virtchnl_iwarp_qv_info qv_info[1]; -}; - -/* VF reset states - these are written into the RSTAT register: - * I40E_VFGEN_RSTAT1 on the PF - * I40E_VFGEN_RSTAT on the VF - * When the PF initiates a reset, it writes 0 - * When the reset is complete, it writes 1 - * When the PF detects that the VF has recovered, it writes 2 - * VF checks this register periodically to determine if a reset has occurred, - * then polls it to know when the reset is complete. - * If either the PF or VF reads the register while the hardware - * is in a reset state, it will return DEADBEEF, which, when masked - * will result in 3. - */ -enum i40e_vfr_states { - I40E_VFR_INPROGRESS = 0, - I40E_VFR_COMPLETED, - I40E_VFR_VFACTIVE, - I40E_VFR_UNKNOWN, -}; - -#endif /* _I40E_VIRTCHNL_H_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 95c23fbaa211..6bee254d34ee 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -39,7 +39,7 @@ * send a message to all VFs on a given PF **/ static void i40e_vc_vf_broadcast(struct i40e_pf *pf, - enum i40e_virtchnl_ops v_opcode, + enum virtchnl_ops v_opcode, i40e_status v_retval, u8 *msg, u16 msglen) { @@ -70,14 +70,14 @@ static void i40e_vc_vf_broadcast(struct i40e_pf *pf, **/ static void i40e_vc_notify_vf_link_state(struct i40e_vf *vf) { - struct i40e_virtchnl_pf_event pfe; + struct virtchnl_pf_event pfe; struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; struct i40e_link_status *ls = &pf->hw.phy.link_info; int abs_vf_id = vf->vf_id + (int)hw->func_caps.vf_base_id; - pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE; - pfe.severity = I40E_PF_EVENT_SEVERITY_INFO; + pfe.event = VIRTCHNL_EVENT_LINK_CHANGE; + pfe.severity = PF_EVENT_SEVERITY_INFO; if (vf->link_forced) { pfe.event_data.link_event.link_status = vf->link_up; pfe.event_data.link_event.link_speed = @@ -85,9 +85,10 @@ static void i40e_vc_notify_vf_link_state(struct i40e_vf *vf) } else { pfe.event_data.link_event.link_status = ls->link_info & I40E_AQ_LINK_UP; - pfe.event_data.link_event.link_speed = ls->link_speed; + pfe.event_data.link_event.link_speed = + (enum virtchnl_link_speed)ls->link_speed; } - i40e_aq_send_msg_to_vf(hw, abs_vf_id, I40E_VIRTCHNL_OP_EVENT, + i40e_aq_send_msg_to_vf(hw, abs_vf_id, VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe, sizeof(pfe), NULL); } @@ -113,12 +114,12 @@ void i40e_vc_notify_link_state(struct i40e_pf *pf) **/ void i40e_vc_notify_reset(struct i40e_pf *pf) { - struct i40e_virtchnl_pf_event pfe; + struct virtchnl_pf_event pfe; - pfe.event = I40E_VIRTCHNL_EVENT_RESET_IMPENDING; - pfe.severity = I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM; - i40e_vc_vf_broadcast(pf, I40E_VIRTCHNL_OP_EVENT, 0, - (u8 *)&pfe, sizeof(struct i40e_virtchnl_pf_event)); + pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING; + pfe.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM; + i40e_vc_vf_broadcast(pf, VIRTCHNL_OP_EVENT, 0, + (u8 *)&pfe, sizeof(struct virtchnl_pf_event)); } /** @@ -129,7 +130,7 @@ void i40e_vc_notify_reset(struct i40e_pf *pf) **/ void i40e_vc_notify_vf_reset(struct i40e_vf *vf) { - struct i40e_virtchnl_pf_event pfe; + struct virtchnl_pf_event pfe; int abs_vf_id; /* validate the request */ @@ -143,11 +144,11 @@ void i40e_vc_notify_vf_reset(struct i40e_vf *vf) abs_vf_id = vf->vf_id + (int)vf->pf->hw.func_caps.vf_base_id; - pfe.event = I40E_VIRTCHNL_EVENT_RESET_IMPENDING; - pfe.severity = I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM; - i40e_aq_send_msg_to_vf(&vf->pf->hw, abs_vf_id, I40E_VIRTCHNL_OP_EVENT, + pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING; + pfe.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM; + i40e_aq_send_msg_to_vf(&vf->pf->hw, abs_vf_id, VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe, - sizeof(struct i40e_virtchnl_pf_event), NULL); + sizeof(struct virtchnl_pf_event), NULL); } /***********************misc routines*****************************/ @@ -250,7 +251,7 @@ static u16 i40e_vc_get_pf_queue_id(struct i40e_vf *vf, u16 vsi_id, * configure irq link list from the map **/ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id, - struct i40e_virtchnl_vector_map *vecmap) + struct virtchnl_vector_map *vecmap) { unsigned long linklistmap = 0, tempmap; struct i40e_pf *pf = vf->pf; @@ -338,7 +339,7 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id, /* if the vf is running in polling mode and using interrupt zero, * need to disable auto-mask on enabling zero interrupt for VFs. */ - if ((vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING) && + if ((vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_POLLING) && (vector_id == 0)) { reg = rd32(hw, I40E_GLINT_CTL); if (!(reg & I40E_GLINT_CTL_DIS_AUTOMASK_VF0_MASK)) { @@ -359,7 +360,7 @@ irq_list_done: static void i40e_release_iwarp_qvlist(struct i40e_vf *vf) { struct i40e_pf *pf = vf->pf; - struct i40e_virtchnl_iwarp_qvlist_info *qvlist_info = vf->qvlist_info; + struct virtchnl_iwarp_qvlist_info *qvlist_info = vf->qvlist_info; u32 msix_vf; u32 i; @@ -368,7 +369,7 @@ static void i40e_release_iwarp_qvlist(struct i40e_vf *vf) msix_vf = pf->hw.func_caps.num_msix_vectors_vf; for (i = 0; i < qvlist_info->num_vectors; i++) { - struct i40e_virtchnl_iwarp_qv_info *qv_info; + struct virtchnl_iwarp_qv_info *qv_info; u32 next_q_index, next_q_type; struct i40e_hw *hw = &pf->hw; u32 v_idx, reg_idx, reg; @@ -409,17 +410,17 @@ static void i40e_release_iwarp_qvlist(struct i40e_vf *vf) * Return 0 on success or < 0 on error **/ static int i40e_config_iwarp_qvlist(struct i40e_vf *vf, - struct i40e_virtchnl_iwarp_qvlist_info *qvlist_info) + struct virtchnl_iwarp_qvlist_info *qvlist_info) { struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; - struct i40e_virtchnl_iwarp_qv_info *qv_info; + struct virtchnl_iwarp_qv_info *qv_info; u32 v_idx, i, reg_idx, reg; u32 next_q_idx, next_q_type; u32 msix_vf, size; - size = sizeof(struct i40e_virtchnl_iwarp_qvlist_info) + - (sizeof(struct i40e_virtchnl_iwarp_qv_info) * + size = sizeof(struct virtchnl_iwarp_qvlist_info) + + (sizeof(struct virtchnl_iwarp_qv_info) * (qvlist_info->num_vectors - 1)); vf->qvlist_info = kzalloc(size, GFP_KERNEL); vf->qvlist_info->num_vectors = qvlist_info->num_vectors; @@ -492,7 +493,7 @@ err: **/ static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_id, u16 vsi_queue_id, - struct i40e_virtchnl_txq_info *info) + struct virtchnl_txq_info *info) { struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; @@ -569,7 +570,7 @@ error_context: **/ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_id, u16 vsi_queue_id, - struct i40e_virtchnl_rxq_info *info) + struct virtchnl_rxq_info *info) { struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; @@ -1017,7 +1018,7 @@ static void i40e_cleanup_reset_vf(struct i40e_vf *vf) * after VF has been fully initialized, because the VF driver may * request resources immediately after setting this flag. */ - wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE); + wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), VIRTCHNL_VFR_VFACTIVE); } /** @@ -1461,7 +1462,7 @@ static int i40e_vc_send_msg_to_vf(struct i40e_vf *vf, u32 v_opcode, * send resp msg to VF **/ static int i40e_vc_send_resp_to_vf(struct i40e_vf *vf, - enum i40e_virtchnl_ops opcode, + enum virtchnl_ops opcode, i40e_status retval) { return i40e_vc_send_msg_to_vf(vf, opcode, retval, NULL, 0); @@ -1475,18 +1476,17 @@ static int i40e_vc_send_resp_to_vf(struct i40e_vf *vf, **/ static int i40e_vc_get_version_msg(struct i40e_vf *vf, u8 *msg) { - struct i40e_virtchnl_version_info info = { - I40E_VIRTCHNL_VERSION_MAJOR, I40E_VIRTCHNL_VERSION_MINOR + struct virtchnl_version_info info = { + VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR }; - vf->vf_ver = *(struct i40e_virtchnl_version_info *)msg; + vf->vf_ver = *(struct virtchnl_version_info *)msg; /* VFs running the 1.0 API expect to get 1.0 back or they will cry. */ - if (VF_IS_V10(vf)) - info.minor = I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS; - return i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_VERSION, + if (VF_IS_V10(&vf->vf_ver)) + info.minor = VIRTCHNL_VERSION_MINOR_NO_VF_CAPS; + return i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_VERSION, I40E_SUCCESS, (u8 *)&info, - sizeof(struct - i40e_virtchnl_version_info)); + sizeof(struct virtchnl_version_info)); } /** @@ -1499,7 +1499,7 @@ static int i40e_vc_get_version_msg(struct i40e_vf *vf, u8 *msg) **/ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) { - struct i40e_virtchnl_vf_resource *vfres = NULL; + struct virtchnl_vf_resource *vfres = NULL; struct i40e_pf *pf = vf->pf; i40e_status aq_ret = 0; struct i40e_vsi *vsi; @@ -1512,8 +1512,8 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) goto err; } - len = (sizeof(struct i40e_virtchnl_vf_resource) + - sizeof(struct i40e_virtchnl_vsi_resource) * num_vsis); + len = (sizeof(struct virtchnl_vf_resource) + + sizeof(struct virtchnl_vsi_resource) * num_vsis); vfres = kzalloc(len, GFP_KERNEL); if (!vfres) { @@ -1521,50 +1521,48 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) len = 0; goto err; } - if (VF_IS_V11(vf)) + if (VF_IS_V11(&vf->vf_ver)) vf->driver_caps = *(u32 *)msg; else - vf->driver_caps = I40E_VIRTCHNL_VF_OFFLOAD_L2 | - I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG | - I40E_VIRTCHNL_VF_OFFLOAD_VLAN; + vf->driver_caps = VIRTCHNL_VF_OFFLOAD_L2 | + VIRTCHNL_VF_OFFLOAD_RSS_REG | + VIRTCHNL_VF_OFFLOAD_VLAN; - vfres->vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2; + vfres->vf_offload_flags = VIRTCHNL_VF_OFFLOAD_L2; vsi = pf->vsi[vf->lan_vsi_idx]; if (!vsi->info.pvid) - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN; + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_VLAN; if (i40e_vf_client_capable(pf, vf->vf_id) && - (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_IWARP)) { - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_IWARP; + (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_IWARP)) { + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_IWARP; set_bit(I40E_VF_STATE_IWARPENA, &vf->vf_states); } - if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF) { - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF; + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) { + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF; } else { if ((pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) && - (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ)) - vfres->vf_offload_flags |= - I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ; + (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_AQ)) + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_RSS_AQ; else - vfres->vf_offload_flags |= - I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG; + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_RSS_REG; } if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE) { - if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) vfres->vf_offload_flags |= - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2; + VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2; } - if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_ENCAP) - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_ENCAP; + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP) + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP; if ((pf->flags & I40E_FLAG_OUTER_UDP_CSUM_CAPABLE) && - (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM)) - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM; + (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM)) + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM; - if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING) { + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_POLLING) { if (pf->flags & I40E_FLAG_MFP_ENABLED) { dev_err(&pf->pdev->dev, "VF %d requested polling mode: this feature is supported only when the device is running in single function per port (SFP) mode\n", @@ -1572,13 +1570,13 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) ret = I40E_ERR_PARAM; goto err; } - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING; + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_RX_POLLING; } if (pf->flags & I40E_FLAG_WB_ON_ITR_CAPABLE) { - if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) vfres->vf_offload_flags |= - I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR; + VIRTCHNL_VF_OFFLOAD_WB_ON_ITR; } vfres->num_vsis = num_vsis; @@ -1589,7 +1587,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) if (vf->lan_vsi_idx) { vfres->vsi_res[0].vsi_id = vf->lan_vsi_id; - vfres->vsi_res[0].vsi_type = I40E_VSI_SRIOV; + vfres->vsi_res[0].vsi_type = VIRTCHNL_VSI_SRIOV; vfres->vsi_res[0].num_queue_pairs = vsi->alloc_queue_pairs; /* VFs only use TC 0 */ vfres->vsi_res[0].qset_handle @@ -1601,7 +1599,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) err: /* send the response back to the VF */ - ret = i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, + ret = i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_VF_RESOURCES, aq_ret, (u8 *)vfres, len); kfree(vfres); @@ -1655,8 +1653,8 @@ static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi) static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_promisc_info *info = - (struct i40e_virtchnl_promisc_info *)msg; + struct virtchnl_promisc_info *info = + (struct virtchnl_promisc_info *)msg; struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; struct i40e_mac_filter *f; @@ -1683,7 +1681,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, goto error_param; } /* Multicast promiscuous handling*/ - if (info->flags & I40E_FLAG_VF_MULTICAST_PROMISC) + if (info->flags & FLAG_VF_MULTICAST_PROMISC) allmulti = true; if (vf->port_vlan_id) { @@ -1734,7 +1732,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, clear_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states); } - if (info->flags & I40E_FLAG_VF_UNICAST_PROMISC) + if (info->flags & FLAG_VF_UNICAST_PROMISC) alluni = true; if (vf->port_vlan_id) { aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, vsi->seid, @@ -1788,7 +1786,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, error_param: /* send the response to the VF */ return i40e_vc_send_resp_to_vf(vf, - I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, + VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, aq_ret); } @@ -1803,9 +1801,9 @@ error_param: **/ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_vsi_queue_config_info *qci = - (struct i40e_virtchnl_vsi_queue_config_info *)msg; - struct i40e_virtchnl_queue_pair_info *qpi; + struct virtchnl_vsi_queue_config_info *qci = + (struct virtchnl_vsi_queue_config_info *)msg; + struct virtchnl_queue_pair_info *qpi; struct i40e_pf *pf = vf->pf; u16 vsi_id, vsi_queue_id; i40e_status aq_ret = 0; @@ -1845,7 +1843,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES, aq_ret); } @@ -1860,9 +1858,9 @@ error_param: **/ static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_irq_map_info *irqmap_info = - (struct i40e_virtchnl_irq_map_info *)msg; - struct i40e_virtchnl_vector_map *map; + struct virtchnl_irq_map_info *irqmap_info = + (struct virtchnl_irq_map_info *)msg; + struct virtchnl_vector_map *map; u16 vsi_id, vsi_queue_id, vector_id; i40e_status aq_ret = 0; unsigned long tempmap; @@ -1908,7 +1906,7 @@ static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) } error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_IRQ_MAP, aq_ret); } @@ -1922,8 +1920,8 @@ error_param: **/ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_queue_select *vqs = - (struct i40e_virtchnl_queue_select *)msg; + struct virtchnl_queue_select *vqs = + (struct virtchnl_queue_select *)msg; struct i40e_pf *pf = vf->pf; u16 vsi_id = vqs->vsi_id; i40e_status aq_ret = 0; @@ -1947,7 +1945,7 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) aq_ret = I40E_ERR_TIMEOUT; error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES, aq_ret); } @@ -1962,8 +1960,8 @@ error_param: **/ static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_queue_select *vqs = - (struct i40e_virtchnl_queue_select *)msg; + struct virtchnl_queue_select *vqs = + (struct virtchnl_queue_select *)msg; struct i40e_pf *pf = vf->pf; i40e_status aq_ret = 0; @@ -1986,7 +1984,7 @@ static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DISABLE_QUEUES, aq_ret); } @@ -2000,8 +1998,8 @@ error_param: **/ static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_queue_select *vqs = - (struct i40e_virtchnl_queue_select *)msg; + struct virtchnl_queue_select *vqs = + (struct virtchnl_queue_select *)msg; struct i40e_pf *pf = vf->pf; struct i40e_eth_stats stats; i40e_status aq_ret = 0; @@ -2029,7 +2027,7 @@ static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response back to the VF */ - return i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_GET_STATS, aq_ret, + return i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_STATS, aq_ret, (u8 *)&stats, sizeof(stats)); } @@ -2088,8 +2086,8 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf, u8 *macaddr) **/ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_ether_addr_list *al = - (struct i40e_virtchnl_ether_addr_list *)msg; + struct virtchnl_ether_addr_list *al = + (struct virtchnl_ether_addr_list *)msg; struct i40e_pf *pf = vf->pf; struct i40e_vsi *vsi = NULL; u16 vsi_id = al->vsi_id; @@ -2143,7 +2141,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ADD_ETH_ADDR, ret); } @@ -2157,8 +2155,8 @@ error_param: **/ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_ether_addr_list *al = - (struct i40e_virtchnl_ether_addr_list *)msg; + struct virtchnl_ether_addr_list *al = + (struct virtchnl_ether_addr_list *)msg; struct i40e_pf *pf = vf->pf; struct i40e_vsi *vsi = NULL; u16 vsi_id = al->vsi_id; @@ -2203,7 +2201,7 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DEL_ETH_ADDR, ret); } @@ -2217,8 +2215,8 @@ error_param: **/ static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_vlan_filter_list *vfl = - (struct i40e_virtchnl_vlan_filter_list *)msg; + struct virtchnl_vlan_filter_list *vfl = + (struct virtchnl_vlan_filter_list *)msg; struct i40e_pf *pf = vf->pf; struct i40e_vsi *vsi = NULL; u16 vsi_id = vfl->vsi_id; @@ -2277,7 +2275,7 @@ static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_ADD_VLAN, aq_ret); + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ADD_VLAN, aq_ret); } /** @@ -2290,8 +2288,8 @@ error_param: **/ static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_vlan_filter_list *vfl = - (struct i40e_virtchnl_vlan_filter_list *)msg; + struct virtchnl_vlan_filter_list *vfl = + (struct virtchnl_vlan_filter_list *)msg; struct i40e_pf *pf = vf->pf; struct i40e_vsi *vsi = NULL; u16 vsi_id = vfl->vsi_id; @@ -2335,7 +2333,7 @@ static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_DEL_VLAN, aq_ret); + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DEL_VLAN, aq_ret); } /** @@ -2363,7 +2361,7 @@ static int i40e_vc_iwarp_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_IWARP, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_IWARP, aq_ret); } @@ -2379,8 +2377,8 @@ error_param: static int i40e_vc_iwarp_qvmap_msg(struct i40e_vf *vf, u8 *msg, u16 msglen, bool config) { - struct i40e_virtchnl_iwarp_qvlist_info *qvlist_info = - (struct i40e_virtchnl_iwarp_qvlist_info *)msg; + struct virtchnl_iwarp_qvlist_info *qvlist_info = + (struct virtchnl_iwarp_qvlist_info *)msg; i40e_status aq_ret = 0; if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) || @@ -2399,8 +2397,8 @@ static int i40e_vc_iwarp_qvmap_msg(struct i40e_vf *vf, u8 *msg, u16 msglen, error_param: /* send the response to the VF */ return i40e_vc_send_resp_to_vf(vf, - config ? I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP : - I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP, + config ? VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP : + VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP, aq_ret); } @@ -2414,8 +2412,8 @@ error_param: **/ static int i40e_vc_config_rss_key(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_rss_key *vrk = - (struct i40e_virtchnl_rss_key *)msg; + struct virtchnl_rss_key *vrk = + (struct virtchnl_rss_key *)msg; struct i40e_pf *pf = vf->pf; struct i40e_vsi *vsi = NULL; u16 vsi_id = vrk->vsi_id; @@ -2432,7 +2430,7 @@ static int i40e_vc_config_rss_key(struct i40e_vf *vf, u8 *msg, u16 msglen) aq_ret = i40e_config_rss(vsi, vrk->key, NULL, 0); err: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_CONFIG_RSS_KEY, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_KEY, aq_ret); } @@ -2446,8 +2444,8 @@ err: **/ static int i40e_vc_config_rss_lut(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_rss_lut *vrl = - (struct i40e_virtchnl_rss_lut *)msg; + struct virtchnl_rss_lut *vrl = + (struct virtchnl_rss_lut *)msg; struct i40e_pf *pf = vf->pf; struct i40e_vsi *vsi = NULL; u16 vsi_id = vrl->vsi_id; @@ -2464,7 +2462,7 @@ static int i40e_vc_config_rss_lut(struct i40e_vf *vf, u8 *msg, u16 msglen) aq_ret = i40e_config_rss(vsi, NULL, vrl->lut, I40E_VF_HLUT_ARRAY_SIZE); /* send the response to the VF */ err: - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_CONFIG_RSS_LUT, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_LUT, aq_ret); } @@ -2478,7 +2476,7 @@ err: **/ static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_rss_hena *vrh = NULL; + struct virtchnl_rss_hena *vrh = NULL; struct i40e_pf *pf = vf->pf; i40e_status aq_ret = 0; int len = 0; @@ -2487,7 +2485,7 @@ static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen) aq_ret = I40E_ERR_PARAM; goto err; } - len = sizeof(struct i40e_virtchnl_rss_hena); + len = sizeof(struct virtchnl_rss_hena); vrh = kzalloc(len, GFP_KERNEL); if (!vrh) { @@ -2498,7 +2496,7 @@ static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen) vrh->hena = i40e_pf_get_default_rss_hena(pf); err: /* send the response back to the VF */ - aq_ret = i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS, + aq_ret = i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_RSS_HENA_CAPS, aq_ret, (u8 *)vrh, len); kfree(vrh); return aq_ret; @@ -2514,8 +2512,8 @@ err: **/ static int i40e_vc_set_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_rss_hena *vrh = - (struct i40e_virtchnl_rss_hena *)msg; + struct virtchnl_rss_hena *vrh = + (struct virtchnl_rss_hena *)msg; struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; i40e_status aq_ret = 0; @@ -2530,170 +2528,7 @@ static int i40e_vc_set_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen) /* send the response to the VF */ err: - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_SET_RSS_HENA, - aq_ret); -} - -/** - * i40e_vc_validate_vf_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * @msglen: msg length - * @msghndl: msg handle - * - * validate msg - **/ -static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, - u32 v_retval, u8 *msg, u16 msglen) -{ - bool err_msg_format = false; - int valid_len = 0; - - /* Check if VF is disabled. */ - if (test_bit(I40E_VF_STATE_DISABLED, &vf->vf_states)) - return I40E_ERR_PARAM; - - /* Validate message length. */ - switch (v_opcode) { - case I40E_VIRTCHNL_OP_VERSION: - valid_len = sizeof(struct i40e_virtchnl_version_info); - break; - case I40E_VIRTCHNL_OP_RESET_VF: - break; - case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: - if (VF_IS_V11(vf)) - valid_len = sizeof(u32); - break; - case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE: - valid_len = sizeof(struct i40e_virtchnl_txq_info); - break; - case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE: - valid_len = sizeof(struct i40e_virtchnl_rxq_info); - break; - case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: - valid_len = sizeof(struct i40e_virtchnl_vsi_queue_config_info); - if (msglen >= valid_len) { - struct i40e_virtchnl_vsi_queue_config_info *vqc = - (struct i40e_virtchnl_vsi_queue_config_info *)msg; - valid_len += (vqc->num_queue_pairs * - sizeof(struct - i40e_virtchnl_queue_pair_info)); - if (vqc->num_queue_pairs == 0) - err_msg_format = true; - } - break; - case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: - valid_len = sizeof(struct i40e_virtchnl_irq_map_info); - if (msglen >= valid_len) { - struct i40e_virtchnl_irq_map_info *vimi = - (struct i40e_virtchnl_irq_map_info *)msg; - valid_len += (vimi->num_vectors * - sizeof(struct i40e_virtchnl_vector_map)); - if (vimi->num_vectors == 0) - err_msg_format = true; - } - break; - case I40E_VIRTCHNL_OP_ENABLE_QUEUES: - case I40E_VIRTCHNL_OP_DISABLE_QUEUES: - valid_len = sizeof(struct i40e_virtchnl_queue_select); - break; - case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: - case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: - valid_len = sizeof(struct i40e_virtchnl_ether_addr_list); - if (msglen >= valid_len) { - struct i40e_virtchnl_ether_addr_list *veal = - (struct i40e_virtchnl_ether_addr_list *)msg; - valid_len += veal->num_elements * - sizeof(struct i40e_virtchnl_ether_addr); - if (veal->num_elements == 0) - err_msg_format = true; - } - break; - case I40E_VIRTCHNL_OP_ADD_VLAN: - case I40E_VIRTCHNL_OP_DEL_VLAN: - valid_len = sizeof(struct i40e_virtchnl_vlan_filter_list); - if (msglen >= valid_len) { - struct i40e_virtchnl_vlan_filter_list *vfl = - (struct i40e_virtchnl_vlan_filter_list *)msg; - valid_len += vfl->num_elements * sizeof(u16); - if (vfl->num_elements == 0) - err_msg_format = true; - } - break; - case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: - valid_len = sizeof(struct i40e_virtchnl_promisc_info); - break; - case I40E_VIRTCHNL_OP_GET_STATS: - valid_len = sizeof(struct i40e_virtchnl_queue_select); - break; - case I40E_VIRTCHNL_OP_IWARP: - /* These messages are opaque to us and will be validated in - * the RDMA client code. We just need to check for nonzero - * length. The firmware will enforce max length restrictions. - */ - if (msglen) - valid_len = msglen; - else - err_msg_format = true; - break; - case I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP: - valid_len = 0; - break; - case I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: - valid_len = sizeof(struct i40e_virtchnl_iwarp_qvlist_info); - if (msglen >= valid_len) { - struct i40e_virtchnl_iwarp_qvlist_info *qv = - (struct i40e_virtchnl_iwarp_qvlist_info *)msg; - if (qv->num_vectors == 0) { - err_msg_format = true; - break; - } - valid_len += ((qv->num_vectors - 1) * - sizeof(struct i40e_virtchnl_iwarp_qv_info)); - } - break; - case I40E_VIRTCHNL_OP_CONFIG_RSS_KEY: - valid_len = sizeof(struct i40e_virtchnl_rss_key); - if (msglen >= valid_len) { - struct i40e_virtchnl_rss_key *vrk = - (struct i40e_virtchnl_rss_key *)msg; - if (vrk->key_len != I40E_HKEY_ARRAY_SIZE) { - err_msg_format = true; - break; - } - valid_len += vrk->key_len - 1; - } - break; - case I40E_VIRTCHNL_OP_CONFIG_RSS_LUT: - valid_len = sizeof(struct i40e_virtchnl_rss_lut); - if (msglen >= valid_len) { - struct i40e_virtchnl_rss_lut *vrl = - (struct i40e_virtchnl_rss_lut *)msg; - if (vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE) { - err_msg_format = true; - break; - } - valid_len += vrl->lut_entries - 1; - } - break; - case I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS: - break; - case I40E_VIRTCHNL_OP_SET_RSS_HENA: - valid_len = sizeof(struct i40e_virtchnl_rss_hena); - break; - /* These are always errors coming from the VF. */ - case I40E_VIRTCHNL_OP_EVENT: - case I40E_VIRTCHNL_OP_UNKNOWN: - default: - return -EPERM; - } - /* few more checks */ - if ((valid_len != msglen) || (err_msg_format)) { - i40e_vc_send_resp_to_vf(vf, v_opcode, I40E_ERR_PARAM); - return -EINVAL; - } else { - return 0; - } + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_SET_RSS_HENA, aq_ret); } /** @@ -2719,80 +2554,104 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode, if (local_vf_id >= pf->num_alloc_vfs) return -EINVAL; vf = &(pf->vf[local_vf_id]); + + /* Check if VF is disabled. */ + if (test_bit(I40E_VF_STATE_DISABLED, &vf->vf_states)) + return I40E_ERR_PARAM; + /* perform basic checks on the msg */ - ret = i40e_vc_validate_vf_msg(vf, v_opcode, v_retval, msg, msglen); + ret = virtchnl_vc_validate_vf_msg(&vf->vf_ver, v_opcode, msg, msglen); + + /* perform additional checks specific to this driver */ + if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_KEY) { + struct virtchnl_rss_key *vrk = (struct virtchnl_rss_key *)msg; + + if (vrk->key_len != I40E_HKEY_ARRAY_SIZE) + ret = -EINVAL; + } else if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_LUT) { + struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg; + + if (vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE) + ret = -EINVAL; + } if (ret) { + i40e_vc_send_resp_to_vf(vf, v_opcode, I40E_ERR_PARAM); dev_err(&pf->pdev->dev, "Invalid message from VF %d, opcode %d, len %d\n", local_vf_id, v_opcode, msglen); - return ret; + switch (ret) { + case VIRTCHNL_ERR_PARAM: + return -EPERM; + default: + return -EINVAL; + } } switch (v_opcode) { - case I40E_VIRTCHNL_OP_VERSION: + case VIRTCHNL_OP_VERSION: ret = i40e_vc_get_version_msg(vf, msg); break; - case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: + case VIRTCHNL_OP_GET_VF_RESOURCES: ret = i40e_vc_get_vf_resources_msg(vf, msg); break; - case I40E_VIRTCHNL_OP_RESET_VF: + case VIRTCHNL_OP_RESET_VF: i40e_vc_reset_vf_msg(vf); ret = 0; break; - case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: + case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: ret = i40e_vc_config_promiscuous_mode_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: + case VIRTCHNL_OP_CONFIG_VSI_QUEUES: ret = i40e_vc_config_queues_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: + case VIRTCHNL_OP_CONFIG_IRQ_MAP: ret = i40e_vc_config_irq_map_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_ENABLE_QUEUES: + case VIRTCHNL_OP_ENABLE_QUEUES: ret = i40e_vc_enable_queues_msg(vf, msg, msglen); i40e_vc_notify_vf_link_state(vf); break; - case I40E_VIRTCHNL_OP_DISABLE_QUEUES: + case VIRTCHNL_OP_DISABLE_QUEUES: ret = i40e_vc_disable_queues_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: + case VIRTCHNL_OP_ADD_ETH_ADDR: ret = i40e_vc_add_mac_addr_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: + case VIRTCHNL_OP_DEL_ETH_ADDR: ret = i40e_vc_del_mac_addr_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_ADD_VLAN: + case VIRTCHNL_OP_ADD_VLAN: ret = i40e_vc_add_vlan_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_DEL_VLAN: + case VIRTCHNL_OP_DEL_VLAN: ret = i40e_vc_remove_vlan_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_GET_STATS: + case VIRTCHNL_OP_GET_STATS: ret = i40e_vc_get_stats_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_IWARP: + case VIRTCHNL_OP_IWARP: ret = i40e_vc_iwarp_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: + case VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: ret = i40e_vc_iwarp_qvmap_msg(vf, msg, msglen, true); break; - case I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP: + case VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP: ret = i40e_vc_iwarp_qvmap_msg(vf, msg, msglen, false); break; - case I40E_VIRTCHNL_OP_CONFIG_RSS_KEY: + case VIRTCHNL_OP_CONFIG_RSS_KEY: ret = i40e_vc_config_rss_key(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_CONFIG_RSS_LUT: + case VIRTCHNL_OP_CONFIG_RSS_LUT: ret = i40e_vc_config_rss_lut(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS: + case VIRTCHNL_OP_GET_RSS_HENA_CAPS: ret = i40e_vc_get_rss_hena(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_SET_RSS_HENA: + case VIRTCHNL_OP_SET_RSS_HENA: ret = i40e_vc_set_rss_hena(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_UNKNOWN: + case VIRTCHNL_OP_UNKNOWN: default: dev_err(&pf->pdev->dev, "Unsupported opcode %d from VF %d\n", v_opcode, local_vf_id); @@ -3218,7 +3077,7 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link) { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_pf *pf = np->vsi->back; - struct i40e_virtchnl_pf_event pfe; + struct virtchnl_pf_event pfe; struct i40e_hw *hw = &pf->hw; struct i40e_vf *vf; int abs_vf_id; @@ -3234,8 +3093,8 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link) vf = &pf->vf[vf_id]; abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; - pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE; - pfe.severity = I40E_PF_EVENT_SEVERITY_INFO; + pfe.event = VIRTCHNL_EVENT_LINK_CHANGE; + pfe.severity = PF_EVENT_SEVERITY_INFO; switch (link) { case IFLA_VF_LINK_STATE_AUTO: @@ -3243,6 +3102,7 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link) pfe.event_data.link_event.link_status = pf->hw.phy.link_info.link_info & I40E_AQ_LINK_UP; pfe.event_data.link_event.link_speed = + (enum virtchnl_link_speed) pf->hw.phy.link_info.link_speed; break; case IFLA_VF_LINK_STATE_ENABLE: @@ -3262,7 +3122,7 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link) goto error_out; } /* Notify the VF of its new link state */ - i40e_aq_send_msg_to_vf(hw, abs_vf_id, I40E_VIRTCHNL_OP_EVENT, + i40e_aq_send_msg_to_vf(hw, abs_vf_id, VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe, sizeof(pfe), NULL); error_out: diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index 20d7c8160e9e..1f4b0c504368 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -40,9 +40,6 @@ #define I40E_VLAN_MASK 0xFFF #define I40E_PRIORITY_MASK 0x7000 -#define VF_IS_V10(_v) (((_v)->vf_ver.major == 1) && ((_v)->vf_ver.minor == 0)) -#define VF_IS_V11(_v) (((_v)->vf_ver.major == 1) && ((_v)->vf_ver.minor == 1)) - /* Various queue ctrls */ enum i40e_queue_ctrl { I40E_QUEUE_CTRL_UNKNOWN = 0, @@ -81,13 +78,13 @@ struct i40e_vf { s16 vf_id; /* all VF vsis connect to the same parent */ enum i40e_switch_element_types parent_type; - struct i40e_virtchnl_version_info vf_ver; + struct virtchnl_version_info vf_ver; u32 driver_caps; /* reported by VF driver */ /* VF Port Extender (PE) stag if used */ u16 stag; - struct i40e_virtchnl_ether_addr default_lan_addr; + struct virtchnl_ether_addr default_lan_addr; u16 port_vlan_id; bool pf_set_mac; /* The VMM admin set the VF MAC address */ bool trusted; @@ -115,7 +112,7 @@ struct i40e_vf { u16 num_vlan; /* RDMA Client */ - struct i40e_virtchnl_iwarp_qvlist_info *qvlist_info; + struct virtchnl_iwarp_qvlist_info *qvlist_info; }; void i40e_free_vfs(struct i40e_pf *pf); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index 43f10761f4ba..1dd1938f594f 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -27,7 +27,7 @@ #include "i40e_type.h" #include "i40e_adminq.h" #include "i40e_prototype.h" -#include "i40e_virtchnl.h" +#include <linux/avf/virtchnl.h> /** * i40e_set_mac_type - Sets MAC type @@ -68,6 +68,7 @@ i40e_status i40e_set_mac_type(struct i40e_hw *hw) break; case I40E_DEV_ID_VF: case I40E_DEV_ID_VF_HV: + case I40E_DEV_ID_ADAPTIVE_VF: hw->mac.type = I40E_MAC_VF; break; default: @@ -1054,7 +1055,7 @@ do_retry: * completion before returning. **/ i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, - enum i40e_virtchnl_ops v_opcode, + enum virtchnl_ops v_opcode, i40e_status v_retval, u8 *msg, u16 msglen, struct i40e_asq_cmd_details *cmd_details) @@ -1092,9 +1093,9 @@ i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, * with appropriate information. **/ void i40e_vf_parse_hw_config(struct i40e_hw *hw, - struct i40e_virtchnl_vf_resource *msg) + struct virtchnl_vf_resource *msg) { - struct i40e_virtchnl_vsi_resource *vsi_res; + struct virtchnl_vsi_resource *vsi_res; int i; vsi_res = &msg->vsi_res[0]; @@ -1104,11 +1105,10 @@ void i40e_vf_parse_hw_config(struct i40e_hw *hw, hw->dev_caps.num_tx_qp = msg->num_queue_pairs; hw->dev_caps.num_msix_vectors_vf = msg->max_vectors; hw->dev_caps.dcb = msg->vf_offload_flags & - I40E_VIRTCHNL_VF_OFFLOAD_L2; - hw->dev_caps.fcoe = (msg->vf_offload_flags & - I40E_VIRTCHNL_VF_OFFLOAD_FCOE) ? 1 : 0; + VIRTCHNL_VF_OFFLOAD_L2; + hw->dev_caps.fcoe = 0; for (i = 0; i < msg->num_vsis; i++) { - if (vsi_res->vsi_type == I40E_VSI_SRIOV) { + if (vsi_res->vsi_type == VIRTCHNL_VSI_SRIOV) { ether_addr_copy(hw->mac.perm_addr, vsi_res->default_mac_addr); ether_addr_copy(hw->mac.addr, @@ -1128,7 +1128,7 @@ void i40e_vf_parse_hw_config(struct i40e_hw *hw, **/ i40e_status i40e_vf_reset(struct i40e_hw *hw) { - return i40e_aq_send_msg_to_pf(hw, I40E_VIRTCHNL_OP_RESET_VF, + return i40e_aq_send_msg_to_pf(hw, VIRTCHNL_OP_RESET_VF, 0, NULL, 0, NULL); } diff --git a/drivers/net/ethernet/intel/i40evf/i40e_devids.h b/drivers/net/ethernet/intel/i40evf/i40e_devids.h index d76393c95056..0469e4bfd3ec 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_devids.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_devids.h @@ -43,6 +43,7 @@ #define I40E_DEV_ID_25G_SFP28 0x158B #define I40E_DEV_ID_VF 0x154C #define I40E_DEV_ID_VF_HV 0x1571 +#define I40E_DEV_ID_ADAPTIVE_VF 0x1889 #define I40E_DEV_ID_SFP_X722 0x37D0 #define I40E_DEV_ID_1G_BASE_T_X722 0x37D1 #define I40E_DEV_ID_10G_BASE_T_X722 0x37D2 diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h index 741223d5d809..c9836bba487d 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h @@ -29,7 +29,7 @@ #include "i40e_type.h" #include "i40e_alloc.h" -#include "i40e_virtchnl.h" +#include <linux/avf/virtchnl.h> /* Prototypes for shared code functions that are not in * the standard function pointer structures. These are @@ -87,10 +87,10 @@ static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) /* i40e_common for VF drivers*/ void i40e_vf_parse_hw_config(struct i40e_hw *hw, - struct i40e_virtchnl_vf_resource *msg); + struct virtchnl_vf_resource *msg); i40e_status i40e_vf_reset(struct i40e_hw *hw); i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, - enum i40e_virtchnl_ops v_opcode, + enum virtchnl_ops v_opcode, i40e_status v_retval, u8 *msg, u16 msglen, struct i40e_asq_cmd_details *cmd_details); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h b/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h deleted file mode 100644 index c5ad0388c3d5..000000000000 --- a/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h +++ /dev/null @@ -1,449 +0,0 @@ -/******************************************************************************* - * - * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver - * Copyright(c) 2013 - 2014 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - ******************************************************************************/ - -#ifndef _I40E_VIRTCHNL_H_ -#define _I40E_VIRTCHNL_H_ - -#include "i40e_type.h" - -/* Description: - * This header file describes the VF-PF communication protocol used - * by the various i40e drivers. - * - * Admin queue buffer usage: - * desc->opcode is always i40e_aqc_opc_send_msg_to_pf - * flags, retval, datalen, and data addr are all used normally. - * Firmware copies the cookie fields when sending messages between the PF and - * VF, but uses all other fields internally. Due to this limitation, we - * must send all messages as "indirect", i.e. using an external buffer. - * - * All the vsi indexes are relative to the VF. Each VF can have maximum of - * three VSIs. All the queue indexes are relative to the VSI. Each VF can - * have a maximum of sixteen queues for all of its VSIs. - * - * The PF is required to return a status code in v_retval for all messages - * except RESET_VF, which does not require any response. The return value is of - * i40e_status_code type, defined in the i40e_type.h. - * - * In general, VF driver initialization should roughly follow the order of these - * opcodes. The VF driver must first validate the API version of the PF driver, - * then request a reset, then get resources, then configure queues and - * interrupts. After these operations are complete, the VF driver may start - * its queues, optionally add MAC and VLAN filters, and process traffic. - */ - -/* Opcodes for VF-PF communication. These are placed in the v_opcode field - * of the virtchnl_msg structure. - */ -enum i40e_virtchnl_ops { -/* The PF sends status change events to VFs using - * the I40E_VIRTCHNL_OP_EVENT opcode. - * VFs send requests to the PF using the other ops. - */ - I40E_VIRTCHNL_OP_UNKNOWN = 0, - I40E_VIRTCHNL_OP_VERSION = 1, /* must ALWAYS be 1 */ - I40E_VIRTCHNL_OP_RESET_VF = 2, - I40E_VIRTCHNL_OP_GET_VF_RESOURCES = 3, - I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE = 4, - I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE = 5, - I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES = 6, - I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP = 7, - I40E_VIRTCHNL_OP_ENABLE_QUEUES = 8, - I40E_VIRTCHNL_OP_DISABLE_QUEUES = 9, - I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS = 10, - I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS = 11, - I40E_VIRTCHNL_OP_ADD_VLAN = 12, - I40E_VIRTCHNL_OP_DEL_VLAN = 13, - I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE = 14, - I40E_VIRTCHNL_OP_GET_STATS = 15, - I40E_VIRTCHNL_OP_FCOE = 16, - I40E_VIRTCHNL_OP_EVENT = 17, /* must ALWAYS be 17 */ - I40E_VIRTCHNL_OP_IWARP = 20, - I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP = 21, - I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP = 22, - I40E_VIRTCHNL_OP_CONFIG_RSS_KEY = 23, - I40E_VIRTCHNL_OP_CONFIG_RSS_LUT = 24, - I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS = 25, - I40E_VIRTCHNL_OP_SET_RSS_HENA = 26, - -}; - -/* Virtual channel message descriptor. This overlays the admin queue - * descriptor. All other data is passed in external buffers. - */ - -struct i40e_virtchnl_msg { - u8 pad[8]; /* AQ flags/opcode/len/retval fields */ - enum i40e_virtchnl_ops v_opcode; /* avoid confusion with desc->opcode */ - i40e_status v_retval; /* ditto for desc->retval */ - u32 vfid; /* used by PF when sending to VF */ -}; - -/* Message descriptions and data structures.*/ - -/* I40E_VIRTCHNL_OP_VERSION - * VF posts its version number to the PF. PF responds with its version number - * in the same format, along with a return code. - * Reply from PF has its major/minor versions also in param0 and param1. - * If there is a major version mismatch, then the VF cannot operate. - * If there is a minor version mismatch, then the VF can operate but should - * add a warning to the system log. - * - * This enum element MUST always be specified as == 1, regardless of other - * changes in the API. The PF must always respond to this message without - * error regardless of version mismatch. - */ -#define I40E_VIRTCHNL_VERSION_MAJOR 1 -#define I40E_VIRTCHNL_VERSION_MINOR 1 -#define I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS 0 - -struct i40e_virtchnl_version_info { - u32 major; - u32 minor; -}; - -/* I40E_VIRTCHNL_OP_RESET_VF - * VF sends this request to PF with no parameters - * PF does NOT respond! VF driver must delay then poll VFGEN_RSTAT register - * until reset completion is indicated. The admin queue must be reinitialized - * after this operation. - * - * When reset is complete, PF must ensure that all queues in all VSIs associated - * with the VF are stopped, all queue configurations in the HMC are set to 0, - * and all MAC and VLAN filters (except the default MAC address) on all VSIs - * are cleared. - */ - -/* I40E_VIRTCHNL_OP_GET_VF_RESOURCES - * Version 1.0 VF sends this request to PF with no parameters - * Version 1.1 VF sends this request to PF with u32 bitmap of its capabilities - * PF responds with an indirect message containing - * i40e_virtchnl_vf_resource and one or more - * i40e_virtchnl_vsi_resource structures. - */ - -struct i40e_virtchnl_vsi_resource { - u16 vsi_id; - u16 num_queue_pairs; - enum i40e_vsi_type vsi_type; - u16 qset_handle; - u8 default_mac_addr[ETH_ALEN]; -}; -/* VF offload flags */ -#define I40E_VIRTCHNL_VF_OFFLOAD_L2 0x00000001 -#define I40E_VIRTCHNL_VF_OFFLOAD_IWARP 0x00000002 -#define I40E_VIRTCHNL_VF_OFFLOAD_FCOE 0x00000004 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ 0x00000008 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG 0x00000010 -#define I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR 0x00000020 -#define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000 -#define I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING 0x00020000 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 0x00040000 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF 0X00080000 -#define I40E_VIRTCHNL_VF_OFFLOAD_ENCAP 0X00100000 -#define I40E_VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM 0X00200000 - -#define I40E_VF_BASE_MODE_OFFLOADS (I40E_VIRTCHNL_VF_OFFLOAD_L2 | \ - I40E_VIRTCHNL_VF_OFFLOAD_VLAN | \ - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF) - -struct i40e_virtchnl_vf_resource { - u16 num_vsis; - u16 num_queue_pairs; - u16 max_vectors; - u16 max_mtu; - - u32 vf_offload_flags; - u32 rss_key_size; - u32 rss_lut_size; - - struct i40e_virtchnl_vsi_resource vsi_res[1]; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE - * VF sends this message to set up parameters for one TX queue. - * External data buffer contains one instance of i40e_virtchnl_txq_info. - * PF configures requested queue and returns a status code. - */ - -/* Tx queue config info */ -struct i40e_virtchnl_txq_info { - u16 vsi_id; - u16 queue_id; - u16 ring_len; /* number of descriptors, multiple of 8 */ - u16 headwb_enabled; - u64 dma_ring_addr; - u64 dma_headwb_addr; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE - * VF sends this message to set up parameters for one RX queue. - * External data buffer contains one instance of i40e_virtchnl_rxq_info. - * PF configures requested queue and returns a status code. - */ - -/* Rx queue config info */ -struct i40e_virtchnl_rxq_info { - u16 vsi_id; - u16 queue_id; - u32 ring_len; /* number of descriptors, multiple of 32 */ - u16 hdr_size; - u16 splithdr_enabled; - u32 databuffer_size; - u32 max_pkt_size; - u64 dma_ring_addr; - enum i40e_hmc_obj_rx_hsplit_0 rx_split_pos; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES - * VF sends this message to set parameters for all active TX and RX queues - * associated with the specified VSI. - * PF configures queues and returns status. - * If the number of queues specified is greater than the number of queues - * associated with the VSI, an error is returned and no queues are configured. - */ -struct i40e_virtchnl_queue_pair_info { - /* NOTE: vsi_id and queue_id should be identical for both queues. */ - struct i40e_virtchnl_txq_info txq; - struct i40e_virtchnl_rxq_info rxq; -}; - -struct i40e_virtchnl_vsi_queue_config_info { - u16 vsi_id; - u16 num_queue_pairs; - struct i40e_virtchnl_queue_pair_info qpair[1]; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP - * VF uses this message to map vectors to queues. - * The rxq_map and txq_map fields are bitmaps used to indicate which queues - * are to be associated with the specified vector. - * The "other" causes are always mapped to vector 0. - * PF configures interrupt mapping and returns status. - */ -struct i40e_virtchnl_vector_map { - u16 vsi_id; - u16 vector_id; - u16 rxq_map; - u16 txq_map; - u16 rxitr_idx; - u16 txitr_idx; -}; - -struct i40e_virtchnl_irq_map_info { - u16 num_vectors; - struct i40e_virtchnl_vector_map vecmap[1]; -}; - -/* I40E_VIRTCHNL_OP_ENABLE_QUEUES - * I40E_VIRTCHNL_OP_DISABLE_QUEUES - * VF sends these message to enable or disable TX/RX queue pairs. - * The queues fields are bitmaps indicating which queues to act upon. - * (Currently, we only support 16 queues per VF, but we make the field - * u32 to allow for expansion.) - * PF performs requested action and returns status. - */ -struct i40e_virtchnl_queue_select { - u16 vsi_id; - u16 pad; - u32 rx_queues; - u32 tx_queues; -}; - -/* I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS - * VF sends this message in order to add one or more unicast or multicast - * address filters for the specified VSI. - * PF adds the filters and returns status. - */ - -/* I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS - * VF sends this message in order to remove one or more unicast or multicast - * filters for the specified VSI. - * PF removes the filters and returns status. - */ - -struct i40e_virtchnl_ether_addr { - u8 addr[ETH_ALEN]; - u8 pad[2]; -}; - -struct i40e_virtchnl_ether_addr_list { - u16 vsi_id; - u16 num_elements; - struct i40e_virtchnl_ether_addr list[1]; -}; - -/* I40E_VIRTCHNL_OP_ADD_VLAN - * VF sends this message to add one or more VLAN tag filters for receives. - * PF adds the filters and returns status. - * If a port VLAN is configured by the PF, this operation will return an - * error to the VF. - */ - -/* I40E_VIRTCHNL_OP_DEL_VLAN - * VF sends this message to remove one or more VLAN tag filters for receives. - * PF removes the filters and returns status. - * If a port VLAN is configured by the PF, this operation will return an - * error to the VF. - */ - -struct i40e_virtchnl_vlan_filter_list { - u16 vsi_id; - u16 num_elements; - u16 vlan_id[1]; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE - * VF sends VSI id and flags. - * PF returns status code in retval. - * Note: we assume that broadcast accept mode is always enabled. - */ -struct i40e_virtchnl_promisc_info { - u16 vsi_id; - u16 flags; -}; - -#define I40E_FLAG_VF_UNICAST_PROMISC 0x00000001 -#define I40E_FLAG_VF_MULTICAST_PROMISC 0x00000002 - -/* I40E_VIRTCHNL_OP_GET_STATS - * VF sends this message to request stats for the selected VSI. VF uses - * the i40e_virtchnl_queue_select struct to specify the VSI. The queue_id - * field is ignored by the PF. - * - * PF replies with struct i40e_eth_stats in an external buffer. - */ - -/* I40E_VIRTCHNL_OP_CONFIG_RSS_KEY - * I40E_VIRTCHNL_OP_CONFIG_RSS_LUT - * VF sends these messages to configure RSS. Only supported if both PF - * and VF drivers set the I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF bit during - * configuration negotiation. If this is the case, then the RSS fields in - * the VF resource struct are valid. - * Both the key and LUT are initialized to 0 by the PF, meaning that - * RSS is effectively disabled until set up by the VF. - */ -struct i40e_virtchnl_rss_key { - u16 vsi_id; - u16 key_len; - u8 key[1]; /* RSS hash key, packed bytes */ -}; - -struct i40e_virtchnl_rss_lut { - u16 vsi_id; - u16 lut_entries; - u8 lut[1]; /* RSS lookup table*/ -}; - -/* I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS - * I40E_VIRTCHNL_OP_SET_RSS_HENA - * VF sends these messages to get and set the hash filter enable bits for RSS. - * By default, the PF sets these to all possible traffic types that the - * hardware supports. The VF can query this value if it wants to change the - * traffic types that are hashed by the hardware. - * Traffic types are defined in the i40e_filter_pctype enum in i40e_type.h - */ -struct i40e_virtchnl_rss_hena { - u64 hena; -}; - -/* I40E_VIRTCHNL_OP_EVENT - * PF sends this message to inform the VF driver of events that may affect it. - * No direct response is expected from the VF, though it may generate other - * messages in response to this one. - */ -enum i40e_virtchnl_event_codes { - I40E_VIRTCHNL_EVENT_UNKNOWN = 0, - I40E_VIRTCHNL_EVENT_LINK_CHANGE, - I40E_VIRTCHNL_EVENT_RESET_IMPENDING, - I40E_VIRTCHNL_EVENT_PF_DRIVER_CLOSE, -}; -#define I40E_PF_EVENT_SEVERITY_INFO 0 -#define I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM 255 - -struct i40e_virtchnl_pf_event { - enum i40e_virtchnl_event_codes event; - union { - struct { - enum i40e_aq_link_speed link_speed; - bool link_status; - } link_event; - } event_data; - - int severity; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP - * VF uses this message to request PF to map IWARP vectors to IWARP queues. - * The request for this originates from the VF IWARP driver through - * a client interface between VF LAN and VF IWARP driver. - * A vector could have an AEQ and CEQ attached to it although - * there is a single AEQ per VF IWARP instance in which case - * most vectors will have an INVALID_IDX for aeq and valid idx for ceq. - * There will never be a case where there will be multiple CEQs attached - * to a single vector. - * PF configures interrupt mapping and returns status. - */ - -/* HW does not define a type value for AEQ; only for RX/TX and CEQ. - * In order for us to keep the interface simple, SW will define a - * unique type value for AEQ. - */ -#define I40E_QUEUE_TYPE_PE_AEQ 0x80 -#define I40E_QUEUE_INVALID_IDX 0xFFFF - -struct i40e_virtchnl_iwarp_qv_info { - u32 v_idx; /* msix_vector */ - u16 ceq_idx; - u16 aeq_idx; - u8 itr_idx; -}; - -struct i40e_virtchnl_iwarp_qvlist_info { - u32 num_vectors; - struct i40e_virtchnl_iwarp_qv_info qv_info[1]; -}; - -/* VF reset states - these are written into the RSTAT register: - * I40E_VFGEN_RSTAT1 on the PF - * I40E_VFGEN_RSTAT on the VF - * When the PF initiates a reset, it writes 0 - * When the reset is complete, it writes 1 - * When the PF detects that the VF has recovered, it writes 2 - * VF checks this register periodically to determine if a reset has occurred, - * then polls it to know when the reset is complete. - * If either the PF or VF reads the register while the hardware - * is in a reset state, it will return DEADBEEF, which, when masked - * will result in 3. - */ -enum i40e_vfr_states { - I40E_VFR_INPROGRESS = 0, - I40E_VFR_COMPLETED, - I40E_VFR_VFACTIVE, - I40E_VFR_UNKNOWN, -}; - -#endif /* _I40E_VIRTCHNL_H_ */ diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index b8ada6d8d890..6cc92089fecb 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -43,7 +43,7 @@ #include <net/udp.h> #include "i40e_type.h" -#include "i40e_virtchnl.h" +#include <linux/avf/virtchnl.h> #include "i40e_txrx.h" #define DEFAULT_DEBUG_LEVEL_SHIFT 3 @@ -263,26 +263,26 @@ struct i40evf_adapter { struct work_struct watchdog_task; bool netdev_registered; bool link_up; - enum i40e_aq_link_speed link_speed; - enum i40e_virtchnl_ops current_op; + enum virtchnl_link_speed link_speed; + enum virtchnl_ops current_op; #define CLIENT_ALLOWED(_a) ((_a)->vf_res ? \ (_a)->vf_res->vf_offload_flags & \ - I40E_VIRTCHNL_VF_OFFLOAD_IWARP : \ + VIRTCHNL_VF_OFFLOAD_IWARP : \ 0) #define CLIENT_ENABLED(_a) ((_a)->cinst) /* RSS by the PF should be preferred over RSS via other methods. */ #define RSS_PF(_a) ((_a)->vf_res->vf_offload_flags & \ - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF) + VIRTCHNL_VF_OFFLOAD_RSS_PF) #define RSS_AQ(_a) ((_a)->vf_res->vf_offload_flags & \ - I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ) + VIRTCHNL_VF_OFFLOAD_RSS_AQ) #define RSS_REG(_a) (!((_a)->vf_res->vf_offload_flags & \ - (I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ | \ - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF))) + (VIRTCHNL_VF_OFFLOAD_RSS_AQ | \ + VIRTCHNL_VF_OFFLOAD_RSS_PF))) #define VLAN_ALLOWED(_a) ((_a)->vf_res->vf_offload_flags & \ - I40E_VIRTCHNL_VF_OFFLOAD_VLAN) - struct i40e_virtchnl_vf_resource *vf_res; /* incl. all VSIs */ - struct i40e_virtchnl_vsi_resource *vsi_res; /* our LAN VSI */ - struct i40e_virtchnl_version_info pf_version; + VIRTCHNL_VF_OFFLOAD_VLAN) + struct virtchnl_vf_resource *vf_res; /* incl. all VSIs */ + struct virtchnl_vsi_resource *vsi_res; /* our LAN VSI */ + struct virtchnl_version_info pf_version; #define PF_IS_V11(_a) (((_a)->pf_version.major == 1) && \ ((_a)->pf_version.minor == 1)) u16 msg_enable; @@ -348,7 +348,7 @@ void i40evf_set_hena(struct i40evf_adapter *adapter); void i40evf_set_rss_key(struct i40evf_adapter *adapter); void i40evf_set_rss_lut(struct i40evf_adapter *adapter); void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, - enum i40e_virtchnl_ops v_opcode, + enum virtchnl_ops v_opcode, i40e_status v_retval, u8 *msg, u16 msglen); int i40evf_config_rss(struct i40evf_adapter *adapter); int i40evf_lan_add_device(struct i40evf_adapter *adapter); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_client.c b/drivers/net/ethernet/intel/i40evf/i40evf_client.c index ee737680a0e9..93cf5fd17d91 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_client.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_client.c @@ -120,7 +120,7 @@ static int i40evf_client_release_qvlist(struct i40e_info *ldev) return -EAGAIN; err = i40e_aq_send_msg_to_pf(&adapter->hw, - I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP, + VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP, I40E_SUCCESS, NULL, 0, NULL); if (err) @@ -410,7 +410,7 @@ static u32 i40evf_client_virtchnl_send(struct i40e_info *ldev, if (adapter->aq_required) return -EAGAIN; - err = i40e_aq_send_msg_to_pf(&adapter->hw, I40E_VIRTCHNL_OP_IWARP, + err = i40e_aq_send_msg_to_pf(&adapter->hw, VIRTCHNL_OP_IWARP, I40E_SUCCESS, msg, len, NULL); if (err) dev_err(&adapter->pdev->dev, "Unable to send iWarp message to PF, error %d, aq status %d\n", @@ -431,7 +431,7 @@ static int i40evf_client_setup_qvlist(struct i40e_info *ldev, struct i40e_client *client, struct i40e_qvlist_info *qvlist_info) { - struct i40e_virtchnl_iwarp_qvlist_info *v_qvlist_info; + struct virtchnl_iwarp_qvlist_info *v_qvlist_info; struct i40evf_adapter *adapter = ldev->vf; struct i40e_qv_info *qv_info; i40e_status err; @@ -453,14 +453,14 @@ static int i40evf_client_setup_qvlist(struct i40e_info *ldev, return -EINVAL; } - v_qvlist_info = (struct i40e_virtchnl_iwarp_qvlist_info *)qvlist_info; - msg_size = sizeof(struct i40e_virtchnl_iwarp_qvlist_info) + - (sizeof(struct i40e_virtchnl_iwarp_qv_info) * + v_qvlist_info = (struct virtchnl_iwarp_qvlist_info *)qvlist_info; + msg_size = sizeof(struct virtchnl_iwarp_qvlist_info) + + (sizeof(struct virtchnl_iwarp_qv_info) * (v_qvlist_info->num_vectors - 1)); - adapter->client_pending |= BIT(I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP); + adapter->client_pending |= BIT(VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP); err = i40e_aq_send_msg_to_pf(&adapter->hw, - I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP, + VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP, I40E_SUCCESS, (u8 *)v_qvlist_info, msg_size, NULL); if (err) { @@ -474,7 +474,7 @@ static int i40evf_client_setup_qvlist(struct i40e_info *ldev, for (i = 0; i < 5; i++) { msleep(100); if (!(adapter->client_pending & - BIT(I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP))) { + BIT(VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP))) { err = 0; break; } diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index ea110a730e16..3a3ca965b242 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -44,9 +44,9 @@ static const char i40evf_driver_string[] = #define DRV_KERN "-k" -#define DRV_VERSION_MAJOR 2 -#define DRV_VERSION_MINOR 1 -#define DRV_VERSION_BUILD 14 +#define DRV_VERSION_MAJOR 3 +#define DRV_VERSION_MINOR 0 +#define DRV_VERSION_BUILD 0 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) \ @@ -67,6 +67,7 @@ static const struct pci_device_id i40evf_pci_tbl[] = { {PCI_VDEVICE(INTEL, I40E_DEV_ID_VF), 0}, {PCI_VDEVICE(INTEL, I40E_DEV_ID_VF_HV), 0}, {PCI_VDEVICE(INTEL, I40E_DEV_ID_X722_VF), 0}, + {PCI_VDEVICE(INTEL, I40E_DEV_ID_ADAPTIVE_VF), 0}, /* required last entry */ {0, } }; @@ -1131,7 +1132,7 @@ void i40evf_down(struct i40evf_adapter *adapter) if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) && adapter->state != __I40EVF_RESETTING) { /* cancel any current operation */ - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->current_op = VIRTCHNL_OP_UNKNOWN; /* Schedule operations to close down the HW. Don't wait * here for this to complete. The watchdog is still running * and it will take care of this. @@ -1311,7 +1312,7 @@ static int i40evf_config_rss_aq(struct i40evf_adapter *adapter) struct i40e_hw *hw = &adapter->hw; int ret = 0; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot configure RSS, command %d pending\n", adapter->current_op); @@ -1410,7 +1411,7 @@ static int i40evf_init_rss(struct i40evf_adapter *adapter) if (!RSS_PF(adapter)) { /* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */ if (adapter->vf_res->vf_offload_flags & - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) + VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) adapter->hena = I40E_DEFAULT_RSS_HENA_EXPANDED; else adapter->hena = I40E_DEFAULT_RSS_HENA; @@ -1588,8 +1589,8 @@ static void i40evf_watchdog_task(struct work_struct *work) if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) { reg_val = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; - if ((reg_val == I40E_VFR_VFACTIVE) || - (reg_val == I40E_VFR_COMPLETED)) { + if ((reg_val == VIRTCHNL_VFR_VFACTIVE) || + (reg_val == VIRTCHNL_VFR_COMPLETED)) { /* A chance for redemption! */ dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n"); adapter->state = __I40EVF_STARTUP; @@ -1605,7 +1606,7 @@ static void i40evf_watchdog_task(struct work_struct *work) return; } adapter->aq_required = 0; - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->current_op = VIRTCHNL_OP_UNKNOWN; goto watchdog_done; } @@ -1621,7 +1622,7 @@ static void i40evf_watchdog_task(struct work_struct *work) dev_err(&adapter->pdev->dev, "Hardware reset detected\n"); schedule_work(&adapter->reset_task); adapter->aq_required = 0; - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->current_op = VIRTCHNL_OP_UNKNOWN; goto watchdog_done; } @@ -1707,13 +1708,13 @@ static void i40evf_watchdog_task(struct work_struct *work) } if (adapter->aq_required & I40EVF_FLAG_AQ_REQUEST_PROMISC) { - i40evf_set_promiscuous(adapter, I40E_FLAG_VF_UNICAST_PROMISC | - I40E_FLAG_VF_MULTICAST_PROMISC); + i40evf_set_promiscuous(adapter, FLAG_VF_UNICAST_PROMISC | + FLAG_VF_MULTICAST_PROMISC); goto watchdog_done; } if (adapter->aq_required & I40EVF_FLAG_AQ_REQUEST_ALLMULTI) { - i40evf_set_promiscuous(adapter, I40E_FLAG_VF_MULTICAST_PROMISC); + i40evf_set_promiscuous(adapter, FLAG_VF_MULTICAST_PROMISC); goto watchdog_done; } @@ -1854,7 +1855,7 @@ static void i40evf_reset_task(struct work_struct *work) reg_val = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; - if (reg_val == I40E_VFR_VFACTIVE) + if (reg_val == VIRTCHNL_VFR_VFACTIVE) break; } @@ -1888,7 +1889,7 @@ continue_reset: /* kill and reinit the admin queue */ i40evf_shutdown_adminq(hw); - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->current_op = VIRTCHNL_OP_UNKNOWN; err = i40evf_init_adminq(hw); if (err) dev_info(&adapter->pdev->dev, "Failed to init adminq: %d\n", @@ -1949,7 +1950,7 @@ static void i40evf_adminq_task(struct work_struct *work) container_of(work, struct i40evf_adapter, adminq_task); struct i40e_hw *hw = &adapter->hw; struct i40e_arq_event_info event; - struct i40e_virtchnl_msg *v_msg; + struct virtchnl_msg *v_msg; i40e_status ret; u32 val, oldval; u16 pending; @@ -1962,14 +1963,15 @@ static void i40evf_adminq_task(struct work_struct *work) if (!event.msg_buf) goto out; - v_msg = (struct i40e_virtchnl_msg *)&event.desc; + v_msg = (struct virtchnl_msg *)&event.desc; do { ret = i40evf_clean_arq_element(hw, &event, &pending); if (ret || !v_msg->v_opcode) break; /* No event to process or error cleaning ARQ */ i40evf_virtchnl_completion(adapter, v_msg->v_opcode, - v_msg->v_retval, event.msg_buf, + (i40e_status)v_msg->v_retval, + event.msg_buf, event.msg_len); if (pending != 0) memset(event.msg_buf, 0, I40EVF_MAX_AQ_BUF_SIZE); @@ -2347,7 +2349,7 @@ static netdev_features_t i40evf_fix_features(struct net_device *netdev, struct i40evf_adapter *adapter = netdev_priv(netdev); features &= ~I40EVF_VLAN_FEATURES; - if (adapter->vf_res->vf_offload_flags & I40E_VIRTCHNL_VF_OFFLOAD_VLAN) + if (adapter->vf_res->vf_offload_flags & VIRTCHNL_VF_OFFLOAD_VLAN) features |= I40EVF_VLAN_FEATURES; return features; } @@ -2384,8 +2386,8 @@ static int i40evf_check_reset_complete(struct i40e_hw *hw) for (i = 0; i < 100; i++) { rstat = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; - if ((rstat == I40E_VFR_VFACTIVE) || - (rstat == I40E_VFR_COMPLETED)) + if ((rstat == VIRTCHNL_VFR_VFACTIVE) || + (rstat == VIRTCHNL_VFR_COMPLETED)) return 0; usleep_range(10, 20); } @@ -2401,7 +2403,7 @@ static int i40evf_check_reset_complete(struct i40e_hw *hw) **/ int i40evf_process_config(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_vf_resource *vfres = adapter->vf_res; + struct virtchnl_vf_resource *vfres = adapter->vf_res; struct net_device *netdev = adapter->netdev; struct i40e_vsi *vsi = &adapter->vsi; int i; @@ -2410,7 +2412,7 @@ int i40evf_process_config(struct i40evf_adapter *adapter) /* got VF config message back from PF, now we can parse it */ for (i = 0; i < vfres->num_vsis; i++) { - if (vfres->vsi_res[i].vsi_type == I40E_VSI_SRIOV) + if (vfres->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV) adapter->vsi_res = &vfres->vsi_res[i]; } if (!adapter->vsi_res) { @@ -2434,7 +2436,7 @@ int i40evf_process_config(struct i40evf_adapter *adapter) /* advertise to stack only if offloads for encapsulated packets is * supported */ - if (vfres->vf_offload_flags & I40E_VIRTCHNL_VF_OFFLOAD_ENCAP) { + if (vfres->vf_offload_flags & VIRTCHNL_VF_OFFLOAD_ENCAP) { hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM | @@ -2445,7 +2447,7 @@ int i40evf_process_config(struct i40evf_adapter *adapter) 0; if (!(vfres->vf_offload_flags & - I40E_VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM)) + VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM)) netdev->gso_partial_features |= NETIF_F_GSO_UDP_TUNNEL_CSUM; @@ -2472,7 +2474,7 @@ int i40evf_process_config(struct i40evf_adapter *adapter) adapter->vsi.work_limit = I40E_DEFAULT_IRQ_WORK; vsi->netdev = adapter->netdev; vsi->qs_handle = adapter->vsi_res->qset_handle; - if (vfres->vf_offload_flags & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF) { + if (vfres->vf_offload_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) { adapter->rss_key_size = vfres->rss_key_size; adapter->rss_lut_size = vfres->rss_lut_size; } else { @@ -2558,8 +2560,8 @@ static void i40evf_init_task(struct work_struct *work) dev_err(&pdev->dev, "Unsupported PF API version %d.%d, expected %d.%d\n", adapter->pf_version.major, adapter->pf_version.minor, - I40E_VIRTCHNL_VERSION_MAJOR, - I40E_VIRTCHNL_VERSION_MINOR); + VIRTCHNL_VERSION_MAJOR, + VIRTCHNL_VERSION_MINOR); goto err; } err = i40evf_send_vf_config_msg(adapter); @@ -2573,9 +2575,9 @@ static void i40evf_init_task(struct work_struct *work) case __I40EVF_INIT_GET_RESOURCES: /* aq msg sent, awaiting reply */ if (!adapter->vf_res) { - bufsz = sizeof(struct i40e_virtchnl_vf_resource) + + bufsz = sizeof(struct virtchnl_vf_resource) + (I40E_MAX_VF_VSI * - sizeof(struct i40e_virtchnl_vsi_resource)); + sizeof(struct virtchnl_vsi_resource)); adapter->vf_res = kzalloc(bufsz, GFP_KERNEL); if (!adapter->vf_res) goto err; @@ -2606,7 +2608,7 @@ static void i40evf_init_task(struct work_struct *work) if (i40evf_process_config(adapter)) goto err_alloc; - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->current_op = VIRTCHNL_OP_UNKNOWN; adapter->flags |= I40EVF_FLAG_RX_CSUM_ENABLED; @@ -2644,7 +2646,7 @@ static void i40evf_init_task(struct work_struct *work) goto err_sw_init; i40evf_map_rings_to_vectors(adapter); if (adapter->vf_res->vf_offload_flags & - I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) + VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) adapter->flags |= I40EVF_FLAG_WB_ON_ITR_CAPABLE; err = i40evf_request_misc_irq(adapter); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index deb2cb8dac6b..d2bb250a71af 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -42,7 +42,7 @@ * Send message to PF and print status if failure. **/ static int i40evf_send_pf_msg(struct i40evf_adapter *adapter, - enum i40e_virtchnl_ops op, u8 *msg, u16 len) + enum virtchnl_ops op, u8 *msg, u16 len) { struct i40e_hw *hw = &adapter->hw; i40e_status err; @@ -68,12 +68,12 @@ static int i40evf_send_pf_msg(struct i40evf_adapter *adapter, **/ int i40evf_send_api_ver(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_version_info vvi; + struct virtchnl_version_info vvi; - vvi.major = I40E_VIRTCHNL_VERSION_MAJOR; - vvi.minor = I40E_VIRTCHNL_VERSION_MINOR; + vvi.major = VIRTCHNL_VERSION_MAJOR; + vvi.minor = VIRTCHNL_VERSION_MINOR; - return i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_VERSION, (u8 *)&vvi, + return i40evf_send_pf_msg(adapter, VIRTCHNL_OP_VERSION, (u8 *)&vvi, sizeof(vvi)); } @@ -88,10 +88,10 @@ int i40evf_send_api_ver(struct i40evf_adapter *adapter) **/ int i40evf_verify_api_ver(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_version_info *pf_vvi; + struct virtchnl_version_info *pf_vvi; struct i40e_hw *hw = &adapter->hw; struct i40e_arq_event_info event; - enum i40e_virtchnl_ops op; + enum virtchnl_ops op; i40e_status err; event.buf_len = I40EVF_MAX_AQ_BUF_SIZE; @@ -109,8 +109,8 @@ int i40evf_verify_api_ver(struct i40evf_adapter *adapter) if (err) goto out_alloc; op = - (enum i40e_virtchnl_ops)le32_to_cpu(event.desc.cookie_high); - if (op == I40E_VIRTCHNL_OP_VERSION) + (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high); + if (op == VIRTCHNL_OP_VERSION) break; } @@ -119,19 +119,19 @@ int i40evf_verify_api_ver(struct i40evf_adapter *adapter) if (err) goto out_alloc; - if (op != I40E_VIRTCHNL_OP_VERSION) { + if (op != VIRTCHNL_OP_VERSION) { dev_info(&adapter->pdev->dev, "Invalid reply type %d from PF\n", op); err = -EIO; goto out_alloc; } - pf_vvi = (struct i40e_virtchnl_version_info *)event.msg_buf; + pf_vvi = (struct virtchnl_version_info *)event.msg_buf; adapter->pf_version = *pf_vvi; - if ((pf_vvi->major > I40E_VIRTCHNL_VERSION_MAJOR) || - ((pf_vvi->major == I40E_VIRTCHNL_VERSION_MAJOR) && - (pf_vvi->minor > I40E_VIRTCHNL_VERSION_MINOR))) + if ((pf_vvi->major > VIRTCHNL_VERSION_MAJOR) || + ((pf_vvi->major == VIRTCHNL_VERSION_MAJOR) && + (pf_vvi->minor > VIRTCHNL_VERSION_MINOR))) err = -EIO; out_alloc: @@ -152,26 +152,25 @@ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter) { u32 caps; - adapter->current_op = I40E_VIRTCHNL_OP_GET_VF_RESOURCES; - adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG; - caps = I40E_VIRTCHNL_VF_OFFLOAD_L2 | - I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ | - I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG | - I40E_VIRTCHNL_VF_OFFLOAD_VLAN | - I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 | - I40E_VIRTCHNL_VF_OFFLOAD_ENCAP | - I40E_VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM; - - adapter->current_op = I40E_VIRTCHNL_OP_GET_VF_RESOURCES; + caps = VIRTCHNL_VF_OFFLOAD_L2 | + VIRTCHNL_VF_OFFLOAD_RSS_PF | + VIRTCHNL_VF_OFFLOAD_RSS_AQ | + VIRTCHNL_VF_OFFLOAD_RSS_REG | + VIRTCHNL_VF_OFFLOAD_VLAN | + VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | + VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 | + VIRTCHNL_VF_OFFLOAD_ENCAP | + VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM; + + adapter->current_op = VIRTCHNL_OP_GET_VF_RESOURCES; adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG; if (PF_IS_V11(adapter)) return i40evf_send_pf_msg(adapter, - I40E_VIRTCHNL_OP_GET_VF_RESOURCES, + VIRTCHNL_OP_GET_VF_RESOURCES, (u8 *)&caps, sizeof(caps)); else return i40evf_send_pf_msg(adapter, - I40E_VIRTCHNL_OP_GET_VF_RESOURCES, + VIRTCHNL_OP_GET_VF_RESOURCES, NULL, 0); } @@ -189,12 +188,12 @@ int i40evf_get_vf_config(struct i40evf_adapter *adapter) { struct i40e_hw *hw = &adapter->hw; struct i40e_arq_event_info event; - enum i40e_virtchnl_ops op; + enum virtchnl_ops op; i40e_status err; u16 len; - len = sizeof(struct i40e_virtchnl_vf_resource) + - I40E_MAX_VF_VSI * sizeof(struct i40e_virtchnl_vsi_resource); + len = sizeof(struct virtchnl_vf_resource) + + I40E_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource); event.buf_len = len; event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL); if (!event.msg_buf) { @@ -210,8 +209,8 @@ int i40evf_get_vf_config(struct i40evf_adapter *adapter) if (err) goto out_alloc; op = - (enum i40e_virtchnl_ops)le32_to_cpu(event.desc.cookie_high); - if (op == I40E_VIRTCHNL_OP_GET_VF_RESOURCES) + (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high); + if (op == VIRTCHNL_OP_GET_VF_RESOURCES) break; } @@ -233,20 +232,20 @@ out: **/ void i40evf_configure_queues(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_vsi_queue_config_info *vqci; - struct i40e_virtchnl_queue_pair_info *vqpi; + struct virtchnl_vsi_queue_config_info *vqci; + struct virtchnl_queue_pair_info *vqpi; int pairs = adapter->num_active_queues; int i, len, max_frame = I40E_MAX_RXBUFFER; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot configure queues, command %d pending\n", adapter->current_op); return; } - adapter->current_op = I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES; - len = sizeof(struct i40e_virtchnl_vsi_queue_config_info) + - (sizeof(struct i40e_virtchnl_queue_pair_info) * pairs); + adapter->current_op = VIRTCHNL_OP_CONFIG_VSI_QUEUES; + len = sizeof(struct virtchnl_vsi_queue_config_info) + + (sizeof(struct virtchnl_queue_pair_info) * pairs); vqci = kzalloc(len, GFP_KERNEL); if (!vqci) return; @@ -279,7 +278,7 @@ void i40evf_configure_queues(struct i40evf_adapter *adapter) } adapter->aq_required &= ~I40EVF_FLAG_AQ_CONFIGURE_QUEUES; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_VSI_QUEUES, (u8 *)vqci, len); kfree(vqci); } @@ -292,20 +291,20 @@ void i40evf_configure_queues(struct i40evf_adapter *adapter) **/ void i40evf_enable_queues(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_queue_select vqs; + struct virtchnl_queue_select vqs; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot enable queues, command %d pending\n", adapter->current_op); return; } - adapter->current_op = I40E_VIRTCHNL_OP_ENABLE_QUEUES; + adapter->current_op = VIRTCHNL_OP_ENABLE_QUEUES; vqs.vsi_id = adapter->vsi_res->vsi_id; vqs.tx_queues = BIT(adapter->num_active_queues) - 1; vqs.rx_queues = vqs.tx_queues; adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_QUEUES; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ENABLE_QUEUES, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_QUEUES, (u8 *)&vqs, sizeof(vqs)); } @@ -317,20 +316,20 @@ void i40evf_enable_queues(struct i40evf_adapter *adapter) **/ void i40evf_disable_queues(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_queue_select vqs; + struct virtchnl_queue_select vqs; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot disable queues, command %d pending\n", adapter->current_op); return; } - adapter->current_op = I40E_VIRTCHNL_OP_DISABLE_QUEUES; + adapter->current_op = VIRTCHNL_OP_DISABLE_QUEUES; vqs.vsi_id = adapter->vsi_res->vsi_id; vqs.tx_queues = BIT(adapter->num_active_queues) - 1; vqs.rx_queues = vqs.tx_queues; adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_QUEUES; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DISABLE_QUEUES, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_QUEUES, (u8 *)&vqs, sizeof(vqs)); } @@ -343,23 +342,23 @@ void i40evf_disable_queues(struct i40evf_adapter *adapter) **/ void i40evf_map_queues(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_irq_map_info *vimi; + struct virtchnl_irq_map_info *vimi; int v_idx, q_vectors, len; struct i40e_q_vector *q_vector; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot map queues to vectors, command %d pending\n", adapter->current_op); return; } - adapter->current_op = I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP; + adapter->current_op = VIRTCHNL_OP_CONFIG_IRQ_MAP; q_vectors = adapter->num_msix_vectors - NONQ_VECS; - len = sizeof(struct i40e_virtchnl_irq_map_info) + + len = sizeof(struct virtchnl_irq_map_info) + (adapter->num_msix_vectors * - sizeof(struct i40e_virtchnl_vector_map)); + sizeof(struct virtchnl_vector_map)); vimi = kzalloc(len, GFP_KERNEL); if (!vimi) return; @@ -380,7 +379,7 @@ void i40evf_map_queues(struct i40evf_adapter *adapter) vimi->vecmap[v_idx].rxq_map = 0; adapter->aq_required &= ~I40EVF_FLAG_AQ_MAP_VECTORS; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_IRQ_MAP, (u8 *)vimi, len); kfree(vimi); } @@ -395,12 +394,12 @@ void i40evf_map_queues(struct i40evf_adapter *adapter) **/ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_ether_addr_list *veal; + struct virtchnl_ether_addr_list *veal; int len, i = 0, count = 0; struct i40evf_mac_filter *f; bool more = false; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot add filters, command %d pending\n", adapter->current_op); @@ -414,17 +413,17 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter) adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER; return; } - adapter->current_op = I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS; + adapter->current_op = VIRTCHNL_OP_ADD_ETH_ADDR; - len = sizeof(struct i40e_virtchnl_ether_addr_list) + - (count * sizeof(struct i40e_virtchnl_ether_addr)); + len = sizeof(struct virtchnl_ether_addr_list) + + (count * sizeof(struct virtchnl_ether_addr)); if (len > I40EVF_MAX_AQ_BUF_SIZE) { dev_warn(&adapter->pdev->dev, "Too many add MAC changes in one request\n"); count = (I40EVF_MAX_AQ_BUF_SIZE - - sizeof(struct i40e_virtchnl_ether_addr_list)) / - sizeof(struct i40e_virtchnl_ether_addr); - len = sizeof(struct i40e_virtchnl_ether_addr_list) + - (count * sizeof(struct i40e_virtchnl_ether_addr)); + sizeof(struct virtchnl_ether_addr_list)) / + sizeof(struct virtchnl_ether_addr); + len = sizeof(struct virtchnl_ether_addr_list) + + (count * sizeof(struct virtchnl_ether_addr)); more = true; } @@ -445,7 +444,7 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter) } if (!more) adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_ETH_ADDR, (u8 *)veal, len); kfree(veal); } @@ -460,12 +459,12 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter) **/ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_ether_addr_list *veal; + struct virtchnl_ether_addr_list *veal; struct i40evf_mac_filter *f, *ftmp; int len, i = 0, count = 0; bool more = false; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot remove filters, command %d pending\n", adapter->current_op); @@ -479,17 +478,17 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter) adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER; return; } - adapter->current_op = I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS; + adapter->current_op = VIRTCHNL_OP_DEL_ETH_ADDR; - len = sizeof(struct i40e_virtchnl_ether_addr_list) + - (count * sizeof(struct i40e_virtchnl_ether_addr)); + len = sizeof(struct virtchnl_ether_addr_list) + + (count * sizeof(struct virtchnl_ether_addr)); if (len > I40EVF_MAX_AQ_BUF_SIZE) { dev_warn(&adapter->pdev->dev, "Too many delete MAC changes in one request\n"); count = (I40EVF_MAX_AQ_BUF_SIZE - - sizeof(struct i40e_virtchnl_ether_addr_list)) / - sizeof(struct i40e_virtchnl_ether_addr); - len = sizeof(struct i40e_virtchnl_ether_addr_list) + - (count * sizeof(struct i40e_virtchnl_ether_addr)); + sizeof(struct virtchnl_ether_addr_list)) / + sizeof(struct virtchnl_ether_addr); + len = sizeof(struct virtchnl_ether_addr_list) + + (count * sizeof(struct virtchnl_ether_addr)); more = true; } veal = kzalloc(len, GFP_KERNEL); @@ -510,7 +509,7 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter) } if (!more) adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_ETH_ADDR, (u8 *)veal, len); kfree(veal); } @@ -525,12 +524,12 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter) **/ void i40evf_add_vlans(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_vlan_filter_list *vvfl; + struct virtchnl_vlan_filter_list *vvfl; int len, i = 0, count = 0; struct i40evf_vlan_filter *f; bool more = false; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot add VLANs, command %d pending\n", adapter->current_op); @@ -545,16 +544,16 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter) adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER; return; } - adapter->current_op = I40E_VIRTCHNL_OP_ADD_VLAN; + adapter->current_op = VIRTCHNL_OP_ADD_VLAN; - len = sizeof(struct i40e_virtchnl_vlan_filter_list) + + len = sizeof(struct virtchnl_vlan_filter_list) + (count * sizeof(u16)); if (len > I40EVF_MAX_AQ_BUF_SIZE) { dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n"); count = (I40EVF_MAX_AQ_BUF_SIZE - - sizeof(struct i40e_virtchnl_vlan_filter_list)) / + sizeof(struct virtchnl_vlan_filter_list)) / sizeof(u16); - len = sizeof(struct i40e_virtchnl_vlan_filter_list) + + len = sizeof(struct virtchnl_vlan_filter_list) + (count * sizeof(u16)); more = true; } @@ -575,7 +574,7 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter) } if (!more) adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len); + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len); kfree(vvfl); } @@ -589,12 +588,12 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter) **/ void i40evf_del_vlans(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_vlan_filter_list *vvfl; + struct virtchnl_vlan_filter_list *vvfl; struct i40evf_vlan_filter *f, *ftmp; int len, i = 0, count = 0; bool more = false; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot remove VLANs, command %d pending\n", adapter->current_op); @@ -609,16 +608,16 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter) adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER; return; } - adapter->current_op = I40E_VIRTCHNL_OP_DEL_VLAN; + adapter->current_op = VIRTCHNL_OP_DEL_VLAN; - len = sizeof(struct i40e_virtchnl_vlan_filter_list) + + len = sizeof(struct virtchnl_vlan_filter_list) + (count * sizeof(u16)); if (len > I40EVF_MAX_AQ_BUF_SIZE) { dev_warn(&adapter->pdev->dev, "Too many delete VLAN changes in one request\n"); count = (I40EVF_MAX_AQ_BUF_SIZE - - sizeof(struct i40e_virtchnl_vlan_filter_list)) / + sizeof(struct virtchnl_vlan_filter_list)) / sizeof(u16); - len = sizeof(struct i40e_virtchnl_vlan_filter_list) + + len = sizeof(struct virtchnl_vlan_filter_list) + (count * sizeof(u16)); more = true; } @@ -640,7 +639,7 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter) } if (!more) adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len); + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len); kfree(vvfl); } @@ -653,25 +652,25 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter) **/ void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags) { - struct i40e_virtchnl_promisc_info vpi; + struct virtchnl_promisc_info vpi; int promisc_all; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot set promiscuous mode, command %d pending\n", adapter->current_op); return; } - promisc_all = I40E_FLAG_VF_UNICAST_PROMISC | - I40E_FLAG_VF_MULTICAST_PROMISC; + promisc_all = FLAG_VF_UNICAST_PROMISC | + FLAG_VF_MULTICAST_PROMISC; if ((flags & promisc_all) == promisc_all) { adapter->flags |= I40EVF_FLAG_PROMISC_ON; adapter->aq_required &= ~I40EVF_FLAG_AQ_REQUEST_PROMISC; dev_info(&adapter->pdev->dev, "Entering promiscuous mode\n"); } - if (flags & I40E_FLAG_VF_MULTICAST_PROMISC) { + if (flags & FLAG_VF_MULTICAST_PROMISC) { adapter->flags |= I40EVF_FLAG_ALLMULTI_ON; adapter->aq_required &= ~I40EVF_FLAG_AQ_REQUEST_ALLMULTI; dev_info(&adapter->pdev->dev, "Entering multicast promiscuous mode\n"); @@ -683,10 +682,10 @@ void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags) dev_info(&adapter->pdev->dev, "Leaving promiscuous mode\n"); } - adapter->current_op = I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE; + adapter->current_op = VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE; vpi.vsi_id = adapter->vsi_res->vsi_id; vpi.flags = flags; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, (u8 *)&vpi, sizeof(vpi)); } @@ -698,19 +697,19 @@ void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags) **/ void i40evf_request_stats(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_queue_select vqs; + struct virtchnl_queue_select vqs; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* no error message, this isn't crucial */ return; } - adapter->current_op = I40E_VIRTCHNL_OP_GET_STATS; + adapter->current_op = VIRTCHNL_OP_GET_STATS; vqs.vsi_id = adapter->vsi_res->vsi_id; /* queue maps are ignored for this message - only the vsi is used */ - if (i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_GET_STATS, + if (i40evf_send_pf_msg(adapter, VIRTCHNL_OP_GET_STATS, (u8 *)&vqs, sizeof(vqs))) /* if the request failed, don't lock out others */ - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->current_op = VIRTCHNL_OP_UNKNOWN; } /** @@ -721,15 +720,15 @@ void i40evf_request_stats(struct i40evf_adapter *adapter) **/ void i40evf_get_hena(struct i40evf_adapter *adapter) { - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot get RSS hash capabilities, command %d pending\n", adapter->current_op); return; } - adapter->current_op = I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS; + adapter->current_op = VIRTCHNL_OP_GET_RSS_HENA_CAPS; adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_HENA; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_GET_RSS_HENA_CAPS, NULL, 0); } @@ -741,18 +740,18 @@ void i40evf_get_hena(struct i40evf_adapter *adapter) **/ void i40evf_set_hena(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_rss_hena vrh; + struct virtchnl_rss_hena vrh; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot set RSS hash enable, command %d pending\n", adapter->current_op); return; } vrh.hena = adapter->hena; - adapter->current_op = I40E_VIRTCHNL_OP_SET_RSS_HENA; + adapter->current_op = VIRTCHNL_OP_SET_RSS_HENA; adapter->aq_required &= ~I40EVF_FLAG_AQ_SET_HENA; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_SET_RSS_HENA, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_SET_RSS_HENA, (u8 *)&vrh, sizeof(vrh)); } @@ -764,16 +763,16 @@ void i40evf_set_hena(struct i40evf_adapter *adapter) **/ void i40evf_set_rss_key(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_rss_key *vrk; + struct virtchnl_rss_key *vrk; int len; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot set RSS key, command %d pending\n", adapter->current_op); return; } - len = sizeof(struct i40e_virtchnl_rss_key) + + len = sizeof(struct virtchnl_rss_key) + (adapter->rss_key_size * sizeof(u8)) - 1; vrk = kzalloc(len, GFP_KERNEL); if (!vrk) @@ -782,9 +781,9 @@ void i40evf_set_rss_key(struct i40evf_adapter *adapter) vrk->key_len = adapter->rss_key_size; memcpy(vrk->key, adapter->rss_key, adapter->rss_key_size); - adapter->current_op = I40E_VIRTCHNL_OP_CONFIG_RSS_KEY; + adapter->current_op = VIRTCHNL_OP_CONFIG_RSS_KEY; adapter->aq_required &= ~I40EVF_FLAG_AQ_SET_RSS_KEY; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_RSS_KEY, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_RSS_KEY, (u8 *)vrk, len); kfree(vrk); } @@ -797,16 +796,16 @@ void i40evf_set_rss_key(struct i40evf_adapter *adapter) **/ void i40evf_set_rss_lut(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_rss_lut *vrl; + struct virtchnl_rss_lut *vrl; int len; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot set RSS LUT, command %d pending\n", adapter->current_op); return; } - len = sizeof(struct i40e_virtchnl_rss_lut) + + len = sizeof(struct virtchnl_rss_lut) + (adapter->rss_lut_size * sizeof(u8)) - 1; vrl = kzalloc(len, GFP_KERNEL); if (!vrl) @@ -814,9 +813,9 @@ void i40evf_set_rss_lut(struct i40evf_adapter *adapter) vrl->vsi_id = adapter->vsi.id; vrl->lut_entries = adapter->rss_lut_size; memcpy(vrl->lut, adapter->rss_lut, adapter->rss_lut_size); - adapter->current_op = I40E_VIRTCHNL_OP_CONFIG_RSS_LUT; + adapter->current_op = VIRTCHNL_OP_CONFIG_RSS_LUT; adapter->aq_required &= ~I40EVF_FLAG_AQ_SET_RSS_LUT; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_RSS_LUT, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_RSS_LUT, (u8 *)vrl, len); kfree(vrl); } @@ -872,8 +871,8 @@ static void i40evf_print_link_message(struct i40evf_adapter *adapter) void i40evf_request_reset(struct i40evf_adapter *adapter) { /* Don't check CURRENT_OP - this is always higher priority */ - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_RESET_VF, NULL, 0); - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_RESET_VF, NULL, 0); + adapter->current_op = VIRTCHNL_OP_UNKNOWN; } /** @@ -889,17 +888,17 @@ void i40evf_request_reset(struct i40evf_adapter *adapter) * This function handles the reply messages. **/ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, - enum i40e_virtchnl_ops v_opcode, + enum virtchnl_ops v_opcode, i40e_status v_retval, u8 *msg, u16 msglen) { struct net_device *netdev = adapter->netdev; - if (v_opcode == I40E_VIRTCHNL_OP_EVENT) { - struct i40e_virtchnl_pf_event *vpe = - (struct i40e_virtchnl_pf_event *)msg; + if (v_opcode == VIRTCHNL_OP_EVENT) { + struct virtchnl_pf_event *vpe = + (struct virtchnl_pf_event *)msg; switch (vpe->event) { - case I40E_VIRTCHNL_EVENT_LINK_CHANGE: + case VIRTCHNL_EVENT_LINK_CHANGE: adapter->link_speed = vpe->event_data.link_event.link_speed; if (adapter->link_up != @@ -916,7 +915,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, i40evf_print_link_message(adapter); } break; - case I40E_VIRTCHNL_EVENT_RESET_IMPENDING: + case VIRTCHNL_EVENT_RESET_IMPENDING: dev_info(&adapter->pdev->dev, "PF reset warning received\n"); if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING)) { adapter->flags |= I40EVF_FLAG_RESET_PENDING; @@ -933,19 +932,19 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, } if (v_retval) { switch (v_opcode) { - case I40E_VIRTCHNL_OP_ADD_VLAN: + case VIRTCHNL_OP_ADD_VLAN: dev_err(&adapter->pdev->dev, "Failed to add VLAN filter, error %s\n", i40evf_stat_str(&adapter->hw, v_retval)); break; - case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: + case VIRTCHNL_OP_ADD_ETH_ADDR: dev_err(&adapter->pdev->dev, "Failed to add MAC filter, error %s\n", i40evf_stat_str(&adapter->hw, v_retval)); break; - case I40E_VIRTCHNL_OP_DEL_VLAN: + case VIRTCHNL_OP_DEL_VLAN: dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n", i40evf_stat_str(&adapter->hw, v_retval)); break; - case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: + case VIRTCHNL_OP_DEL_ETH_ADDR: dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n", i40evf_stat_str(&adapter->hw, v_retval)); break; @@ -957,7 +956,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, } } switch (v_opcode) { - case I40E_VIRTCHNL_OP_GET_STATS: { + case VIRTCHNL_OP_GET_STATS: { struct i40e_eth_stats *stats = (struct i40e_eth_stats *)msg; netdev->stats.rx_packets = stats->rx_unicast + @@ -974,10 +973,10 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, adapter->current_stats = *stats; } break; - case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: { - u16 len = sizeof(struct i40e_virtchnl_vf_resource) + + case VIRTCHNL_OP_GET_VF_RESOURCES: { + u16 len = sizeof(struct virtchnl_vf_resource) + I40E_MAX_VF_VSI * - sizeof(struct i40e_virtchnl_vsi_resource); + sizeof(struct virtchnl_vsi_resource); memcpy(adapter->vf_res, msg, min(msglen, len)); i40e_vf_parse_hw_config(&adapter->hw, adapter->vf_res); /* restore current mac address */ @@ -985,18 +984,18 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, i40evf_process_config(adapter); } break; - case I40E_VIRTCHNL_OP_ENABLE_QUEUES: + case VIRTCHNL_OP_ENABLE_QUEUES: /* enable transmits */ i40evf_irq_enable(adapter, true); break; - case I40E_VIRTCHNL_OP_DISABLE_QUEUES: + case VIRTCHNL_OP_DISABLE_QUEUES: i40evf_free_all_tx_resources(adapter); i40evf_free_all_rx_resources(adapter); if (adapter->state == __I40EVF_DOWN_PENDING) adapter->state = __I40EVF_DOWN; break; - case I40E_VIRTCHNL_OP_VERSION: - case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: + case VIRTCHNL_OP_VERSION: + case VIRTCHNL_OP_CONFIG_IRQ_MAP: /* Don't display an error if we get these out of sequence. * If the firmware needed to get kicked, we'll get these and * it's no problem. @@ -1004,7 +1003,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, if (v_opcode != adapter->current_op) return; break; - case I40E_VIRTCHNL_OP_IWARP: + case VIRTCHNL_OP_IWARP: /* Gobble zero-length replies from the PF. They indicate that * a previous message was received OK, and the client doesn't * care about that. @@ -1014,13 +1013,12 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, msg, msglen); break; - case I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: + case VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: adapter->client_pending &= - ~(BIT(I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP)); + ~(BIT(VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP)); break; - case I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS: { - struct i40e_virtchnl_rss_hena *vrh = - (struct i40e_virtchnl_rss_hena *)msg; + case VIRTCHNL_OP_GET_RSS_HENA_CAPS: { + struct virtchnl_rss_hena *vrh = (struct virtchnl_rss_hena *)msg; if (msglen == sizeof(*vrh)) adapter->hena = vrh->hena; else @@ -1034,5 +1032,5 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, adapter->current_op, v_opcode); break; } /* switch v_opcode */ - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->current_op = VIRTCHNL_OP_UNKNOWN; } diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index ee443985581f..4a50870e0fa7 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -257,6 +257,7 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw) } /* Set phy->phy_addr and phy->id. */ + igb_write_phy_reg_82580(hw, I347AT4_PAGE_SELECT, 0); ret_val = igb_get_phy_id_82575(hw); if (ret_val) return ret_val; diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index bf9bf9056d0c..06ffb2bc713e 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -563,6 +563,7 @@ struct igb_adapter { struct cyclecounter cc; struct timecounter tc; u32 tx_hwtstamp_timeouts; + u32 tx_hwtstamp_skipped; u32 rx_hwtstamp_cleared; bool pps_sys_wrap_on; @@ -666,7 +667,7 @@ void igb_setup_tctl(struct igb_adapter *); void igb_setup_rctl(struct igb_adapter *); netdev_tx_t igb_xmit_frame_ring(struct sk_buff *, struct igb_ring *); void igb_alloc_rx_buffers(struct igb_ring *, u16); -void igb_update_stats(struct igb_adapter *, struct rtnl_link_stats64 *); +void igb_update_stats(struct igb_adapter *); bool igb_has_link(struct igb_adapter *adapter); void igb_set_ethtool_ops(struct net_device *); void igb_power_up_link(struct igb_adapter *); @@ -676,6 +677,7 @@ void igb_ptp_stop(struct igb_adapter *adapter); void igb_ptp_reset(struct igb_adapter *adapter); void igb_ptp_suspend(struct igb_adapter *adapter); void igb_ptp_rx_hang(struct igb_adapter *adapter); +void igb_ptp_tx_hang(struct igb_adapter *adapter); void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb); void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va, struct sk_buff *skb); diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 0efb62db6efd..d06a8db514d4 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -90,6 +90,7 @@ static const struct igb_stats igb_gstrings_stats[] = { IGB_STAT("os2bmc_tx_by_host", stats.o2bspc), IGB_STAT("os2bmc_rx_by_host", stats.b2ogprc), IGB_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), + IGB_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped), IGB_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared), }; @@ -2315,7 +2316,7 @@ static void igb_get_ethtool_stats(struct net_device *netdev, char *p; spin_lock(&adapter->stats64_lock); - igb_update_stats(adapter, net_stats); + igb_update_stats(adapter); for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { p = (char *)adapter + igb_gstrings_stats[i].stat_offset; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 1cf74aa4ebd9..7e433344a13c 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -191,10 +191,7 @@ static int igb_disable_sriov(struct pci_dev *dev); static int igb_pci_disable_sriov(struct pci_dev *dev); #endif -#ifdef CONFIG_PM -#ifdef CONFIG_PM_SLEEP static int igb_suspend(struct device *); -#endif static int igb_resume(struct device *); static int igb_runtime_suspend(struct device *dev); static int igb_runtime_resume(struct device *dev); @@ -204,7 +201,6 @@ static const struct dev_pm_ops igb_pm_ops = { SET_RUNTIME_PM_OPS(igb_runtime_suspend, igb_runtime_resume, igb_runtime_idle) }; -#endif static void igb_shutdown(struct pci_dev *); static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs); #ifdef CONFIG_IGB_DCA @@ -1822,7 +1818,7 @@ void igb_down(struct igb_adapter *adapter) /* record the stats before reset*/ spin_lock(&adapter->stats64_lock); - igb_update_stats(adapter, &adapter->stats64); + igb_update_stats(adapter); spin_unlock(&adapter->stats64_lock); adapter->link_speed = 0; @@ -4690,7 +4686,7 @@ no_wait: } spin_lock(&adapter->stats64_lock); - igb_update_stats(adapter, &adapter->stats64); + igb_update_stats(adapter); spin_unlock(&adapter->stats64_lock); for (i = 0; i < adapter->num_tx_queues; i++) { @@ -4726,6 +4722,7 @@ no_wait: igb_spoof_check(adapter); igb_ptp_rx_hang(adapter); + igb_ptp_tx_hang(adapter); /* Check LVMMC register on i350/i354 only */ if ((adapter->hw.mac.type == e1000_i350) || @@ -5201,9 +5198,9 @@ static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size) return __igb_maybe_stop_tx(tx_ring, size); } -static void igb_tx_map(struct igb_ring *tx_ring, - struct igb_tx_buffer *first, - const u8 hdr_len) +static int igb_tx_map(struct igb_ring *tx_ring, + struct igb_tx_buffer *first, + const u8 hdr_len) { struct sk_buff *skb = first->skb; struct igb_tx_buffer *tx_buffer; @@ -5314,7 +5311,7 @@ static void igb_tx_map(struct igb_ring *tx_ring, */ mmiowb(); } - return; + return 0; dma_error: dev_err(tx_ring->dev, "TX DMA map failed\n"); @@ -5345,6 +5342,8 @@ dma_error: tx_buffer->skb = NULL; tx_ring->next_to_use = i; + + return -1; } netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, @@ -5390,6 +5389,8 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, adapter->ptp_tx_start = jiffies; if (adapter->hw.mac.type == e1000_82576) schedule_work(&adapter->ptp_tx_work); + } else { + adapter->tx_hwtstamp_skipped++; } } @@ -5410,13 +5411,24 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, else if (!tso) igb_tx_csum(tx_ring, first); - igb_tx_map(tx_ring, first, hdr_len); + if (igb_tx_map(tx_ring, first, hdr_len)) + goto cleanup_tx_tstamp; return NETDEV_TX_OK; out_drop: dev_kfree_skb_any(first->skb); first->skb = NULL; +cleanup_tx_tstamp: + if (unlikely(tx_flags & IGB_TX_FLAGS_TSTAMP)) { + struct igb_adapter *adapter = netdev_priv(tx_ring->netdev); + + dev_kfree_skb_any(adapter->ptp_tx_skb); + adapter->ptp_tx_skb = NULL; + if (adapter->hw.mac.type == e1000_82576) + cancel_work_sync(&adapter->ptp_tx_work); + clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); + } return NETDEV_TX_OK; } @@ -5487,7 +5499,7 @@ static void igb_get_stats64(struct net_device *netdev, struct igb_adapter *adapter = netdev_priv(netdev); spin_lock(&adapter->stats64_lock); - igb_update_stats(adapter, &adapter->stats64); + igb_update_stats(adapter); memcpy(stats, &adapter->stats64, sizeof(*stats)); spin_unlock(&adapter->stats64_lock); } @@ -5536,9 +5548,9 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu) * igb_update_stats - Update the board statistics counters * @adapter: board private structure **/ -void igb_update_stats(struct igb_adapter *adapter, - struct rtnl_link_stats64 *net_stats) +void igb_update_stats(struct igb_adapter *adapter) { + struct rtnl_link_stats64 *net_stats = &adapter->stats64; struct e1000_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; u32 reg, mpc; @@ -8015,9 +8027,7 @@ static void igb_deliver_wake_packet(struct net_device *netdev) netif_rx(skb); } -#ifdef CONFIG_PM -#ifdef CONFIG_PM_SLEEP -static int igb_suspend(struct device *dev) +static int __maybe_unused igb_suspend(struct device *dev) { int retval; bool wake; @@ -8036,9 +8046,8 @@ static int igb_suspend(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ -static int igb_resume(struct device *dev) +static int __maybe_unused igb_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); @@ -8092,7 +8101,7 @@ static int igb_resume(struct device *dev) return err; } -static int igb_runtime_idle(struct device *dev) +static int __maybe_unused igb_runtime_idle(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); @@ -8104,7 +8113,7 @@ static int igb_runtime_idle(struct device *dev) return -EBUSY; } -static int igb_runtime_suspend(struct device *dev) +static int __maybe_unused igb_runtime_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); int retval; @@ -8124,11 +8133,10 @@ static int igb_runtime_suspend(struct device *dev) return 0; } -static int igb_runtime_resume(struct device *dev) +static int __maybe_unused igb_runtime_resume(struct device *dev) { return igb_resume(dev); } -#endif /* CONFIG_PM */ static void igb_shutdown(struct pci_dev *pdev) { diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 7a3fd4d74592..841c2a083349 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -712,6 +712,35 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter) } /** + * igb_ptp_tx_hang - detect error case where Tx timestamp never finishes + * @adapter: private network adapter structure + */ +void igb_ptp_tx_hang(struct igb_adapter *adapter) +{ + bool timeout = time_is_before_jiffies(adapter->ptp_tx_start + + IGB_PTP_TX_TIMEOUT); + + if (!adapter->ptp_tx_skb) + return; + + if (!test_bit(__IGB_PTP_TX_IN_PROGRESS, &adapter->state)) + return; + + /* If we haven't received a timestamp within the timeout, it is + * reasonable to assume that it will never occur, so we can unlock the + * timestamp bit when this occurs. + */ + if (timeout) { + cancel_work_sync(&adapter->ptp_tx_work); + dev_kfree_skb_any(adapter->ptp_tx_skb); + adapter->ptp_tx_skb = NULL; + clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); + adapter->tx_hwtstamp_timeouts++; + dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n"); + } +} + +/** * igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp * @adapter: Board private structure. * @@ -721,6 +750,7 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter) **/ static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) { + struct sk_buff *skb = adapter->ptp_tx_skb; struct e1000_hw *hw = &adapter->hw; struct skb_shared_hwtstamps shhwtstamps; u64 regval; @@ -748,10 +778,17 @@ static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) shhwtstamps.hwtstamp = ktime_add_ns(shhwtstamps.hwtstamp, adjust); - skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps); - dev_kfree_skb_any(adapter->ptp_tx_skb); + /* Clear the lock early before calling skb_tstamp_tx so that + * applications are not woken up before the lock bit is clear. We use + * a copy of the skb pointer to ensure other threads can't change it + * while we're notifying the stack. + */ adapter->ptp_tx_skb = NULL; clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); + + /* Notify the stack and free the skb after we've unlocked */ + skb_tstamp_tx(skb, &shhwtstamps); + dev_kfree_skb_any(skb); } /** @@ -941,6 +978,7 @@ static int igb_ptp_set_timestamp_mode(struct igb_adapter *adapter, is_l4 = true; break; case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: /* 82576 cannot timestamp all packets, which it needs to do to * support both V1 Sync and Delay_Req messages diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index c8ac46049f34..d602637ccc40 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -1589,15 +1589,17 @@ s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw, switch (ntohs(input_mask->formatted.vlan_id) & 0xEFFF) { case 0x0000: - /* mask VLAN ID, fall through to mask VLAN priority */ + /* mask VLAN ID */ fdirm |= IXGBE_FDIRM_VLANID; + /* fall through */ case 0x0FFF: /* mask VLAN priority */ fdirm |= IXGBE_FDIRM_VLANP; break; case 0xE000: - /* mask VLAN ID only, fall through */ + /* mask VLAN ID only */ fdirm |= IXGBE_FDIRM_VLANID; + /* fall through */ case 0xEFFF: /* no VLAN fields masked */ break; @@ -1608,8 +1610,9 @@ s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw, switch (input_mask->formatted.flex_bytes & 0xFFFF) { case 0x0000: - /* Mask Flex Bytes, fall through */ + /* Mask Flex Bytes */ fdirm |= IXGBE_FDIRM_FLEX; + /* fall through */ case 0xFFFF: break; default: diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index c38d50c1fcf7..4e35e7017f3d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -155,7 +155,7 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw) if (ret_val) return ret_val; - /* only backplane uses autoc so fall though */ + /* fall through - only backplane uses autoc */ case ixgbe_media_type_fiber: reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); @@ -395,7 +395,8 @@ s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw) } /* Initialize the LED link active for LED blink support */ - hw->mac.ops.init_led_link_act(hw); + if (hw->mac.ops.init_led_link_act) + hw->mac.ops.init_led_link_act(hw); return status; } @@ -3548,7 +3549,7 @@ void ixgbe_set_rxpba_generic(struct ixgbe_hw *hw, rxpktsize <<= IXGBE_RXPBSIZE_SHIFT; for (; i < (num_pb / 2); i++) IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize); - /* Fall through to configure remaining packet buffers */ + /* fall through - configure remaining packet buffers */ case (PBA_STRATEGY_EQUAL): /* Divide the remaining Rx packet buffer evenly among the TCs */ rxpktsize = (pbsize / (num_pb - i)) << IXGBE_RXPBSIZE_SHIFT; @@ -4120,15 +4121,6 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, speedcnt++; highest_link_speed = IXGBE_LINK_SPEED_10GB_FULL; - /* If we already have link at this speed, just jump out */ - status = hw->mac.ops.check_link(hw, &link_speed, &link_up, - false); - if (status) - return status; - - if (link_speed == IXGBE_LINK_SPEED_10GB_FULL && link_up) - goto out; - /* Set the module link speed */ switch (hw->phy.media_type) { case ixgbe_media_type_fiber: @@ -4180,15 +4172,6 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, if (highest_link_speed == IXGBE_LINK_SPEED_UNKNOWN) highest_link_speed = IXGBE_LINK_SPEED_1GB_FULL; - /* If we already have link at this speed, just jump out */ - status = hw->mac.ops.check_link(hw, &link_speed, &link_up, - false); - if (status) - return status; - - if (link_speed == IXGBE_LINK_SPEED_1GB_FULL && link_up) - goto out; - /* Set the module link speed */ switch (hw->phy.media_type) { case ixgbe_media_type_fiber: @@ -4295,4 +4278,23 @@ void ixgbe_set_soft_rate_select_speed(struct ixgbe_hw *hw, hw_dbg(hw, "Failed to write Rx Rate Select RS0\n"); return; } + + /* Set RS1 */ + status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB, + IXGBE_I2C_EEPROM_DEV_ADDR2, + &eeprom_data); + if (status) { + hw_dbg(hw, "Failed to read Rx Rate Select RS1\n"); + return; + } + + eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) | rs; + + status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB, + IXGBE_I2C_EEPROM_DEV_ADDR2, + eeprom_data); + if (status) { + hw_dbg(hw, "Failed to write Rx Rate Select RS1\n"); + return; + } } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 7e5e336d7dcc..9113e8099b03 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -2254,6 +2254,9 @@ static int ixgbe_set_phys_id(struct net_device *netdev, struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; + if (!hw->mac.ops.led_on || !hw->mac.ops.led_off) + return -EOPNOTSUPP; + switch (state) { case ETHTOOL_ID_ACTIVE: adapter->led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); @@ -2665,6 +2668,7 @@ static int ixgbe_flowspec_to_flow_type(struct ethtool_rx_flow_spec *fsp, *flow_type = IXGBE_ATR_FLOW_TYPE_IPV4; break; } + /* fall through */ default: return 0; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index d39cba214320..54463f03b3db 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -58,6 +58,7 @@ #include <net/tc_act/tc_gact.h> #include <net/tc_act/tc_mirred.h> #include <net/vxlan.h> +#include <net/mpls.h> #include "ixgbe.h" #include "ixgbe_common.h" @@ -1451,7 +1452,7 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) IXGBE_DCA_CTRL_DCA_MODE_CB2); break; } - /* Fall Through since DCA is disabled. */ + /* fall through - DCA is disabled. */ case DCA_PROVIDER_REMOVE: if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { dca_remove_requester(dev); @@ -2232,6 +2233,7 @@ static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter, break; default: bpf_warn_invalid_xdp_action(act); + /* fallthrough */ case XDP_ABORTED: trace_xdp_exception(rx_ring->netdev, xdp_prog, act); /* fallthrough -- handle aborts by dropping packet */ @@ -2638,8 +2640,7 @@ static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter) if (test_bit(__IXGBE_DOWN, &adapter->state)) return; - if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && - !(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_EVENT)) + if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_EVENT)) return; adapter->flags2 &= ~IXGBE_FLAG2_TEMP_SENSOR_EVENT; @@ -3105,23 +3106,23 @@ int ixgbe_poll(struct napi_struct *napi, int budget) static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter) { struct net_device *netdev = adapter->netdev; + unsigned int ri = 0, ti = 0; int vector, err; - int ri = 0, ti = 0; for (vector = 0; vector < adapter->num_q_vectors; vector++) { struct ixgbe_q_vector *q_vector = adapter->q_vector[vector]; struct msix_entry *entry = &adapter->msix_entries[vector]; if (q_vector->tx.ring && q_vector->rx.ring) { - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-%s-%d", netdev->name, "TxRx", ri++); + snprintf(q_vector->name, sizeof(q_vector->name), + "%s-TxRx-%u", netdev->name, ri++); ti++; } else if (q_vector->rx.ring) { - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-%s-%d", netdev->name, "rx", ri++); + snprintf(q_vector->name, sizeof(q_vector->name), + "%s-rx-%u", netdev->name, ri++); } else if (q_vector->tx.ring) { - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-%s-%d", netdev->name, "tx", ti++); + snprintf(q_vector->name, sizeof(q_vector->name), + "%s-tx-%u", netdev->name, ti++); } else { /* skip this unused q_vector */ continue; @@ -3802,6 +3803,9 @@ static void ixgbe_setup_mrqc(struct ixgbe_adapter *adapter) mrqc = IXGBE_MRQC_VMDQRSS32EN; else mrqc = IXGBE_MRQC_VMDQRSS64EN; + + /* Enable L3/L4 for Tx Switched packets */ + mrqc |= IXGBE_MRQC_L3L4TXSWEN; } else { if (tcs > 4) mrqc = IXGBE_MRQC_RTRSS8TCEN; @@ -4174,7 +4178,7 @@ static void ixgbe_setup_rdrxctl(struct ixgbe_adapter *adapter) case ixgbe_mac_x550em_a: if (adapter->num_vfs) rdrxctl |= IXGBE_RDRXCTL_PSP; - /* fall through for older HW */ + /* fall through */ case ixgbe_mac_82599EB: case ixgbe_mac_X540: /* Disable RSC for ACK packets */ @@ -6183,8 +6187,6 @@ int ixgbe_setup_tx_resources(struct ixgbe_ring *tx_ring) if (!tx_ring->tx_buffer_info) goto err; - u64_stats_init(&tx_ring->syncp); - /* round up to nearest 4K */ tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc); tx_ring->size = ALIGN(tx_ring->size, 4096); @@ -6278,8 +6280,6 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, if (!rx_ring->rx_buffer_info) goto err; - u64_stats_init(&rx_ring->syncp); - /* Round up to nearest 4K */ rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc); rx_ring->size = ALIGN(rx_ring->size, 4096); @@ -6886,6 +6886,7 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) hwstats->o2bspc += IXGBE_READ_REG(hw, IXGBE_O2BSPC); hwstats->b2ospc += IXGBE_READ_REG(hw, IXGBE_B2OSPC); hwstats->b2ogprc += IXGBE_READ_REG(hw, IXGBE_B2OGPRC); + /* fall through */ case ixgbe_mac_82599EB: for (i = 0; i < 16; i++) adapter->hw_rx_no_dma_resources += @@ -7667,7 +7668,10 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring, if (err < 0) return err; - ip.hdr = skb_network_header(skb); + if (eth_p_mpls(first->protocol)) + ip.hdr = skb_inner_network_header(skb); + else + ip.hdr = skb_network_header(skb); l4.hdr = skb_checksum_start(skb); /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ @@ -8205,6 +8209,7 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb, if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) break; + /* fall through */ default: return fallback(dev, skb); } @@ -9929,6 +9934,7 @@ bool ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id, /* only support first port */ if (hw->bus.func != 0) break; + /* fall through */ case IXGBE_SUBDEV_ID_82599_SP_560FLR: case IXGBE_SUBDEV_ID_82599_SFP: case IXGBE_SUBDEV_ID_82599_RNDC: @@ -10191,7 +10197,11 @@ skip_sriov: netdev->vlan_features |= netdev->features | NETIF_F_TSO_MANGLEID; netdev->hw_enc_features |= netdev->vlan_features; - netdev->mpls_features |= NETIF_F_HW_CSUM; + netdev->mpls_features |= NETIF_F_SG | + NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_HW_CSUM; + netdev->mpls_features |= IXGBE_GSO_PARTIAL_FEATURES; /* set this bit last since it cannot be part of vlan_features */ netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | @@ -10275,6 +10285,10 @@ skip_sriov: if (err) goto err_sw_init; + for (i = 0; i < adapter->num_rx_queues; i++) + u64_stats_init(&adapter->rx_ring[i]->syncp); + for (i = 0; i < adapter->num_tx_queues; i++) + u64_stats_init(&adapter->tx_ring[i]->syncp); for (i = 0; i < adapter->num_xdp_queues; i++) u64_stats_init(&adapter->xdp_ring[i]->syncp); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h index 5aa2c3cf7aec..b0cac961df3b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h @@ -84,8 +84,9 @@ #define IXGBE_CS4227_GLOBAL_ID_LSB 0 #define IXGBE_CS4227_GLOBAL_ID_MSB 1 #define IXGBE_CS4227_SCRATCH 2 -#define IXGBE_CS4223_PHY_ID 0x7003 /* Quad port */ -#define IXGBE_CS4227_PHY_ID 0x3003 /* Dual port */ +#define IXGBE_CS4227_EFUSE_PDF_SKU 0x19F +#define IXGBE_CS4223_SKU_ID 0x0010 /* Quad port */ +#define IXGBE_CS4227_SKU_ID 0x0014 /* Dual port */ #define IXGBE_CS4227_RESET_PENDING 0x1357 #define IXGBE_CS4227_RESET_COMPLETE 0x5AA5 #define IXGBE_CS4227_RETRIES 15 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index ef0635e0918c..d44c728fdc0b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -883,6 +883,7 @@ static int ixgbe_ptp_set_timestamp_mode(struct ixgbe_adapter *adapter, IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); break; case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: /* The X550 controller is capable of timestamping all packets, * which allows it to accept any filter. diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index 8baf298a8516..e2766da5fe02 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -540,16 +540,15 @@ static s32 ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf) case ixgbe_mbox_api_11: case ixgbe_mbox_api_12: case ixgbe_mbox_api_13: - /* - * Version 1.1 supports jumbo frames on VFs if PF has + /* Version 1.1 supports jumbo frames on VFs if PF has * jumbo frames enabled which means legacy VFs are * disabled */ if (pf_max_frame > ETH_FRAME_LEN) break; + /* fall through */ default: - /* - * If the PF or VF are running w/ jumbo frames enabled + /* If the PF or VF are running w/ jumbo frames enabled * we need to shut down the VF Rx path as we cannot * support jumbo frames on legacy VFs */ @@ -778,11 +777,17 @@ static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf) static int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter, int vf, unsigned char *mac_addr) { + s32 retval; + ixgbe_del_mac_filter(adapter, adapter->vfinfo[vf].vf_mac_addresses, vf); - memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr, ETH_ALEN); - ixgbe_add_mac_filter(adapter, adapter->vfinfo[vf].vf_mac_addresses, vf); + retval = ixgbe_add_mac_filter(adapter, mac_addr, vf); + if (retval >= 0) + memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr, + ETH_ALEN); + else + memset(adapter->vfinfo[vf].vf_mac_addresses, 0, ETH_ALEN); - return 0; + return retval; } int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask) @@ -1347,27 +1352,49 @@ void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter) int ixgbe_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) { struct ixgbe_adapter *adapter = netdev_priv(netdev); + s32 retval; if (vf >= adapter->num_vfs) return -EINVAL; - if (is_zero_ether_addr(mac)) { - adapter->vfinfo[vf].pf_set_mac = false; - dev_info(&adapter->pdev->dev, "removing MAC on VF %d\n", vf); - } else if (is_valid_ether_addr(mac)) { - adapter->vfinfo[vf].pf_set_mac = true; + if (is_valid_ether_addr(mac)) { dev_info(&adapter->pdev->dev, "setting MAC %pM on VF %d\n", mac, vf); dev_info(&adapter->pdev->dev, "Reload the VF driver to make this change effective."); - if (test_bit(__IXGBE_DOWN, &adapter->state)) { - dev_warn(&adapter->pdev->dev, "The VF MAC address has been set, but the PF device is not up.\n"); - dev_warn(&adapter->pdev->dev, "Bring the PF device up before attempting to use the VF device.\n"); + + retval = ixgbe_set_vf_mac(adapter, vf, mac); + if (retval >= 0) { + adapter->vfinfo[vf].pf_set_mac = true; + + if (test_bit(__IXGBE_DOWN, &adapter->state)) { + dev_warn(&adapter->pdev->dev, "The VF MAC address has been set, but the PF device is not up.\n"); + dev_warn(&adapter->pdev->dev, "Bring the PF device up before attempting to use the VF device.\n"); + } + } else { + dev_warn(&adapter->pdev->dev, "The VF MAC address was NOT set due to invalid or duplicate MAC address.\n"); + } + } else if (is_zero_ether_addr(mac)) { + unsigned char *vf_mac_addr = + adapter->vfinfo[vf].vf_mac_addresses; + + /* nothing to do */ + if (is_zero_ether_addr(vf_mac_addr)) + return 0; + + dev_info(&adapter->pdev->dev, "removing MAC on VF %d\n", vf); + + retval = ixgbe_del_mac_filter(adapter, vf_mac_addr, vf); + if (retval >= 0) { + adapter->vfinfo[vf].pf_set_mac = false; + memcpy(vf_mac_addr, mac, ETH_ALEN); + } else { + dev_warn(&adapter->pdev->dev, "Could NOT remove the VF MAC address.\n"); } } else { - return -EINVAL; + retval = -EINVAL; } - return ixgbe_set_vf_mac(adapter, vf, mac); + return retval; } static int ixgbe_enable_port_vlan(struct ixgbe_adapter *adapter, int vf, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index 2ba024b575ea..72d84a065e34 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -1750,14 +1750,14 @@ ixgbe_setup_mac_link_sfp_n(struct ixgbe_hw *hw, ixgbe_link_speed speed, if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT) return 0; - if (!ret_val) + if (ret_val) return ret_val; /* Configure internal PHY for native SFI based on module type */ ret_val = hw->mac.ops.read_iosf_sb_reg(hw, IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, ®_phy_int); - if (!ret_val) + if (ret_val) return ret_val; reg_phy_int &= IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_DA; @@ -1767,7 +1767,7 @@ ixgbe_setup_mac_link_sfp_n(struct ixgbe_hw *hw, ixgbe_link_speed speed, ret_val = hw->mac.ops.write_iosf_sb_reg(hw, IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, reg_phy_int); - if (!ret_val) + if (ret_val) return ret_val; /* Setup SFI internal link. */ @@ -1798,7 +1798,7 @@ ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, ixgbe_link_speed speed, if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT) return 0; - if (!ret_val) + if (ret_val) return ret_val; /* Configure internal PHY for KR/KX. */ @@ -1807,16 +1807,16 @@ ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, ixgbe_link_speed speed, if (hw->phy.mdio.prtad == MDIO_PRTAD_NONE) return IXGBE_ERR_PHY_ADDR_INVALID; - /* Get external PHY device id */ - ret_val = hw->phy.ops.read_reg(hw, IXGBE_CS4227_GLOBAL_ID_MSB, - IXGBE_MDIO_ZERO_DEV_TYPE, ®_phy_ext); + /* Get external PHY SKU id */ + ret_val = hw->phy.ops.read_reg(hw, IXGBE_CS4227_EFUSE_PDF_SKU, + IXGBE_MDIO_ZERO_DEV_TYPE, ®_phy_ext); if (ret_val) return ret_val; /* When configuring quad port CS4223, the MAC instance is part * of the slice offset. */ - if (reg_phy_ext == IXGBE_CS4223_PHY_ID) + if (reg_phy_ext == IXGBE_CS4223_SKU_ID) slice_offset = (hw->bus.lan_id + (hw->bus.instance_id << 1)) << 12; else @@ -1824,12 +1824,28 @@ ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, ixgbe_link_speed speed, /* Configure CS4227/CS4223 LINE side to proper mode. */ reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + slice_offset; + + ret_val = hw->phy.ops.read_reg(hw, reg_slice, + IXGBE_MDIO_ZERO_DEV_TYPE, ®_phy_ext); + if (ret_val) + return ret_val; + + reg_phy_ext &= ~((IXGBE_CS4227_EDC_MODE_CX1 << 1) | + (IXGBE_CS4227_EDC_MODE_SR << 1)); + if (setup_linear) reg_phy_ext = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 1; else reg_phy_ext = (IXGBE_CS4227_EDC_MODE_SR << 1) | 1; - return hw->phy.ops.write_reg(hw, reg_slice, IXGBE_MDIO_ZERO_DEV_TYPE, - reg_phy_ext); + + ret_val = hw->phy.ops.write_reg(hw, reg_slice, + IXGBE_MDIO_ZERO_DEV_TYPE, reg_phy_ext); + if (ret_val) + return ret_val; + + /* Flush previous write with a read */ + return hw->phy.ops.read_reg(hw, reg_slice, + IXGBE_MDIO_ZERO_DEV_TYPE, ®_phy_ext); } /** @@ -3206,6 +3222,7 @@ static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) phy->ops.setup_link = NULL; phy->ops.read_reg = NULL; phy->ops.write_reg = NULL; + phy->ops.reset = NULL; break; default: break; @@ -3819,6 +3836,28 @@ static const struct ixgbe_mac_operations mac_ops_X550EM_x = { .write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550, }; +static const struct ixgbe_mac_operations mac_ops_X550EM_x_fw = { + X550_COMMON_MAC + .led_on = NULL, + .led_off = NULL, + .init_led_link_act = NULL, + .reset_hw = &ixgbe_reset_hw_X550em, + .get_media_type = &ixgbe_get_media_type_X550em, + .get_san_mac_addr = NULL, + .get_wwn_prefix = NULL, + .setup_link = &ixgbe_setup_mac_link_X540, + .get_link_capabilities = &ixgbe_get_link_capabilities_X550em, + .get_bus_info = &ixgbe_get_bus_info_X550em, + .setup_sfp = ixgbe_setup_sfp_modules_X550em, + .acquire_swfw_sync = &ixgbe_acquire_swfw_sync_X550em, + .release_swfw_sync = &ixgbe_release_swfw_sync_X550em, + .init_swfw_sync = &ixgbe_init_swfw_sync_X540, + .setup_fc = NULL, + .fc_autoneg = ixgbe_fc_autoneg, + .read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550, + .write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550, +}; + static struct ixgbe_mac_operations mac_ops_x550em_a = { X550_COMMON_MAC .led_on = ixgbe_led_on_t_x550em, @@ -3986,7 +4025,7 @@ const struct ixgbe_info ixgbe_X550EM_x_info = { const struct ixgbe_info ixgbe_x550em_x_fw_info = { .mac = ixgbe_mac_X550EM_x, .get_invariants = ixgbe_get_invariants_X550_x_fw, - .mac_ops = &mac_ops_X550EM_x, + .mac_ops = &mac_ops_X550EM_x_fw, .eeprom_ops = &eeprom_ops_X550EM_x, .phy_ops = &phy_ops_x550em_x_fw, .mbx_ops = &mbx_ops_generic, diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index eee29bddddc1..aced91c9c034 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -49,6 +49,7 @@ #include <linux/if.h> #include <linux/if_vlan.h> #include <linux/prefetch.h> +#include <net/mpls.h> #include "ixgbevf.h" @@ -1350,23 +1351,23 @@ static int ixgbevf_request_msix_irqs(struct ixgbevf_adapter *adapter) { struct net_device *netdev = adapter->netdev; int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + unsigned int ri = 0, ti = 0; int vector, err; - int ri = 0, ti = 0; for (vector = 0; vector < q_vectors; vector++) { struct ixgbevf_q_vector *q_vector = adapter->q_vector[vector]; struct msix_entry *entry = &adapter->msix_entries[vector]; if (q_vector->tx.ring && q_vector->rx.ring) { - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-%s-%d", netdev->name, "TxRx", ri++); + snprintf(q_vector->name, sizeof(q_vector->name), + "%s-TxRx-%u", netdev->name, ri++); ti++; } else if (q_vector->rx.ring) { - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-%s-%d", netdev->name, "rx", ri++); + snprintf(q_vector->name, sizeof(q_vector->name), + "%s-rx-%u", netdev->name, ri++); } else if (q_vector->tx.ring) { - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-%s-%d", netdev->name, "tx", ti++); + snprintf(q_vector->name, sizeof(q_vector->name), + "%s-tx-%u", netdev->name, ti++); } else { /* skip this unused q_vector */ continue; @@ -3321,7 +3322,10 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring, if (err < 0) return err; - ip.hdr = skb_network_header(skb); + if (eth_p_mpls(first->protocol)) + ip.hdr = skb_inner_network_header(skb); + else + ip.hdr = skb_network_header(skb); l4.hdr = skb_checksum_start(skb); /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ @@ -4075,7 +4079,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->features |= NETIF_F_HIGHDMA; netdev->vlan_features |= netdev->features | NETIF_F_TSO_MANGLEID; - netdev->mpls_features |= NETIF_F_HW_CSUM; + netdev->mpls_features |= NETIF_F_SG | + NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_HW_CSUM; + netdev->mpls_features |= IXGBEVF_GSO_PARTIAL_FEATURES; netdev->hw_enc_features |= netdev->vlan_features; /* set this bit last since it cannot be part of vlan_features */ diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.c b/drivers/net/ethernet/intel/ixgbevf/vf.c index b6d0c01eab10..0c25006ce9af 100644 --- a/drivers/net/ethernet/intel/ixgbevf/vf.c +++ b/drivers/net/ethernet/intel/ixgbevf/vf.c @@ -335,6 +335,7 @@ int ixgbevf_get_reta_locked(struct ixgbe_hw *hw, u32 *reta, int num_rx_queues) case ixgbe_mbox_api_12: if (hw->mac.type < ixgbe_mac_X550_vf) break; + /* fall through */ default: return -EOPNOTSUPP; } @@ -401,6 +402,7 @@ int ixgbevf_get_rss_key_locked(struct ixgbe_hw *hw, u8 *rss_key) case ixgbe_mbox_api_12: if (hw->mac.type < ixgbe_mac_X550_vf) break; + /* fall through */ default: return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index f580b49e6b67..62d848df26ef 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -691,17 +691,6 @@ jme_enable_tx_engine(struct jme_adapter *jme) } static inline void -jme_restart_tx_engine(struct jme_adapter *jme) -{ - /* - * Restart TX Engine - */ - jwrite32(jme, JME_TXCS, jme->reg_txcs | - TXCS_SELECT_QUEUE0 | - TXCS_ENABLE); -} - -static inline void jme_disable_tx_engine(struct jme_adapter *jme) { int i; @@ -2382,37 +2371,6 @@ jme_tx_timeout(struct net_device *netdev) jme_reset_link(jme); } -static inline void jme_pause_rx(struct jme_adapter *jme) -{ - atomic_dec(&jme->link_changing); - - jme_set_rx_pcc(jme, PCC_OFF); - if (test_bit(JME_FLAG_POLL, &jme->flags)) { - JME_NAPI_DISABLE(jme); - } else { - tasklet_disable(&jme->rxclean_task); - tasklet_disable(&jme->rxempty_task); - } -} - -static inline void jme_resume_rx(struct jme_adapter *jme) -{ - struct dynpcc_info *dpi = &(jme->dpi); - - if (test_bit(JME_FLAG_POLL, &jme->flags)) { - JME_NAPI_ENABLE(jme); - } else { - tasklet_enable(&jme->rxclean_task); - tasklet_enable(&jme->rxempty_task); - } - dpi->cur = PCC_P1; - dpi->attempt = PCC_P1; - dpi->cnt = 0; - jme_set_rx_pcc(jme, PCC_P1); - - atomic_inc(&jme->link_changing); -} - static void jme_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) @@ -2652,12 +2610,11 @@ jme_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { struct jme_adapter *jme = netdev_priv(netdev); - int rc; spin_lock_bh(&jme->phy_lock); - rc = mii_ethtool_get_link_ksettings(&jme->mii_if, cmd); + mii_ethtool_get_link_ksettings(&jme->mii_if, cmd); spin_unlock_bh(&jme->phy_lock); - return rc; + return 0; } static int diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c index 9fae98caf83a..3c0a6451273d 100644 --- a/drivers/net/ethernet/korina.c +++ b/drivers/net/ethernet/korina.c @@ -699,13 +699,12 @@ static int netdev_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct korina_private *lp = netdev_priv(dev); - int rc; spin_lock_irq(&lp->lock); - rc = mii_ethtool_get_link_ksettings(&lp->mii_if, cmd); + mii_ethtool_get_link_ksettings(&lp->mii_if, cmd); spin_unlock_irq(&lp->lock); - return rc; + return 0; } static int netdev_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/mellanox/Kconfig b/drivers/net/ethernet/mellanox/Kconfig index d54701047401..84a200764111 100644 --- a/drivers/net/ethernet/mellanox/Kconfig +++ b/drivers/net/ethernet/mellanox/Kconfig @@ -19,5 +19,6 @@ if NET_VENDOR_MELLANOX source "drivers/net/ethernet/mellanox/mlx4/Kconfig" source "drivers/net/ethernet/mellanox/mlx5/core/Kconfig" source "drivers/net/ethernet/mellanox/mlxsw/Kconfig" +source "drivers/net/ethernet/mellanox/mlxfw/Kconfig" endif # NET_VENDOR_MELLANOX diff --git a/drivers/net/ethernet/mellanox/Makefile b/drivers/net/ethernet/mellanox/Makefile index 2e2a5ec509ac..016aa263bc04 100644 --- a/drivers/net/ethernet/mellanox/Makefile +++ b/drivers/net/ethernet/mellanox/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_MLX4_CORE) += mlx4/ obj-$(CONFIG_MLX5_CORE) += mlx5/core/ obj-$(CONFIG_MLXSW_CORE) += mlxsw/ +obj-$(CONFIG_MLXFW) += mlxfw/ diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 94fab20ef146..82436742ad75 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2375,6 +2375,7 @@ static int mlx4_en_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: config.rx_filter = HWTSTAMP_FILTER_ALL; break; default: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig index 27251a78075c..cf1ef48bfd8d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig +++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig @@ -11,6 +11,16 @@ config MLX5_CORE Core driver for low level functionality of the ConnectX-4 and Connect-IB cards by Mellanox Technologies. +config MLX5_FPGA + bool "Mellanox Technologies Innova support" + depends on MLX5_CORE + ---help--- + Build support for the Innova family of network cards by Mellanox + Technologies. Innova network cards are comprised of a ConnectX chip + and an FPGA chip on one board. If you select this option, the + mlx5_core driver will include the Innova FPGA core and allow building + sandbox-specific client drivers. + config MLX5_CORE_EN bool "Mellanox Technologies ConnectX-4 Ethernet support" depends on NETDEVICES && ETHERNET && INET && PCI && MLX5_CORE diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 9e644615f07a..12556c03eec4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -1,10 +1,13 @@ obj-$(CONFIG_MLX5_CORE) += mlx5_core.o +subdir-ccflags-y += -I$(src) mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \ mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \ fs_counters.o rl.o lag.o dev.o +mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o + mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o eswitch_offloads.o \ en_main.o en_common.o en_fs.o en_ethtool.o en_tx.o \ en_rx.o en_rx_am.o en_txrx.o en_clock.o vxlan.o \ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c index e94a9532e218..de40b6cfee95 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c @@ -405,7 +405,7 @@ static u64 cq_read_field(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, u32 *out; int err; - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return param; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c index c8a005326e30..f4017c06ddd2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c @@ -180,9 +180,8 @@ static int arfs_add_default_rule(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec; int err = 0; - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { - netdev_err(priv->netdev, "%s: alloc failed\n", __func__); err = -ENOMEM; goto out; } @@ -237,7 +236,7 @@ static int arfs_create_groups(struct mlx5e_flow_table *ft, ft->g = kcalloc(MLX5E_ARFS_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in || !ft->g) { kvfree(ft->g); kvfree(in); @@ -481,9 +480,8 @@ static struct mlx5_flow_handle *arfs_add_rule(struct mlx5e_priv *priv, struct mlx5_flow_table *ft; int err = 0; - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { - netdev_err(priv->netdev, "%s: alloc failed\n", __func__); err = -ENOMEM; goto out; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c index e706a87fc8b2..e29494464cae 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c @@ -128,6 +128,7 @@ int mlx5e_hwstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: /* Disable CQE compression */ netdev_warn(dev, "Disabling cqe compression"); err = mlx5e_modify_rx_cqe_compression_locked(priv, false); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c index f1f17f7a3cd0..46e56ec4c26f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c @@ -65,7 +65,7 @@ static int mlx5e_create_mkey(struct mlx5_core_dev *mdev, u32 pdn, u32 *in; int err; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -147,7 +147,7 @@ int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb) inlen = MLX5_ST_SZ_BYTES(modify_tir_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) goto out; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 8209affa75c3..e9e33fd68279 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -39,7 +39,7 @@ static void mlx5e_get_drvinfo(struct net_device *dev, struct mlx5_core_dev *mdev = priv->mdev; strlcpy(drvinfo->driver, DRIVER_NAME, sizeof(drvinfo->driver)); - strlcpy(drvinfo->version, DRIVER_VERSION " (" DRIVER_RELDATE ")", + strlcpy(drvinfo->version, DRIVER_VERSION, sizeof(drvinfo->version)); snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d.%d.%04d (%.16s)", @@ -1048,7 +1048,7 @@ static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir, (hfunc != ETH_RSS_HASH_TOP)) return -EINVAL; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c index 53ed58320a24..7acc4fba7ece 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c @@ -218,11 +218,9 @@ static int mlx5e_add_vlan_rule(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec; int err = 0; - spec = mlx5_vzalloc(sizeof(*spec)); - if (!spec) { - netdev_err(priv->netdev, "%s: alloc failed\n", __func__); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) return -ENOMEM; - } if (rule_type == MLX5E_VLAN_RULE_TYPE_MATCH_VID) mlx5e_vport_context_update_vlans(priv); @@ -660,11 +658,9 @@ mlx5e_generate_ttc_rule(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec; int err = 0; - spec = mlx5_vzalloc(sizeof(*spec)); - if (!spec) { - netdev_err(priv->netdev, "%s: alloc failed\n", __func__); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) return ERR_PTR(-ENOMEM); - } if (proto) { spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; @@ -742,7 +738,7 @@ static int mlx5e_create_ttc_table_groups(struct mlx5e_ttc_table *ttc) sizeof(*ft->g), GFP_KERNEL); if (!ft->g) return -ENOMEM; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { kfree(ft->g); return -ENOMEM; @@ -852,11 +848,9 @@ static int mlx5e_add_l2_flow_rule(struct mlx5e_priv *priv, u8 *mc_dmac; u8 *mv_dmac; - spec = mlx5_vzalloc(sizeof(*spec)); - if (!spec) { - netdev_err(priv->netdev, "%s: alloc failed\n", __func__); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) return -ENOMEM; - } mc_dmac = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, outer_headers.dmac_47_16); @@ -916,7 +910,7 @@ static int mlx5e_create_l2_table_groups(struct mlx5e_l2_table *l2_table) ft->g = kcalloc(MLX5E_NUM_L2_GROUPS, sizeof(*ft->g), GFP_KERNEL); if (!ft->g) return -ENOMEM; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { kfree(ft->g); return -ENOMEM; @@ -1071,7 +1065,7 @@ static int mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft) int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); int err; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c index 85bf4a389295..bdd82c9b3992 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c @@ -296,7 +296,7 @@ add_ethtool_flow_rule(struct mlx5e_priv *priv, struct mlx5_flow_handle *rule; int err = 0; - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return ERR_PTR(-ENOMEM); err = set_flow_attrs(spec->match_criteria, spec->match_value, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 41cd22a223dc..cdff04b2aea1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -252,9 +252,9 @@ static void mlx5e_update_pport_counters(struct mlx5e_priv *priv) void *out; u32 *in; - in = mlx5_vzalloc(sz); + in = kvzalloc(sz, GFP_KERNEL); if (!in) - goto free_out; + return; MLX5_SET(ppcnt_reg, in, local_port, 1); @@ -288,7 +288,6 @@ static void mlx5e_update_pport_counters(struct mlx5e_priv *priv) MLX5_REG_PPCNT, 0, 0); } -free_out: kvfree(in); } @@ -314,7 +313,7 @@ static void mlx5e_update_pcie_counters(struct mlx5e_priv *priv) if (!MLX5_CAP_MCAM_FEATURE(mdev, pcie_performance_group)) return; - in = mlx5_vzalloc(sz); + in = kvzalloc(sz, GFP_KERNEL); if (!in) return; @@ -503,7 +502,7 @@ static int mlx5e_create_umr_mkey(struct mlx5_core_dev *mdev, if (!MLX5E_VALID_NUM_MTTS(npages)) return -EINVAL; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -711,7 +710,7 @@ static int mlx5e_create_rq(struct mlx5e_rq *rq, inlen = MLX5_ST_SZ_BYTES(create_rq_in) + sizeof(u64) * rq->wq_ctrl.buf.npages; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -748,7 +747,7 @@ static int mlx5e_modify_rq_state(struct mlx5e_rq *rq, int curr_state, int err; inlen = MLX5_ST_SZ_BYTES(modify_rq_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -776,7 +775,7 @@ static int mlx5e_modify_rq_scatter_fcs(struct mlx5e_rq *rq, bool enable) int err; inlen = MLX5_ST_SZ_BYTES(modify_rq_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -805,7 +804,7 @@ static int mlx5e_modify_rq_vsd(struct mlx5e_rq *rq, bool vsd) int err; inlen = MLX5_ST_SZ_BYTES(modify_rq_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -1134,7 +1133,7 @@ static int mlx5e_create_sq(struct mlx5_core_dev *mdev, inlen = MLX5_ST_SZ_BYTES(create_sq_in) + sizeof(u64) * csp->wq_ctrl->buf.npages; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -1182,7 +1181,7 @@ static int mlx5e_modify_sq(struct mlx5_core_dev *mdev, u32 sqn, int err; inlen = MLX5_ST_SZ_BYTES(modify_sq_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -1496,7 +1495,7 @@ static int mlx5e_create_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param) inlen = MLX5_ST_SZ_BYTES(create_cq_in) + sizeof(u64) * cq->wq_ctrl.frag_buf.npages; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2091,7 +2090,7 @@ mlx5e_create_rqt(struct mlx5e_priv *priv, int sz, struct mlx5e_rqt *rqt) int i; inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * sz; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2210,7 +2209,7 @@ int mlx5e_redirect_rqt(struct mlx5e_priv *priv, u32 rqtn, int sz, int err; inlen = MLX5_ST_SZ_BYTES(modify_rqt_in) + sizeof(u32) * sz; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2433,7 +2432,7 @@ static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv) int ix; inlen = MLX5_ST_SZ_BYTES(modify_tir_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2850,7 +2849,7 @@ int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv) int tt; inlen = MLX5_ST_SZ_BYTES(create_tir_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2889,7 +2888,7 @@ int mlx5e_create_direct_tirs(struct mlx5e_priv *priv) int ix; inlen = MLX5_ST_SZ_BYTES(create_tir_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index ec63158ab643..8ec13f9be660 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -581,7 +581,9 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | - BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL))) { + BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | + BIT(FLOW_DISSECTOR_KEY_TCP) | + BIT(FLOW_DISSECTOR_KEY_IP))) { netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n", f->dissector->used_keys); return -EOPNOTSUPP; @@ -808,6 +810,48 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, *min_inline = MLX5_INLINE_MODE_TCP_UDP; } + if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_IP)) { + struct flow_dissector_key_ip *key = + skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_IP, + f->key); + struct flow_dissector_key_ip *mask = + skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_IP, + f->mask); + + MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_ecn, mask->tos & 0x3); + MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, key->tos & 0x3); + + MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_dscp, mask->tos >> 2); + MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, key->tos >> 2); + + if (mask->tos) + *min_inline = MLX5_INLINE_MODE_IP; + + if (mask->ttl) /* currently not supported */ + return -EOPNOTSUPP; + } + + if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_TCP)) { + struct flow_dissector_key_tcp *key = + skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_TCP, + f->key); + struct flow_dissector_key_tcp *mask = + skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_TCP, + f->mask); + + MLX5_SET(fte_match_set_lyr_2_4, headers_c, tcp_flags, + ntohs(mask->flags)); + MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags, + ntohs(key->flags)); + + if (mask->flags) + *min_inline = MLX5_INLINE_MODE_TCP_UDP; + } + return 0; } @@ -1436,8 +1480,8 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv, if (!(nud_state & NUD_VALID)) { neigh_event_send(n, NULL); - neigh_release(n); - return -EAGAIN; + err = -EAGAIN; + goto out; } err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, @@ -1542,8 +1586,8 @@ static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv, if (!(nud_state & NUD_VALID)) { neigh_event_send(n, NULL); - neigh_release(n); - return -EAGAIN; + err = -EAGAIN; + goto out; } err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, @@ -1778,7 +1822,7 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol, } flow = kzalloc(sizeof(*flow) + attr_size, GFP_KERNEL); - parse_attr = mlx5_vzalloc(sizeof(*parse_attr)); + parse_attr = kvzalloc(sizeof(*parse_attr), GFP_KERNEL); if (!parse_attr || !flow) { err = -ENOMEM; goto err_free; @@ -1863,9 +1907,7 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv, { struct mlx5e_tc_table *tc = &priv->fs.tc; struct mlx5e_tc_flow *flow; - struct tc_action *a; struct mlx5_fc *counter; - LIST_HEAD(actions); u64 bytes; u64 packets; u64 lastuse; @@ -1884,13 +1926,7 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv, mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse); - preempt_disable(); - - tcf_exts_to_list(f->exts, &actions); - list_for_each_entry(a, &actions, list) - tcf_action_stats_update(a, bytes, packets, lastuse); - - preempt_enable(); + tcf_exts_stats_update(f->exts, bytes, packets, lastuse); return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 33eae5ad2fb0..0ed8e90ba54f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -35,6 +35,7 @@ #include <linux/mlx5/driver.h> #include <linux/mlx5/cmd.h> #include "mlx5_core.h" +#include "fpga/core.h" #ifdef CONFIG_MLX5_CORE_EN #include "eswitch.h" #endif @@ -156,6 +157,8 @@ static const char *eqe_type_str(u8 type) return "MLX5_EVENT_TYPE_PAGE_FAULT"; case MLX5_EVENT_TYPE_PPS_EVENT: return "MLX5_EVENT_TYPE_PPS_EVENT"; + case MLX5_EVENT_TYPE_FPGA_ERROR: + return "MLX5_EVENT_TYPE_FPGA_ERROR"; default: return "Unrecognized event"; } @@ -476,6 +479,11 @@ static irqreturn_t mlx5_eq_int(int irq, void *eq_ptr) if (dev->event) dev->event(dev, MLX5_DEV_EVENT_PPS, (unsigned long)eqe); break; + + case MLX5_EVENT_TYPE_FPGA_ERROR: + mlx5_fpga_event(dev, eqe->type, &eqe->data.raw); + break; + default: mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n", eqe->type, eq->eqn); @@ -548,7 +556,7 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx, inlen = MLX5_ST_SZ_BYTES(create_eq_in) + MLX5_FLD_SZ_BYTES(create_eq_in, pas[0]) * eq->buf.npages; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { err = -ENOMEM; goto err_buf; @@ -693,6 +701,9 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev) if (MLX5_CAP_GEN(dev, pps)) async_event_mask |= (1ull << MLX5_EVENT_TYPE_PPS_EVENT); + if (MLX5_CAP_GEN(dev, fpga)) + async_event_mask |= (1ull << MLX5_EVENT_TYPE_FPGA_ERROR); + err = mlx5_create_map_eq(dev, &table->cmd_eq, MLX5_EQ_VEC_CMD, MLX5_NUM_CMD_EQE, 1ull << MLX5_EVENT_TYPE_CMD, "mlx5_cmd_eq", MLX5_EQ_TYPE_ASYNC); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 2e34d95ea776..81dfcd90b1f5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -248,11 +248,10 @@ __esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u32 vport, bool rx_rule, if (rx_rule) match_header |= MLX5_MATCH_MISC_PARAMETERS; - spec = mlx5_vzalloc(sizeof(*spec)); - if (!spec) { - esw_warn(esw->dev, "FDB: Failed to alloc match parameters\n"); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) return NULL; - } + dmac_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers.dmac_47_16); dmac_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, @@ -350,10 +349,9 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw, int nvports) return -EOPNOTSUPP; } - flow_group_in = mlx5_vzalloc(inlen); + flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) return -ENOMEM; - memset(flow_group_in, 0, inlen); table_size = BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size)); @@ -961,7 +959,7 @@ static int esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, return -EOPNOTSUPP; } - flow_group_in = mlx5_vzalloc(inlen); + flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) return -ENOMEM; @@ -1078,7 +1076,7 @@ static int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, return -EOPNOTSUPP; } - flow_group_in = mlx5_vzalloc(inlen); + flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) return -ENOMEM; @@ -1241,11 +1239,9 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, "vport[%d] configure ingress rules, vlan(%d) qos(%d)\n", vport->vport, vport->info.vlan, vport->info.qos); - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { err = -ENOMEM; - esw_warn(esw->dev, "vport[%d] configure ingress rules failed, err(%d)\n", - vport->vport, err); goto out; } @@ -1322,11 +1318,9 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw, "vport[%d] configure egress rules, vlan(%d) qos(%d)\n", vport->vport, vport->info.vlan, vport->info.qos); - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { err = -ENOMEM; - esw_warn(esw->dev, "vport[%d] configure egress rules failed, err(%d)\n", - vport->vport, err); goto out; } @@ -2158,7 +2152,7 @@ int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw, if (!LEGAL_VPORT(esw, vport)) return -EINVAL; - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index f991f669047e..3795943ef2d1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -311,9 +311,8 @@ mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *esw, int vport, u32 sqn struct mlx5_flow_spec *spec; void *misc; - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { - esw_warn(esw->dev, "FDB: Failed to alloc match parameters\n"); flow_rule = ERR_PTR(-ENOMEM); goto out; } @@ -401,9 +400,8 @@ static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw) struct mlx5_flow_spec *spec; int err = 0; - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { - esw_warn(esw->dev, "FDB: Failed to alloc match parameters\n"); err = -ENOMEM; goto out; } @@ -488,7 +486,7 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports) u32 *flow_group_in; esw_debug(esw->dev, "Create offloads FDB Tables\n"); - flow_group_in = mlx5_vzalloc(inlen); + flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) return -ENOMEM; @@ -631,7 +629,7 @@ static int esw_create_vport_rx_group(struct mlx5_eswitch *esw) int err = 0; int nvports = priv->sriov.num_vfs + 2; - flow_group_in = mlx5_vzalloc(inlen); + flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) return -ENOMEM; @@ -675,9 +673,8 @@ mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn) struct mlx5_flow_spec *spec; void *misc; - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { - esw_warn(esw->dev, "Failed to alloc match parameters\n"); flow_rule = ERR_PTR(-ENOMEM); goto out; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c new file mode 100644 index 000000000000..99cba644b4fc --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/etherdevice.h> +#include <linux/mlx5/cmd.h> +#include <linux/mlx5/driver.h> + +#include "mlx5_core.h" +#include "fpga/cmd.h" + +int mlx5_fpga_caps(struct mlx5_core_dev *dev, u32 *caps) +{ + u32 in[MLX5_ST_SZ_DW(fpga_cap)] = {0}; + + return mlx5_core_access_reg(dev, in, sizeof(in), caps, + MLX5_ST_SZ_BYTES(fpga_cap), + MLX5_REG_FPGA_CAP, 0, 0); +} + +int mlx5_fpga_query(struct mlx5_core_dev *dev, struct mlx5_fpga_query *query) +{ + u32 in[MLX5_ST_SZ_DW(fpga_ctrl)] = {0}; + u32 out[MLX5_ST_SZ_DW(fpga_ctrl)]; + int err; + + err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), + MLX5_REG_FPGA_CTRL, 0, false); + if (err) + return err; + + query->status = MLX5_GET(fpga_ctrl, out, status); + query->admin_image = MLX5_GET(fpga_ctrl, out, flash_select_admin); + query->oper_image = MLX5_GET(fpga_ctrl, out, flash_select_oper); + return 0; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h new file mode 100644 index 000000000000..a74396a61bc3 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017, Mellanox Technologies, Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __MLX5_FPGA_H__ +#define __MLX5_FPGA_H__ + +#include <linux/mlx5/driver.h> + +enum mlx5_fpga_image { + MLX5_FPGA_IMAGE_USER = 0, + MLX5_FPGA_IMAGE_FACTORY, +}; + +enum mlx5_fpga_status { + MLX5_FPGA_STATUS_SUCCESS = 0, + MLX5_FPGA_STATUS_FAILURE = 1, + MLX5_FPGA_STATUS_IN_PROGRESS = 2, + MLX5_FPGA_STATUS_NONE = 0xFFFF, +}; + +struct mlx5_fpga_query { + enum mlx5_fpga_image admin_image; + enum mlx5_fpga_image oper_image; + enum mlx5_fpga_status status; +}; + +int mlx5_fpga_caps(struct mlx5_core_dev *dev, u32 *caps); +int mlx5_fpga_query(struct mlx5_core_dev *dev, struct mlx5_fpga_query *query); + +#endif /* __MLX5_FPGA_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c new file mode 100644 index 000000000000..d88b332e9669 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2017, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/module.h> +#include <linux/etherdevice.h> +#include <linux/mlx5/driver.h> + +#include "mlx5_core.h" +#include "fpga/core.h" + +static const char *const mlx5_fpga_error_strings[] = { + "Null Syndrome", + "Corrupted DDR", + "Flash Timeout", + "Internal Link Error", + "Watchdog HW Failure", + "I2C Failure", + "Image Changed", + "Temperature Critical", +}; + +static struct mlx5_fpga_device *mlx5_fpga_device_alloc(void) +{ + struct mlx5_fpga_device *fdev = NULL; + + fdev = kzalloc(sizeof(*fdev), GFP_KERNEL); + if (!fdev) + return NULL; + + spin_lock_init(&fdev->state_lock); + fdev->state = MLX5_FPGA_STATUS_NONE; + return fdev; +} + +static const char *mlx5_fpga_image_name(enum mlx5_fpga_image image) +{ + switch (image) { + case MLX5_FPGA_IMAGE_USER: + return "user"; + case MLX5_FPGA_IMAGE_FACTORY: + return "factory"; + default: + return "unknown"; + } +} + +static int mlx5_fpga_device_load_check(struct mlx5_fpga_device *fdev) +{ + struct mlx5_fpga_query query; + int err; + + err = mlx5_fpga_query(fdev->mdev, &query); + if (err) { + mlx5_fpga_err(fdev, "Failed to query status: %d\n", err); + return err; + } + + fdev->last_admin_image = query.admin_image; + fdev->last_oper_image = query.oper_image; + + mlx5_fpga_dbg(fdev, "Status %u; Admin image %u; Oper image %u\n", + query.status, query.admin_image, query.oper_image); + + if (query.status != MLX5_FPGA_STATUS_SUCCESS) { + mlx5_fpga_err(fdev, "%s image failed to load; status %u\n", + mlx5_fpga_image_name(fdev->last_oper_image), + query.status); + return -EIO; + } + + return 0; +} + +int mlx5_fpga_device_start(struct mlx5_core_dev *mdev) +{ + struct mlx5_fpga_device *fdev = mdev->fpga; + unsigned long flags; + int err; + + if (!fdev) + return 0; + + err = mlx5_fpga_device_load_check(fdev); + if (err) + goto out; + + err = mlx5_fpga_caps(fdev->mdev, + fdev->mdev->caps.hca_cur[MLX5_CAP_FPGA]); + if (err) + goto out; + + mlx5_fpga_info(fdev, "device %u; %s image, version %u\n", + MLX5_CAP_FPGA(fdev->mdev, fpga_device), + mlx5_fpga_image_name(fdev->last_oper_image), + MLX5_CAP_FPGA(fdev->mdev, image_version)); + +out: + spin_lock_irqsave(&fdev->state_lock, flags); + fdev->state = err ? MLX5_FPGA_STATUS_FAILURE : MLX5_FPGA_STATUS_SUCCESS; + spin_unlock_irqrestore(&fdev->state_lock, flags); + return err; +} + +int mlx5_fpga_device_init(struct mlx5_core_dev *mdev) +{ + struct mlx5_fpga_device *fdev = NULL; + + if (!MLX5_CAP_GEN(mdev, fpga)) { + mlx5_core_dbg(mdev, "FPGA capability not present\n"); + return 0; + } + + mlx5_core_dbg(mdev, "Initializing FPGA\n"); + + fdev = mlx5_fpga_device_alloc(); + if (!fdev) + return -ENOMEM; + + fdev->mdev = mdev; + mdev->fpga = fdev; + + return 0; +} + +void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev) +{ + kfree(mdev->fpga); + mdev->fpga = NULL; +} + +static const char *mlx5_fpga_syndrome_to_string(u8 syndrome) +{ + if (syndrome < ARRAY_SIZE(mlx5_fpga_error_strings)) + return mlx5_fpga_error_strings[syndrome]; + return "Unknown"; +} + +void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data) +{ + struct mlx5_fpga_device *fdev = mdev->fpga; + const char *event_name; + bool teardown = false; + unsigned long flags; + u8 syndrome; + + if (event != MLX5_EVENT_TYPE_FPGA_ERROR) { + mlx5_fpga_warn_ratelimited(fdev, "Unexpected event %u\n", + event); + return; + } + + syndrome = MLX5_GET(fpga_error_event, data, syndrome); + event_name = mlx5_fpga_syndrome_to_string(syndrome); + + spin_lock_irqsave(&fdev->state_lock, flags); + switch (fdev->state) { + case MLX5_FPGA_STATUS_SUCCESS: + mlx5_fpga_warn(fdev, "Error %u: %s\n", syndrome, event_name); + teardown = true; + break; + default: + mlx5_fpga_warn_ratelimited(fdev, "Unexpected error event %u: %s\n", + syndrome, event_name); + } + spin_unlock_irqrestore(&fdev->state_lock, flags); + /* We tear-down the card's interfaces and functionality because + * the FPGA bump-on-the-wire is misbehaving and we lose ability + * to communicate with the network. User may still be able to + * recover by re-programming or debugging the FPGA + */ + if (teardown) + mlx5_trigger_health_work(fdev->mdev); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h new file mode 100644 index 000000000000..c55044d66778 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017, Mellanox Technologies, Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __MLX5_FPGA_CORE_H__ +#define __MLX5_FPGA_CORE_H__ + +#ifdef CONFIG_MLX5_FPGA + +#include "fpga/cmd.h" + +/* Represents an Innova device */ +struct mlx5_fpga_device { + struct mlx5_core_dev *mdev; + spinlock_t state_lock; /* Protects state transitions */ + enum mlx5_fpga_status state; + enum mlx5_fpga_image last_admin_image; + enum mlx5_fpga_image last_oper_image; +}; + +#define mlx5_fpga_dbg(__adev, format, ...) \ + dev_dbg(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d:(pid %d): " format, \ + __func__, __LINE__, current->pid, ##__VA_ARGS__) + +#define mlx5_fpga_err(__adev, format, ...) \ + dev_err(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d:(pid %d): " format, \ + __func__, __LINE__, current->pid, ##__VA_ARGS__) + +#define mlx5_fpga_warn(__adev, format, ...) \ + dev_warn(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d:(pid %d): " format, \ + __func__, __LINE__, current->pid, ##__VA_ARGS__) + +#define mlx5_fpga_warn_ratelimited(__adev, format, ...) \ + dev_warn_ratelimited(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d: " \ + format, __func__, __LINE__, ##__VA_ARGS__) + +#define mlx5_fpga_notice(__adev, format, ...) \ + dev_notice(&(__adev)->mdev->pdev->dev, "FPGA: " format, ##__VA_ARGS__) + +#define mlx5_fpga_info(__adev, format, ...) \ + dev_info(&(__adev)->mdev->pdev->dev, "FPGA: " format, ##__VA_ARGS__) + +int mlx5_fpga_device_init(struct mlx5_core_dev *mdev); +void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev); +int mlx5_fpga_device_start(struct mlx5_core_dev *mdev); +void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data); + +#else + +static inline int mlx5_fpga_device_init(struct mlx5_core_dev *mdev) +{ + return 0; +} + +static inline void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev) +{ +} + +static inline int mlx5_fpga_device_start(struct mlx5_core_dev *mdev) +{ + return 0; +} + +static inline void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, + void *data) +{ +} + +#endif + +#endif /* __MLX5_FPGA_CORE_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index fcec7bedd3cd..abb44a268563 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -232,11 +232,9 @@ static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev, u32 *in; int err; - in = mlx5_vzalloc(inlen); - if (!in) { - mlx5_core_warn(dev, "failed to allocate inbox\n"); + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) return -ENOMEM; - } MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); MLX5_SET(set_fte_in, in, op_mod, opmod); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 0e487e8ca634..6c636c21d24f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -376,11 +376,9 @@ static void del_rule(struct fs_node *node) int err; bool update_fte = false; - match_value = mlx5_vzalloc(match_len); - if (!match_value) { - mlx5_core_warn(dev, "failed to allocate inbox\n"); + match_value = kvzalloc(match_len, GFP_KERNEL); + if (!match_value) return; - } fs_get_obj(rule, node); fs_get_obj(fte, rule->node.parent); @@ -1157,7 +1155,7 @@ static struct mlx5_flow_group *create_autogroup(struct mlx5_flow_table *ft, if (!ft->autogroup.active) return ERR_PTR(-ENOENT); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return ERR_PTR(-ENOMEM); @@ -1777,7 +1775,7 @@ static struct mlx5_flow_root_namespace *create_root_ns(struct mlx5_flow_steering struct mlx5_flow_namespace *ns; /* Create the root namespace */ - root_ns = mlx5_vzalloc(sizeof(*root_ns)); + root_ns = kvzalloc(sizeof(*root_ns), GFP_KERNEL); if (!root_ns) return NULL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 44f59b1d6f0f..80b23333de7a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -185,6 +185,7 @@ static void health_care(struct work_struct *work) struct mlx5_core_health *health; struct mlx5_core_dev *dev; struct mlx5_priv *priv; + unsigned long flags; health = container_of(work, struct mlx5_core_health, work); priv = container_of(health, struct mlx5_priv, health); @@ -192,13 +193,13 @@ static void health_care(struct work_struct *work) mlx5_core_warn(dev, "handling bad device here\n"); mlx5_handle_bad_state(dev); - spin_lock(&health->wq_lock); + spin_lock_irqsave(&health->wq_lock, flags); if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags)) schedule_delayed_work(&health->recover_work, recover_delay); else dev_err(&dev->pdev->dev, "new health works are not permitted at this stage\n"); - spin_unlock(&health->wq_lock); + spin_unlock_irqrestore(&health->wq_lock, flags); } static const char *hsynd_str(u8 synd) @@ -269,6 +270,20 @@ static unsigned long get_next_poll_jiffies(void) return next; } +void mlx5_trigger_health_work(struct mlx5_core_dev *dev) +{ + struct mlx5_core_health *health = &dev->priv.health; + unsigned long flags; + + spin_lock_irqsave(&health->wq_lock, flags); + if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags)) + queue_work(health->wq, &health->work); + else + dev_err(&dev->pdev->dev, + "new health works are not permitted at this stage\n"); + spin_unlock_irqrestore(&health->wq_lock, flags); +} + static void poll_health(unsigned long data) { struct mlx5_core_dev *dev = (struct mlx5_core_dev *)data; @@ -297,13 +312,7 @@ static void poll_health(unsigned long data) if (in_fatal(dev) && !health->sick) { health->sick = true; print_health_info(dev); - spin_lock(&health->wq_lock); - if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags)) - queue_work(health->wq, &health->work); - else - dev_err(&dev->pdev->dev, - "new health works are not permitted at this stage\n"); - spin_unlock(&health->wq_lock); + mlx5_trigger_health_work(dev); } } @@ -333,10 +342,11 @@ void mlx5_stop_health_poll(struct mlx5_core_dev *dev) void mlx5_drain_health_wq(struct mlx5_core_dev *dev) { struct mlx5_core_health *health = &dev->priv.health; + unsigned long flags; - spin_lock(&health->wq_lock); + spin_lock_irqsave(&health->wq_lock, flags); set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags); - spin_unlock(&health->wq_lock); + spin_unlock_irqrestore(&health->wq_lock, flags); cancel_delayed_work_sync(&health->recover_work); cancel_work_sync(&health->work); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib.c index cc1858752e70..22ca59145e6c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib.c @@ -102,7 +102,7 @@ static int mlx5i_create_underlay_qp(struct mlx5_core_dev *mdev, struct mlx5_core void *qpc; inlen = MLX5_ST_SZ_BYTES(create_qp_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index af945edfee19..9274d93d3183 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -56,6 +56,7 @@ #ifdef CONFIG_MLX5_CORE_EN #include "eswitch.h" #endif +#include "fpga/core.h" MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>"); MODULE_DESCRIPTION("Mellanox Connect-IB, ConnectX-4 core driver"); @@ -1105,10 +1106,16 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, goto err_disable_msix; } + err = mlx5_fpga_device_init(dev); + if (err) { + dev_err(&pdev->dev, "fpga device init failed %d\n", err); + goto err_put_uars; + } + err = mlx5_start_eqs(dev); if (err) { dev_err(&pdev->dev, "Failed to start pages and async EQs\n"); - goto err_put_uars; + goto err_fpga_init; } err = alloc_comp_eqs(dev); @@ -1139,6 +1146,12 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, goto err_sriov; } + err = mlx5_fpga_device_start(dev); + if (err) { + dev_err(&pdev->dev, "fpga device start failed %d\n", err); + goto err_reg_dev; + } + if (mlx5_device_registered(dev)) { mlx5_attach_device(dev); } else { @@ -1174,6 +1187,9 @@ err_affinity_hints: err_stop_eqs: mlx5_stop_eqs(dev); +err_fpga_init: + mlx5_fpga_device_cleanup(dev); + err_put_uars: mlx5_put_uars_page(dev, priv->uar); @@ -1238,6 +1254,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, mlx5_irq_clear_affinity_hints(dev); free_comp_eqs(dev); mlx5_stop_eqs(dev); + mlx5_fpga_device_cleanup(dev); mlx5_put_uars_page(dev, priv->uar); mlx5_disable_msix(dev); if (cleanup) @@ -1512,6 +1529,8 @@ static const struct pci_device_id mlx5_core_pci_table[] = { { PCI_VDEVICE(MELLANOX, 0x101a), MLX5_PCI_DEV_IS_VF}, /* ConnectX-5 Ex VF */ { PCI_VDEVICE(MELLANOX, 0x101b) }, /* ConnectX-6 */ { PCI_VDEVICE(MELLANOX, 0x101c), MLX5_PCI_DEV_IS_VF}, /* ConnectX-6 VF */ + { PCI_VDEVICE(MELLANOX, 0xa2d2) }, /* BlueField integrated ConnectX-5 network controller */ + { PCI_VDEVICE(MELLANOX, 0xa2d3), MLX5_PCI_DEV_IS_VF}, /* BlueField integrated ConnectX-5 network controller VF */ { 0, } }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index fbc6e9e9e305..cf69b42278df 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -39,8 +39,7 @@ #include <linux/if_link.h> #define DRIVER_NAME "mlx5_core" -#define DRIVER_VERSION "3.0-1" -#define DRIVER_RELDATE "January 2015" +#define DRIVER_VERSION "5.0-0" #define MLX5_TOTAL_VPORTS(mdev) (1 + pci_sriov_get_totalvfs(mdev->pdev)) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index a57d5a81eb05..efcded7ca27a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -279,7 +279,7 @@ static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages, int i; inlen += npages * MLX5_FLD_SZ_BYTES(manage_pages_in, pas[0]); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { err = -ENOMEM; mlx5_core_warn(dev, "vzalloc failed %d\n", inlen); @@ -376,7 +376,7 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages, *nclaimed = 0; outlen += npages * MLX5_FLD_SZ_BYTES(manage_pages_out, pas[0]); - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 141583daf5a2..1975d4388d4f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -47,8 +47,8 @@ int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in, u32 *in = NULL; void *data; - in = mlx5_vzalloc(inlen); - out = mlx5_vzalloc(outlen); + in = kvzalloc(inlen, GFP_KERNEL); + out = kvzalloc(outlen, GFP_KERNEL); if (!in || !out) goto out; @@ -454,7 +454,7 @@ int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev, u32 *in; int err; - in = mlx5_vzalloc(sz); + in = kvzalloc(sz, GFP_KERNEL); if (!in) { err = -ENOMEM; return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index cbbcef2884be..573a6b27fed8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -527,7 +527,7 @@ int mlx5_core_query_out_of_buffer(struct mlx5_core_dev *dev, u16 counter_id, void *out; int err; - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/srq.c b/drivers/net/ethernet/mellanox/mlx5/core/srq.c index 3099630015d7..f774de6f5fcb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/srq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/srq.c @@ -162,7 +162,7 @@ static int create_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, pas_size = get_pas_size(in); inlen = MLX5_ST_SZ_BYTES(create_srq_in) + pas_size; - create_in = mlx5_vzalloc(inlen); + create_in = kvzalloc(inlen, GFP_KERNEL); if (!create_in) return -ENOMEM; @@ -221,7 +221,7 @@ static int query_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, void *srqc; int err; - srq_out = mlx5_vzalloc(MLX5_ST_SZ_BYTES(query_srq_out)); + srq_out = kvzalloc(MLX5_ST_SZ_BYTES(query_srq_out), GFP_KERNEL); if (!srq_out) return -ENOMEM; @@ -256,7 +256,7 @@ static int create_xrc_srq_cmd(struct mlx5_core_dev *dev, pas_size = get_pas_size(in); inlen = MLX5_ST_SZ_BYTES(create_xrc_srq_in) + pas_size; - create_in = mlx5_vzalloc(inlen); + create_in = kvzalloc(inlen, GFP_KERNEL); if (!create_in) return -ENOMEM; @@ -320,7 +320,7 @@ static int query_xrc_srq_cmd(struct mlx5_core_dev *dev, void *xrc_srqc; int err; - xrcsrq_out = mlx5_vzalloc(MLX5_ST_SZ_BYTES(query_xrc_srq_out)); + xrcsrq_out = kvzalloc(MLX5_ST_SZ_BYTES(query_xrc_srq_out), GFP_KERNEL); if (!xrcsrq_out) return -ENOMEM; memset(xrcsrq_in, 0, sizeof(xrcsrq_in)); @@ -357,7 +357,7 @@ static int create_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, pas_size = get_pas_size(in); inlen = MLX5_ST_SZ_BYTES(create_rmp_in) + pas_size; - create_in = mlx5_vzalloc(inlen); + create_in = kvzalloc(inlen, GFP_KERNEL); if (!create_in) return -ENOMEM; @@ -390,7 +390,7 @@ static int arm_rmp_cmd(struct mlx5_core_dev *dev, void *bitmask; int err; - in = mlx5_vzalloc(MLX5_ST_SZ_BYTES(modify_rmp_in)); + in = kvzalloc(MLX5_ST_SZ_BYTES(modify_rmp_in), GFP_KERNEL); if (!in) return -ENOMEM; @@ -417,7 +417,7 @@ static int query_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, void *rmpc; int err; - rmp_out = mlx5_vzalloc(MLX5_ST_SZ_BYTES(query_rmp_out)); + rmp_out = kvzalloc(MLX5_ST_SZ_BYTES(query_rmp_out), GFP_KERNEL); if (!rmp_out) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c index a00ff49eec18..5e128d7a9ffd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c @@ -284,7 +284,7 @@ int mlx5_core_arm_rmp(struct mlx5_core_dev *dev, u32 rmpn, u16 lwm) void *bitmask; int err; - in = mlx5_vzalloc(MLX5_ST_SZ_BYTES(modify_rmp_in)); + in = kvzalloc(MLX5_ST_SZ_BYTES(modify_rmp_in), GFP_KERNEL); if (!in) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index 15c2294dd2b4..06019d00ab7b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -172,7 +172,7 @@ int mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev, u8 *out_addr; int err; - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -197,11 +197,9 @@ int mlx5_modify_nic_vport_mac_address(struct mlx5_core_dev *mdev, void *nic_vport_ctx; u8 *perm_mac; - in = mlx5_vzalloc(inlen); - if (!in) { - mlx5_core_warn(mdev, "failed to allocate inbox\n"); + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) return -ENOMEM; - } MLX5_SET(modify_nic_vport_context_in, in, field_select.permanent_address, 1); @@ -231,7 +229,7 @@ int mlx5_query_nic_vport_mtu(struct mlx5_core_dev *mdev, u16 *mtu) u32 *out; int err; - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -251,7 +249,7 @@ int mlx5_modify_nic_vport_mtu(struct mlx5_core_dev *mdev, u16 mtu) void *in; int err; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -501,7 +499,7 @@ int mlx5_query_nic_vport_system_image_guid(struct mlx5_core_dev *mdev, u32 *out; int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out); - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -521,7 +519,7 @@ int mlx5_query_nic_vport_node_guid(struct mlx5_core_dev *mdev, u64 *node_guid) u32 *out; int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out); - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -551,7 +549,7 @@ int mlx5_modify_nic_vport_node_guid(struct mlx5_core_dev *mdev, if (!MLX5_CAP_ESW(mdev, nic_vport_node_guid_modify)) return -EOPNOTSUPP; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -577,7 +575,7 @@ int mlx5_query_nic_vport_qkey_viol_cntr(struct mlx5_core_dev *mdev, u32 *out; int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out); - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -879,11 +877,9 @@ int mlx5_modify_nic_vport_promisc(struct mlx5_core_dev *mdev, int inlen = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in); int err; - in = mlx5_vzalloc(inlen); - if (!in) { - mlx5_core_err(mdev, "failed to allocate inbox\n"); + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) return -ENOMEM; - } MLX5_SET(modify_nic_vport_context_in, in, field_select.promisc, 1); MLX5_SET(modify_nic_vport_context_in, in, @@ -913,11 +909,9 @@ static int mlx5_nic_vport_update_roce_state(struct mlx5_core_dev *mdev, int inlen = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in); int err; - in = mlx5_vzalloc(inlen); - if (!in) { - mlx5_core_warn(mdev, "failed to allocate inbox\n"); + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) return -ENOMEM; - } MLX5_SET(modify_nic_vport_context_in, in, field_select.roce_en, 1); MLX5_SET(modify_nic_vport_context_in, in, nic_vport_context.roce_en, @@ -952,7 +946,7 @@ int mlx5_core_query_vport_counter(struct mlx5_core_dev *dev, u8 other_vport, int err; is_group_manager = MLX5_CAP_GEN(dev, vport_group_manager); - in = mlx5_vzalloc(in_sz); + in = kvzalloc(in_sz, GFP_KERNEL); if (!in) { err = -ENOMEM; return err; diff --git a/drivers/net/ethernet/mellanox/mlxfw/Kconfig b/drivers/net/ethernet/mellanox/mlxfw/Kconfig new file mode 100644 index 000000000000..2b21af8a2b1d --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/Kconfig @@ -0,0 +1,7 @@ +# +# Mellanox firmware flash library configuration +# + +config MLXFW + tristate "mlxfw" if COMPILE_TEST + select XZ_DEC diff --git a/drivers/net/ethernet/mellanox/mlxfw/Makefile b/drivers/net/ethernet/mellanox/mlxfw/Makefile new file mode 100644 index 000000000000..7448b301104c --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_MLXFW) += mlxfw.o +mlxfw-objs := mlxfw_fsm.o mlxfw_mfa2_tlv_multi.o mlxfw_mfa2.o diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h new file mode 100644 index 000000000000..beea4ba83495 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h @@ -0,0 +1,102 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw.h + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com> + * + * 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. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +#ifndef _MLXFW_H +#define _MLXFW_H + +#include <linux/firmware.h> + +enum mlxfw_fsm_state { + MLXFW_FSM_STATE_IDLE, + MLXFW_FSM_STATE_LOCKED, + MLXFW_FSM_STATE_INITIALIZE, + MLXFW_FSM_STATE_DOWNLOAD, + MLXFW_FSM_STATE_VERIFY, + MLXFW_FSM_STATE_APPLY, + MLXFW_FSM_STATE_ACTIVATE, +}; + +enum mlxfw_fsm_state_err { + MLXFW_FSM_STATE_ERR_OK, + MLXFW_FSM_STATE_ERR_ERROR, + MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR, + MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE, + MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY, + MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED, + MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED, + MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE, + MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT, + MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET, + MLXFW_FSM_STATE_ERR_MAX, +}; + +struct mlxfw_dev; + +struct mlxfw_dev_ops { + int (*component_query)(struct mlxfw_dev *mlxfw_dev, u16 component_index, + u32 *p_max_size, u8 *p_align_bits, + u16 *p_max_write_size); + + int (*fsm_lock)(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle); + + int (*fsm_component_update)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + u16 component_index, u32 component_size); + + int (*fsm_block_download)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + u8 *data, u16 size, u32 offset); + + int (*fsm_component_verify)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + u16 component_index); + + int (*fsm_activate)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle); + + int (*fsm_query_state)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + enum mlxfw_fsm_state *fsm_state, + enum mlxfw_fsm_state_err *fsm_state_err); + + void (*fsm_cancel)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle); + + void (*fsm_release)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle); +}; + +struct mlxfw_dev { + const struct mlxfw_dev_ops *ops; + const char *psid; + u16 psid_size; +}; + +int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, + const struct firmware *firmware); + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c new file mode 100644 index 000000000000..2cf89126fb23 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c @@ -0,0 +1,273 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw.c + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com> + * + * 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. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +#define pr_fmt(fmt) "mlxfw: " fmt + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> + +#include "mlxfw.h" +#include "mlxfw_mfa2.h" + +#define MLXFW_FSM_STATE_WAIT_CYCLE_MS 200 +#define MLXFW_FSM_STATE_WAIT_TIMEOUT_MS 30000 +#define MLXFW_FSM_STATE_WAIT_ROUNDS \ + (MLXFW_FSM_STATE_WAIT_TIMEOUT_MS / MLXFW_FSM_STATE_WAIT_CYCLE_MS) +#define MLXFW_FSM_MAX_COMPONENT_SIZE (10 * (1 << 20)) + +static const char * const mlxfw_fsm_state_err_str[] = { + [MLXFW_FSM_STATE_ERR_ERROR] = + "general error", + [MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR] = + "component hash mismatch", + [MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE] = + "component not applicable", + [MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY] = + "unknown key", + [MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED] = + "authentication failed", + [MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED] = + "component was not signed", + [MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE] = + "key not applicable", + [MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT] = + "bad format", + [MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET] = + "pending reset", + [MLXFW_FSM_STATE_ERR_MAX] = + "unknown error" +}; + +static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + enum mlxfw_fsm_state fsm_state) +{ + enum mlxfw_fsm_state_err fsm_state_err; + enum mlxfw_fsm_state curr_fsm_state; + int times; + int err; + + times = MLXFW_FSM_STATE_WAIT_ROUNDS; +retry: + err = mlxfw_dev->ops->fsm_query_state(mlxfw_dev, fwhandle, + &curr_fsm_state, &fsm_state_err); + if (err) + return err; + + if (fsm_state_err != MLXFW_FSM_STATE_ERR_OK) { + pr_err("Firmware flash failed: %s\n", + mlxfw_fsm_state_err_str[fsm_state_err]); + return -EINVAL; + } + if (curr_fsm_state != fsm_state) { + if (--times == 0) { + pr_err("Timeout reached on FSM state change"); + return -ETIMEDOUT; + } + msleep(MLXFW_FSM_STATE_WAIT_CYCLE_MS); + goto retry; + } + return 0; +} + +#define MLXFW_ALIGN_DOWN(x, align_bits) ((x) & ~((1 << (align_bits)) - 1)) +#define MLXFW_ALIGN_UP(x, align_bits) \ + MLXFW_ALIGN_DOWN((x) + ((1 << (align_bits)) - 1), (align_bits)) + +static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev, + u32 fwhandle, + struct mlxfw_mfa2_component *comp) +{ + u16 comp_max_write_size; + u8 comp_align_bits; + u32 comp_max_size; + u16 block_size; + u8 *block_ptr; + u32 offset; + int err; + + err = mlxfw_dev->ops->component_query(mlxfw_dev, comp->index, + &comp_max_size, &comp_align_bits, + &comp_max_write_size); + if (err) + return err; + + comp_max_size = min_t(u32, comp_max_size, MLXFW_FSM_MAX_COMPONENT_SIZE); + if (comp->data_size > comp_max_size) { + pr_err("Component %d is of size %d which is bigger than limit %d\n", + comp->index, comp->data_size, comp_max_size); + return -EINVAL; + } + + comp_max_write_size = MLXFW_ALIGN_DOWN(comp_max_write_size, + comp_align_bits); + + pr_debug("Component update\n"); + err = mlxfw_dev->ops->fsm_component_update(mlxfw_dev, fwhandle, + comp->index, + comp->data_size); + if (err) + return err; + + err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, + MLXFW_FSM_STATE_DOWNLOAD); + if (err) + goto err_out; + + pr_debug("Component download\n"); + for (offset = 0; + offset < MLXFW_ALIGN_UP(comp->data_size, comp_align_bits); + offset += comp_max_write_size) { + block_ptr = comp->data + offset; + block_size = (u16) min_t(u32, comp->data_size - offset, + comp_max_write_size); + err = mlxfw_dev->ops->fsm_block_download(mlxfw_dev, fwhandle, + block_ptr, block_size, + offset); + if (err) + goto err_out; + } + + pr_debug("Component verify\n"); + err = mlxfw_dev->ops->fsm_component_verify(mlxfw_dev, fwhandle, + comp->index); + if (err) + goto err_out; + + err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED); + if (err) + goto err_out; + return 0; + +err_out: + mlxfw_dev->ops->fsm_cancel(mlxfw_dev, fwhandle); + return err; +} + +static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + struct mlxfw_mfa2_file *mfa2_file) +{ + u32 component_count; + int err; + int i; + + err = mlxfw_mfa2_file_component_count(mfa2_file, mlxfw_dev->psid, + mlxfw_dev->psid_size, + &component_count); + if (err) { + pr_err("Could not find device PSID in MFA2 file\n"); + return err; + } + + for (i = 0; i < component_count; i++) { + struct mlxfw_mfa2_component *comp; + + comp = mlxfw_mfa2_file_component_get(mfa2_file, mlxfw_dev->psid, + mlxfw_dev->psid_size, i); + if (IS_ERR(comp)) + return PTR_ERR(comp); + + pr_info("Flashing component type %d\n", comp->index); + err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp); + mlxfw_mfa2_file_component_put(comp); + if (err) + return err; + } + return 0; +} + +int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, + const struct firmware *firmware) +{ + struct mlxfw_mfa2_file *mfa2_file; + u32 fwhandle; + int err; + + if (!mlxfw_mfa2_check(firmware)) { + pr_err("Firmware file is not MFA2\n"); + return -EINVAL; + } + + mfa2_file = mlxfw_mfa2_file_init(firmware); + if (IS_ERR(mfa2_file)) + return PTR_ERR(mfa2_file); + + pr_info("Initialize firmware flash process\n"); + err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle); + if (err) { + pr_err("Could not lock the firmware FSM\n"); + goto err_fsm_lock; + } + + err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, + MLXFW_FSM_STATE_LOCKED); + if (err) + goto err_state_wait_idle_to_locked; + + err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file); + if (err) + goto err_flash_components; + + pr_debug("Activate image\n"); + err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle); + if (err) { + pr_err("Could not activate the downloaded image\n"); + goto err_fsm_activate; + } + + err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED); + if (err) + goto err_state_wait_activate_to_locked; + + pr_debug("Handle release\n"); + mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle); + + pr_info("Firmware flash done.\n"); + mlxfw_mfa2_file_fini(mfa2_file); + return 0; + +err_state_wait_activate_to_locked: +err_fsm_activate: +err_flash_components: +err_state_wait_idle_to_locked: + mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle); +err_fsm_lock: + mlxfw_mfa2_file_fini(mfa2_file); + return err; +} +EXPORT_SYMBOL(mlxfw_firmware_flash); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>"); +MODULE_DESCRIPTION("Mellanox firmware flash lib"); diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c new file mode 100644 index 000000000000..628150d28061 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c @@ -0,0 +1,618 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com> + * + * 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. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +#define pr_fmt(fmt) "mlxfw_mfa2: " fmt + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netlink.h> +#include <linux/xz.h> +#include "mlxfw_mfa2.h" +#include "mlxfw_mfa2_file.h" +#include "mlxfw_mfa2_tlv.h" +#include "mlxfw_mfa2_format.h" +#include "mlxfw_mfa2_tlv_multi.h" + +/* MFA2 FILE + * +----------------------------------+ + * | MFA2 finger print | + * +----------------------------------+ + * | package descriptor multi_tlv | + * | +------------------------------+ | +-----------------+ + * | | package descriptor tlv +-----> |num_devices=n | + * | +------------------------------+ | |num_components=m | + * +----------------------------------+ |CB offset | + * | device descriptor multi_tlv | |... | + * | +------------------------------+ | | | + * | | PSID tlv | | +-----------------+ + * | +------------------------------+ | + * | | component index tlv | | + * | +------------------------------+ | + * +----------------------------------+ + * | component descriptor multi_tlv | + * | +------------------------------+ | +-----------------+ + * | | component descriptor tlv +-----> |Among others: | + * | +------------------------------+ | |CB offset=o | + * +----------------------------------+ |comp index=i | + * | | |... | + * | | | | + * | | +-----------------+ + * | COMPONENT BLOCK (CB) | + * | | + * | | + * | | + * +----------------------------------+ + * + * On the top level, an MFA2 file contains: + * - Fingerprint + * - Several multi_tlvs (TLVs of type MLXFW_MFA2_TLV_MULTI, as defined in + * mlxfw_mfa2_format.h) + * - Compresses content block + * + * The first multi_tlv + * ------------------- + * The first multi TLV is treated as package descriptor, and expected to have a + * first TLV child of type MLXFW_MFA2_TLV_PACKAGE_DESCRIPTOR which contains all + * the global information needed to parse the file. Among others, it contains + * the number of device descriptors and component descriptor following this + * multi TLV. + * + * The device descriptor multi_tlv + * ------------------------------- + * The multi TLVs following the package descriptor are treated as device + * descriptor, and are expected to have the following children: + * - PSID TLV child of type MLXFW_MFA2_TLV_PSID containing that device PSID. + * - Component index of type MLXFW_MFA2_TLV_COMPONENT_PTR that contains that + * device component index. + * + * The component descriptor multi_tlv + * ---------------------------------- + * The multi TLVs following the device descriptor multi TLVs are treated as + * component descriptor, and are expected to have a first child of type + * MLXFW_MFA2_TLV_COMPONENT_DESCRIPTOR that contains mostly the component index, + * needed for the flash process and the offset to the binary within the + * component block. + */ + +static const u8 mlxfw_mfa2_fingerprint[] = "MLNX.MFA2.XZ.00!"; +static const int mlxfw_mfa2_fingerprint_len = + sizeof(mlxfw_mfa2_fingerprint) - 1; + +static const u8 mlxfw_mfa2_comp_magic[] = "#BIN.COMPONENT!#"; +static const int mlxfw_mfa2_comp_magic_len = sizeof(mlxfw_mfa2_comp_magic) - 1; + +bool mlxfw_mfa2_check(const struct firmware *fw) +{ + if (fw->size < sizeof(mlxfw_mfa2_fingerprint)) + return false; + + return memcmp(fw->data, mlxfw_mfa2_fingerprint, + mlxfw_mfa2_fingerprint_len) == 0; +} + +static bool +mlxfw_mfa2_tlv_multi_validate(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv_multi *multi) +{ + const struct mlxfw_mfa2_tlv *tlv; + u16 idx; + + /* Check that all children are valid */ + mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) { + if (!tlv) { + pr_err("Multi has invalid child"); + return false; + } + } + return true; +} + +static bool +mlxfw_mfa2_file_dev_validate(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv *dev_tlv, + u16 dev_idx) +{ + const struct mlxfw_mfa2_tlv_component_ptr *cptr; + const struct mlxfw_mfa2_tlv_multi *multi; + const struct mlxfw_mfa2_tlv_psid *psid; + const struct mlxfw_mfa2_tlv *tlv; + u16 cptr_count; + u16 cptr_idx; + int err; + + pr_debug("Device %d\n", dev_idx); + + multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, dev_tlv); + if (!multi) { + pr_err("Device %d is not a valid TLV error\n", dev_idx); + return false; + } + + if (!mlxfw_mfa2_tlv_multi_validate(mfa2_file, multi)) + return false; + + /* Validate the device has PSID tlv */ + tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, multi, + MLXFW_MFA2_TLV_PSID, 0); + if (!tlv) { + pr_err("Device %d does not have PSID\n", dev_idx); + return false; + } + + psid = mlxfw_mfa2_tlv_psid_get(mfa2_file, tlv); + if (!psid) { + pr_err("Device %d PSID TLV is not valid\n", dev_idx); + return false; + } + + print_hex_dump_debug(" -- Device PSID ", DUMP_PREFIX_NONE, 16, 16, + psid->psid, be16_to_cpu(tlv->len), true); + + /* Validate the device has COMPONENT_PTR */ + err = mlxfw_mfa2_tlv_multi_child_count(mfa2_file, multi, + MLXFW_MFA2_TLV_COMPONENT_PTR, + &cptr_count); + if (err) + return false; + + if (cptr_count == 0) { + pr_err("Device %d has no components\n", dev_idx); + return false; + } + + for (cptr_idx = 0; cptr_idx < cptr_count; cptr_idx++) { + tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, multi, + MLXFW_MFA2_TLV_COMPONENT_PTR, + cptr_idx); + if (!tlv) + return false; + + cptr = mlxfw_mfa2_tlv_component_ptr_get(mfa2_file, tlv); + if (!cptr) { + pr_err("Device %d COMPONENT_PTR TLV is not valid\n", + dev_idx); + return false; + } + + pr_debug(" -- Component index %d\n", + be16_to_cpu(cptr->component_index)); + } + return true; +} + +static bool +mlxfw_mfa2_file_comp_validate(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv *comp_tlv, + u16 comp_idx) +{ + const struct mlxfw_mfa2_tlv_component_descriptor *cdesc; + const struct mlxfw_mfa2_tlv_multi *multi; + const struct mlxfw_mfa2_tlv *tlv; + + pr_debug("Component %d\n", comp_idx); + + multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, comp_tlv); + if (!multi) { + pr_err("Component %d is not a valid TLV error\n", comp_idx); + return false; + } + + if (!mlxfw_mfa2_tlv_multi_validate(mfa2_file, multi)) + return false; + + /* Check that component have COMPONENT_DESCRIPTOR as first child */ + tlv = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi); + if (!tlv) { + pr_err("Component descriptor %d multi TLV error\n", comp_idx); + return false; + } + + cdesc = mlxfw_mfa2_tlv_component_descriptor_get(mfa2_file, tlv); + if (!cdesc) { + pr_err("Component %d does not have a valid descriptor\n", + comp_idx); + return false; + } + pr_debug(" -- Component type %d\n", be16_to_cpu(cdesc->identifier)); + pr_debug(" -- Offset 0x%llx and size %d\n", + ((u64) be32_to_cpu(cdesc->cb_offset_h) << 32) + | be32_to_cpu(cdesc->cb_offset_l), be32_to_cpu(cdesc->size)); + + return true; +} + +static bool mlxfw_mfa2_file_validate(const struct mlxfw_mfa2_file *mfa2_file) +{ + const struct mlxfw_mfa2_tlv *tlv; + u16 idx; + + pr_debug("Validating file\n"); + + /* check that all the devices exist */ + mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, mfa2_file->first_dev, + mfa2_file->dev_count) { + if (!tlv) { + pr_err("Device TLV error\n"); + return false; + } + + /* Check each device */ + if (!mlxfw_mfa2_file_dev_validate(mfa2_file, tlv, idx)) + return false; + } + + /* check that all the components exist */ + mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, mfa2_file->first_component, + mfa2_file->component_count) { + if (!tlv) { + pr_err("Device TLV error\n"); + return false; + } + + /* Check each component */ + if (!mlxfw_mfa2_file_comp_validate(mfa2_file, tlv, idx)) + return false; + } + return true; +} + +struct mlxfw_mfa2_file *mlxfw_mfa2_file_init(const struct firmware *fw) +{ + const struct mlxfw_mfa2_tlv_package_descriptor *pd; + const struct mlxfw_mfa2_tlv_multi *multi; + const struct mlxfw_mfa2_tlv *multi_child; + const struct mlxfw_mfa2_tlv *first_tlv; + struct mlxfw_mfa2_file *mfa2_file; + const void *first_tlv_ptr; + const void *cb_top_ptr; + + mfa2_file = kcalloc(1, sizeof(*mfa2_file), GFP_KERNEL); + if (!mfa2_file) + return ERR_PTR(-ENOMEM); + + mfa2_file->fw = fw; + first_tlv_ptr = fw->data + NLA_ALIGN(mlxfw_mfa2_fingerprint_len); + first_tlv = mlxfw_mfa2_tlv_get(mfa2_file, first_tlv_ptr); + if (!first_tlv) { + pr_err("Could not parse package descriptor TLV\n"); + goto err_out; + } + + multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, first_tlv); + if (!multi) { + pr_err("First TLV is not of valid multi type\n"); + goto err_out; + } + + multi_child = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi); + if (!multi_child) + goto err_out; + + pd = mlxfw_mfa2_tlv_package_descriptor_get(mfa2_file, multi_child); + if (!pd) { + pr_err("Could not parse package descriptor TLV\n"); + goto err_out; + } + + mfa2_file->first_dev = mlxfw_mfa2_tlv_next(mfa2_file, first_tlv); + if (!mfa2_file->first_dev) { + pr_err("First device TLV is not valid\n"); + goto err_out; + } + + mfa2_file->dev_count = be16_to_cpu(pd->num_devices); + mfa2_file->first_component = mlxfw_mfa2_tlv_advance(mfa2_file, + mfa2_file->first_dev, + mfa2_file->dev_count); + mfa2_file->component_count = be16_to_cpu(pd->num_components); + mfa2_file->cb = fw->data + NLA_ALIGN(be32_to_cpu(pd->cb_offset)); + if (!mlxfw_mfa2_valid_ptr(mfa2_file, mfa2_file->cb)) { + pr_err("Component block is out side the file\n"); + goto err_out; + } + mfa2_file->cb_archive_size = be32_to_cpu(pd->cb_archive_size); + cb_top_ptr = mfa2_file->cb + mfa2_file->cb_archive_size - 1; + if (!mlxfw_mfa2_valid_ptr(mfa2_file, cb_top_ptr)) { + pr_err("Component block size is too big\n"); + goto err_out; + } + + if (!mlxfw_mfa2_file_validate(mfa2_file)) + goto err_out; + return mfa2_file; +err_out: + kfree(mfa2_file); + return ERR_PTR(-EINVAL); +} + +static const struct mlxfw_mfa2_tlv_multi * +mlxfw_mfa2_tlv_dev_get(const struct mlxfw_mfa2_file *mfa2_file, + const char *psid, u16 psid_size) +{ + const struct mlxfw_mfa2_tlv_psid *tlv_psid; + const struct mlxfw_mfa2_tlv_multi *dev_multi; + const struct mlxfw_mfa2_tlv *dev_tlv; + const struct mlxfw_mfa2_tlv *tlv; + u32 idx; + + /* for each device tlv */ + mlxfw_mfa2_tlv_foreach(mfa2_file, dev_tlv, idx, mfa2_file->first_dev, + mfa2_file->dev_count) { + if (!dev_tlv) + return NULL; + + dev_multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, dev_tlv); + if (!dev_multi) + return NULL; + + /* find psid child and compare */ + tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, dev_multi, + MLXFW_MFA2_TLV_PSID, 0); + if (!tlv) + return NULL; + if (be16_to_cpu(tlv->len) != psid_size) + continue; + + tlv_psid = mlxfw_mfa2_tlv_psid_get(mfa2_file, tlv); + if (!tlv_psid) + return NULL; + + if (memcmp(psid, tlv_psid->psid, psid_size) == 0) + return dev_multi; + } + + return NULL; +} + +int mlxfw_mfa2_file_component_count(const struct mlxfw_mfa2_file *mfa2_file, + const char *psid, u32 psid_size, + u32 *p_count) +{ + const struct mlxfw_mfa2_tlv_multi *dev_multi; + u16 count; + int err; + + dev_multi = mlxfw_mfa2_tlv_dev_get(mfa2_file, psid, psid_size); + if (!dev_multi) + return -EINVAL; + + err = mlxfw_mfa2_tlv_multi_child_count(mfa2_file, dev_multi, + MLXFW_MFA2_TLV_COMPONENT_PTR, + &count); + if (err) + return err; + + *p_count = count; + return 0; +} + +static int mlxfw_mfa2_xz_dec_run(struct xz_dec *xz_dec, struct xz_buf *xz_buf, + bool *finished) +{ + enum xz_ret xz_ret; + + xz_ret = xz_dec_run(xz_dec, xz_buf); + + switch (xz_ret) { + case XZ_STREAM_END: + *finished = true; + return 0; + case XZ_OK: + *finished = false; + return 0; + case XZ_MEM_ERROR: + pr_err("xz no memory\n"); + return -ENOMEM; + case XZ_DATA_ERROR: + pr_err("xz file corrupted\n"); + return -EINVAL; + case XZ_FORMAT_ERROR: + pr_err("xz format not found\n"); + return -EINVAL; + case XZ_OPTIONS_ERROR: + pr_err("unsupported xz option\n"); + return -EINVAL; + case XZ_MEMLIMIT_ERROR: + pr_err("xz dictionary too small\n"); + return -EINVAL; + default: + pr_err("xz error %d\n", xz_ret); + return -EINVAL; + } +} + +static int mlxfw_mfa2_file_cb_offset_xz(const struct mlxfw_mfa2_file *mfa2_file, + off_t off, size_t size, u8 *buf) +{ + struct xz_dec *xz_dec; + struct xz_buf dec_buf; + off_t curr_off = 0; + bool finished; + int err; + + xz_dec = xz_dec_init(XZ_DYNALLOC, (u32) -1); + if (!xz_dec) + return -EINVAL; + + dec_buf.in_size = mfa2_file->cb_archive_size; + dec_buf.in = mfa2_file->cb; + dec_buf.in_pos = 0; + dec_buf.out = buf; + + /* decode up to the offset */ + do { + dec_buf.out_pos = 0; + dec_buf.out_size = min_t(size_t, size, off - curr_off); + if (dec_buf.out_size == 0) + break; + + err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished); + if (err) + goto out; + if (finished) { + pr_err("xz section too short\n"); + err = -EINVAL; + goto out; + } + curr_off += dec_buf.out_pos; + } while (curr_off != off); + + /* decode the needed section */ + dec_buf.out_pos = 0; + dec_buf.out_size = size; + err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished); +out: + xz_dec_end(xz_dec); + return err; +} + +static const struct mlxfw_mfa2_tlv_component_descriptor * +mlxfw_mfa2_file_component_tlv_get(const struct mlxfw_mfa2_file *mfa2_file, + u16 comp_index) +{ + const struct mlxfw_mfa2_tlv_multi *multi; + const struct mlxfw_mfa2_tlv *multi_child; + const struct mlxfw_mfa2_tlv *comp_tlv; + + if (comp_index > mfa2_file->component_count) + return NULL; + + comp_tlv = mlxfw_mfa2_tlv_advance(mfa2_file, mfa2_file->first_component, + comp_index); + if (!comp_tlv) + return NULL; + + multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, comp_tlv); + if (!multi) + return NULL; + + multi_child = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi); + if (!multi_child) + return NULL; + + return mlxfw_mfa2_tlv_component_descriptor_get(mfa2_file, multi_child); +} + +struct mlxfw_mfa2_comp_data { + struct mlxfw_mfa2_component comp; + u8 buff[0]; +}; + +static const struct mlxfw_mfa2_tlv_component_descriptor * +mlxfw_mfa2_file_component_find(const struct mlxfw_mfa2_file *mfa2_file, + const char *psid, int psid_size, + int component_index) +{ + const struct mlxfw_mfa2_tlv_component_ptr *cptr; + const struct mlxfw_mfa2_tlv_multi *dev_multi; + const struct mlxfw_mfa2_tlv *cptr_tlv; + u16 comp_idx; + + dev_multi = mlxfw_mfa2_tlv_dev_get(mfa2_file, psid, psid_size); + if (!dev_multi) + return NULL; + + cptr_tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, dev_multi, + MLXFW_MFA2_TLV_COMPONENT_PTR, + component_index); + if (!cptr_tlv) + return NULL; + + cptr = mlxfw_mfa2_tlv_component_ptr_get(mfa2_file, cptr_tlv); + if (!cptr) + return NULL; + + comp_idx = be16_to_cpu(cptr->component_index); + return mlxfw_mfa2_file_component_tlv_get(mfa2_file, comp_idx); +} + +struct mlxfw_mfa2_component * +mlxfw_mfa2_file_component_get(const struct mlxfw_mfa2_file *mfa2_file, + const char *psid, int psid_size, + int component_index) +{ + const struct mlxfw_mfa2_tlv_component_descriptor *comp; + struct mlxfw_mfa2_comp_data *comp_data; + u32 comp_buf_size; + off_t cb_offset; + u32 comp_size; + int err; + + comp = mlxfw_mfa2_file_component_find(mfa2_file, psid, psid_size, + component_index); + if (!comp) + return ERR_PTR(-EINVAL); + + cb_offset = (u64) be32_to_cpu(comp->cb_offset_h) << 32 | + be32_to_cpu(comp->cb_offset_l); + comp_size = be32_to_cpu(comp->size); + comp_buf_size = comp_size + mlxfw_mfa2_comp_magic_len; + + comp_data = kmalloc(sizeof(*comp_data) + comp_buf_size, GFP_KERNEL); + if (!comp_data) + return ERR_PTR(-ENOMEM); + comp_data->comp.data_size = comp_size; + comp_data->comp.index = be16_to_cpu(comp->identifier); + err = mlxfw_mfa2_file_cb_offset_xz(mfa2_file, cb_offset, comp_buf_size, + comp_data->buff); + if (err) { + pr_err("Component could not be reached in CB\n"); + goto err_out; + } + + if (memcmp(comp_data->buff, mlxfw_mfa2_comp_magic, + mlxfw_mfa2_comp_magic_len) != 0) { + pr_err("Component has wrong magic\n"); + goto err_out; + } + + comp_data->comp.data = comp_data->buff + mlxfw_mfa2_comp_magic_len; + return &comp_data->comp; +err_out: + kfree(comp_data); + return ERR_PTR(err); +} + +void mlxfw_mfa2_file_component_put(struct mlxfw_mfa2_component *comp) +{ + const struct mlxfw_mfa2_comp_data *comp_data; + + comp_data = container_of(comp, struct mlxfw_mfa2_comp_data, comp); + kfree(comp_data); +} + +void mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file *mfa2_file) +{ + kfree(mfa2_file); +} diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.h new file mode 100644 index 000000000000..20472aa139cd --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.h @@ -0,0 +1,66 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.h + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com> + * + * 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. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +#ifndef _MLXFW_MFA2_H +#define _MLXFW_MFA2_H + +#include <linux/firmware.h> +#include "mlxfw.h" + +struct mlxfw_mfa2_component { + u16 index; + u32 data_size; + u8 *data; +}; + +struct mlxfw_mfa2_file; + +bool mlxfw_mfa2_check(const struct firmware *fw); + +struct mlxfw_mfa2_file *mlxfw_mfa2_file_init(const struct firmware *fw); + +int mlxfw_mfa2_file_component_count(const struct mlxfw_mfa2_file *mfa2_file, + const char *psid, u32 psid_size, + u32 *p_count); + +struct mlxfw_mfa2_component * +mlxfw_mfa2_file_component_get(const struct mlxfw_mfa2_file *mfa2_file, + const char *psid, int psid_size, + int component_index); + +void mlxfw_mfa2_file_component_put(struct mlxfw_mfa2_component *component); + +void mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file *mfa2_file); + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_file.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_file.h new file mode 100644 index 000000000000..f667942b1ea3 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_file.h @@ -0,0 +1,60 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_file.h + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com> + * + * 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. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +#ifndef _MLXFW_MFA2_FILE_H +#define _MLXFW_MFA2_FILE_H + +#include <linux/firmware.h> +#include <linux/kernel.h> + +struct mlxfw_mfa2_file { + const struct firmware *fw; + const struct mlxfw_mfa2_tlv *first_dev; + u16 dev_count; + const struct mlxfw_mfa2_tlv *first_component; + u16 component_count; + const void *cb; /* components block */ + u32 cb_archive_size; /* size of compressed components block */ +}; + +static inline bool mlxfw_mfa2_valid_ptr(const struct mlxfw_mfa2_file *mfa2_file, + const void *ptr) +{ + const void *valid_to = mfa2_file->fw->data + mfa2_file->fw->size; + const void *valid_from = mfa2_file->fw->data; + + return ptr > valid_from && ptr < valid_to; +} + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h new file mode 100644 index 000000000000..dd66737c033d --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h @@ -0,0 +1,103 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com> + * + * 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. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ +#ifndef _MLXFW_MFA2_FORMAT_H +#define _MLXFW_MFA2_FORMAT_H + +#include "mlxfw_mfa2_file.h" +#include "mlxfw_mfa2_tlv.h" + +enum mlxfw_mfa2_tlv_type { + MLXFW_MFA2_TLV_MULTI_PART = 0x01, + MLXFW_MFA2_TLV_PACKAGE_DESCRIPTOR = 0x02, + MLXFW_MFA2_TLV_COMPONENT_DESCRIPTOR = 0x04, + MLXFW_MFA2_TLV_COMPONENT_PTR = 0x22, + MLXFW_MFA2_TLV_PSID = 0x2A, +}; + +enum mlxfw_mfa2_compression_type { + MLXFW_MFA2_COMPRESSION_TYPE_NONE, + MLXFW_MFA2_COMPRESSION_TYPE_XZ, +}; + +struct mlxfw_mfa2_tlv_package_descriptor { + __be16 num_components; + __be16 num_devices; + __be32 cb_offset; + __be32 cb_archive_size; + __be32 cb_size_h; + __be32 cb_size_l; + u8 padding[3]; + u8 cv_compression; + __be32 user_data_offset; +} __packed; + +MLXFW_MFA2_TLV(package_descriptor, struct mlxfw_mfa2_tlv_package_descriptor, + MLXFW_MFA2_TLV_PACKAGE_DESCRIPTOR); + +struct mlxfw_mfa2_tlv_multi { + __be16 num_extensions; + __be16 total_len; +} __packed; + +MLXFW_MFA2_TLV(multi, struct mlxfw_mfa2_tlv_multi, + MLXFW_MFA2_TLV_MULTI_PART); + +struct mlxfw_mfa2_tlv_psid { + u8 psid[0]; +} __packed; + +MLXFW_MFA2_TLV_VARSIZE(psid, struct mlxfw_mfa2_tlv_psid, + MLXFW_MFA2_TLV_PSID); + +struct mlxfw_mfa2_tlv_component_ptr { + __be16 storage_id; + __be16 component_index; + __be32 storage_address; +} __packed; + +MLXFW_MFA2_TLV(component_ptr, struct mlxfw_mfa2_tlv_component_ptr, + MLXFW_MFA2_TLV_COMPONENT_PTR); + +struct mlxfw_mfa2_tlv_component_descriptor { + __be16 pldm_classification; + __be16 identifier; + __be32 cb_offset_h; + __be32 cb_offset_l; + __be32 size; +} __packed; + +MLXFW_MFA2_TLV(component_descriptor, struct mlxfw_mfa2_tlv_component_descriptor, + MLXFW_MFA2_TLV_COMPONENT_DESCRIPTOR); + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv.h new file mode 100644 index 000000000000..cc013e77b326 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv.h @@ -0,0 +1,98 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv.h + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com> + * + * 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. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +#ifndef _MLXFW_MFA2_TLV_H +#define _MLXFW_MFA2_TLV_H + +#include <linux/kernel.h> +#include "mlxfw_mfa2_file.h" + +struct mlxfw_mfa2_tlv { + u8 version; + u8 type; + __be16 len; + u8 data[0]; +} __packed; + +static inline const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_get(const struct mlxfw_mfa2_file *mfa2_file, const void *ptr) +{ + if (!mlxfw_mfa2_valid_ptr(mfa2_file, ptr) || + !mlxfw_mfa2_valid_ptr(mfa2_file, ptr + sizeof(struct mlxfw_mfa2_tlv))) + return NULL; + return ptr; +} + +static inline const void * +mlxfw_mfa2_tlv_payload_get(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv *tlv, u8 payload_type, + size_t payload_size, bool varsize) +{ + void *tlv_top; + + tlv_top = (void *) tlv + be16_to_cpu(tlv->len) - 1; + if (!mlxfw_mfa2_valid_ptr(mfa2_file, tlv) || + !mlxfw_mfa2_valid_ptr(mfa2_file, tlv_top)) + return NULL; + if (tlv->type != payload_type) + return NULL; + if (varsize && (be16_to_cpu(tlv->len) < payload_size)) + return NULL; + if (!varsize && (be16_to_cpu(tlv->len) != payload_size)) + return NULL; + + return tlv->data; +} + +#define MLXFW_MFA2_TLV(name, payload_type, tlv_type) \ +static inline const payload_type * \ +mlxfw_mfa2_tlv_ ## name ## _get(const struct mlxfw_mfa2_file *mfa2_file, \ + const struct mlxfw_mfa2_tlv *tlv) \ +{ \ + return mlxfw_mfa2_tlv_payload_get(mfa2_file, tlv, \ + tlv_type, sizeof(payload_type), \ + false); \ +} + +#define MLXFW_MFA2_TLV_VARSIZE(name, payload_type, tlv_type) \ +static inline const payload_type * \ +mlxfw_mfa2_tlv_ ## name ## _get(const struct mlxfw_mfa2_file *mfa2_file, \ + const struct mlxfw_mfa2_tlv *tlv) \ +{ \ + return mlxfw_mfa2_tlv_payload_get(mfa2_file, tlv, \ + tlv_type, sizeof(payload_type), \ + true); \ +} + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c new file mode 100644 index 000000000000..0094b92a233b --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c @@ -0,0 +1,126 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com> + * + * 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. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +#define pr_fmt(fmt) "MFA2: " fmt + +#include "mlxfw_mfa2_tlv_multi.h" +#include <uapi/linux/netlink.h> + +#define MLXFW_MFA2_TLV_TOTAL_SIZE(tlv) \ + NLA_ALIGN(sizeof(*(tlv)) + be16_to_cpu((tlv)->len)) + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_multi_child(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv_multi *multi) +{ + size_t multi_len; + + multi_len = NLA_ALIGN(sizeof(struct mlxfw_mfa2_tlv_multi)); + return mlxfw_mfa2_tlv_get(mfa2_file, (void *) multi + multi_len); +} + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_next(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv *tlv) +{ + const struct mlxfw_mfa2_tlv_multi *multi; + u16 tlv_len; + void *next; + + tlv_len = MLXFW_MFA2_TLV_TOTAL_SIZE(tlv); + + if (tlv->type == MLXFW_MFA2_TLV_MULTI_PART) { + multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, tlv); + tlv_len = NLA_ALIGN(tlv_len + be16_to_cpu(multi->total_len)); + } + + next = (void *) tlv + tlv_len; + return mlxfw_mfa2_tlv_get(mfa2_file, next); +} + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_advance(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv *from_tlv, u16 count) +{ + const struct mlxfw_mfa2_tlv *tlv; + u16 idx; + + mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, from_tlv, count) + if (!tlv) + return NULL; + return tlv; +} + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_multi_child_find(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv_multi *multi, + enum mlxfw_mfa2_tlv_type type, u16 index) +{ + const struct mlxfw_mfa2_tlv *tlv; + u16 skip = 0; + u16 idx; + + mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) { + if (!tlv) { + pr_err("TLV parsing error\n"); + return NULL; + } + if (tlv->type == type) + if (skip++ == index) + return tlv; + } + return NULL; +} + +int mlxfw_mfa2_tlv_multi_child_count(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv_multi *multi, + enum mlxfw_mfa2_tlv_type type, + u16 *p_count) +{ + const struct mlxfw_mfa2_tlv *tlv; + u16 count = 0; + u16 idx; + + mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) { + if (!tlv) { + pr_err("TLV parsing error\n"); + return -EINVAL; + } + + if (tlv->type == type) + count++; + } + *p_count = count; + return 0; +} diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.h new file mode 100644 index 000000000000..2c667894f3a2 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.h @@ -0,0 +1,71 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.h + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com> + * + * 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. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ +#ifndef _MLXFW_MFA2_TLV_MULTI_H +#define _MLXFW_MFA2_TLV_MULTI_H + +#include "mlxfw_mfa2_tlv.h" +#include "mlxfw_mfa2_format.h" +#include "mlxfw_mfa2_file.h" + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_multi_child(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv_multi *multi); + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_next(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv *tlv); + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_advance(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv *from_tlv, u16 count); + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_multi_child_find(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv_multi *multi, + enum mlxfw_mfa2_tlv_type type, u16 index); + +int mlxfw_mfa2_tlv_multi_child_count(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv_multi *multi, + enum mlxfw_mfa2_tlv_type type, + u16 *p_count); + +#define mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, from_tlv, count) \ + for (idx = 0, tlv = from_tlv; idx < (count); \ + idx++, tlv = mlxfw_mfa2_tlv_next(mfa2_file, tlv)) + +#define mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) \ + mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, \ + mlxfw_mfa2_tlv_multi_child(mfa2_file, multi), \ + be16_to_cpu(multi->num_extensions) + 1) +#endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig index ef23eaedc2ff..695adff89d71 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig +++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig @@ -74,7 +74,9 @@ config MLXSW_SPECTRUM tristate "Mellanox Technologies Spectrum support" depends on MLXSW_CORE && MLXSW_PCI && NET_SWITCHDEV && VLAN_8021Q depends on PSAMPLE || PSAMPLE=n + depends on BRIDGE || BRIDGE=n select PARMAN + select MLXFW default m ---help--- This driver supports Mellanox Technologies Spectrum Ethernet diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile index 2fb8c6585ac7..62fc42f396bb 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Makefile +++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile @@ -16,7 +16,8 @@ mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \ spectrum_switchdev.o spectrum_router.o \ spectrum_kvdl.o spectrum_acl_tcam.o \ spectrum_acl.o spectrum_flower.o \ - spectrum_cnt.o spectrum_dpipe.o + spectrum_cnt.o spectrum_dpipe.o \ + spectrum_fid.o mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o obj-$(CONFIG_MLXSW_MINIMAL) += mlxsw_minimal.o mlxsw_minimal-objs := minimal.o diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index 7fb35395adf5..6e966af72fc4 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -344,15 +344,17 @@ struct mlxsw_bus { u8 features; }; +struct mlxsw_fw_rev { + u16 major; + u16 minor; + u16 subminor; +}; + struct mlxsw_bus_info { const char *device_kind; const char *device_name; struct device *dev; - struct { - u16 major; - u16 minor; - u16 subminor; - } fw_rev; + struct mlxsw_fw_rev fw_rev; u8 vsd[MLXSW_CMD_BOARDINFO_VSD_LEN]; u8 psid[MLXSW_CMD_BOARDINFO_PSID_LEN]; }; diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c index 46304ffb9449..5ae110172c22 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c @@ -40,6 +40,7 @@ #include <linux/list.h> #include "item.h" +#include "trap.h" #include "core_acl_flex_actions.h" enum mlxsw_afa_set_type { @@ -662,6 +663,16 @@ EXPORT_SYMBOL(mlxsw_afa_block_append_vlan_modify); #define MLXSW_AFA_TRAPDISC_CODE 0x03 #define MLXSW_AFA_TRAPDISC_SIZE 1 +enum mlxsw_afa_trapdisc_trap_action { + MLXSW_AFA_TRAPDISC_TRAP_ACTION_NOP = 0, + MLXSW_AFA_TRAPDISC_TRAP_ACTION_TRAP = 2, +}; + +/* afa_trapdisc_trap_action + * Trap Action. + */ +MLXSW_ITEM32(afa, trapdisc, trap_action, 0x00, 24, 4); + enum mlxsw_afa_trapdisc_forward_action { MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD = 3, }; @@ -671,11 +682,20 @@ enum mlxsw_afa_trapdisc_forward_action { */ MLXSW_ITEM32(afa, trapdisc, forward_action, 0x00, 0, 4); +/* afa_trapdisc_trap_id + * Trap ID to configure. + */ +MLXSW_ITEM32(afa, trapdisc, trap_id, 0x04, 0, 9); + static inline void mlxsw_afa_trapdisc_pack(char *payload, - enum mlxsw_afa_trapdisc_forward_action forward_action) + enum mlxsw_afa_trapdisc_trap_action trap_action, + enum mlxsw_afa_trapdisc_forward_action forward_action, + u16 trap_id) { + mlxsw_afa_trapdisc_trap_action_set(payload, trap_action); mlxsw_afa_trapdisc_forward_action_set(payload, forward_action); + mlxsw_afa_trapdisc_trap_id_set(payload, trap_id); } int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block) @@ -686,11 +706,27 @@ int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block) if (!act) return -ENOBUFS; - mlxsw_afa_trapdisc_pack(act, MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD); + mlxsw_afa_trapdisc_pack(act, MLXSW_AFA_TRAPDISC_TRAP_ACTION_NOP, + MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD, 0); return 0; } EXPORT_SYMBOL(mlxsw_afa_block_append_drop); +int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block) +{ + char *act = mlxsw_afa_block_append_action(block, + MLXSW_AFA_TRAPDISC_CODE, + MLXSW_AFA_TRAPDISC_SIZE); + + if (!act) + return -ENOBUFS; + mlxsw_afa_trapdisc_pack(act, MLXSW_AFA_TRAPDISC_TRAP_ACTION_TRAP, + MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD, + MLXSW_TRAP_ID_ACL0); + return 0; +} +EXPORT_SYMBOL(mlxsw_afa_block_append_trap); + /* Forwarding Action * ----------------- * Forwarding Action can be used to implement Policy Based Switching (PBS) diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h index bd8b91d02880..f99c341b2497 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h @@ -60,6 +60,7 @@ u32 mlxsw_afa_block_first_set_kvdl_index(struct mlxsw_afa_block *block); void mlxsw_afa_block_continue(struct mlxsw_afa_block *block); void mlxsw_afa_block_jump(struct mlxsw_afa_block *block, u16 group_id); int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block); +int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block); int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block *block, u8 local_port, bool in_port); int mlxsw_afa_block_append_vlan_modify(struct mlxsw_afa_block *block, diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h index c75e9141e3ec..9807ef814e42 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h @@ -56,6 +56,7 @@ enum mlxsw_afk_element { MLXSW_AFK_ELEMENT_SRC_L4_PORT, MLXSW_AFK_ELEMENT_VID, MLXSW_AFK_ELEMENT_PCP, + MLXSW_AFK_ELEMENT_TCP_FLAGS, MLXSW_AFK_ELEMENT_MAX, }; @@ -102,6 +103,7 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = { MLXSW_AFK_ELEMENT_INFO_U32(IP_PROTO, 0x10, 0, 8), MLXSW_AFK_ELEMENT_INFO_U32(VID, 0x10, 8, 12), MLXSW_AFK_ELEMENT_INFO_U32(PCP, 0x10, 20, 3), + MLXSW_AFK_ELEMENT_INFO_U32(TCP_FLAGS, 0x10, 23, 9), MLXSW_AFK_ELEMENT_INFO_U32(SRC_IP4, 0x18, 0, 32), MLXSW_AFK_ELEMENT_INFO_U32(DST_IP4, 0x1C, 0, 32), MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_HI, 0x18, 8), diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h index 0af3338bfcb4..a6441208e9d9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h @@ -155,7 +155,7 @@ MLXSW_ITEM32(pci, cqe, byte_count, 0x04, 0, 14); /* pci_cqe_trap_id * Trap ID that captured the packet. */ -MLXSW_ITEM32(pci, cqe, trap_id, 0x08, 0, 8); +MLXSW_ITEM32(pci, cqe, trap_id, 0x08, 0, 9); /* pci_cqe_crc * Length include CRC. Indicates the length field includes diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 83b277c8090e..157b9b6f8485 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -958,7 +958,7 @@ enum mlxsw_flood_table_type { MLXSW_REG_SFGC_TABLE_TYPE_VID = 1, MLXSW_REG_SFGC_TABLE_TYPE_SINGLE = 2, MLXSW_REG_SFGC_TABLE_TYPE_ANY = 0, - MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST = 3, + MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET = 3, MLXSW_REG_SFGC_TABLE_TYPE_FID = 4, }; @@ -5643,6 +5643,222 @@ static inline void mlxsw_reg_mlcr_pack(char *payload, u8 local_port, MLXSW_REG_MLCR_DURATION_MAX : 0); } +/* MCQI - Management Component Query Information + * --------------------------------------------- + * This register allows querying information about firmware components. + */ +#define MLXSW_REG_MCQI_ID 0x9061 +#define MLXSW_REG_MCQI_BASE_LEN 0x18 +#define MLXSW_REG_MCQI_CAP_LEN 0x14 +#define MLXSW_REG_MCQI_LEN (MLXSW_REG_MCQI_BASE_LEN + MLXSW_REG_MCQI_CAP_LEN) + +MLXSW_REG_DEFINE(mcqi, MLXSW_REG_MCQI_ID, MLXSW_REG_MCQI_LEN); + +/* reg_mcqi_component_index + * Index of the accessed component. + * Access: Index + */ +MLXSW_ITEM32(reg, mcqi, component_index, 0x00, 0, 16); + +enum mlxfw_reg_mcqi_info_type { + MLXSW_REG_MCQI_INFO_TYPE_CAPABILITIES, +}; + +/* reg_mcqi_info_type + * Component properties set. + * Access: RW + */ +MLXSW_ITEM32(reg, mcqi, info_type, 0x08, 0, 5); + +/* reg_mcqi_offset + * The requested/returned data offset from the section start, given in bytes. + * Must be DWORD aligned. + * Access: RW + */ +MLXSW_ITEM32(reg, mcqi, offset, 0x10, 0, 32); + +/* reg_mcqi_data_size + * The requested/returned data size, given in bytes. If data_size is not DWORD + * aligned, the last bytes are zero padded. + * Access: RW + */ +MLXSW_ITEM32(reg, mcqi, data_size, 0x14, 0, 16); + +/* reg_mcqi_cap_max_component_size + * Maximum size for this component, given in bytes. + * Access: RO + */ +MLXSW_ITEM32(reg, mcqi, cap_max_component_size, 0x20, 0, 32); + +/* reg_mcqi_cap_log_mcda_word_size + * Log 2 of the access word size in bytes. Read and write access must be aligned + * to the word size. Write access must be done for an integer number of words. + * Access: RO + */ +MLXSW_ITEM32(reg, mcqi, cap_log_mcda_word_size, 0x24, 28, 4); + +/* reg_mcqi_cap_mcda_max_write_size + * Maximal write size for MCDA register + * Access: RO + */ +MLXSW_ITEM32(reg, mcqi, cap_mcda_max_write_size, 0x24, 0, 16); + +static inline void mlxsw_reg_mcqi_pack(char *payload, u16 component_index) +{ + MLXSW_REG_ZERO(mcqi, payload); + mlxsw_reg_mcqi_component_index_set(payload, component_index); + mlxsw_reg_mcqi_info_type_set(payload, + MLXSW_REG_MCQI_INFO_TYPE_CAPABILITIES); + mlxsw_reg_mcqi_offset_set(payload, 0); + mlxsw_reg_mcqi_data_size_set(payload, MLXSW_REG_MCQI_CAP_LEN); +} + +static inline void mlxsw_reg_mcqi_unpack(char *payload, + u32 *p_cap_max_component_size, + u8 *p_cap_log_mcda_word_size, + u16 *p_cap_mcda_max_write_size) +{ + *p_cap_max_component_size = + mlxsw_reg_mcqi_cap_max_component_size_get(payload); + *p_cap_log_mcda_word_size = + mlxsw_reg_mcqi_cap_log_mcda_word_size_get(payload); + *p_cap_mcda_max_write_size = + mlxsw_reg_mcqi_cap_mcda_max_write_size_get(payload); +} + +/* MCC - Management Component Control + * ---------------------------------- + * Controls the firmware component and updates the FSM. + */ +#define MLXSW_REG_MCC_ID 0x9062 +#define MLXSW_REG_MCC_LEN 0x1C + +MLXSW_REG_DEFINE(mcc, MLXSW_REG_MCC_ID, MLXSW_REG_MCC_LEN); + +enum mlxsw_reg_mcc_instruction { + MLXSW_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01, + MLXSW_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02, + MLXSW_REG_MCC_INSTRUCTION_UPDATE_COMPONENT = 0x03, + MLXSW_REG_MCC_INSTRUCTION_VERIFY_COMPONENT = 0x04, + MLXSW_REG_MCC_INSTRUCTION_ACTIVATE = 0x06, + MLXSW_REG_MCC_INSTRUCTION_CANCEL = 0x08, +}; + +/* reg_mcc_instruction + * Command to be executed by the FSM. + * Applicable for write operation only. + * Access: RW + */ +MLXSW_ITEM32(reg, mcc, instruction, 0x00, 0, 8); + +/* reg_mcc_component_index + * Index of the accessed component. Applicable only for commands that + * refer to components. Otherwise, this field is reserved. + * Access: Index + */ +MLXSW_ITEM32(reg, mcc, component_index, 0x04, 0, 16); + +/* reg_mcc_update_handle + * Token representing the current flow executed by the FSM. + * Access: WO + */ +MLXSW_ITEM32(reg, mcc, update_handle, 0x08, 0, 24); + +/* reg_mcc_error_code + * Indicates the successful completion of the instruction, or the reason it + * failed + * Access: RO + */ +MLXSW_ITEM32(reg, mcc, error_code, 0x0C, 8, 8); + +/* reg_mcc_control_state + * Current FSM state + * Access: RO + */ +MLXSW_ITEM32(reg, mcc, control_state, 0x0C, 0, 4); + +/* reg_mcc_component_size + * Component size in bytes. Valid for UPDATE_COMPONENT instruction. Specifying + * the size may shorten the update time. Value 0x0 means that size is + * unspecified. + * Access: WO + */ +MLXSW_ITEM32(reg, mcc, component_size, 0x10, 0, 32); + +static inline void mlxsw_reg_mcc_pack(char *payload, + enum mlxsw_reg_mcc_instruction instr, + u16 component_index, u32 update_handle, + u32 component_size) +{ + MLXSW_REG_ZERO(mcc, payload); + mlxsw_reg_mcc_instruction_set(payload, instr); + mlxsw_reg_mcc_component_index_set(payload, component_index); + mlxsw_reg_mcc_update_handle_set(payload, update_handle); + mlxsw_reg_mcc_component_size_set(payload, component_size); +} + +static inline void mlxsw_reg_mcc_unpack(char *payload, u32 *p_update_handle, + u8 *p_error_code, u8 *p_control_state) +{ + if (p_update_handle) + *p_update_handle = mlxsw_reg_mcc_update_handle_get(payload); + if (p_error_code) + *p_error_code = mlxsw_reg_mcc_error_code_get(payload); + if (p_control_state) + *p_control_state = mlxsw_reg_mcc_control_state_get(payload); +} + +/* MCDA - Management Component Data Access + * --------------------------------------- + * This register allows reading and writing a firmware component. + */ +#define MLXSW_REG_MCDA_ID 0x9063 +#define MLXSW_REG_MCDA_BASE_LEN 0x10 +#define MLXSW_REG_MCDA_MAX_DATA_LEN 0x80 +#define MLXSW_REG_MCDA_LEN \ + (MLXSW_REG_MCDA_BASE_LEN + MLXSW_REG_MCDA_MAX_DATA_LEN) + +MLXSW_REG_DEFINE(mcda, MLXSW_REG_MCDA_ID, MLXSW_REG_MCDA_LEN); + +/* reg_mcda_update_handle + * Token representing the current flow executed by the FSM. + * Access: RW + */ +MLXSW_ITEM32(reg, mcda, update_handle, 0x00, 0, 24); + +/* reg_mcda_offset + * Offset of accessed address relative to component start. Accesses must be in + * accordance to log_mcda_word_size in MCQI reg. + * Access: RW + */ +MLXSW_ITEM32(reg, mcda, offset, 0x04, 0, 32); + +/* reg_mcda_size + * Size of the data accessed, given in bytes. + * Access: RW + */ +MLXSW_ITEM32(reg, mcda, size, 0x08, 0, 16); + +/* reg_mcda_data + * Data block accessed. + * Access: RW + */ +MLXSW_ITEM32_INDEXED(reg, mcda, data, 0x10, 0, 32, 4, 0, false); + +static inline void mlxsw_reg_mcda_pack(char *payload, u32 update_handle, + u32 offset, u16 size, u8 *data) +{ + int i; + + MLXSW_REG_ZERO(mcda, payload); + mlxsw_reg_mcda_update_handle_set(payload, update_handle); + mlxsw_reg_mcda_offset_set(payload, offset); + mlxsw_reg_mcda_size_set(payload, size); + + for (i = 0; i < size / 4; i++) + mlxsw_reg_mcda_data_set(payload, i, *(u32 *) &data[i * 4]); +} + /* MPSC - Monitoring Packet Sampling Configuration Register * -------------------------------------------------------- * MPSC Register is used to configure the Packet Sampling mechanism. @@ -6221,6 +6437,9 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(mpar), MLXSW_REG(mlcr), MLXSW_REG(mpsc), + MLXSW_REG(mcqi), + MLXSW_REG(mcc), + MLXSW_REG(mcda), MLXSW_REG(mgpc), MLXSW_REG(sbpr), MLXSW_REG(sbcm), diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 88357cee7679..f60e2ba515d0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -68,6 +68,22 @@ #include "txheader.h" #include "spectrum_cnt.h" #include "spectrum_dpipe.h" +#include "../mlxfw/mlxfw.h" + +#define MLXSW_FWREV_MAJOR 13 +#define MLXSW_FWREV_MINOR 1420 +#define MLXSW_FWREV_SUBMINOR 122 + +static const struct mlxsw_fw_rev mlxsw_sp_supported_fw_rev = { + .major = MLXSW_FWREV_MAJOR, + .minor = MLXSW_FWREV_MINOR, + .subminor = MLXSW_FWREV_SUBMINOR +}; + +#define MLXSW_SP_FW_FILENAME \ + "mellanox/mlxsw_spectrum-" __stringify(MLXSW_FWREV_MAJOR) \ + "." __stringify(MLXSW_FWREV_MINOR) \ + "." __stringify(MLXSW_FWREV_SUBMINOR) ".mfa2" static const char mlxsw_sp_driver_name[] = "mlxsw_spectrum"; static const char mlxsw_sp_driver_version[] = "1.0"; @@ -140,6 +156,223 @@ MLXSW_ITEM32(tx, hdr, fid, 0x08, 0, 16); */ MLXSW_ITEM32(tx, hdr, type, 0x0C, 0, 4); +struct mlxsw_sp_mlxfw_dev { + struct mlxfw_dev mlxfw_dev; + struct mlxsw_sp *mlxsw_sp; +}; + +static int mlxsw_sp_component_query(struct mlxfw_dev *mlxfw_dev, + u16 component_index, u32 *p_max_size, + u8 *p_align_bits, u16 *p_max_write_size) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcqi_pl[MLXSW_REG_MCQI_LEN]; + int err; + + mlxsw_reg_mcqi_pack(mcqi_pl, component_index); + err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mcqi), mcqi_pl); + if (err) + return err; + mlxsw_reg_mcqi_unpack(mcqi_pl, p_max_size, p_align_bits, + p_max_write_size); + + *p_align_bits = max_t(u8, *p_align_bits, 2); + *p_max_write_size = min_t(u16, *p_max_write_size, + MLXSW_REG_MCDA_MAX_DATA_LEN); + return 0; +} + +static int mlxsw_sp_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcc_pl[MLXSW_REG_MCC_LEN]; + u8 control_state; + int err; + + mlxsw_reg_mcc_pack(mcc_pl, 0, 0, 0, 0); + err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); + if (err) + return err; + + mlxsw_reg_mcc_unpack(mcc_pl, fwhandle, NULL, &control_state); + if (control_state != MLXFW_FSM_STATE_IDLE) + return -EBUSY; + + mlxsw_reg_mcc_pack(mcc_pl, + MLXSW_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE, + 0, *fwhandle, 0); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); +} + +static int mlxsw_sp_fsm_component_update(struct mlxfw_dev *mlxfw_dev, + u32 fwhandle, u16 component_index, + u32 component_size) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcc_pl[MLXSW_REG_MCC_LEN]; + + mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_UPDATE_COMPONENT, + component_index, fwhandle, component_size); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); +} + +static int mlxsw_sp_fsm_block_download(struct mlxfw_dev *mlxfw_dev, + u32 fwhandle, u8 *data, u16 size, + u32 offset) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcda_pl[MLXSW_REG_MCDA_LEN]; + + mlxsw_reg_mcda_pack(mcda_pl, fwhandle, offset, size, data); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcda), mcda_pl); +} + +static int mlxsw_sp_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, + u32 fwhandle, u16 component_index) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcc_pl[MLXSW_REG_MCC_LEN]; + + mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_VERIFY_COMPONENT, + component_index, fwhandle, 0); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); +} + +static int mlxsw_sp_fsm_activate(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcc_pl[MLXSW_REG_MCC_LEN]; + + mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_ACTIVATE, 0, + fwhandle, 0); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); +} + +static int mlxsw_sp_fsm_query_state(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + enum mlxfw_fsm_state *fsm_state, + enum mlxfw_fsm_state_err *fsm_state_err) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcc_pl[MLXSW_REG_MCC_LEN]; + u8 control_state; + u8 error_code; + int err; + + mlxsw_reg_mcc_pack(mcc_pl, 0, 0, fwhandle, 0); + err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); + if (err) + return err; + + mlxsw_reg_mcc_unpack(mcc_pl, NULL, &error_code, &control_state); + *fsm_state = control_state; + *fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code, + MLXFW_FSM_STATE_ERR_MAX); + return 0; +} + +static void mlxsw_sp_fsm_cancel(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcc_pl[MLXSW_REG_MCC_LEN]; + + mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_CANCEL, 0, + fwhandle, 0); + mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); +} + +static void mlxsw_sp_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcc_pl[MLXSW_REG_MCC_LEN]; + + mlxsw_reg_mcc_pack(mcc_pl, + MLXSW_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, 0, + fwhandle, 0); + mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); +} + +static const struct mlxfw_dev_ops mlxsw_sp_mlxfw_dev_ops = { + .component_query = mlxsw_sp_component_query, + .fsm_lock = mlxsw_sp_fsm_lock, + .fsm_component_update = mlxsw_sp_fsm_component_update, + .fsm_block_download = mlxsw_sp_fsm_block_download, + .fsm_component_verify = mlxsw_sp_fsm_component_verify, + .fsm_activate = mlxsw_sp_fsm_activate, + .fsm_query_state = mlxsw_sp_fsm_query_state, + .fsm_cancel = mlxsw_sp_fsm_cancel, + .fsm_release = mlxsw_sp_fsm_release +}; + +static int mlxsw_sp_firmware_flash(struct mlxsw_sp *mlxsw_sp, + const struct firmware *firmware) +{ + struct mlxsw_sp_mlxfw_dev mlxsw_sp_mlxfw_dev = { + .mlxfw_dev = { + .ops = &mlxsw_sp_mlxfw_dev_ops, + .psid = mlxsw_sp->bus_info->psid, + .psid_size = strlen(mlxsw_sp->bus_info->psid), + }, + .mlxsw_sp = mlxsw_sp + }; + + return mlxfw_firmware_flash(&mlxsw_sp_mlxfw_dev.mlxfw_dev, firmware); +} + +static bool mlxsw_sp_fw_rev_ge(const struct mlxsw_fw_rev *a, + const struct mlxsw_fw_rev *b) +{ + if (a->major != b->major) + return a->major > b->major; + if (a->minor != b->minor) + return a->minor > b->minor; + return a->subminor >= b->subminor; +} + +static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp) +{ + const struct mlxsw_fw_rev *rev = &mlxsw_sp->bus_info->fw_rev; + const struct firmware *firmware; + int err; + + if (mlxsw_sp_fw_rev_ge(rev, &mlxsw_sp_supported_fw_rev)) + return 0; + + dev_info(mlxsw_sp->bus_info->dev, "The firmware version %d.%d.%d out of data\n", + rev->major, rev->minor, rev->subminor); + dev_info(mlxsw_sp->bus_info->dev, "Upgrading firmware using file %s\n", + MLXSW_SP_FW_FILENAME); + + err = request_firmware_direct(&firmware, MLXSW_SP_FW_FILENAME, + mlxsw_sp->bus_info->dev); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Could not request firmware file %s\n", + MLXSW_SP_FW_FILENAME); + return err; + } + + err = mlxsw_sp_firmware_flash(mlxsw_sp, firmware); + release_firmware(firmware); + return err; +} + int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp, unsigned int counter_index, u64 *packets, u64 *bytes) @@ -210,6 +443,41 @@ static void mlxsw_sp_txhdr_construct(struct sk_buff *skb, mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL); } +int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, + u8 state) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + enum mlxsw_reg_spms_state spms_state; + char *spms_pl; + int err; + + switch (state) { + case BR_STATE_FORWARDING: + spms_state = MLXSW_REG_SPMS_STATE_FORWARDING; + break; + case BR_STATE_LEARNING: + spms_state = MLXSW_REG_SPMS_STATE_LEARNING; + break; + case BR_STATE_LISTENING: /* fall-through */ + case BR_STATE_DISABLED: /* fall-through */ + case BR_STATE_BLOCKING: + spms_state = MLXSW_REG_SPMS_STATE_DISCARDING; + break; + default: + BUG(); + } + + spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL); + if (!spms_pl) + return -ENOMEM; + mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port); + mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state); + + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl); + kfree(spms_pl); + return err; +} + static int mlxsw_sp_base_mac_get(struct mlxsw_sp *mlxsw_sp) { char spad_pl[MLXSW_REG_SPAD_LEN] = {0}; @@ -609,8 +877,7 @@ static int mlxsw_sp_port_swid_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 swid) swid); } -static int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, - bool enable) +int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; char svpe_pl[MLXSW_REG_SVPE_LEN]; @@ -619,21 +886,8 @@ static int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svpe), svpe_pl); } -int mlxsw_sp_port_vid_to_fid_set(struct mlxsw_sp_port *mlxsw_sp_port, - enum mlxsw_reg_svfa_mt mt, bool valid, u16 fid, - u16 vid) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - char svfa_pl[MLXSW_REG_SVFA_LEN]; - - mlxsw_reg_svfa_pack(svfa_pl, mlxsw_sp_port->local_port, mt, valid, - fid, vid); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); -} - -int __mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid_begin, u16 vid_end, - bool learn_enable) +int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, + bool learn_enable) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; char *spvmlr_pl; @@ -642,18 +896,56 @@ int __mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, spvmlr_pl = kmalloc(MLXSW_REG_SPVMLR_LEN, GFP_KERNEL); if (!spvmlr_pl) return -ENOMEM; - mlxsw_reg_spvmlr_pack(spvmlr_pl, mlxsw_sp_port->local_port, vid_begin, - vid_end, learn_enable); + mlxsw_reg_spvmlr_pack(spvmlr_pl, mlxsw_sp_port->local_port, vid, vid, + learn_enable); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvmlr), spvmlr_pl); kfree(spvmlr_pl); return err; } -static int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid, bool learn_enable) +static int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + char spvid_pl[MLXSW_REG_SPVID_LEN]; + + mlxsw_reg_spvid_pack(spvid_pl, mlxsw_sp_port->local_port, vid); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl); +} + +static int mlxsw_sp_port_allow_untagged_set(struct mlxsw_sp_port *mlxsw_sp_port, + bool allow) { - return __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, vid, - learn_enable); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + char spaft_pl[MLXSW_REG_SPAFT_LEN]; + + mlxsw_reg_spaft_pack(spaft_pl, mlxsw_sp_port->local_port, allow); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spaft), spaft_pl); +} + +int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + int err; + + if (!vid) { + err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, false); + if (err) + return err; + } else { + err = __mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid); + if (err) + return err; + err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, true); + if (err) + goto err_port_allow_untagged_set; + } + + mlxsw_sp_port->pvid = vid; + return 0; + +err_port_allow_untagged_set: + __mlxsw_sp_port_pvid_set(mlxsw_sp_port, mlxsw_sp_port->pvid); + return err; } static int @@ -1100,95 +1392,82 @@ int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, return 0; } -static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) +static void mlxsw_sp_port_vlan_flush(struct mlxsw_sp_port *mlxsw_sp_port) { - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - u16 vid, last_visited_vid; - int err; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, *tmp; - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) { - err = mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true, vid, - vid); - if (err) { - last_visited_vid = vid; - goto err_port_vid_to_fid_set; - } - } - - err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); - if (err) { - last_visited_vid = VLAN_N_VID; - goto err_port_vid_to_fid_set; - } - - return 0; - -err_port_vid_to_fid_set: - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, last_visited_vid) - mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, vid, - vid); - return err; + list_for_each_entry_safe(mlxsw_sp_port_vlan, tmp, + &mlxsw_sp_port->vlans_list, list) + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); } -static int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) +static struct mlxsw_sp_port_vlan * +mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) { - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - u16 vid; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + bool untagged = vid == 1; int err; - err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); + err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true, untagged); if (err) - return err; + return ERR_PTR(err); - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) { - err = mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, - vid, vid); - if (err) - return err; + mlxsw_sp_port_vlan = kzalloc(sizeof(*mlxsw_sp_port_vlan), GFP_KERNEL); + if (!mlxsw_sp_port_vlan) { + err = -ENOMEM; + goto err_port_vlan_alloc; } - return 0; + mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port; + mlxsw_sp_port_vlan->vid = vid; + list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list); + + return mlxsw_sp_port_vlan; + +err_port_vlan_alloc: + mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false); + return ERR_PTR(err); } -static struct mlxsw_sp_port * -mlxsw_sp_port_vport_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +static void +mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { - struct mlxsw_sp_port *mlxsw_sp_vport; + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + u16 vid = mlxsw_sp_port_vlan->vid; - mlxsw_sp_vport = kzalloc(sizeof(*mlxsw_sp_vport), GFP_KERNEL); - if (!mlxsw_sp_vport) - return NULL; + list_del(&mlxsw_sp_port_vlan->list); + kfree(mlxsw_sp_port_vlan); + mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false); +} - /* dev will be set correctly after the VLAN device is linked - * with the real device. In case of bridge SELF invocation, dev - * will remain as is. - */ - mlxsw_sp_vport->dev = mlxsw_sp_port->dev; - mlxsw_sp_vport->mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - mlxsw_sp_vport->local_port = mlxsw_sp_port->local_port; - mlxsw_sp_vport->stp_state = BR_STATE_FORWARDING; - mlxsw_sp_vport->lagged = mlxsw_sp_port->lagged; - mlxsw_sp_vport->lag_id = mlxsw_sp_port->lag_id; - mlxsw_sp_vport->vport.vid = vid; +struct mlxsw_sp_port_vlan * +mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - list_add(&mlxsw_sp_vport->vport.list, &mlxsw_sp_port->vports_list); + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); + if (mlxsw_sp_port_vlan) + return mlxsw_sp_port_vlan; - return mlxsw_sp_vport; + return mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid); } -static void mlxsw_sp_port_vport_destroy(struct mlxsw_sp_port *mlxsw_sp_vport) +void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { - list_del(&mlxsw_sp_vport->vport.list); - kfree(mlxsw_sp_vport); + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + + if (mlxsw_sp_port_vlan->bridge_port) + mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); + else if (fid) + mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); + + mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); } static int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto, u16 vid) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); - struct mlxsw_sp_port *mlxsw_sp_vport; - bool untagged = vid == 1; - int err; /* VLAN 0 is added to HW filter when device goes up, but it is * reserved in our case, so simply return. @@ -1196,43 +1475,14 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev, if (!vid) return 0; - if (mlxsw_sp_port_vport_find(mlxsw_sp_port, vid)) - return 0; - - mlxsw_sp_vport = mlxsw_sp_port_vport_create(mlxsw_sp_port, vid); - if (!mlxsw_sp_vport) - return -ENOMEM; - - /* When adding the first VLAN interface on a bridged port we need to - * transition all the active 802.1Q bridge VLANs to use explicit - * {Port, VID} to FID mappings and set the port's mode to Virtual mode. - */ - if (list_is_singular(&mlxsw_sp_port->vports_list)) { - err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); - if (err) - goto err_port_vp_mode_trans; - } - - err = mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, true, untagged); - if (err) - goto err_port_add_vid; - - return 0; - -err_port_add_vid: - if (list_is_singular(&mlxsw_sp_port->vports_list)) - mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); -err_port_vp_mode_trans: - mlxsw_sp_port_vport_destroy(mlxsw_sp_vport); - return err; + return PTR_ERR_OR_ZERO(mlxsw_sp_port_vlan_get(mlxsw_sp_port, vid)); } static int mlxsw_sp_port_kill_vid(struct net_device *dev, __be16 __always_unused proto, u16 vid) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); - struct mlxsw_sp_port *mlxsw_sp_vport; - struct mlxsw_sp_fid *f; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; /* VLAN 0 is removed from HW filter when device goes down, but * it is reserved in our case, so simply return. @@ -1240,27 +1490,10 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev, if (!vid) return 0; - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); - if (WARN_ON(!mlxsw_sp_vport)) + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); + if (!mlxsw_sp_port_vlan) return 0; - - mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, false, false); - - /* Drop FID reference. If this was the last reference the - * resources will be freed. - */ - f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - if (f && !WARN_ON(!f->leave)) - f->leave(mlxsw_sp_vport); - - /* When removing the last VLAN interface on a bridged port we need to - * transition all active 802.1Q bridge VLANs to use VID to FID - * mappings and set port's mode to VLAN mode. - */ - if (list_is_singular(&mlxsw_sp_port->vports_list)) - mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); - - mlxsw_sp_port_vport_destroy(mlxsw_sp_vport); + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); return 0; } @@ -2269,6 +2502,31 @@ mlxsw_sp_port_set_link_ksettings(struct net_device *dev, return 0; } +static int mlxsw_sp_flash_device(struct net_device *dev, + struct ethtool_flash *flash) +{ + struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + const struct firmware *firmware; + int err; + + if (flash->region != ETHTOOL_FLASH_ALL_REGIONS) + return -EOPNOTSUPP; + + dev_hold(dev); + rtnl_unlock(); + + err = request_firmware_direct(&firmware, flash->data, &dev->dev); + if (err) + goto out; + err = mlxsw_sp_firmware_flash(mlxsw_sp, firmware); + release_firmware(firmware); +out: + rtnl_lock(); + dev_put(dev); + return err; +} + static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = { .get_drvinfo = mlxsw_sp_port_get_drvinfo, .get_link = ethtool_op_get_link, @@ -2280,6 +2538,7 @@ static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = { .get_sset_count = mlxsw_sp_port_get_sset_count, .get_link_ksettings = mlxsw_sp_port_get_link_ksettings, .set_link_ksettings = mlxsw_sp_port_set_link_ksettings, + .flash_device = mlxsw_sp_flash_device, }; static int @@ -2398,24 +2657,12 @@ static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port) return 0; } -static int mlxsw_sp_port_pvid_vport_create(struct mlxsw_sp_port *mlxsw_sp_port) -{ - mlxsw_sp_port->pvid = 1; - - return mlxsw_sp_port_add_vid(mlxsw_sp_port->dev, 0, 1); -} - -static int mlxsw_sp_port_pvid_vport_destroy(struct mlxsw_sp_port *mlxsw_sp_port) -{ - return mlxsw_sp_port_kill_vid(mlxsw_sp_port->dev, 0, 1); -} - static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, bool split, u8 module, u8 width, u8 lane) { + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct mlxsw_sp_port *mlxsw_sp_port; struct net_device *dev; - size_t bytes; int err; dev = alloc_etherdev(sizeof(struct mlxsw_sp_port)); @@ -2426,23 +2673,13 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, mlxsw_sp_port->dev = dev; mlxsw_sp_port->mlxsw_sp = mlxsw_sp; mlxsw_sp_port->local_port = local_port; + mlxsw_sp_port->pvid = 1; mlxsw_sp_port->split = split; mlxsw_sp_port->mapping.module = module; mlxsw_sp_port->mapping.width = width; mlxsw_sp_port->mapping.lane = lane; mlxsw_sp_port->link.autoneg = 1; - bytes = DIV_ROUND_UP(VLAN_N_VID, BITS_PER_BYTE); - mlxsw_sp_port->active_vlans = kzalloc(bytes, GFP_KERNEL); - if (!mlxsw_sp_port->active_vlans) { - err = -ENOMEM; - goto err_port_active_vlans_alloc; - } - mlxsw_sp_port->untagged_vlans = kzalloc(bytes, GFP_KERNEL); - if (!mlxsw_sp_port->untagged_vlans) { - err = -ENOMEM; - goto err_port_untagged_vlans_alloc; - } - INIT_LIST_HEAD(&mlxsw_sp_port->vports_list); + INIT_LIST_HEAD(&mlxsw_sp_port->vlans_list); INIT_LIST_HEAD(&mlxsw_sp_port->mall_tc_list); mlxsw_sp_port->pcpu_stats = @@ -2547,11 +2784,18 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, goto err_port_dcb_init; } - err = mlxsw_sp_port_pvid_vport_create(mlxsw_sp_port); + err = mlxsw_sp_port_fids_init(mlxsw_sp_port); if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create PVID vPort\n", + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize FIDs\n", mlxsw_sp_port->local_port); - goto err_port_pvid_vport_create; + goto err_port_fids_init; + } + + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1); + if (IS_ERR(mlxsw_sp_port_vlan)) { + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n", + mlxsw_sp_port->local_port); + goto err_port_vlan_get; } mlxsw_sp_port_switchdev_init(mlxsw_sp_port); @@ -2572,8 +2816,10 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, err_register_netdev: mlxsw_sp->ports[local_port] = NULL; mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); - mlxsw_sp_port_pvid_vport_destroy(mlxsw_sp_port); -err_port_pvid_vport_create: + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); +err_port_vlan_get: + mlxsw_sp_port_fids_fini(mlxsw_sp_port); +err_port_fids_init: mlxsw_sp_port_dcb_fini(mlxsw_sp_port); err_port_dcb_init: err_port_ets_init: @@ -2591,10 +2837,6 @@ err_alloc_hw_stats: err_alloc_sample: free_percpu(mlxsw_sp_port->pcpu_stats); err_alloc_stats: - kfree(mlxsw_sp_port->untagged_vlans); -err_port_untagged_vlans_alloc: - kfree(mlxsw_sp_port->active_vlans); -err_port_active_vlans_alloc: free_netdev(dev); return err; } @@ -2630,16 +2872,15 @@ static void __mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */ mlxsw_sp->ports[local_port] = NULL; mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); - mlxsw_sp_port_pvid_vport_destroy(mlxsw_sp_port); + mlxsw_sp_port_vlan_flush(mlxsw_sp_port); + mlxsw_sp_port_fids_fini(mlxsw_sp_port); mlxsw_sp_port_dcb_fini(mlxsw_sp_port); mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT); mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port); kfree(mlxsw_sp_port->hw_stats.cache); kfree(mlxsw_sp_port->sample); free_percpu(mlxsw_sp_port->pcpu_stats); - kfree(mlxsw_sp_port->untagged_vlans); - kfree(mlxsw_sp_port->active_vlans); - WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vports_list)); + WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vlans_list)); free_netdev(mlxsw_sp_port->dev); } @@ -3020,7 +3261,9 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { MLXSW_SP_RXL_NO_MARK(BGP_IPV4, TRAP_TO_CPU, BGP_IPV4, false), /* PKT Sample trap */ MLXSW_RXL(mlxsw_sp_rx_listener_sample_func, PKT_SAMPLE, MIRROR_TO_CPU, - false, SP_IP2ME, DISCARD) + false, SP_IP2ME, DISCARD), + /* ACL trap */ + MLXSW_SP_RXL_NO_MARK(ACL0, TRAP_TO_CPU, IP2ME, false), }; static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core) @@ -3192,57 +3435,6 @@ static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) } } -static int __mlxsw_sp_flood_init(struct mlxsw_core *mlxsw_core, - enum mlxsw_reg_sfgc_type type, - enum mlxsw_reg_sfgc_bridge_type bridge_type) -{ - enum mlxsw_flood_table_type table_type; - enum mlxsw_sp_flood_table flood_table; - char sfgc_pl[MLXSW_REG_SFGC_LEN]; - - if (bridge_type == MLXSW_REG_SFGC_BRIDGE_TYPE_VFID) - table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID; - else - table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST; - - switch (type) { - case MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST: - flood_table = MLXSW_SP_FLOOD_TABLE_UC; - break; - case MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4: - flood_table = MLXSW_SP_FLOOD_TABLE_MC; - break; - default: - flood_table = MLXSW_SP_FLOOD_TABLE_BC; - } - - mlxsw_reg_sfgc_pack(sfgc_pl, type, bridge_type, table_type, - flood_table); - return mlxsw_reg_write(mlxsw_core, MLXSW_REG(sfgc), sfgc_pl); -} - -static int mlxsw_sp_flood_init(struct mlxsw_sp *mlxsw_sp) -{ - int type, err; - - for (type = 0; type < MLXSW_REG_SFGC_TYPE_MAX; type++) { - if (type == MLXSW_REG_SFGC_TYPE_RESERVED) - continue; - - err = __mlxsw_sp_flood_init(mlxsw_sp->core, type, - MLXSW_REG_SFGC_BRIDGE_TYPE_VFID); - if (err) - return err; - - err = __mlxsw_sp_flood_init(mlxsw_sp->core, type, - MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID); - if (err) - return err; - } - - return 0; -} - static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) { char slcr_pl[MLXSW_REG_SLCR_LEN]; @@ -3290,18 +3482,6 @@ static int mlxsw_sp_basic_trap_groups_set(struct mlxsw_core *mlxsw_core) return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); } -static int mlxsw_sp_vfid_op(struct mlxsw_sp *mlxsw_sp, u16 fid, bool create); - -static int mlxsw_sp_dummy_fid_init(struct mlxsw_sp *mlxsw_sp) -{ - return mlxsw_sp_vfid_op(mlxsw_sp, MLXSW_SP_DUMMY_FID, true); -} - -static void mlxsw_sp_dummy_fid_fini(struct mlxsw_sp *mlxsw_sp) -{ - mlxsw_sp_vfid_op(mlxsw_sp, MLXSW_SP_DUMMY_FID, false); -} - static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, const struct mlxsw_bus_info *mlxsw_bus_info) { @@ -3310,9 +3490,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->core = mlxsw_core; mlxsw_sp->bus_info = mlxsw_bus_info; - INIT_LIST_HEAD(&mlxsw_sp->fids); - INIT_LIST_HEAD(&mlxsw_sp->vfids.list); - INIT_LIST_HEAD(&mlxsw_sp->br_mids.list); + + err = mlxsw_sp_fw_rev_validate(mlxsw_sp); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Could not upgrade firmware\n"); + return err; + } err = mlxsw_sp_base_mac_get(mlxsw_sp); if (err) { @@ -3320,16 +3503,16 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, return err; } - err = mlxsw_sp_traps_init(mlxsw_sp); + err = mlxsw_sp_fids_init(mlxsw_sp); if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps\n"); + dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n"); return err; } - err = mlxsw_sp_flood_init(mlxsw_sp); + err = mlxsw_sp_traps_init(mlxsw_sp); if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize flood tables\n"); - goto err_flood_init; + dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps\n"); + goto err_traps_init; } err = mlxsw_sp_buffers_init(mlxsw_sp); @@ -3380,12 +3563,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, goto err_dpipe_init; } - err = mlxsw_sp_dummy_fid_init(mlxsw_sp); - if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Failed to init dummy FID\n"); - goto err_dummy_fid_init; - } - err = mlxsw_sp_ports_create(mlxsw_sp); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n"); @@ -3395,8 +3572,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, return 0; err_ports_create: - mlxsw_sp_dummy_fid_fini(mlxsw_sp); -err_dummy_fid_init: mlxsw_sp_dpipe_fini(mlxsw_sp); err_dpipe_init: mlxsw_sp_counter_pool_fini(mlxsw_sp); @@ -3413,8 +3588,9 @@ err_switchdev_init: err_lag_init: mlxsw_sp_buffers_fini(mlxsw_sp); err_buffers_init: -err_flood_init: mlxsw_sp_traps_fini(mlxsw_sp); +err_traps_init: + mlxsw_sp_fids_fini(mlxsw_sp); return err; } @@ -3423,7 +3599,6 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); mlxsw_sp_ports_remove(mlxsw_sp); - mlxsw_sp_dummy_fid_fini(mlxsw_sp); mlxsw_sp_dpipe_fini(mlxsw_sp); mlxsw_sp_counter_pool_fini(mlxsw_sp); mlxsw_sp_acl_fini(mlxsw_sp); @@ -3433,8 +3608,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) mlxsw_sp_lag_fini(mlxsw_sp); mlxsw_sp_buffers_fini(mlxsw_sp); mlxsw_sp_traps_fini(mlxsw_sp); - WARN_ON(!list_empty(&mlxsw_sp->vfids.list)); - WARN_ON(!list_empty(&mlxsw_sp->fids)); + mlxsw_sp_fids_fini(mlxsw_sp); } static struct mlxsw_config_profile mlxsw_sp_config_profile = { @@ -3450,7 +3624,7 @@ static struct mlxsw_config_profile mlxsw_sp_config_profile = { .max_fid_offset_flood_tables = 3, .fid_offset_flood_table_size = VLAN_N_VID - 1, .max_fid_flood_tables = 3, - .fid_flood_table_size = MLXSW_SP_VFID_MAX, + .fid_flood_table_size = MLXSW_SP_FID_8021D_MAX, .used_max_ib_mc = 1, .max_ib_mc = 0, .used_max_pkey = 1, @@ -3510,7 +3684,7 @@ static int mlxsw_sp_lower_dev_walk(struct net_device *lower_dev, void *data) return ret; } -static struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev) +struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev) { struct mlxsw_sp_port *mlxsw_sp_port; @@ -3562,176 +3736,6 @@ void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port) dev_put(mlxsw_sp_port->dev); } -static bool mlxsw_sp_lag_port_fid_member(struct mlxsw_sp_port *lag_port, - u16 fid) -{ - if (mlxsw_sp_fid_is_vfid(fid)) - return mlxsw_sp_port_vport_find_by_fid(lag_port, fid); - else - return test_bit(fid, lag_port->active_vlans); -} - -static bool mlxsw_sp_port_fdb_should_flush(struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - u8 local_port = mlxsw_sp_port->local_port; - u16 lag_id = mlxsw_sp_port->lag_id; - u64 max_lag_members; - int i, count = 0; - - if (!mlxsw_sp_port->lagged) - return true; - - max_lag_members = MLXSW_CORE_RES_GET(mlxsw_sp->core, - MAX_LAG_MEMBERS); - for (i = 0; i < max_lag_members; i++) { - struct mlxsw_sp_port *lag_port; - - lag_port = mlxsw_sp_port_lagged_get(mlxsw_sp, lag_id, i); - if (!lag_port || lag_port->local_port == local_port) - continue; - if (mlxsw_sp_lag_port_fid_member(lag_port, fid)) - count++; - } - - return !count; -} - -static int -mlxsw_sp_port_fdb_flush_by_port_fid(const struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - char sfdf_pl[MLXSW_REG_SFDF_LEN]; - - mlxsw_reg_sfdf_pack(sfdf_pl, MLXSW_REG_SFDF_FLUSH_PER_PORT_AND_FID); - mlxsw_reg_sfdf_fid_set(sfdf_pl, fid); - mlxsw_reg_sfdf_port_fid_system_port_set(sfdf_pl, - mlxsw_sp_port->local_port); - - netdev_dbg(mlxsw_sp_port->dev, "FDB flushed using Port=%d, FID=%d\n", - mlxsw_sp_port->local_port, fid); - - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl); -} - -static int -mlxsw_sp_port_fdb_flush_by_lag_id_fid(const struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - char sfdf_pl[MLXSW_REG_SFDF_LEN]; - - mlxsw_reg_sfdf_pack(sfdf_pl, MLXSW_REG_SFDF_FLUSH_PER_LAG_AND_FID); - mlxsw_reg_sfdf_fid_set(sfdf_pl, fid); - mlxsw_reg_sfdf_lag_fid_lag_id_set(sfdf_pl, mlxsw_sp_port->lag_id); - - netdev_dbg(mlxsw_sp_port->dev, "FDB flushed using LAG ID=%d, FID=%d\n", - mlxsw_sp_port->lag_id, fid); - - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl); -} - -int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid) -{ - if (!mlxsw_sp_port_fdb_should_flush(mlxsw_sp_port, fid)) - return 0; - - if (mlxsw_sp_port->lagged) - return mlxsw_sp_port_fdb_flush_by_lag_id_fid(mlxsw_sp_port, - fid); - else - return mlxsw_sp_port_fdb_flush_by_port_fid(mlxsw_sp_port, fid); -} - -static void mlxsw_sp_master_bridge_gone_sync(struct mlxsw_sp *mlxsw_sp) -{ - struct mlxsw_sp_fid *f, *tmp; - - list_for_each_entry_safe(f, tmp, &mlxsw_sp->fids, list) - if (--f->ref_count == 0) - mlxsw_sp_fid_destroy(mlxsw_sp, f); - else - WARN_ON_ONCE(1); -} - -static bool mlxsw_sp_master_bridge_check(struct mlxsw_sp *mlxsw_sp, - struct net_device *br_dev) -{ - return !mlxsw_sp->master_bridge.dev || - mlxsw_sp->master_bridge.dev == br_dev; -} - -static void mlxsw_sp_master_bridge_inc(struct mlxsw_sp *mlxsw_sp, - struct net_device *br_dev) -{ - mlxsw_sp->master_bridge.dev = br_dev; - mlxsw_sp->master_bridge.ref_count++; -} - -static void mlxsw_sp_master_bridge_dec(struct mlxsw_sp *mlxsw_sp) -{ - if (--mlxsw_sp->master_bridge.ref_count == 0) { - mlxsw_sp->master_bridge.dev = NULL; - /* It's possible upper VLAN devices are still holding - * references to underlying FIDs. Drop the reference - * and release the resources if it was the last one. - * If it wasn't, then something bad happened. - */ - mlxsw_sp_master_bridge_gone_sync(mlxsw_sp); - } -} - -static int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, - struct net_device *br_dev) -{ - struct net_device *dev = mlxsw_sp_port->dev; - int err; - - /* When port is not bridged untagged packets are tagged with - * PVID=VID=1, thereby creating an implicit VLAN interface in - * the device. Remove it and let bridge code take care of its - * own VLANs. - */ - err = mlxsw_sp_port_kill_vid(dev, 0, 1); - if (err) - return err; - - mlxsw_sp_master_bridge_inc(mlxsw_sp_port->mlxsw_sp, br_dev); - - mlxsw_sp_port->learning = 1; - mlxsw_sp_port->learning_sync = 1; - mlxsw_sp_port->uc_flood = 1; - mlxsw_sp_port->mc_flood = 1; - mlxsw_sp_port->mc_router = 0; - mlxsw_sp_port->mc_disabled = 1; - mlxsw_sp_port->bridged = 1; - - return 0; -} - -static void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port) -{ - struct net_device *dev = mlxsw_sp_port->dev; - - mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1); - - mlxsw_sp_master_bridge_dec(mlxsw_sp_port->mlxsw_sp); - - mlxsw_sp_port->learning = 0; - mlxsw_sp_port->learning_sync = 0; - mlxsw_sp_port->uc_flood = 0; - mlxsw_sp_port->mc_flood = 0; - mlxsw_sp_port->mc_router = 0; - mlxsw_sp_port->bridged = 0; - - /* Add implicit VLAN interface in the device, so that untagged - * packets will be classified to the default vFID. - */ - mlxsw_sp_port_add_vid(dev, 0, 1); -} - static int mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, u16 lag_id) { char sldr_pl[MLXSW_REG_SLDR_LEN]; @@ -3850,51 +3854,11 @@ static int mlxsw_sp_port_lag_index_get(struct mlxsw_sp *mlxsw_sp, return -EBUSY; } -static void -mlxsw_sp_port_pvid_vport_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, - struct net_device *lag_dev, u16 lag_id) -{ - struct mlxsw_sp_port *mlxsw_sp_vport; - struct mlxsw_sp_fid *f; - - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, 1); - if (WARN_ON(!mlxsw_sp_vport)) - return; - - /* If vPort is assigned a RIF, then leave it since it's no - * longer valid. - */ - f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - if (f) - f->leave(mlxsw_sp_vport); - - mlxsw_sp_vport->lag_id = lag_id; - mlxsw_sp_vport->lagged = 1; - mlxsw_sp_vport->dev = lag_dev; -} - -static void -mlxsw_sp_port_pvid_vport_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port) -{ - struct mlxsw_sp_port *mlxsw_sp_vport; - struct mlxsw_sp_fid *f; - - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, 1); - if (WARN_ON(!mlxsw_sp_vport)) - return; - - f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - if (f) - f->leave(mlxsw_sp_vport); - - mlxsw_sp_vport->dev = mlxsw_sp_port->dev; - mlxsw_sp_vport->lagged = 0; -} - static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, struct net_device *lag_dev) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct mlxsw_sp_upper *lag; u16 lag_id; u8 port_index; @@ -3927,7 +3891,10 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_port->lagged = 1; lag->ref_count++; - mlxsw_sp_port_pvid_vport_lag_join(mlxsw_sp_port, lag_dev, lag_id); + /* Port is no longer usable as a router interface */ + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, 1); + if (mlxsw_sp_port_vlan->fid) + mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); return 0; @@ -3954,10 +3921,8 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_lag_col_port_disable(mlxsw_sp_port, lag_id); mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id); - if (mlxsw_sp_port->bridged) { - mlxsw_sp_port_active_vlans_del(mlxsw_sp_port); - mlxsw_sp_port_bridge_leave(mlxsw_sp_port); - } + /* Any VLANs configured on the port are no longer valid */ + mlxsw_sp_port_vlan_flush(mlxsw_sp_port); if (lag->ref_count == 1) mlxsw_sp_lag_destroy(mlxsw_sp, lag_id); @@ -3967,7 +3932,9 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_port->lagged = 0; lag->ref_count--; - mlxsw_sp_port_pvid_vport_lag_leave(mlxsw_sp_port); + mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1); + /* Make sure untagged frames are allowed to ingress */ + mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1); } static int mlxsw_sp_lag_dist_port_add(struct mlxsw_sp_port *mlxsw_sp_port, @@ -4009,34 +3976,6 @@ static int mlxsw_sp_port_lag_changed(struct mlxsw_sp_port *mlxsw_sp_port, return mlxsw_sp_port_lag_tx_en_set(mlxsw_sp_port, info->tx_enabled); } -static int mlxsw_sp_port_vlan_link(struct mlxsw_sp_port *mlxsw_sp_port, - struct net_device *vlan_dev) -{ - struct mlxsw_sp_port *mlxsw_sp_vport; - u16 vid = vlan_dev_vlan_id(vlan_dev); - - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); - if (WARN_ON(!mlxsw_sp_vport)) - return -EINVAL; - - mlxsw_sp_vport->dev = vlan_dev; - - return 0; -} - -static void mlxsw_sp_port_vlan_unlink(struct mlxsw_sp_port *mlxsw_sp_port, - struct net_device *vlan_dev) -{ - struct mlxsw_sp_port *mlxsw_sp_vport; - u16 vid = vlan_dev_vlan_id(vlan_dev); - - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); - if (WARN_ON(!mlxsw_sp_vport)) - return; - - mlxsw_sp_vport->dev = mlxsw_sp_port->dev; -} - static int mlxsw_sp_port_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable) { @@ -4066,9 +4005,12 @@ static int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port) { int err; - err = mlxsw_sp_port_stp_set(mlxsw_sp_port, true); + err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); if (err) return err; + err = mlxsw_sp_port_stp_set(mlxsw_sp_port, true); + if (err) + goto err_port_stp_set; err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, 2, VLAN_N_VID - 1, true, false); if (err) @@ -4077,6 +4019,8 @@ static int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port) err_port_vlan_set: mlxsw_sp_port_stp_set(mlxsw_sp_port, false); +err_port_stp_set: + mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); return err; } @@ -4085,9 +4029,11 @@ static void mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port *mlxsw_sp_port) mlxsw_sp_port_vlan_set(mlxsw_sp_port, 2, VLAN_N_VID - 1, false, false); mlxsw_sp_port_stp_set(mlxsw_sp_port, false); + mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); } -static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev, +static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, + struct net_device *dev, unsigned long event, void *ptr) { struct netdev_notifier_changeupper_info *info; @@ -4110,10 +4056,6 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev, return -EINVAL; if (!info->linking) break; - /* HW limitation forbids to put ports to multiple bridges. */ - if (netif_is_bridge_master(upper_dev) && - !mlxsw_sp_master_bridge_check(mlxsw_sp, upper_dev)) - return -EINVAL; if (netif_is_lag_master(upper_dev) && !mlxsw_sp_master_lag_check(mlxsw_sp, upper_dev, info->upper_info)) @@ -4130,19 +4072,15 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev, break; case NETDEV_CHANGEUPPER: upper_dev = info->upper_dev; - if (is_vlan_dev(upper_dev)) { - if (info->linking) - err = mlxsw_sp_port_vlan_link(mlxsw_sp_port, - upper_dev); - else - mlxsw_sp_port_vlan_unlink(mlxsw_sp_port, - upper_dev); - } else if (netif_is_bridge_master(upper_dev)) { + if (netif_is_bridge_master(upper_dev)) { if (info->linking) err = mlxsw_sp_port_bridge_join(mlxsw_sp_port, + lower_dev, upper_dev); else - mlxsw_sp_port_bridge_leave(mlxsw_sp_port); + mlxsw_sp_port_bridge_leave(mlxsw_sp_port, + lower_dev, + upper_dev); } else if (netif_is_lag_master(upper_dev)) { if (info->linking) err = mlxsw_sp_port_lag_join(mlxsw_sp_port, @@ -4155,9 +4093,6 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev, err = mlxsw_sp_port_ovs_join(mlxsw_sp_port); else mlxsw_sp_port_ovs_leave(mlxsw_sp_port); - } else { - err = -EINVAL; - WARN_ON(1); } break; } @@ -4189,15 +4124,18 @@ static int mlxsw_sp_netdevice_port_lower_event(struct net_device *dev, return 0; } -static int mlxsw_sp_netdevice_port_event(struct net_device *dev, +static int mlxsw_sp_netdevice_port_event(struct net_device *lower_dev, + struct net_device *port_dev, unsigned long event, void *ptr) { switch (event) { case NETDEV_PRECHANGEUPPER: case NETDEV_CHANGEUPPER: - return mlxsw_sp_netdevice_port_upper_event(dev, event, ptr); + return mlxsw_sp_netdevice_port_upper_event(lower_dev, port_dev, + event, ptr); case NETDEV_CHANGELOWERSTATE: - return mlxsw_sp_netdevice_port_lower_event(dev, event, ptr); + return mlxsw_sp_netdevice_port_lower_event(port_dev, event, + ptr); } return 0; @@ -4212,7 +4150,8 @@ static int mlxsw_sp_netdevice_lag_event(struct net_device *lag_dev, netdev_for_each_lower_dev(lag_dev, dev, iter) { if (mlxsw_sp_port_dev_check(dev)) { - ret = mlxsw_sp_netdevice_port_event(dev, event, ptr); + ret = mlxsw_sp_netdevice_port_event(lag_dev, dev, event, + ptr); if (ret) return ret; } @@ -4221,322 +4160,33 @@ static int mlxsw_sp_netdevice_lag_event(struct net_device *lag_dev, return 0; } -static int mlxsw_sp_master_bridge_vlan_link(struct mlxsw_sp *mlxsw_sp, - struct net_device *vlan_dev) -{ - u16 fid = vlan_dev_vlan_id(vlan_dev); - struct mlxsw_sp_fid *f; - - f = mlxsw_sp_fid_find(mlxsw_sp, fid); - if (!f) { - f = mlxsw_sp_fid_create(mlxsw_sp, fid); - if (IS_ERR(f)) - return PTR_ERR(f); - } - - f->ref_count++; - - return 0; -} - -static void mlxsw_sp_master_bridge_vlan_unlink(struct mlxsw_sp *mlxsw_sp, - struct net_device *vlan_dev) -{ - u16 fid = vlan_dev_vlan_id(vlan_dev); - struct mlxsw_sp_fid *f; - - f = mlxsw_sp_fid_find(mlxsw_sp, fid); - if (f && f->rif) - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif); - if (f && --f->ref_count == 0) - mlxsw_sp_fid_destroy(mlxsw_sp, f); -} - -static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev, - unsigned long event, void *ptr) -{ - struct netdev_notifier_changeupper_info *info; - struct net_device *upper_dev; - struct mlxsw_sp *mlxsw_sp; - int err = 0; - - mlxsw_sp = mlxsw_sp_lower_get(br_dev); - if (!mlxsw_sp) - return 0; - - info = ptr; - - switch (event) { - case NETDEV_PRECHANGEUPPER: - upper_dev = info->upper_dev; - if (!is_vlan_dev(upper_dev)) - return -EINVAL; - if (is_vlan_dev(upper_dev) && - br_dev != mlxsw_sp->master_bridge.dev) - return -EINVAL; - break; - case NETDEV_CHANGEUPPER: - upper_dev = info->upper_dev; - if (is_vlan_dev(upper_dev)) { - if (info->linking) - err = mlxsw_sp_master_bridge_vlan_link(mlxsw_sp, - upper_dev); - else - mlxsw_sp_master_bridge_vlan_unlink(mlxsw_sp, - upper_dev); - } else { - err = -EINVAL; - WARN_ON(1); - } - break; - } - - return err; -} - -static u16 mlxsw_sp_avail_vfid_get(const struct mlxsw_sp *mlxsw_sp) -{ - return find_first_zero_bit(mlxsw_sp->vfids.mapped, - MLXSW_SP_VFID_MAX); -} - -static int mlxsw_sp_vfid_op(struct mlxsw_sp *mlxsw_sp, u16 fid, bool create) -{ - char sfmr_pl[MLXSW_REG_SFMR_LEN]; - - mlxsw_reg_sfmr_pack(sfmr_pl, !create, fid, 0); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); -} - -static void mlxsw_sp_vport_vfid_leave(struct mlxsw_sp_port *mlxsw_sp_vport); - -static struct mlxsw_sp_fid *mlxsw_sp_vfid_create(struct mlxsw_sp *mlxsw_sp, - struct net_device *br_dev) -{ - struct device *dev = mlxsw_sp->bus_info->dev; - struct mlxsw_sp_fid *f; - u16 vfid, fid; - int err; - - vfid = mlxsw_sp_avail_vfid_get(mlxsw_sp); - if (vfid == MLXSW_SP_VFID_MAX) { - dev_err(dev, "No available vFIDs\n"); - return ERR_PTR(-ERANGE); - } - - fid = mlxsw_sp_vfid_to_fid(vfid); - err = mlxsw_sp_vfid_op(mlxsw_sp, fid, true); - if (err) { - dev_err(dev, "Failed to create FID=%d\n", fid); - return ERR_PTR(err); - } - - f = kzalloc(sizeof(*f), GFP_KERNEL); - if (!f) - goto err_allocate_vfid; - - f->leave = mlxsw_sp_vport_vfid_leave; - f->fid = fid; - f->dev = br_dev; - - list_add(&f->list, &mlxsw_sp->vfids.list); - set_bit(vfid, mlxsw_sp->vfids.mapped); - - return f; - -err_allocate_vfid: - mlxsw_sp_vfid_op(mlxsw_sp, fid, false); - return ERR_PTR(-ENOMEM); -} - -static void mlxsw_sp_vfid_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_fid *f) -{ - u16 vfid = mlxsw_sp_fid_to_vfid(f->fid); - u16 fid = f->fid; - - clear_bit(vfid, mlxsw_sp->vfids.mapped); - list_del(&f->list); - - if (f->rif) - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif); - - kfree(f); - - mlxsw_sp_vfid_op(mlxsw_sp, fid, false); -} - -static int mlxsw_sp_vport_fid_map(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid, - bool valid) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); - - return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_vport, mt, valid, fid, - vid); -} - -static int mlxsw_sp_vport_vfid_join(struct mlxsw_sp_port *mlxsw_sp_vport, - struct net_device *br_dev) -{ - struct mlxsw_sp_fid *f; - int err; - - f = mlxsw_sp_vfid_find(mlxsw_sp_vport->mlxsw_sp, br_dev); - if (!f) { - f = mlxsw_sp_vfid_create(mlxsw_sp_vport->mlxsw_sp, br_dev); - if (IS_ERR(f)) - return PTR_ERR(f); - } - - err = mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, true); - if (err) - goto err_vport_flood_set; - - err = mlxsw_sp_vport_fid_map(mlxsw_sp_vport, f->fid, true); - if (err) - goto err_vport_fid_map; - - mlxsw_sp_vport_fid_set(mlxsw_sp_vport, f); - f->ref_count++; - - netdev_dbg(mlxsw_sp_vport->dev, "Joined FID=%d\n", f->fid); - - return 0; - -err_vport_fid_map: - mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, false); -err_vport_flood_set: - if (!f->ref_count) - mlxsw_sp_vfid_destroy(mlxsw_sp_vport->mlxsw_sp, f); - return err; -} - -static void mlxsw_sp_vport_vfid_leave(struct mlxsw_sp_port *mlxsw_sp_vport) -{ - struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - - netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid); - - mlxsw_sp_vport_fid_map(mlxsw_sp_vport, f->fid, false); - - mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, false); - - mlxsw_sp_port_fdb_flush(mlxsw_sp_vport, f->fid); - - mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); - if (--f->ref_count == 0) - mlxsw_sp_vfid_destroy(mlxsw_sp_vport->mlxsw_sp, f); -} - -static int mlxsw_sp_vport_bridge_join(struct mlxsw_sp_port *mlxsw_sp_vport, - struct net_device *br_dev) -{ - struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); - struct net_device *dev = mlxsw_sp_vport->dev; - int err; - - if (f && !WARN_ON(!f->leave)) - f->leave(mlxsw_sp_vport); - - err = mlxsw_sp_vport_vfid_join(mlxsw_sp_vport, br_dev); - if (err) { - netdev_err(dev, "Failed to join vFID\n"); - return err; - } - - err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true); - if (err) { - netdev_err(dev, "Failed to enable learning\n"); - goto err_port_vid_learning_set; - } - - mlxsw_sp_vport->learning = 1; - mlxsw_sp_vport->learning_sync = 1; - mlxsw_sp_vport->uc_flood = 1; - mlxsw_sp_vport->mc_flood = 1; - mlxsw_sp_vport->mc_router = 0; - mlxsw_sp_vport->mc_disabled = 1; - mlxsw_sp_vport->bridged = 1; - - return 0; - -err_port_vid_learning_set: - mlxsw_sp_vport_vfid_leave(mlxsw_sp_vport); - return err; -} - -static void mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport) -{ - u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); - - mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, false); - - mlxsw_sp_vport_vfid_leave(mlxsw_sp_vport); - - mlxsw_sp_vport->learning = 0; - mlxsw_sp_vport->learning_sync = 0; - mlxsw_sp_vport->uc_flood = 0; - mlxsw_sp_vport->mc_flood = 0; - mlxsw_sp_vport->mc_router = 0; - mlxsw_sp_vport->bridged = 0; -} - -static bool -mlxsw_sp_port_master_bridge_check(const struct mlxsw_sp_port *mlxsw_sp_port, - const struct net_device *br_dev) -{ - struct mlxsw_sp_port *mlxsw_sp_vport; - - list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list, - vport.list) { - struct net_device *dev = mlxsw_sp_vport_dev_get(mlxsw_sp_vport); - - if (dev && dev == br_dev) - return false; - } - - return true; -} - -static int mlxsw_sp_netdevice_vport_event(struct net_device *dev, - unsigned long event, void *ptr, - u16 vid) +static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev, + struct net_device *dev, + unsigned long event, void *ptr, + u16 vid) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); struct netdev_notifier_changeupper_info *info = ptr; - struct mlxsw_sp_port *mlxsw_sp_vport; struct net_device *upper_dev; int err = 0; - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); - if (!mlxsw_sp_vport) - return 0; - switch (event) { case NETDEV_PRECHANGEUPPER: upper_dev = info->upper_dev; if (!netif_is_bridge_master(upper_dev)) return -EINVAL; - if (!info->linking) - break; - /* We can't have multiple VLAN interfaces configured on - * the same port and being members in the same bridge. - */ - if (netif_is_bridge_master(upper_dev) && - !mlxsw_sp_port_master_bridge_check(mlxsw_sp_port, - upper_dev)) - return -EINVAL; break; case NETDEV_CHANGEUPPER: upper_dev = info->upper_dev; if (netif_is_bridge_master(upper_dev)) { if (info->linking) - err = mlxsw_sp_vport_bridge_join(mlxsw_sp_vport, - upper_dev); + err = mlxsw_sp_port_bridge_join(mlxsw_sp_port, + vlan_dev, + upper_dev); else - mlxsw_sp_vport_bridge_leave(mlxsw_sp_vport); + mlxsw_sp_port_bridge_leave(mlxsw_sp_port, + vlan_dev, + upper_dev); } else { err = -EINVAL; WARN_ON(1); @@ -4547,9 +4197,10 @@ static int mlxsw_sp_netdevice_vport_event(struct net_device *dev, return err; } -static int mlxsw_sp_netdevice_lag_vport_event(struct net_device *lag_dev, - unsigned long event, void *ptr, - u16 vid) +static int mlxsw_sp_netdevice_lag_port_vlan_event(struct net_device *vlan_dev, + struct net_device *lag_dev, + unsigned long event, + void *ptr, u16 vid) { struct net_device *dev; struct list_head *iter; @@ -4557,8 +4208,9 @@ static int mlxsw_sp_netdevice_lag_vport_event(struct net_device *lag_dev, netdev_for_each_lower_dev(lag_dev, dev, iter) { if (mlxsw_sp_port_dev_check(dev)) { - ret = mlxsw_sp_netdevice_vport_event(dev, event, ptr, - vid); + ret = mlxsw_sp_netdevice_port_vlan_event(vlan_dev, dev, + event, ptr, + vid); if (ret) return ret; } @@ -4574,11 +4226,12 @@ static int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev, u16 vid = vlan_dev_vlan_id(vlan_dev); if (mlxsw_sp_port_dev_check(real_dev)) - return mlxsw_sp_netdevice_vport_event(real_dev, event, ptr, - vid); + return mlxsw_sp_netdevice_port_vlan_event(vlan_dev, real_dev, + event, ptr, vid); else if (netif_is_lag_master(real_dev)) - return mlxsw_sp_netdevice_lag_vport_event(real_dev, event, ptr, - vid); + return mlxsw_sp_netdevice_lag_port_vlan_event(vlan_dev, + real_dev, event, + ptr, vid); return 0; } @@ -4603,11 +4256,9 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *unused, else if (mlxsw_sp_is_vrf_event(event, ptr)) err = mlxsw_sp_netdevice_vrf_event(dev, event, ptr); else if (mlxsw_sp_port_dev_check(dev)) - err = mlxsw_sp_netdevice_port_event(dev, event, ptr); + err = mlxsw_sp_netdevice_port_event(dev, dev, event, ptr); else if (netif_is_lag_master(dev)) err = mlxsw_sp_netdevice_lag_event(dev, event, ptr); - else if (netif_is_bridge_master(dev)) - err = mlxsw_sp_netdevice_bridge_event(dev, event, ptr); else if (is_vlan_dev(dev)) err = mlxsw_sp_netdevice_vlan_event(dev, event, ptr); @@ -4680,3 +4331,4 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>"); MODULE_DESCRIPTION("Mellanox Spectrum driver"); MODULE_DEVICE_TABLE(pci, mlxsw_sp_pci_id_table); +MODULE_FIRMWARE(MLXSW_SP_FW_FILENAME); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 0c23bc1e946d..4a7a39a9f1a1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -54,12 +54,7 @@ #include "core_acl_flex_keys.h" #include "core_acl_flex_actions.h" -#define MLXSW_SP_VFID_BASE VLAN_N_VID -#define MLXSW_SP_VFID_MAX 1024 /* Bridged VLAN interfaces */ - -#define MLXSW_SP_DUMMY_FID 15359 - -#define MLXSW_SP_RFID_BASE 15360 +#define MLXSW_SP_FID_8021D_MAX 1024 #define MLXSW_SP_MID_MAX 7000 @@ -78,13 +73,19 @@ struct mlxsw_sp_upper { unsigned int ref_count; }; -struct mlxsw_sp_fid { - void (*leave)(struct mlxsw_sp_port *mlxsw_sp_vport); - struct list_head list; - unsigned int ref_count; - struct net_device *dev; - struct mlxsw_sp_rif *rif; - u16 fid; +enum mlxsw_sp_rif_type { + MLXSW_SP_RIF_TYPE_SUBPORT, + MLXSW_SP_RIF_TYPE_VLAN, + MLXSW_SP_RIF_TYPE_FID, + MLXSW_SP_RIF_TYPE_MAX, +}; + +enum mlxsw_sp_fid_type { + MLXSW_SP_FID_TYPE_8021Q, + MLXSW_SP_FID_TYPE_8021D, + MLXSW_SP_FID_TYPE_RFID, + MLXSW_SP_FID_TYPE_DUMMY, + MLXSW_SP_FID_TYPE_MAX, }; struct mlxsw_sp_mid { @@ -95,85 +96,6 @@ struct mlxsw_sp_mid { unsigned int ref_count; }; -static inline u16 mlxsw_sp_vfid_to_fid(u16 vfid) -{ - return MLXSW_SP_VFID_BASE + vfid; -} - -static inline u16 mlxsw_sp_fid_to_vfid(u16 fid) -{ - return fid - MLXSW_SP_VFID_BASE; -} - -static inline bool mlxsw_sp_fid_is_vfid(u16 fid) -{ - return fid >= MLXSW_SP_VFID_BASE && fid < MLXSW_SP_DUMMY_FID; -} - -struct mlxsw_sp_sb_pr { - enum mlxsw_reg_sbpr_mode mode; - u32 size; -}; - -struct mlxsw_cp_sb_occ { - u32 cur; - u32 max; -}; - -struct mlxsw_sp_sb_cm { - u32 min_buff; - u32 max_buff; - u8 pool; - struct mlxsw_cp_sb_occ occ; -}; - -struct mlxsw_sp_sb_pm { - u32 min_buff; - u32 max_buff; - struct mlxsw_cp_sb_occ occ; -}; - -#define MLXSW_SP_SB_POOL_COUNT 4 -#define MLXSW_SP_SB_TC_COUNT 8 - -struct mlxsw_sp_sb_port { - struct mlxsw_sp_sb_cm cms[2][MLXSW_SP_SB_TC_COUNT]; - struct mlxsw_sp_sb_pm pms[2][MLXSW_SP_SB_POOL_COUNT]; -}; - -struct mlxsw_sp_sb { - struct mlxsw_sp_sb_pr prs[2][MLXSW_SP_SB_POOL_COUNT]; - struct mlxsw_sp_sb_port *ports; - u32 cell_size; -}; - -#define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE) - -struct mlxsw_sp_prefix_usage { - DECLARE_BITMAP(b, MLXSW_SP_PREFIX_COUNT); -}; - -enum mlxsw_sp_l3proto { - MLXSW_SP_L3_PROTO_IPV4, - MLXSW_SP_L3_PROTO_IPV6, -}; - -struct mlxsw_sp_lpm_tree { - u8 id; /* tree ID */ - unsigned int ref_count; - enum mlxsw_sp_l3proto proto; - struct mlxsw_sp_prefix_usage prefix_usage; -}; - -struct mlxsw_sp_fib; - -struct mlxsw_sp_vr { - u16 id; /* virtual router ID */ - u32 tb_id; /* kernel fib table id */ - unsigned int rif_count; - struct mlxsw_sp_fib *fib4; -}; - enum mlxsw_sp_span_type { MLXSW_SP_SPAN_EGRESS, MLXSW_SP_SPAN_INGRESS @@ -212,58 +134,25 @@ struct mlxsw_sp_port_mall_tc_entry { }; }; -struct mlxsw_sp_router { - struct mlxsw_sp_vr *vrs; - struct rhashtable neigh_ht; - struct rhashtable nexthop_group_ht; - struct rhashtable nexthop_ht; - struct { - struct mlxsw_sp_lpm_tree *trees; - unsigned int tree_count; - } lpm; - struct { - struct delayed_work dw; - unsigned long interval; /* ms */ - } neighs_update; - struct delayed_work nexthop_probe_dw; -#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */ - struct list_head nexthop_neighs_list; - bool aborted; -}; - +struct mlxsw_sp_sb; +struct mlxsw_sp_bridge; +struct mlxsw_sp_router; struct mlxsw_sp_acl; struct mlxsw_sp_counter_pool; +struct mlxsw_sp_fid_core; struct mlxsw_sp { - struct { - struct list_head list; - DECLARE_BITMAP(mapped, MLXSW_SP_VFID_MAX); - } vfids; - struct { - struct list_head list; - DECLARE_BITMAP(mapped, MLXSW_SP_MID_MAX); - } br_mids; - struct list_head fids; /* VLAN-aware bridge FIDs */ - struct mlxsw_sp_rif **rifs; struct mlxsw_sp_port **ports; struct mlxsw_core *core; const struct mlxsw_bus_info *bus_info; unsigned char base_mac[ETH_ALEN]; - struct { - struct delayed_work dw; -#define MLXSW_SP_DEFAULT_LEARNING_INTERVAL 100 - unsigned int interval; /* ms */ - } fdb_notify; -#define MLXSW_SP_MIN_AGEING_TIME 10 -#define MLXSW_SP_MAX_AGEING_TIME 1000000 -#define MLXSW_SP_DEFAULT_AGEING_TIME 300 - u32 ageing_time; - struct mlxsw_sp_upper master_bridge; struct mlxsw_sp_upper *lags; u8 *port_to_module; - struct mlxsw_sp_sb sb; - struct mlxsw_sp_router router; + struct mlxsw_sp_sb *sb; + struct mlxsw_sp_bridge *bridge; + struct mlxsw_sp_router *router; struct mlxsw_sp_acl *acl; + struct mlxsw_sp_fid_core *fid_core; struct { DECLARE_BITMAP(usage, MLXSW_SP_KVD_LINEAR_SIZE); } kvdl; @@ -273,7 +162,6 @@ struct mlxsw_sp { struct mlxsw_sp_span_entry *entries; int entries_count; } span; - struct notifier_block fib_nb; }; static inline struct mlxsw_sp_upper * @@ -282,18 +170,6 @@ mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id) return &mlxsw_sp->lags[lag_id]; } -static inline u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, - u32 cells) -{ - return mlxsw_sp->sb.cell_size * cells; -} - -static inline u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, - u32 bytes) -{ - return DIV_ROUND_UP(bytes, mlxsw_sp->sb.cell_size); -} - struct mlxsw_sp_port_pcpu_stats { u64 rx_packets; u64 rx_bytes; @@ -310,29 +186,28 @@ struct mlxsw_sp_port_sample { bool truncate; }; +struct mlxsw_sp_bridge_port; +struct mlxsw_sp_fid; + +struct mlxsw_sp_port_vlan { + struct list_head list; + struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp_fid *fid; + u16 vid; + struct mlxsw_sp_bridge_port *bridge_port; + struct list_head bridge_vlan_node; +}; + struct mlxsw_sp_port { struct net_device *dev; struct mlxsw_sp_port_pcpu_stats __percpu *pcpu_stats; struct mlxsw_sp *mlxsw_sp; u8 local_port; - u8 stp_state; - u16 learning:1, - learning_sync:1, - uc_flood:1, - mc_flood:1, - mc_router:1, - mc_disabled:1, - bridged:1, - lagged:1, + u8 lagged:1, split:1; u16 pvid; u16 lag_id; struct { - struct list_head list; - struct mlxsw_sp_fid *f; - u16 vid; - } vport; - struct { u8 tx_pause:1, rx_pause:1, autoneg:1; @@ -347,11 +222,6 @@ struct mlxsw_sp_port { u8 width; u8 lane; } mapping; - /* 802.1Q bridge VLANs */ - unsigned long *active_vlans; - unsigned long *untagged_vlans; - /* VLAN interfaces */ - struct list_head vports_list; /* TC handles */ struct list_head mall_tc_list; struct { @@ -360,13 +230,9 @@ struct mlxsw_sp_port { struct delayed_work update_dw; } hw_stats; struct mlxsw_sp_port_sample *sample; + struct list_head vlans_list; }; -bool mlxsw_sp_port_dev_check(const struct net_device *dev); -struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev); -struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev); -void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port); - static inline bool mlxsw_sp_port_is_pause_en(const struct mlxsw_sp_port *mlxsw_sp_port) { @@ -385,102 +251,28 @@ mlxsw_sp_port_lagged_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id, u8 port_index) return mlxsw_sp_port && mlxsw_sp_port->lagged ? mlxsw_sp_port : NULL; } -static inline u16 -mlxsw_sp_vport_vid_get(const struct mlxsw_sp_port *mlxsw_sp_vport) -{ - return mlxsw_sp_vport->vport.vid; -} - -static inline bool -mlxsw_sp_port_is_vport(const struct mlxsw_sp_port *mlxsw_sp_port) +static inline struct mlxsw_sp_port_vlan * +mlxsw_sp_port_vlan_find_by_vid(const struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid) { - u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port); + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - return vid != 0; -} - -static inline void mlxsw_sp_vport_fid_set(struct mlxsw_sp_port *mlxsw_sp_vport, - struct mlxsw_sp_fid *f) -{ - mlxsw_sp_vport->vport.f = f; -} - -static inline struct mlxsw_sp_fid * -mlxsw_sp_vport_fid_get(const struct mlxsw_sp_port *mlxsw_sp_vport) -{ - return mlxsw_sp_vport->vport.f; -} - -static inline struct net_device * -mlxsw_sp_vport_dev_get(const struct mlxsw_sp_port *mlxsw_sp_vport) -{ - struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - - return f ? f->dev : NULL; -} - -static inline struct mlxsw_sp_port * -mlxsw_sp_port_vport_find(const struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) -{ - struct mlxsw_sp_port *mlxsw_sp_vport; - - list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list, - vport.list) { - if (mlxsw_sp_vport_vid_get(mlxsw_sp_vport) == vid) - return mlxsw_sp_vport; + list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, + list) { + if (mlxsw_sp_port_vlan->vid == vid) + return mlxsw_sp_port_vlan; } return NULL; } -static inline struct mlxsw_sp_port * -mlxsw_sp_port_vport_find_by_fid(const struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid) -{ - struct mlxsw_sp_port *mlxsw_sp_vport; - - list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list, - vport.list) { - struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - - if (f && f->fid == fid) - return mlxsw_sp_vport; - } - - return NULL; -} - -static inline struct mlxsw_sp_fid *mlxsw_sp_fid_find(struct mlxsw_sp *mlxsw_sp, - u16 fid) -{ - struct mlxsw_sp_fid *f; - - list_for_each_entry(f, &mlxsw_sp->fids, list) - if (f->fid == fid) - return f; - - return NULL; -} - -static inline struct mlxsw_sp_fid * -mlxsw_sp_vfid_find(const struct mlxsw_sp *mlxsw_sp, - const struct net_device *br_dev) -{ - struct mlxsw_sp_fid *f; - - list_for_each_entry(f, &mlxsw_sp->vfids.list, list) - if (f->dev == br_dev) - return f; - - return NULL; -} - -enum mlxsw_sp_flood_table { - MLXSW_SP_FLOOD_TABLE_UC, - MLXSW_SP_FLOOD_TABLE_BC, - MLXSW_SP_FLOOD_TABLE_MC, +enum mlxsw_sp_flood_type { + MLXSW_SP_FLOOD_TYPE_UC, + MLXSW_SP_FLOOD_TYPE_BC, + MLXSW_SP_FLOOD_TYPE_MC, }; +/* spectrum_buffers.c */ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_buffers_fini(struct mlxsw_sp *mlxsw_sp); int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port); @@ -515,26 +307,26 @@ int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port, unsigned int sb_index, u16 tc_index, enum devlink_sb_pool_type pool_type, u32 *p_cur, u32 *p_max); +u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells); +u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes); +/* spectrum_switchdev.c */ int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp); -int mlxsw_sp_port_vlan_init(struct mlxsw_sp_port *mlxsw_sp_port); void mlxsw_sp_port_switchdev_init(struct mlxsw_sp_port *mlxsw_sp_port); void mlxsw_sp_port_switchdev_fini(struct mlxsw_sp_port *mlxsw_sp_port); -int mlxsw_sp_port_vid_to_fid_set(struct mlxsw_sp_port *mlxsw_sp_port, - enum mlxsw_reg_svfa_mt mt, bool valid, u16 fid, - u16 vid); -int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, - u16 vid_end, bool is_member, bool untagged); -int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid, - bool set); -void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port); -int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); -int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid); int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid, bool adding); -struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid); -void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *f); +void +mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); +int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, + struct net_device *brport_dev, + struct net_device *br_dev); +void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, + struct net_device *brport_dev, + struct net_device *br_dev); + +/* spectrum.c */ int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port, enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index, bool dwrr, u8 dwrr_weight); @@ -546,27 +338,44 @@ int __mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port, int mtu, int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port, enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index, u32 maxrate); -int __mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid_begin, u16 vid_end, - bool learn_enable); +int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, + u8 state); +int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable); +int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, + bool learn_enable); +int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); +struct mlxsw_sp_port_vlan * +mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); +void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); +int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, + u16 vid_end, bool is_member, bool untagged); +int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp, + unsigned int counter_index, u64 *packets, + u64 *bytes); +int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp, + unsigned int *p_counter_index); +void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp, + unsigned int counter_index); +bool mlxsw_sp_port_dev_check(const struct net_device *dev); +struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev); +struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev); +struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev); +void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port); +/* spectrum_dcb.c */ #ifdef CONFIG_MLXSW_SPECTRUM_DCB - int mlxsw_sp_port_dcb_init(struct mlxsw_sp_port *mlxsw_sp_port); void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port); - #else - static inline int mlxsw_sp_port_dcb_init(struct mlxsw_sp_port *mlxsw_sp_port) { return 0; } - static inline void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port) {} - #endif +/* spectrum_router.c */ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp); int mlxsw_sp_router_netevent_event(struct notifier_block *unused, @@ -574,17 +383,17 @@ int mlxsw_sp_router_netevent_event(struct notifier_block *unused, int mlxsw_sp_netdevice_router_port_event(struct net_device *dev); int mlxsw_sp_inetaddr_event(struct notifier_block *unused, unsigned long event, void *ptr); -void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_rif *rif); int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, struct netdev_notifier_changeupper_info *info); +void +mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); +void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif); +/* spectrum_kvdl.c */ int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count, u32 *p_entry_index); void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp, int entry_index); -struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl); - struct mlxsw_sp_acl_rule_info { unsigned int priority; struct mlxsw_afk_element_values values; @@ -625,6 +434,8 @@ struct mlxsw_sp_acl_ops { struct mlxsw_sp_acl_ruleset; +/* spectrum_acl.c */ +struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl); struct mlxsw_sp_acl_ruleset * mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp, struct net_device *dev, bool ingress, @@ -649,6 +460,7 @@ void mlxsw_sp_acl_rulei_act_continue(struct mlxsw_sp_acl_rule_info *rulei); void mlxsw_sp_acl_rulei_act_jump(struct mlxsw_sp_acl_rule_info *rulei, u16 group_id); int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei); +int mlxsw_sp_acl_rulei_act_trap(struct mlxsw_sp_acl_rule_info *rulei); int mlxsw_sp_acl_rulei_act_fwd(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_rule_info *rulei, struct net_device *out_dev); @@ -683,23 +495,48 @@ int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_rule *rule, u64 *packets, u64 *bytes, u64 *last_use); +struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp); + int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp); +/* spectrum_acl_tcam.c */ extern const struct mlxsw_sp_acl_ops mlxsw_sp_acl_tcam_ops; +/* spectrum_flower.c */ int mlxsw_sp_flower_replace(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, __be16 protocol, struct tc_cls_flower_offload *f); void mlxsw_sp_flower_destroy(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, struct tc_cls_flower_offload *f); int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, struct tc_cls_flower_offload *f); -int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp, - unsigned int counter_index, u64 *packets, - u64 *bytes); -int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp, - unsigned int *p_counter_index); -void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp, - unsigned int counter_index); + +/* spectrum_fid.c */ +int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, + enum mlxsw_sp_flood_type packet_type, u8 local_port, + bool member); +int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); +void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); +enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid); +u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid); +enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid); +void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif); +enum mlxsw_sp_rif_type +mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp, + enum mlxsw_sp_fid_type type); +u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid); +struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid); +struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp, + int br_ifindex); +struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp, + u16 rif_index); +struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp); +void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid); +int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port); +void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port); +int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp); +void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp); #endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index 317f7b14627f..01a1501b56ca 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@ -53,6 +53,7 @@ struct mlxsw_sp_acl { struct mlxsw_sp *mlxsw_sp; struct mlxsw_afk *afk; struct mlxsw_afa *afa; + struct mlxsw_sp_fid *dummy_fid; const struct mlxsw_sp_acl_ops *ops; struct rhashtable ruleset_ht; struct list_head rules; @@ -112,6 +113,11 @@ static const struct rhashtable_params mlxsw_sp_acl_rule_ht_params = { .automatic_shrinking = true, }; +struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp) +{ + return mlxsw_sp->acl->dummy_fid; +} + static struct mlxsw_sp_acl_ruleset * mlxsw_sp_acl_ruleset_create(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_acl_profile_ops *ops) @@ -341,6 +347,11 @@ int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei) return mlxsw_afa_block_append_drop(rulei->act_block); } +int mlxsw_sp_acl_rulei_act_trap(struct mlxsw_sp_acl_rule_info *rulei) +{ + return mlxsw_afa_block_append_trap(rulei->act_block); +} + int mlxsw_sp_acl_rulei_act_fwd(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_rule_info *rulei, struct net_device *out_dev) @@ -676,6 +687,7 @@ static const struct mlxsw_afa_ops mlxsw_sp_act_afa_ops = { int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp) { const struct mlxsw_sp_acl_ops *acl_ops = &mlxsw_sp_acl_tcam_ops; + struct mlxsw_sp_fid *fid; struct mlxsw_sp_acl *acl; int err; @@ -706,6 +718,13 @@ int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp) if (err) goto err_rhashtable_init; + fid = mlxsw_sp_fid_dummy_get(mlxsw_sp); + if (IS_ERR(fid)) { + err = PTR_ERR(fid); + goto err_fid_get; + } + acl->dummy_fid = fid; + INIT_LIST_HEAD(&acl->rules); err = acl_ops->init(mlxsw_sp, acl->priv); if (err) @@ -721,6 +740,8 @@ int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp) return 0; err_acl_ops_init: + mlxsw_sp_fid_put(fid); +err_fid_get: rhashtable_destroy(&acl->ruleset_ht); err_rhashtable_init: mlxsw_afa_destroy(acl->afa); @@ -739,6 +760,7 @@ void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp) cancel_delayed_work_sync(&mlxsw_sp->acl->rule_activity_update.dw); acl_ops->fini(mlxsw_sp, acl->priv); WARN_ON(!list_empty(&acl->rules)); + mlxsw_sp_fid_put(acl->dummy_fid); rhashtable_destroy(&acl->ruleset_ht); mlxsw_afa_destroy(acl->afa); mlxsw_afk_destroy(acl->afk); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.h index af7b7bad48df..85d5001a5818 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.h @@ -68,6 +68,11 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_dip[] = { MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16), }; +static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4[] = { + MLXSW_AFK_ELEMENT_INST_U32(SRC_IP4, 0x00, 0, 32), + MLXSW_AFK_ELEMENT_INST_U32(TCP_FLAGS, 0x08, 8, 9), /* TCP_CONTROL+TCP_ECN */ +}; + static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_ex[] = { MLXSW_AFK_ELEMENT_INST_U32(VID, 0x00, 0, 12), MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 29, 3), @@ -102,6 +107,7 @@ static const struct mlxsw_afk_block mlxsw_sp_afk_blocks[] = { MLXSW_AFK_BLOCK(0x12, mlxsw_sp_afk_element_info_l2_smac_ex), MLXSW_AFK_BLOCK(0x30, mlxsw_sp_afk_element_info_ipv4_sip), MLXSW_AFK_BLOCK(0x31, mlxsw_sp_afk_element_info_ipv4_dip), + MLXSW_AFK_BLOCK(0x32, mlxsw_sp_afk_element_info_ipv4), MLXSW_AFK_BLOCK(0x33, mlxsw_sp_afk_element_info_ipv4_ex), MLXSW_AFK_BLOCK(0x60, mlxsw_sp_afk_element_info_ipv6_dip), MLXSW_AFK_BLOCK(0x65, mlxsw_sp_afk_element_info_ipv6_ex1), diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index 3a24289979d9..61a10f166f97 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -983,6 +983,7 @@ static const enum mlxsw_afk_element mlxsw_sp_acl_tcam_pattern_ipv4[] = { MLXSW_AFK_ELEMENT_SRC_L4_PORT, MLXSW_AFK_ELEMENT_VID, MLXSW_AFK_ELEMENT_PCP, + MLXSW_AFK_ELEMENT_TCP_FLAGS, }; static const enum mlxsw_afk_element mlxsw_sp_acl_tcam_pattern_ipv6[] = { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index 997189cfe7fd..93728c694e6d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -43,25 +43,72 @@ #include "port.h" #include "reg.h" +struct mlxsw_sp_sb_pr { + enum mlxsw_reg_sbpr_mode mode; + u32 size; +}; + +struct mlxsw_cp_sb_occ { + u32 cur; + u32 max; +}; + +struct mlxsw_sp_sb_cm { + u32 min_buff; + u32 max_buff; + u8 pool; + struct mlxsw_cp_sb_occ occ; +}; + +struct mlxsw_sp_sb_pm { + u32 min_buff; + u32 max_buff; + struct mlxsw_cp_sb_occ occ; +}; + +#define MLXSW_SP_SB_POOL_COUNT 4 +#define MLXSW_SP_SB_TC_COUNT 8 + +struct mlxsw_sp_sb_port { + struct mlxsw_sp_sb_cm cms[2][MLXSW_SP_SB_TC_COUNT]; + struct mlxsw_sp_sb_pm pms[2][MLXSW_SP_SB_POOL_COUNT]; +}; + +struct mlxsw_sp_sb { + struct mlxsw_sp_sb_pr prs[2][MLXSW_SP_SB_POOL_COUNT]; + struct mlxsw_sp_sb_port *ports; + u32 cell_size; +}; + +u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells) +{ + return mlxsw_sp->sb->cell_size * cells; +} + +u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes) +{ + return DIV_ROUND_UP(bytes, mlxsw_sp->sb->cell_size); +} + static struct mlxsw_sp_sb_pr *mlxsw_sp_sb_pr_get(struct mlxsw_sp *mlxsw_sp, u8 pool, enum mlxsw_reg_sbxx_dir dir) { - return &mlxsw_sp->sb.prs[dir][pool]; + return &mlxsw_sp->sb->prs[dir][pool]; } static struct mlxsw_sp_sb_cm *mlxsw_sp_sb_cm_get(struct mlxsw_sp *mlxsw_sp, u8 local_port, u8 pg_buff, enum mlxsw_reg_sbxx_dir dir) { - return &mlxsw_sp->sb.ports[local_port].cms[dir][pg_buff]; + return &mlxsw_sp->sb->ports[local_port].cms[dir][pg_buff]; } static struct mlxsw_sp_sb_pm *mlxsw_sp_sb_pm_get(struct mlxsw_sp *mlxsw_sp, u8 local_port, u8 pool, enum mlxsw_reg_sbxx_dir dir) { - return &mlxsw_sp->sb.ports[local_port].pms[dir][pool]; + return &mlxsw_sp->sb->ports[local_port].pms[dir][pool]; } static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u8 pool, @@ -215,16 +262,17 @@ static int mlxsw_sp_sb_ports_init(struct mlxsw_sp *mlxsw_sp) { unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); - mlxsw_sp->sb.ports = kcalloc(max_ports, sizeof(struct mlxsw_sp_sb_port), - GFP_KERNEL); - if (!mlxsw_sp->sb.ports) + mlxsw_sp->sb->ports = kcalloc(max_ports, + sizeof(struct mlxsw_sp_sb_port), + GFP_KERNEL); + if (!mlxsw_sp->sb->ports) return -ENOMEM; return 0; } static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp) { - kfree(mlxsw_sp->sb.ports); + kfree(mlxsw_sp->sb->ports); } #define MLXSW_SP_SB_PR_INGRESS_SIZE 12440000 @@ -551,15 +599,19 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, CELL_SIZE)) return -EIO; - mlxsw_sp->sb.cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE); if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_BUFFER_SIZE)) return -EIO; sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE); + mlxsw_sp->sb = kzalloc(sizeof(*mlxsw_sp->sb), GFP_KERNEL); + if (!mlxsw_sp->sb) + return -ENOMEM; + mlxsw_sp->sb->cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE); + err = mlxsw_sp_sb_ports_init(mlxsw_sp); if (err) - return err; + goto err_sb_ports_init; err = mlxsw_sp_sb_prs_init(mlxsw_sp); if (err) goto err_sb_prs_init; @@ -584,6 +636,8 @@ err_sb_mms_init: err_sb_cpu_port_sb_cms_init: err_sb_prs_init: mlxsw_sp_sb_ports_fini(mlxsw_sp); +err_sb_ports_init: + kfree(mlxsw_sp->sb); return err; } @@ -591,6 +645,7 @@ void mlxsw_sp_buffers_fini(struct mlxsw_sp *mlxsw_sp) { devlink_sb_unregister(priv_to_devlink(mlxsw_sp->core), 0); mlxsw_sp_sb_ports_fini(mlxsw_sp); + kfree(mlxsw_sp->sb); } int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c index 5f0a7bc692a4..af2c65a3fd9f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c @@ -218,7 +218,7 @@ static int mlxsw_sp_table_erif_entries_dump(void *priv, bool counters_enabled, struct devlink_dpipe_dump_ctx *dump_ctx) { - struct devlink_dpipe_value match_value = {{0}}, action_value = {{0}}; + struct devlink_dpipe_value match_value, action_value; struct devlink_dpipe_action action = {0}; struct devlink_dpipe_match match = {0}; struct devlink_dpipe_entry entry = {0}; @@ -227,6 +227,9 @@ mlxsw_sp_table_erif_entries_dump(void *priv, bool counters_enabled, int i, j; int err; + memset(&match_value, 0, sizeof(match_value)); + memset(&action_value, 0, sizeof(action_value)); + mlxsw_sp_erif_match_action_prepare(&match, &action); err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match, &action_value, &action); @@ -242,10 +245,11 @@ start_again: return err; j = 0; for (; i < rif_count; i++) { - if (!mlxsw_sp->rifs[i]) + struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); + + if (!rif) continue; - err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, - mlxsw_sp->rifs[i], + err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif, counters_enabled); if (err) goto err_entry_get; @@ -282,15 +286,15 @@ static int mlxsw_sp_table_erif_counters_update(void *priv, bool enable) rtnl_lock(); for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { - if (!mlxsw_sp->rifs[i]) + struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); + + if (!rif) continue; if (enable) - mlxsw_sp_rif_counter_alloc(mlxsw_sp, - mlxsw_sp->rifs[i], + mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS); else - mlxsw_sp_rif_counter_free(mlxsw_sp, - mlxsw_sp->rifs[i], + mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS); } rtnl_unlock(); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c new file mode 100644 index 000000000000..6afbe9ec64e2 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -0,0 +1,992 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Ido Schimmel <idosch@mellanox.com> + * + * 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. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +#include <linux/kernel.h> +#include <linux/bitops.h> +#include <linux/if_vlan.h> +#include <linux/if_bridge.h> +#include <linux/netdevice.h> +#include <linux/rtnetlink.h> + +#include "spectrum.h" +#include "reg.h" + +struct mlxsw_sp_fid_family; + +struct mlxsw_sp_fid_core { + struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX]; + unsigned int *port_fid_mappings; +}; + +struct mlxsw_sp_fid { + struct list_head list; + struct mlxsw_sp_rif *rif; + unsigned int ref_count; + u16 fid_index; + struct mlxsw_sp_fid_family *fid_family; +}; + +struct mlxsw_sp_fid_8021q { + struct mlxsw_sp_fid common; + u16 vid; +}; + +struct mlxsw_sp_fid_8021d { + struct mlxsw_sp_fid common; + int br_ifindex; +}; + +struct mlxsw_sp_flood_table { + enum mlxsw_sp_flood_type packet_type; + enum mlxsw_reg_sfgc_bridge_type bridge_type; + enum mlxsw_flood_table_type table_type; + int table_index; +}; + +struct mlxsw_sp_fid_ops { + void (*setup)(struct mlxsw_sp_fid *fid, const void *arg); + int (*configure)(struct mlxsw_sp_fid *fid); + void (*deconfigure)(struct mlxsw_sp_fid *fid); + int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg, + u16 *p_fid_index); + bool (*compare)(const struct mlxsw_sp_fid *fid, + const void *arg); + u16 (*flood_index)(const struct mlxsw_sp_fid *fid); + int (*port_vid_map)(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *port, u16 vid); + void (*port_vid_unmap)(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *port, u16 vid); +}; + +struct mlxsw_sp_fid_family { + enum mlxsw_sp_fid_type type; + size_t fid_size; + u16 start_index; + u16 end_index; + struct list_head fids_list; + unsigned long *fids_bitmap; + const struct mlxsw_sp_flood_table *flood_tables; + int nr_flood_tables; + enum mlxsw_sp_rif_type rif_type; + const struct mlxsw_sp_fid_ops *ops; + struct mlxsw_sp *mlxsw_sp; +}; + +static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1, +}; + +static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1, + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1, + [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1, + [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1, +}; + +static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, +}; + +static const int *mlxsw_sp_packet_type_sfgc_types[] = { + [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types, + [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types, + [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types, +}; + +static const struct mlxsw_sp_flood_table * +mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid, + enum mlxsw_sp_flood_type packet_type) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + int i; + + for (i = 0; i < fid_family->nr_flood_tables; i++) { + if (fid_family->flood_tables[i].packet_type != packet_type) + continue; + return &fid_family->flood_tables[i]; + } + + return NULL; +} + +int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, + enum mlxsw_sp_flood_type packet_type, u8 local_port, + bool member) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + const struct mlxsw_sp_fid_ops *ops = fid_family->ops; + const struct mlxsw_sp_flood_table *flood_table; + char *sftr_pl; + int err; + + if (WARN_ON(!fid_family->flood_tables || !ops->flood_index)) + return -EINVAL; + + flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type); + if (!flood_table) + return -ESRCH; + + sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL); + if (!sftr_pl) + return -ENOMEM; + + mlxsw_reg_sftr_pack(sftr_pl, flood_table->table_index, + ops->flood_index(fid), flood_table->table_type, 1, + local_port, member); + err = mlxsw_reg_write(fid_family->mlxsw_sp->core, MLXSW_REG(sftr), + sftr_pl); + kfree(sftr_pl); + return err; +} + +int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + if (WARN_ON(!fid->fid_family->ops->port_vid_map)) + return -EINVAL; + return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid); +} + +void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid); +} + +enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_family->rif_type; +} + +u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_index; +} + +enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_family->type; +} + +void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif) +{ + fid->rif = rif; +} + +enum mlxsw_sp_rif_type +mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp, + enum mlxsw_sp_fid_type type) +{ + struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; + + return fid_core->fid_family_arr[type]->rif_type; +} + +static struct mlxsw_sp_fid_8021q * +mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid) +{ + return container_of(fid, struct mlxsw_sp_fid_8021q, common); +} + +u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid) +{ + return mlxsw_sp_fid_8021q_fid(fid)->vid; +} + +static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg) +{ + u16 vid = *(u16 *) arg; + + mlxsw_sp_fid_8021q_fid(fid)->vid = vid; +} + +static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid) +{ + return valid ? MLXSW_REG_SFMR_OP_CREATE_FID : + MLXSW_REG_SFMR_OP_DESTROY_FID; +} + +static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, + u16 fid_offset, bool valid) +{ + char sfmr_pl[MLXSW_REG_SFMR_LEN]; + + mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index, + fid_offset); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); +} + +static int mlxsw_sp_fid_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, + u16 vid, bool valid) +{ + enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID; + char svfa_pl[MLXSW_REG_SVFA_LEN]; + + mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid_index, vid); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); +} + +static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, + u8 local_port, u16 vid, bool valid) +{ + enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; + char svfa_pl[MLXSW_REG_SVFA_LEN]; + + mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); +} + +static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + struct mlxsw_sp_fid_8021q *fid_8021q; + int err; + + err = mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, fid->fid_index, true); + if (err) + return err; + + fid_8021q = mlxsw_sp_fid_8021q_fid(fid); + err = mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, + true); + if (err) + goto err_fid_map; + + return 0; + +err_fid_map: + mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false); + return err; +} + +static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + struct mlxsw_sp_fid_8021q *fid_8021q; + + fid_8021q = mlxsw_sp_fid_8021q_fid(fid); + mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, false); + mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false); +} + +static int mlxsw_sp_fid_8021q_index_alloc(struct mlxsw_sp_fid *fid, + const void *arg, u16 *p_fid_index) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + u16 vid = *(u16 *) arg; + + /* Use 1:1 mapping for simplicity although not a must */ + if (vid < fid_family->start_index || vid > fid_family->end_index) + return -EINVAL; + *p_fid_index = vid; + + return 0; +} + +static bool +mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg) +{ + u16 vid = *(u16 *) arg; + + return mlxsw_sp_fid_8021q_fid(fid)->vid == vid; +} + +static u16 mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_index; +} + +static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + + /* In case there are no {Port, VID} => FID mappings on the port, + * we can use the global VID => FID mapping we created when the + * FID was configured. + */ + if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0) + return 0; + return __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, + vid, true); +} + +static void +mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + + if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0) + return; + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, vid, + false); +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = { + .setup = mlxsw_sp_fid_8021q_setup, + .configure = mlxsw_sp_fid_8021q_configure, + .deconfigure = mlxsw_sp_fid_8021q_deconfigure, + .index_alloc = mlxsw_sp_fid_8021q_index_alloc, + .compare = mlxsw_sp_fid_8021q_compare, + .flood_index = mlxsw_sp_fid_8021q_flood_index, + .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap, +}; + +static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021q_flood_tables[] = { + { + .packet_type = MLXSW_SP_FLOOD_TYPE_UC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, + .table_index = 0, + }, + { + .packet_type = MLXSW_SP_FLOOD_TYPE_MC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, + .table_index = 1, + }, + { + .packet_type = MLXSW_SP_FLOOD_TYPE_BC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, + .table_index = 2, + }, +}; + +/* Range and flood configuration must match mlxsw_config_profile */ +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_family = { + .type = MLXSW_SP_FID_TYPE_8021Q, + .fid_size = sizeof(struct mlxsw_sp_fid_8021q), + .start_index = 1, + .end_index = VLAN_VID_MASK, + .flood_tables = mlxsw_sp_fid_8021q_flood_tables, + .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021q_flood_tables), + .rif_type = MLXSW_SP_RIF_TYPE_VLAN, + .ops = &mlxsw_sp_fid_8021q_ops, +}; + +static struct mlxsw_sp_fid_8021d * +mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid) +{ + return container_of(fid, struct mlxsw_sp_fid_8021d, common); +} + +static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg) +{ + int br_ifindex = *(int *) arg; + + mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex; +} + +static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + + return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true); +} + +static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid) +{ + mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false); +} + +static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid, + const void *arg, u16 *p_fid_index) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + u16 nr_fids, fid_index; + + nr_fids = fid_family->end_index - fid_family->start_index + 1; + fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids); + if (fid_index == nr_fids) + return -ENOBUFS; + *p_fid_index = fid_family->start_index + fid_index; + + return 0; +} + +static bool +mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg) +{ + int br_ifindex = *(int *) arg; + + return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex; +} + +static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_index - fid->fid_family->start_index; +} + +static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + int err; + + list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, + list) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u16 vid = mlxsw_sp_port_vlan->vid; + + if (!fid) + continue; + + err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, + vid, true); + if (err) + goto err_fid_port_vid_map; + } + + err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); + if (err) + goto err_port_vp_mode_set; + + return 0; + +err_port_vp_mode_set: +err_fid_port_vid_map: + list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan, + &mlxsw_sp_port->vlans_list, list) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u16 vid = mlxsw_sp_port_vlan->vid; + + if (!fid) + continue; + + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, + false); + } + return err; +} + +static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); + + list_for_each_entry_reverse(mlxsw_sp_port_vlan, + &mlxsw_sp_port->vlans_list, list) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u16 vid = mlxsw_sp_port_vlan->vid; + + if (!fid) + continue; + + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, + false); + } +} + +static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + int err; + + err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, true); + if (err) + return err; + + if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { + err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); + if (err) + goto err_port_vp_mode_trans; + } + + return 0; + +err_port_vp_mode_trans: + mlxsw_sp->fid_core->port_fid_mappings[local_port]--; + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, false); + return err; +} + +static void +mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + + if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) + mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); + mlxsw_sp->fid_core->port_fid_mappings[local_port]--; + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, false); +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { + .setup = mlxsw_sp_fid_8021d_setup, + .configure = mlxsw_sp_fid_8021d_configure, + .deconfigure = mlxsw_sp_fid_8021d_deconfigure, + .index_alloc = mlxsw_sp_fid_8021d_index_alloc, + .compare = mlxsw_sp_fid_8021d_compare, + .flood_index = mlxsw_sp_fid_8021d_flood_index, + .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap, +}; + +static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = { + { + .packet_type = MLXSW_SP_FLOOD_TYPE_UC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, + .table_index = 0, + }, + { + .packet_type = MLXSW_SP_FLOOD_TYPE_MC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, + .table_index = 1, + }, + { + .packet_type = MLXSW_SP_FLOOD_TYPE_BC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, + .table_index = 2, + }, +}; + +/* Range and flood configuration must match mlxsw_config_profile */ +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = { + .type = MLXSW_SP_FID_TYPE_8021D, + .fid_size = sizeof(struct mlxsw_sp_fid_8021d), + .start_index = VLAN_N_VID, + .end_index = VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1, + .flood_tables = mlxsw_sp_fid_8021d_flood_tables, + .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), + .rif_type = MLXSW_SP_RIF_TYPE_FID, + .ops = &mlxsw_sp_fid_8021d_ops, +}; + +static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid) +{ + /* rFIDs are allocated by the device during init */ + return 0; +} + +static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid) +{ +} + +static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid, + const void *arg, u16 *p_fid_index) +{ + u16 rif_index = *(u16 *) arg; + + *p_fid_index = fid->fid_family->start_index + rif_index; + + return 0; +} + +static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid, + const void *arg) +{ + u16 rif_index = *(u16 *) arg; + + return fid->fid_index == rif_index + fid->fid_family->start_index; +} + +static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + int err; + + /* We only need to transition the port to virtual mode since + * {Port, VID} => FID is done by the firmware upon RIF creation. + */ + if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { + err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); + if (err) + goto err_port_vp_mode_trans; + } + + return 0; + +err_port_vp_mode_trans: + mlxsw_sp->fid_core->port_fid_mappings[local_port]--; + return err; +} + +static void +mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + + if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) + mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); + mlxsw_sp->fid_core->port_fid_mappings[local_port]--; +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = { + .configure = mlxsw_sp_fid_rfid_configure, + .deconfigure = mlxsw_sp_fid_rfid_deconfigure, + .index_alloc = mlxsw_sp_fid_rfid_index_alloc, + .compare = mlxsw_sp_fid_rfid_compare, + .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap, +}; + +#define MLXSW_SP_RFID_BASE (15 * 1024) +#define MLXSW_SP_RFID_MAX 1024 + +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = { + .type = MLXSW_SP_FID_TYPE_RFID, + .fid_size = sizeof(struct mlxsw_sp_fid), + .start_index = MLXSW_SP_RFID_BASE, + .end_index = MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1, + .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT, + .ops = &mlxsw_sp_fid_rfid_ops, +}; + +static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + + return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true); +} + +static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid) +{ + mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false); +} + +static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid, + const void *arg, u16 *p_fid_index) +{ + *p_fid_index = fid->fid_family->start_index; + + return 0; +} + +static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid, + const void *arg) +{ + return true; +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = { + .configure = mlxsw_sp_fid_dummy_configure, + .deconfigure = mlxsw_sp_fid_dummy_deconfigure, + .index_alloc = mlxsw_sp_fid_dummy_index_alloc, + .compare = mlxsw_sp_fid_dummy_compare, +}; + +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = { + .type = MLXSW_SP_FID_TYPE_DUMMY, + .fid_size = sizeof(struct mlxsw_sp_fid), + .start_index = MLXSW_SP_RFID_BASE - 1, + .end_index = MLXSW_SP_RFID_BASE - 1, + .ops = &mlxsw_sp_fid_dummy_ops, +}; + +static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = { + [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp_fid_8021q_family, + [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp_fid_8021d_family, + [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family, + [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family, +}; + +static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, + enum mlxsw_sp_fid_type type, + const void *arg) +{ + struct mlxsw_sp_fid_family *fid_family; + struct mlxsw_sp_fid *fid; + u16 fid_index; + int err; + + fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; + list_for_each_entry(fid, &fid_family->fids_list, list) { + if (!fid->fid_family->ops->compare(fid, arg)) + continue; + fid->ref_count++; + return fid; + } + + fid = kzalloc(fid_family->fid_size, GFP_KERNEL); + if (!fid) + return ERR_PTR(-ENOMEM); + fid->fid_family = fid_family; + + err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index); + if (err) + goto err_index_alloc; + fid->fid_index = fid_index; + __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap); + + if (fid->fid_family->ops->setup) + fid->fid_family->ops->setup(fid, arg); + + err = fid->fid_family->ops->configure(fid); + if (err) + goto err_configure; + + list_add(&fid->list, &fid_family->fids_list); + fid->ref_count++; + return fid; + +err_configure: + __clear_bit(fid_index - fid_family->start_index, + fid_family->fids_bitmap); +err_index_alloc: + kfree(fid); + return ERR_PTR(err); +} + +void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + + if (--fid->ref_count == 1 && fid->rif) { + /* Destroy the associated RIF and let it drop the last + * reference on the FID. + */ + return mlxsw_sp_rif_destroy(fid->rif); + } else if (fid->ref_count == 0) { + list_del(&fid->list); + fid->fid_family->ops->deconfigure(fid); + __clear_bit(fid->fid_index - fid_family->start_index, + fid_family->fids_bitmap); + kfree(fid); + } +} + +struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid) +{ + return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid); +} + +struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp, + int br_ifindex) +{ + return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex); +} + +struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp, + u16 rif_index) +{ + return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index); +} + +struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp) +{ + return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL); +} + +static int +mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_flood_table *flood_table) +{ + enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; + const int *sfgc_packet_types; + int i; + + sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; + for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { + struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; + char sfgc_pl[MLXSW_REG_SFGC_LEN]; + int err; + + if (!sfgc_packet_types[i]) + continue; + mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type, + flood_table->table_type, + flood_table->table_index); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl); + if (err) + return err; + } + + return 0; +} + +static int +mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) +{ + int i; + + for (i = 0; i < fid_family->nr_flood_tables; i++) { + const struct mlxsw_sp_flood_table *flood_table; + int err; + + flood_table = &fid_family->flood_tables[i]; + err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table); + if (err) + return err; + } + + return 0; +} + +static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_fid_family *tmpl) +{ + u16 nr_fids = tmpl->end_index - tmpl->start_index + 1; + struct mlxsw_sp_fid_family *fid_family; + int err; + + fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL); + if (!fid_family) + return -ENOMEM; + + fid_family->mlxsw_sp = mlxsw_sp; + INIT_LIST_HEAD(&fid_family->fids_list); + fid_family->fids_bitmap = kcalloc(BITS_TO_LONGS(nr_fids), + sizeof(unsigned long), GFP_KERNEL); + if (!fid_family->fids_bitmap) { + err = -ENOMEM; + goto err_alloc_fids_bitmap; + } + + if (fid_family->flood_tables) { + err = mlxsw_sp_fid_flood_tables_init(fid_family); + if (err) + goto err_fid_flood_tables_init; + } + + mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family; + + return 0; + +err_fid_flood_tables_init: + kfree(fid_family->fids_bitmap); +err_alloc_fids_bitmap: + kfree(fid_family); + return err; +} + +static void +mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid_family *fid_family) +{ + mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL; + kfree(fid_family->fids_bitmap); + WARN_ON_ONCE(!list_empty(&fid_family->fids_list)); + kfree(fid_family); +} + +int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + + /* Track number of FIDs configured on the port with mapping type + * PORT_VID_TO_FID, so that we know when to transition the port + * back to non-virtual (VLAN) mode. + */ + mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; + + return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); +} + +void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + + mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; +} + +int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp) +{ + unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); + struct mlxsw_sp_fid_core *fid_core; + int err, i; + + fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL); + if (!fid_core) + return -ENOMEM; + mlxsw_sp->fid_core = fid_core; + + fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int), + GFP_KERNEL); + if (!fid_core->port_fid_mappings) { + err = -ENOMEM; + goto err_alloc_port_fid_mappings; + } + + for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) { + err = mlxsw_sp_fid_family_register(mlxsw_sp, + mlxsw_sp_fid_family_arr[i]); + + if (err) + goto err_fid_ops_register; + } + + return 0; + +err_fid_ops_register: + for (i--; i >= 0; i--) { + struct mlxsw_sp_fid_family *fid_family; + + fid_family = fid_core->fid_family_arr[i]; + mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family); + } + kfree(fid_core->port_fid_mappings); +err_alloc_port_fid_mappings: + kfree(fid_core); + return err; +} + +void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp) +{ + struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; + int i; + + for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) + mlxsw_sp_fid_family_unregister(mlxsw_sp, + fid_core->fid_family_arr[i]); + kfree(fid_core->port_fid_mappings); + kfree(fid_core); +} diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 7d87e23578a3..21bb2bf62d3e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -67,12 +67,20 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, err = mlxsw_sp_acl_rulei_act_drop(rulei); if (err) return err; + } else if (is_tcf_gact_trap(a)) { + err = mlxsw_sp_acl_rulei_act_trap(rulei); + if (err) + return err; } else if (is_tcf_mirred_egress_redirect(a)) { int ifindex = tcf_mirred_ifindex(a); struct net_device *out_dev; + struct mlxsw_sp_fid *fid; + u16 fid_index; + fid = mlxsw_sp_acl_dummy_fid(mlxsw_sp); + fid_index = mlxsw_sp_fid_index(fid); err = mlxsw_sp_acl_rulei_act_fid_set(mlxsw_sp, rulei, - MLXSW_SP_DUMMY_FID); + fid_index); if (err) return err; @@ -178,6 +186,32 @@ static int mlxsw_sp_flower_parse_ports(struct mlxsw_sp *mlxsw_sp, return 0; } +static int mlxsw_sp_flower_parse_tcp(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_rule_info *rulei, + struct tc_cls_flower_offload *f, + u8 ip_proto) +{ + struct flow_dissector_key_tcp *key, *mask; + + if (!dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_TCP)) + return 0; + + if (ip_proto != IPPROTO_TCP) { + dev_err(mlxsw_sp->bus_info->dev, "TCP keys supported only for TCP\n"); + return -EINVAL; + } + + key = skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_TCP, + f->key); + mask = skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_TCP, + f->mask); + mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_TCP_FLAGS, + ntohs(key->flags), ntohs(mask->flags)); + return 0; +} + static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp, struct net_device *dev, struct mlxsw_sp_acl_rule_info *rulei, @@ -194,6 +228,7 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp, BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | BIT(FLOW_DISSECTOR_KEY_PORTS) | + BIT(FLOW_DISSECTOR_KEY_TCP) | BIT(FLOW_DISSECTOR_KEY_VLAN))) { dev_err(mlxsw_sp->bus_info->dev, "Unsupported key\n"); return -EOPNOTSUPP; @@ -285,6 +320,9 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp, err = mlxsw_sp_flower_parse_ports(mlxsw_sp, rulei, f, ip_proto); if (err) return err; + err = mlxsw_sp_flower_parse_tcp(mlxsw_sp, rulei, f, ip_proto); + if (err) + return err; return mlxsw_sp_flower_parse_actions(mlxsw_sp, dev, rulei, f->exts); } @@ -363,8 +401,6 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp_acl_ruleset *ruleset; struct mlxsw_sp_acl_rule *rule; - struct tc_action *a; - LIST_HEAD(actions); u64 packets; u64 lastuse; u64 bytes; @@ -385,13 +421,7 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, if (err) goto err_rule_get_stats; - preempt_disable(); - - tcf_exts_to_list(f->exts, &actions); - list_for_each_entry(a, &actions, list) - tcf_action_stats_update(a, bytes, packets, lastuse); - - preempt_enable(); + tcf_exts_stats_update(f->exts, bytes, packets, lastuse); mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset); return 0; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 9f89c4137d21..20061058801e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -42,6 +42,7 @@ #include <linux/notifier.h> #include <linux/inetdevice.h> #include <linux/netdevice.h> +#include <linux/if_bridge.h> #include <net/netevent.h> #include <net/neighbour.h> #include <net/arp.h> @@ -56,21 +57,82 @@ #include "spectrum_dpipe.h" #include "spectrum_router.h" +struct mlxsw_sp_vr; +struct mlxsw_sp_lpm_tree; +struct mlxsw_sp_rif_ops; + +struct mlxsw_sp_router { + struct mlxsw_sp *mlxsw_sp; + struct mlxsw_sp_rif **rifs; + struct mlxsw_sp_vr *vrs; + struct rhashtable neigh_ht; + struct rhashtable nexthop_group_ht; + struct rhashtable nexthop_ht; + struct { + struct mlxsw_sp_lpm_tree *trees; + unsigned int tree_count; + } lpm; + struct { + struct delayed_work dw; + unsigned long interval; /* ms */ + } neighs_update; + struct delayed_work nexthop_probe_dw; +#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */ + struct list_head nexthop_neighs_list; + bool aborted; + struct notifier_block fib_nb; + const struct mlxsw_sp_rif_ops **rif_ops_arr; +}; + struct mlxsw_sp_rif { struct list_head nexthop_list; struct list_head neigh_list; struct net_device *dev; - struct mlxsw_sp_fid *f; + struct mlxsw_sp_fid *fid; unsigned char addr[ETH_ALEN]; int mtu; u16 rif_index; u16 vr_id; + const struct mlxsw_sp_rif_ops *ops; + struct mlxsw_sp *mlxsw_sp; + unsigned int counter_ingress; bool counter_ingress_valid; unsigned int counter_egress; bool counter_egress_valid; }; +struct mlxsw_sp_rif_params { + struct net_device *dev; + union { + u16 system_port; + u16 lag_id; + }; + u16 vid; + bool lag; +}; + +struct mlxsw_sp_rif_subport { + struct mlxsw_sp_rif common; + union { + u16 system_port; + u16 lag_id; + }; + u16 vid; + bool lag; +}; + +struct mlxsw_sp_rif_ops { + enum mlxsw_sp_rif_type type; + size_t rif_size; + + void (*setup)(struct mlxsw_sp_rif *rif, + const struct mlxsw_sp_rif_params *params); + int (*configure)(struct mlxsw_sp_rif *rif); + void (*deconfigure)(struct mlxsw_sp_rif *rif); + struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif); +}; + static unsigned int * mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif *rif, enum mlxsw_sp_rif_counter_dir dir) @@ -219,10 +281,35 @@ void mlxsw_sp_rif_counter_free(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_rif_counter_valid_set(rif, dir, false); } +static void mlxsw_sp_rif_counters_alloc(struct mlxsw_sp_rif *rif) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + struct devlink *devlink; + + devlink = priv_to_devlink(mlxsw_sp->core); + if (!devlink_dpipe_table_counter_enabled(devlink, + MLXSW_SP_DPIPE_TABLE_NAME_ERIF)) + return; + mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS); +} + +static void mlxsw_sp_rif_counters_free(struct mlxsw_sp_rif *rif) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + + mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS); +} + static struct mlxsw_sp_rif * mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, const struct net_device *dev); +#define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE) + +struct mlxsw_sp_prefix_usage { + DECLARE_BITMAP(b, MLXSW_SP_PREFIX_COUNT); +}; + #define mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) \ for_each_set_bit(prefix, (prefix_usage)->b, MLXSW_SP_PREFIX_COUNT) @@ -287,6 +374,7 @@ enum mlxsw_sp_fib_entry_type { }; struct mlxsw_sp_nexthop_group; +struct mlxsw_sp_fib; struct mlxsw_sp_fib_node { struct list_head entry_list; @@ -313,6 +401,18 @@ struct mlxsw_sp_fib_entry { bool offloaded; }; +enum mlxsw_sp_l3proto { + MLXSW_SP_L3_PROTO_IPV4, + MLXSW_SP_L3_PROTO_IPV6, +}; + +struct mlxsw_sp_lpm_tree { + u8 id; /* tree ID */ + unsigned int ref_count; + enum mlxsw_sp_l3proto proto; + struct mlxsw_sp_prefix_usage prefix_usage; +}; + struct mlxsw_sp_fib { struct rhashtable ht; struct list_head node_list; @@ -323,6 +423,13 @@ struct mlxsw_sp_fib { enum mlxsw_sp_l3proto proto; }; +struct mlxsw_sp_vr { + u16 id; /* virtual router ID */ + u32 tb_id; /* kernel fib table id */ + unsigned int rif_count; + struct mlxsw_sp_fib *fib4; +}; + static const struct rhashtable_params mlxsw_sp_fib_ht_params; static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp_vr *vr, @@ -361,8 +468,8 @@ mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp *mlxsw_sp) static struct mlxsw_sp_lpm_tree *lpm_tree; int i; - for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) { - lpm_tree = &mlxsw_sp->router.lpm.trees[i]; + for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) { + lpm_tree = &mlxsw_sp->router->lpm.trees[i]; if (lpm_tree->ref_count == 0) return lpm_tree; } @@ -458,8 +565,8 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_lpm_tree *lpm_tree; int i; - for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) { - lpm_tree = &mlxsw_sp->router.lpm.trees[i]; + for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) { + lpm_tree = &mlxsw_sp->router->lpm.trees[i]; if (lpm_tree->ref_count != 0 && lpm_tree->proto == proto && mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage, @@ -496,15 +603,15 @@ static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp) return -EIO; max_trees = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_LPM_TREES); - mlxsw_sp->router.lpm.tree_count = max_trees - MLXSW_SP_LPM_TREE_MIN; - mlxsw_sp->router.lpm.trees = kcalloc(mlxsw_sp->router.lpm.tree_count, + mlxsw_sp->router->lpm.tree_count = max_trees - MLXSW_SP_LPM_TREE_MIN; + mlxsw_sp->router->lpm.trees = kcalloc(mlxsw_sp->router->lpm.tree_count, sizeof(struct mlxsw_sp_lpm_tree), GFP_KERNEL); - if (!mlxsw_sp->router.lpm.trees) + if (!mlxsw_sp->router->lpm.trees) return -ENOMEM; - for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) { - lpm_tree = &mlxsw_sp->router.lpm.trees[i]; + for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) { + lpm_tree = &mlxsw_sp->router->lpm.trees[i]; lpm_tree->id = i + MLXSW_SP_LPM_TREE_MIN; } @@ -513,7 +620,7 @@ static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp) static void mlxsw_sp_lpm_fini(struct mlxsw_sp *mlxsw_sp) { - kfree(mlxsw_sp->router.lpm.trees); + kfree(mlxsw_sp->router->lpm.trees); } static bool mlxsw_sp_vr_is_used(const struct mlxsw_sp_vr *vr) @@ -527,7 +634,7 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp) int i; for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { - vr = &mlxsw_sp->router.vrs[i]; + vr = &mlxsw_sp->router->vrs[i]; if (!mlxsw_sp_vr_is_used(vr)) return vr; } @@ -573,7 +680,7 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp, tb_id = mlxsw_sp_fix_tb_id(tb_id); for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { - vr = &mlxsw_sp->router.vrs[i]; + vr = &mlxsw_sp->router->vrs[i]; if (mlxsw_sp_vr_is_used(vr) && vr->tb_id == tb_id) return vr; } @@ -680,13 +787,13 @@ static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp) return -EIO; max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); - mlxsw_sp->router.vrs = kcalloc(max_vrs, sizeof(struct mlxsw_sp_vr), - GFP_KERNEL); - if (!mlxsw_sp->router.vrs) + mlxsw_sp->router->vrs = kcalloc(max_vrs, sizeof(struct mlxsw_sp_vr), + GFP_KERNEL); + if (!mlxsw_sp->router->vrs) return -ENOMEM; for (i = 0; i < max_vrs; i++) { - vr = &mlxsw_sp->router.vrs[i]; + vr = &mlxsw_sp->router->vrs[i]; vr->id = i; } @@ -706,7 +813,7 @@ static void mlxsw_sp_vrs_fini(struct mlxsw_sp *mlxsw_sp) */ mlxsw_core_flush_owq(); mlxsw_sp_router_fib_flush(mlxsw_sp); - kfree(mlxsw_sp->router.vrs); + kfree(mlxsw_sp->router->vrs); } struct mlxsw_sp_neigh_key { @@ -758,7 +865,7 @@ static int mlxsw_sp_neigh_entry_insert(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_neigh_entry *neigh_entry) { - return rhashtable_insert_fast(&mlxsw_sp->router.neigh_ht, + return rhashtable_insert_fast(&mlxsw_sp->router->neigh_ht, &neigh_entry->ht_node, mlxsw_sp_neigh_ht_params); } @@ -767,7 +874,7 @@ static void mlxsw_sp_neigh_entry_remove(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_neigh_entry *neigh_entry) { - rhashtable_remove_fast(&mlxsw_sp->router.neigh_ht, + rhashtable_remove_fast(&mlxsw_sp->router->neigh_ht, &neigh_entry->ht_node, mlxsw_sp_neigh_ht_params); } @@ -815,7 +922,7 @@ mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, struct neighbour *n) struct mlxsw_sp_neigh_key key; key.n = n; - return rhashtable_lookup_fast(&mlxsw_sp->router.neigh_ht, + return rhashtable_lookup_fast(&mlxsw_sp->router->neigh_ht, &key, mlxsw_sp_neigh_ht_params); } @@ -824,7 +931,7 @@ mlxsw_sp_router_neighs_update_interval_init(struct mlxsw_sp *mlxsw_sp) { unsigned long interval = NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME); - mlxsw_sp->router.neighs_update.interval = jiffies_to_msecs(interval); + mlxsw_sp->router->neighs_update.interval = jiffies_to_msecs(interval); } static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp, @@ -839,13 +946,13 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp, mlxsw_reg_rauhtd_ent_ipv4_unpack(rauhtd_pl, ent_index, &rif, &dip); - if (!mlxsw_sp->rifs[rif]) { + if (!mlxsw_sp->router->rifs[rif]) { dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n"); return; } dipn = htonl(dip); - dev = mlxsw_sp->rifs[rif]->dev; + dev = mlxsw_sp->router->rifs[rif]->dev; n = neigh_lookup(&arp_tbl, &dipn, dev); if (!n) { netdev_err(dev, "Failed to find matching neighbour for IP=%pI4h\n", @@ -954,7 +1061,7 @@ static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp) /* Take RTNL mutex here to prevent lists from changes */ rtnl_lock(); - list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list, + list_for_each_entry(neigh_entry, &mlxsw_sp->router->nexthop_neighs_list, nexthop_neighs_list_node) /* If this neigh have nexthops, make the kernel think this neigh * is active regardless of the traffic. @@ -966,33 +1073,35 @@ static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp) static void mlxsw_sp_router_neighs_update_work_schedule(struct mlxsw_sp *mlxsw_sp) { - unsigned long interval = mlxsw_sp->router.neighs_update.interval; + unsigned long interval = mlxsw_sp->router->neighs_update.interval; - mlxsw_core_schedule_dw(&mlxsw_sp->router.neighs_update.dw, + mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw, msecs_to_jiffies(interval)); } static void mlxsw_sp_router_neighs_update_work(struct work_struct *work) { - struct mlxsw_sp *mlxsw_sp = container_of(work, struct mlxsw_sp, - router.neighs_update.dw.work); + struct mlxsw_sp_router *router; int err; - err = mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp); + router = container_of(work, struct mlxsw_sp_router, + neighs_update.dw.work); + err = mlxsw_sp_router_neighs_update_rauhtd(router->mlxsw_sp); if (err) - dev_err(mlxsw_sp->bus_info->dev, "Could not update kernel for neigh activity"); + dev_err(router->mlxsw_sp->bus_info->dev, "Could not update kernel for neigh activity"); - mlxsw_sp_router_neighs_update_nh(mlxsw_sp); + mlxsw_sp_router_neighs_update_nh(router->mlxsw_sp); - mlxsw_sp_router_neighs_update_work_schedule(mlxsw_sp); + mlxsw_sp_router_neighs_update_work_schedule(router->mlxsw_sp); } static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work) { struct mlxsw_sp_neigh_entry *neigh_entry; - struct mlxsw_sp *mlxsw_sp = container_of(work, struct mlxsw_sp, - router.nexthop_probe_dw.work); + struct mlxsw_sp_router *router; + router = container_of(work, struct mlxsw_sp_router, + nexthop_probe_dw.work); /* Iterate over nexthop neighbours, find those who are unresolved and * send arp on them. This solves the chicken-egg problem when * the nexthop wouldn't get offloaded until the neighbor is resolved @@ -1002,13 +1111,13 @@ static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work) * Take RTNL mutex here to prevent lists from changes. */ rtnl_lock(); - list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list, + list_for_each_entry(neigh_entry, &router->nexthop_neighs_list, nexthop_neighs_list_node) if (!neigh_entry->connected) neigh_event_send(neigh_entry->key.n, NULL); rtnl_unlock(); - mlxsw_core_schedule_dw(&mlxsw_sp->router.nexthop_probe_dw, + mlxsw_core_schedule_dw(&router->nexthop_probe_dw, MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL); } @@ -1130,7 +1239,7 @@ int mlxsw_sp_router_netevent_event(struct notifier_block *unused, mlxsw_sp = mlxsw_sp_port->mlxsw_sp; interval = jiffies_to_msecs(NEIGH_VAR(p, DELAY_PROBE_TIME)); - mlxsw_sp->router.neighs_update.interval = interval; + mlxsw_sp->router->neighs_update.interval = interval; mlxsw_sp_port_dev_put(mlxsw_sp_port); break; @@ -1171,7 +1280,7 @@ static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp) { int err; - err = rhashtable_init(&mlxsw_sp->router.neigh_ht, + err = rhashtable_init(&mlxsw_sp->router->neigh_ht, &mlxsw_sp_neigh_ht_params); if (err) return err; @@ -1182,20 +1291,20 @@ static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp) mlxsw_sp_router_neighs_update_interval_init(mlxsw_sp); /* Create the delayed works for the activity_update */ - INIT_DELAYED_WORK(&mlxsw_sp->router.neighs_update.dw, + INIT_DELAYED_WORK(&mlxsw_sp->router->neighs_update.dw, mlxsw_sp_router_neighs_update_work); - INIT_DELAYED_WORK(&mlxsw_sp->router.nexthop_probe_dw, + INIT_DELAYED_WORK(&mlxsw_sp->router->nexthop_probe_dw, mlxsw_sp_router_probe_unresolved_nexthops); - mlxsw_core_schedule_dw(&mlxsw_sp->router.neighs_update.dw, 0); - mlxsw_core_schedule_dw(&mlxsw_sp->router.nexthop_probe_dw, 0); + mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw, 0); + mlxsw_core_schedule_dw(&mlxsw_sp->router->nexthop_probe_dw, 0); return 0; } static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp) { - cancel_delayed_work_sync(&mlxsw_sp->router.neighs_update.dw); - cancel_delayed_work_sync(&mlxsw_sp->router.nexthop_probe_dw); - rhashtable_destroy(&mlxsw_sp->router.neigh_ht); + cancel_delayed_work_sync(&mlxsw_sp->router->neighs_update.dw); + cancel_delayed_work_sync(&mlxsw_sp->router->nexthop_probe_dw); + rhashtable_destroy(&mlxsw_sp->router->neigh_ht); } static int mlxsw_sp_neigh_rif_flush(struct mlxsw_sp *mlxsw_sp, @@ -1270,7 +1379,7 @@ static const struct rhashtable_params mlxsw_sp_nexthop_group_ht_params = { static int mlxsw_sp_nexthop_group_insert(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop_group *nh_grp) { - return rhashtable_insert_fast(&mlxsw_sp->router.nexthop_group_ht, + return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_group_ht, &nh_grp->ht_node, mlxsw_sp_nexthop_group_ht_params); } @@ -1278,7 +1387,7 @@ static int mlxsw_sp_nexthop_group_insert(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_nexthop_group_remove(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop_group *nh_grp) { - rhashtable_remove_fast(&mlxsw_sp->router.nexthop_group_ht, + rhashtable_remove_fast(&mlxsw_sp->router->nexthop_group_ht, &nh_grp->ht_node, mlxsw_sp_nexthop_group_ht_params); } @@ -1287,7 +1396,7 @@ static struct mlxsw_sp_nexthop_group * mlxsw_sp_nexthop_group_lookup(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop_group_key key) { - return rhashtable_lookup_fast(&mlxsw_sp->router.nexthop_group_ht, &key, + return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_group_ht, &key, mlxsw_sp_nexthop_group_ht_params); } @@ -1300,14 +1409,14 @@ static const struct rhashtable_params mlxsw_sp_nexthop_ht_params = { static int mlxsw_sp_nexthop_insert(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop *nh) { - return rhashtable_insert_fast(&mlxsw_sp->router.nexthop_ht, + return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_ht, &nh->ht_node, mlxsw_sp_nexthop_ht_params); } static void mlxsw_sp_nexthop_remove(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop *nh) { - rhashtable_remove_fast(&mlxsw_sp->router.nexthop_ht, &nh->ht_node, + rhashtable_remove_fast(&mlxsw_sp->router->nexthop_ht, &nh->ht_node, mlxsw_sp_nexthop_ht_params); } @@ -1315,7 +1424,7 @@ static struct mlxsw_sp_nexthop * mlxsw_sp_nexthop_lookup(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop_key key) { - return rhashtable_lookup_fast(&mlxsw_sp->router.nexthop_ht, &key, + return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_ht, &key, mlxsw_sp_nexthop_ht_params); } @@ -1602,7 +1711,7 @@ static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp, */ if (list_empty(&neigh_entry->nexthop_list)) list_add_tail(&neigh_entry->nexthop_neighs_list_node, - &mlxsw_sp->router.nexthop_neighs_list); + &mlxsw_sp->router->nexthop_neighs_list); nh->neigh_entry = neigh_entry; list_add_tail(&nh->neigh_list_node, &neigh_entry->nexthop_list); @@ -1700,7 +1809,7 @@ static void mlxsw_sp_nexthop_event(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop *nh; struct mlxsw_sp_rif *rif; - if (mlxsw_sp->router.aborted) + if (mlxsw_sp->router->aborted) return; key.fib_nh = fib_nh; @@ -2513,7 +2622,7 @@ mlxsw_sp_router_fib4_add(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib_node *fib_node; int err; - if (mlxsw_sp->router.aborted) + if (mlxsw_sp->router->aborted) return 0; fib_node = mlxsw_sp_fib4_node_get(mlxsw_sp, fen_info); @@ -2553,7 +2662,7 @@ static void mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib_entry *fib_entry; struct mlxsw_sp_fib_node *fib_node; - if (mlxsw_sp->router.aborted) + if (mlxsw_sp->router->aborted) return; fib_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info); @@ -2584,7 +2693,7 @@ static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp) return err; for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { - struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[i]; + struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i]; char raltb_pl[MLXSW_REG_RALTB_LEN]; char ralue_pl[MLXSW_REG_RALUE_LEN]; @@ -2666,7 +2775,7 @@ static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp) int i; for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { - struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[i]; + struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i]; if (!mlxsw_sp_vr_is_used(vr)) continue; @@ -2678,11 +2787,11 @@ static void mlxsw_sp_router_fib4_abort(struct mlxsw_sp *mlxsw_sp) { int err; - if (mlxsw_sp->router.aborted) + if (mlxsw_sp->router->aborted) return; dev_warn(mlxsw_sp->bus_info->dev, "FIB abort triggered. Note that FIB entries are no longer being offloaded to this device.\n"); mlxsw_sp_router_fib_flush(mlxsw_sp); - mlxsw_sp->router.aborted = true; + mlxsw_sp->router->aborted = true; err = mlxsw_sp_router_set_abort_trap(mlxsw_sp); if (err) dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n"); @@ -2748,9 +2857,9 @@ static void mlxsw_sp_router_fib_event_work(struct work_struct *work) static int mlxsw_sp_router_fib_event(struct notifier_block *nb, unsigned long event, void *ptr) { - struct mlxsw_sp *mlxsw_sp = container_of(nb, struct mlxsw_sp, fib_nb); struct mlxsw_sp_fib_event_work *fib_work; struct fib_notifier_info *info = ptr; + struct mlxsw_sp_router *router; if (!net_eq(info->net, &init_net)) return NOTIFY_DONE; @@ -2760,7 +2869,8 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb, return NOTIFY_BAD; INIT_WORK(&fib_work->work, mlxsw_sp_router_fib_event_work); - fib_work->mlxsw_sp = mlxsw_sp; + router = container_of(nb, struct mlxsw_sp_router, fib_nb); + fib_work->mlxsw_sp = router->mlxsw_sp; fib_work->event = event; switch (event) { @@ -2798,8 +2908,9 @@ mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, int i; for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) - if (mlxsw_sp->rifs[i] && mlxsw_sp->rifs[i]->dev == dev) - return mlxsw_sp->rifs[i]; + if (mlxsw_sp->router->rifs[i] && + mlxsw_sp->router->rifs[i]->dev == dev) + return mlxsw_sp->router->rifs[i]; return NULL; } @@ -2849,77 +2960,46 @@ static bool mlxsw_sp_rif_should_config(struct mlxsw_sp_rif *rif, return false; } -#define MLXSW_SP_INVALID_INDEX_RIF 0xffff -static int mlxsw_sp_avail_rif_get(struct mlxsw_sp *mlxsw_sp) -{ - int i; - - for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) - if (!mlxsw_sp->rifs[i]) - return i; - - return MLXSW_SP_INVALID_INDEX_RIF; -} - -static void mlxsw_sp_vport_rif_sp_attr_get(struct mlxsw_sp_port *mlxsw_sp_vport, - bool *p_lagged, u16 *p_system_port) +static enum mlxsw_sp_rif_type +mlxsw_sp_dev_rif_type(const struct mlxsw_sp *mlxsw_sp, + const struct net_device *dev) { - u8 local_port = mlxsw_sp_vport->local_port; - - *p_lagged = mlxsw_sp_vport->lagged; - *p_system_port = *p_lagged ? mlxsw_sp_vport->lag_id : local_port; -} - -static int mlxsw_sp_vport_rif_sp_op(struct mlxsw_sp_port *mlxsw_sp_vport, - u16 vr_id, struct net_device *l3_dev, - u16 rif_index, bool create) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; - bool lagged = mlxsw_sp_vport->lagged; - char ritr_pl[MLXSW_REG_RITR_LEN]; - u16 system_port; - - mlxsw_reg_ritr_pack(ritr_pl, create, MLXSW_REG_RITR_SP_IF, rif_index, - vr_id, l3_dev->mtu, l3_dev->dev_addr); + enum mlxsw_sp_fid_type type; - mlxsw_sp_vport_rif_sp_attr_get(mlxsw_sp_vport, &lagged, &system_port); - mlxsw_reg_ritr_sp_if_pack(ritr_pl, lagged, system_port, - mlxsw_sp_vport_vid_get(mlxsw_sp_vport)); - - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); -} - -static void mlxsw_sp_vport_rif_sp_leave(struct mlxsw_sp_port *mlxsw_sp_vport); + /* RIF type is derived from the type of the underlying FID */ + if (is_vlan_dev(dev) && netif_is_bridge_master(vlan_dev_real_dev(dev))) + type = MLXSW_SP_FID_TYPE_8021Q; + else if (netif_is_bridge_master(dev) && br_vlan_enabled(dev)) + type = MLXSW_SP_FID_TYPE_8021Q; + else if (netif_is_bridge_master(dev)) + type = MLXSW_SP_FID_TYPE_8021D; + else + type = MLXSW_SP_FID_TYPE_RFID; -static u16 mlxsw_sp_rif_sp_to_fid(u16 rif_index) -{ - return MLXSW_SP_RFID_BASE + rif_index; + return mlxsw_sp_fid_type_rif_type(mlxsw_sp, type); } -static struct mlxsw_sp_fid * -mlxsw_sp_rfid_alloc(u16 fid, struct net_device *l3_dev) +static int mlxsw_sp_rif_index_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_rif_index) { - struct mlxsw_sp_fid *f; - - f = kzalloc(sizeof(*f), GFP_KERNEL); - if (!f) - return NULL; + int i; - f->leave = mlxsw_sp_vport_rif_sp_leave; - f->ref_count = 0; - f->dev = l3_dev; - f->fid = fid; + for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { + if (!mlxsw_sp->router->rifs[i]) { + *p_rif_index = i; + return 0; + } + } - return f; + return -ENOBUFS; } -static struct mlxsw_sp_rif * -mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev, - struct mlxsw_sp_fid *f) +static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index, + u16 vr_id, + struct net_device *l3_dev) { struct mlxsw_sp_rif *rif; - rif = kzalloc(sizeof(*rif), GFP_KERNEL); + rif = kzalloc(rif_size, GFP_KERNEL); if (!rif) return NULL; @@ -2930,11 +3010,16 @@ mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev, rif->vr_id = vr_id; rif->dev = l3_dev; rif->rif_index = rif_index; - rif->f = f; return rif; } +struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp, + u16 rif_index) +{ + return mlxsw_sp->router->rifs[rif_index]; +} + u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif) { return rif->rif_index; @@ -2946,152 +3031,199 @@ int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif) } static struct mlxsw_sp_rif * -mlxsw_sp_vport_rif_sp_create(struct mlxsw_sp_port *mlxsw_sp_vport, - struct net_device *l3_dev) +mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_rif_params *params) { - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; - u32 tb_id = l3mdev_fib_table(l3_dev); - struct mlxsw_sp_vr *vr; - struct mlxsw_sp_fid *f; + u32 tb_id = l3mdev_fib_table(params->dev); + const struct mlxsw_sp_rif_ops *ops; + enum mlxsw_sp_rif_type type; struct mlxsw_sp_rif *rif; - u16 fid, rif_index; + struct mlxsw_sp_fid *fid; + struct mlxsw_sp_vr *vr; + u16 rif_index; int err; - rif_index = mlxsw_sp_avail_rif_get(mlxsw_sp); - if (rif_index == MLXSW_SP_INVALID_INDEX_RIF) - return ERR_PTR(-ERANGE); + type = mlxsw_sp_dev_rif_type(mlxsw_sp, params->dev); + ops = mlxsw_sp->router->rif_ops_arr[type]; vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN); if (IS_ERR(vr)) return ERR_CAST(vr); - err = mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, vr->id, l3_dev, - rif_index, true); - if (err) - goto err_vport_rif_sp_op; - - fid = mlxsw_sp_rif_sp_to_fid(rif_index); - err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, true); + err = mlxsw_sp_rif_index_alloc(mlxsw_sp, &rif_index); if (err) - goto err_rif_fdb_op; - - f = mlxsw_sp_rfid_alloc(fid, l3_dev); - if (!f) { - err = -ENOMEM; - goto err_rfid_alloc; - } + goto err_rif_index_alloc; - rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f); + rif = mlxsw_sp_rif_alloc(ops->rif_size, rif_index, vr->id, params->dev); if (!rif) { err = -ENOMEM; goto err_rif_alloc; } + rif->mlxsw_sp = mlxsw_sp; + rif->ops = ops; - if (devlink_dpipe_table_counter_enabled(priv_to_devlink(mlxsw_sp->core), - MLXSW_SP_DPIPE_TABLE_NAME_ERIF)) { - err = mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif, - MLXSW_SP_RIF_COUNTER_EGRESS); - if (err) - netdev_dbg(mlxsw_sp_vport->dev, - "Counter alloc Failed err=%d\n", err); + fid = ops->fid_get(rif); + if (IS_ERR(fid)) { + err = PTR_ERR(fid); + goto err_fid_get; } + rif->fid = fid; + + if (ops->setup) + ops->setup(rif, params); + + err = ops->configure(rif); + if (err) + goto err_configure; + + err = mlxsw_sp_rif_fdb_op(mlxsw_sp, params->dev->dev_addr, + mlxsw_sp_fid_index(fid), true); + if (err) + goto err_rif_fdb_op; - f->rif = rif; - mlxsw_sp->rifs[rif_index] = rif; + mlxsw_sp_rif_counters_alloc(rif); + mlxsw_sp_fid_rif_set(fid, rif); + mlxsw_sp->router->rifs[rif_index] = rif; vr->rif_count++; return rif; -err_rif_alloc: - kfree(f); -err_rfid_alloc: - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false); err_rif_fdb_op: - mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, vr->id, l3_dev, rif_index, - false); -err_vport_rif_sp_op: + ops->deconfigure(rif); +err_configure: + mlxsw_sp_fid_put(fid); +err_fid_get: + kfree(rif); +err_rif_alloc: +err_rif_index_alloc: mlxsw_sp_vr_put(vr); return ERR_PTR(err); } -static void mlxsw_sp_vport_rif_sp_destroy(struct mlxsw_sp_port *mlxsw_sp_vport, - struct mlxsw_sp_rif *rif) +void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif) { - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; - struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[rif->vr_id]; - struct net_device *l3_dev = rif->dev; - struct mlxsw_sp_fid *f = rif->f; - u16 rif_index = rif->rif_index; - u16 fid = f->fid; + const struct mlxsw_sp_rif_ops *ops = rif->ops; + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + struct mlxsw_sp_fid *fid = rif->fid; + struct mlxsw_sp_vr *vr; mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif); - - mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS); - mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_INGRESS); + vr = &mlxsw_sp->router->vrs[rif->vr_id]; vr->rif_count--; - mlxsw_sp->rifs[rif_index] = NULL; - f->rif = NULL; - + mlxsw_sp->router->rifs[rif->rif_index] = NULL; + mlxsw_sp_fid_rif_set(fid, NULL); + mlxsw_sp_rif_counters_free(rif); + mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->dev->dev_addr, + mlxsw_sp_fid_index(fid), false); + ops->deconfigure(rif); + mlxsw_sp_fid_put(fid); kfree(rif); + mlxsw_sp_vr_put(vr); +} - kfree(f); - - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false); +static void +mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params *params, + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) +{ + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; - mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, vr->id, l3_dev, rif_index, - false); - mlxsw_sp_vr_put(vr); + params->vid = mlxsw_sp_port_vlan->vid; + params->lag = mlxsw_sp_port->lagged; + if (params->lag) + params->lag_id = mlxsw_sp_port->lag_id; + else + params->system_port = mlxsw_sp_port->local_port; } -static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport, - struct net_device *l3_dev) +static int +mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, + struct net_device *l3_dev) { - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u16 vid = mlxsw_sp_port_vlan->vid; struct mlxsw_sp_rif *rif; + struct mlxsw_sp_fid *fid; + int err; rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); if (!rif) { - rif = mlxsw_sp_vport_rif_sp_create(mlxsw_sp_vport, l3_dev); + struct mlxsw_sp_rif_params params = { + .dev = l3_dev, + }; + + mlxsw_sp_rif_subport_params_init(¶ms, mlxsw_sp_port_vlan); + rif = mlxsw_sp_rif_create(mlxsw_sp, ¶ms); if (IS_ERR(rif)) return PTR_ERR(rif); } - mlxsw_sp_vport_fid_set(mlxsw_sp_vport, rif->f); - rif->f->ref_count++; + /* FID was already created, just take a reference */ + fid = rif->ops->fid_get(rif); + err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid); + if (err) + goto err_fid_port_vid_map; + + err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false); + if (err) + goto err_port_vid_learning_set; + + err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, + BR_STATE_FORWARDING); + if (err) + goto err_port_vid_stp_set; - netdev_dbg(mlxsw_sp_vport->dev, "Joined FID=%d\n", rif->f->fid); + mlxsw_sp_port_vlan->fid = fid; return 0; + +err_port_vid_stp_set: + mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true); +err_port_vid_learning_set: + mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid); +err_fid_port_vid_map: + mlxsw_sp_fid_put(fid); + return err; } -static void mlxsw_sp_vport_rif_sp_leave(struct mlxsw_sp_port *mlxsw_sp_vport) +void +mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { - struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u16 vid = mlxsw_sp_port_vlan->vid; - netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid); + if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_RFID)) + return; - mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); - if (--f->ref_count == 0) - mlxsw_sp_vport_rif_sp_destroy(mlxsw_sp_vport, f->rif); + mlxsw_sp_port_vlan->fid = NULL; + mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING); + mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true); + mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid); + /* If router port holds the last reference on the rFID, then the + * associated Sub-port RIF will be destroyed. + */ + mlxsw_sp_fid_put(fid); } -static int mlxsw_sp_inetaddr_vport_event(struct net_device *l3_dev, - struct net_device *port_dev, - unsigned long event, u16 vid) +static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev, + struct net_device *port_dev, + unsigned long event, u16 vid) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(port_dev); - struct mlxsw_sp_port *mlxsw_sp_vport; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); - if (WARN_ON(!mlxsw_sp_vport)) + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); + if (WARN_ON(!mlxsw_sp_port_vlan)) return -EINVAL; switch (event) { case NETDEV_UP: - return mlxsw_sp_vport_rif_sp_join(mlxsw_sp_vport, l3_dev); + return mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan, + l3_dev); case NETDEV_DOWN: - mlxsw_sp_vport_rif_sp_leave(mlxsw_sp_vport); + mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); break; } @@ -3106,7 +3238,7 @@ static int mlxsw_sp_inetaddr_port_event(struct net_device *port_dev, netif_is_ovs_port(port_dev)) return 0; - return mlxsw_sp_inetaddr_vport_event(port_dev, port_dev, event, 1); + return mlxsw_sp_inetaddr_port_vlan_event(port_dev, port_dev, event, 1); } static int __mlxsw_sp_inetaddr_lag_event(struct net_device *l3_dev, @@ -3119,8 +3251,9 @@ static int __mlxsw_sp_inetaddr_lag_event(struct net_device *l3_dev, netdev_for_each_lower_dev(lag_dev, port_dev, iter) { if (mlxsw_sp_port_dev_check(port_dev)) { - err = mlxsw_sp_inetaddr_vport_event(l3_dev, port_dev, - event, vid); + err = mlxsw_sp_inetaddr_port_vlan_event(l3_dev, + port_dev, + event, vid); if (err) return err; } @@ -3138,189 +3271,24 @@ static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev, return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event, 1); } -static struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp, - struct net_device *l3_dev) -{ - u16 fid; - - if (is_vlan_dev(l3_dev)) - fid = vlan_dev_vlan_id(l3_dev); - else if (mlxsw_sp->master_bridge.dev == l3_dev) - fid = 1; - else - return mlxsw_sp_vfid_find(mlxsw_sp, l3_dev); - - return mlxsw_sp_fid_find(mlxsw_sp, fid); -} - -static u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp) -{ - return mlxsw_core_max_ports(mlxsw_sp->core) + 1; -} - -static enum mlxsw_flood_table_type mlxsw_sp_flood_table_type_get(u16 fid) -{ - return mlxsw_sp_fid_is_vfid(fid) ? MLXSW_REG_SFGC_TABLE_TYPE_FID : - MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST; -} - -static u16 mlxsw_sp_flood_table_index_get(u16 fid) -{ - return mlxsw_sp_fid_is_vfid(fid) ? mlxsw_sp_fid_to_vfid(fid) : fid; -} - -static int mlxsw_sp_router_port_flood_set(struct mlxsw_sp *mlxsw_sp, u16 fid, - bool set) -{ - u8 router_port = mlxsw_sp_router_port(mlxsw_sp); - enum mlxsw_flood_table_type table_type; - char *sftr_pl; - u16 index; - int err; - - sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL); - if (!sftr_pl) - return -ENOMEM; - - table_type = mlxsw_sp_flood_table_type_get(fid); - index = mlxsw_sp_flood_table_index_get(fid); - mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BC, index, table_type, - 1, router_port, set); - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl); - - kfree(sftr_pl); - return err; -} - -static enum mlxsw_reg_ritr_if_type mlxsw_sp_rif_type_get(u16 fid) -{ - if (mlxsw_sp_fid_is_vfid(fid)) - return MLXSW_REG_RITR_FID_IF; - else - return MLXSW_REG_RITR_VLAN_IF; -} - -static int mlxsw_sp_rif_bridge_op(struct mlxsw_sp *mlxsw_sp, u16 vr_id, - struct net_device *l3_dev, - u16 fid, u16 rif, - bool create) -{ - enum mlxsw_reg_ritr_if_type rif_type; - char ritr_pl[MLXSW_REG_RITR_LEN]; - - rif_type = mlxsw_sp_rif_type_get(fid); - mlxsw_reg_ritr_pack(ritr_pl, create, rif_type, rif, vr_id, l3_dev->mtu, - l3_dev->dev_addr); - mlxsw_reg_ritr_fid_set(ritr_pl, rif_type, fid); - - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); -} - -static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, - struct net_device *l3_dev, - struct mlxsw_sp_fid *f) -{ - u32 tb_id = l3mdev_fib_table(l3_dev); - struct mlxsw_sp_rif *rif; - struct mlxsw_sp_vr *vr; - u16 rif_index; - int err; - - rif_index = mlxsw_sp_avail_rif_get(mlxsw_sp); - if (rif_index == MLXSW_SP_INVALID_INDEX_RIF) - return -ERANGE; - - vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN); - if (IS_ERR(vr)) - return PTR_ERR(vr); - - err = mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, true); - if (err) - goto err_port_flood_set; - - err = mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, - rif_index, true); - if (err) - goto err_rif_bridge_op; - - err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, true); - if (err) - goto err_rif_fdb_op; - - rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f); - if (!rif) { - err = -ENOMEM; - goto err_rif_alloc; - } - - f->rif = rif; - mlxsw_sp->rifs[rif_index] = rif; - vr->rif_count++; - - netdev_dbg(l3_dev, "RIF=%d created\n", rif_index); - - return 0; - -err_rif_alloc: - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false); -err_rif_fdb_op: - mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif_index, - false); -err_rif_bridge_op: - mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false); -err_port_flood_set: - mlxsw_sp_vr_put(vr); - return err; -} - -void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_rif *rif) -{ - struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[rif->vr_id]; - struct net_device *l3_dev = rif->dev; - struct mlxsw_sp_fid *f = rif->f; - u16 rif_index = rif->rif_index; - - mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif); - - vr->rif_count--; - mlxsw_sp->rifs[rif_index] = NULL; - f->rif = NULL; - - kfree(rif); - - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false); - - mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif_index, - false); - - mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false); - - mlxsw_sp_vr_put(vr); - - netdev_dbg(l3_dev, "RIF=%d destroyed\n", rif_index); -} - static int mlxsw_sp_inetaddr_bridge_event(struct net_device *l3_dev, - struct net_device *br_dev, unsigned long event) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev); - struct mlxsw_sp_fid *f; - - /* FID can either be an actual FID if the L3 device is the - * VLAN-aware bridge or a VLAN device on top. Otherwise, the - * L3 device is a VLAN-unaware bridge and we get a vFID. - */ - f = mlxsw_sp_bridge_fid_get(mlxsw_sp, l3_dev); - if (WARN_ON(!f)) - return -EINVAL; + struct mlxsw_sp_rif_params params = { + .dev = l3_dev, + }; + struct mlxsw_sp_rif *rif; switch (event) { case NETDEV_UP: - return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev, f); + rif = mlxsw_sp_rif_create(mlxsw_sp, ¶ms); + if (IS_ERR(rif)) + return PTR_ERR(rif); + break; case NETDEV_DOWN: - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif); + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); + mlxsw_sp_rif_destroy(rif); break; } @@ -3331,19 +3299,16 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev, unsigned long event) { struct net_device *real_dev = vlan_dev_real_dev(vlan_dev); - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(vlan_dev); u16 vid = vlan_dev_vlan_id(vlan_dev); if (mlxsw_sp_port_dev_check(real_dev)) - return mlxsw_sp_inetaddr_vport_event(vlan_dev, real_dev, event, - vid); + return mlxsw_sp_inetaddr_port_vlan_event(vlan_dev, real_dev, + event, vid); else if (netif_is_lag_master(real_dev)) return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event, vid); - else if (netif_is_bridge_master(real_dev) && - mlxsw_sp->master_bridge.dev == real_dev) - return mlxsw_sp_inetaddr_bridge_event(vlan_dev, real_dev, - event); + else if (netif_is_bridge_master(real_dev) && br_vlan_enabled(real_dev)) + return mlxsw_sp_inetaddr_bridge_event(vlan_dev, event); return 0; } @@ -3356,7 +3321,7 @@ static int __mlxsw_sp_inetaddr_event(struct net_device *dev, else if (netif_is_lag_master(dev)) return mlxsw_sp_inetaddr_lag_event(dev, event); else if (netif_is_bridge_master(dev)) - return mlxsw_sp_inetaddr_bridge_event(dev, dev, event); + return mlxsw_sp_inetaddr_bridge_event(dev, event); else if (is_vlan_dev(dev)) return mlxsw_sp_inetaddr_vlan_event(dev, event); else @@ -3406,6 +3371,7 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev) { struct mlxsw_sp *mlxsw_sp; struct mlxsw_sp_rif *rif; + u16 fid_index; int err; mlxsw_sp = mlxsw_sp_lower_get(dev); @@ -3415,8 +3381,9 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev) rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); if (!rif) return 0; + fid_index = mlxsw_sp_fid_index(rif->fid); - err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, rif->f->fid, false); + err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, false); if (err) return err; @@ -3425,7 +3392,7 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev) if (err) goto err_rif_edit; - err = mlxsw_sp_rif_fdb_op(mlxsw_sp, dev->dev_addr, rif->f->fid, true); + err = mlxsw_sp_rif_fdb_op(mlxsw_sp, dev->dev_addr, fid_index, true); if (err) goto err_rif_fdb_op; @@ -3439,7 +3406,7 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev) err_rif_fdb_op: mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, rif->addr, rif->mtu); err_rif_edit: - mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, rif->f->fid, true); + mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, true); return err; } @@ -3492,16 +3459,225 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, return err; } +static struct mlxsw_sp_rif_subport * +mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif *rif) +{ + return container_of(rif, struct mlxsw_sp_rif_subport, common); +} + +static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif *rif, + const struct mlxsw_sp_rif_params *params) +{ + struct mlxsw_sp_rif_subport *rif_subport; + + rif_subport = mlxsw_sp_rif_subport_rif(rif); + rif_subport->vid = params->vid; + rif_subport->lag = params->lag; + if (params->lag) + rif_subport->lag_id = params->lag_id; + else + rif_subport->system_port = params->system_port; +} + +static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif *rif, bool enable) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + struct mlxsw_sp_rif_subport *rif_subport; + char ritr_pl[MLXSW_REG_RITR_LEN]; + + rif_subport = mlxsw_sp_rif_subport_rif(rif); + mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_SP_IF, + rif->rif_index, rif->vr_id, rif->dev->mtu, + rif->dev->dev_addr); + mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag, + rif_subport->lag ? rif_subport->lag_id : + rif_subport->system_port, + rif_subport->vid); + + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); +} + +static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif) +{ + return mlxsw_sp_rif_subport_op(rif, true); +} + +static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif *rif) +{ + mlxsw_sp_rif_subport_op(rif, false); +} + +static struct mlxsw_sp_fid * +mlxsw_sp_rif_subport_fid_get(struct mlxsw_sp_rif *rif) +{ + return mlxsw_sp_fid_rfid_get(rif->mlxsw_sp, rif->rif_index); +} + +static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_subport_ops = { + .type = MLXSW_SP_RIF_TYPE_SUBPORT, + .rif_size = sizeof(struct mlxsw_sp_rif_subport), + .setup = mlxsw_sp_rif_subport_setup, + .configure = mlxsw_sp_rif_subport_configure, + .deconfigure = mlxsw_sp_rif_subport_deconfigure, + .fid_get = mlxsw_sp_rif_subport_fid_get, +}; + +static int mlxsw_sp_rif_vlan_fid_op(struct mlxsw_sp_rif *rif, + enum mlxsw_reg_ritr_if_type type, + u16 vid_fid, bool enable) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + char ritr_pl[MLXSW_REG_RITR_LEN]; + + mlxsw_reg_ritr_pack(ritr_pl, enable, type, rif->rif_index, rif->vr_id, + rif->dev->mtu, rif->dev->dev_addr); + mlxsw_reg_ritr_fid_set(ritr_pl, type, vid_fid); + + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); +} + +static u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp) +{ + return mlxsw_core_max_ports(mlxsw_sp->core) + 1; +} + +static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif *rif) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid); + int err; + + err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, true); + if (err) + return err; + + err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, + mlxsw_sp_router_port(mlxsw_sp), true); + if (err) + goto err_fid_bc_flood_set; + + return 0; + +err_fid_bc_flood_set: + mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, false); + return err; +} + +static void mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif *rif) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid); + + mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, + mlxsw_sp_router_port(mlxsw_sp), false); + mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, false); +} + +static struct mlxsw_sp_fid * +mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif) +{ + u16 vid = is_vlan_dev(rif->dev) ? vlan_dev_vlan_id(rif->dev) : 1; + + return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, vid); +} + +static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_vlan_ops = { + .type = MLXSW_SP_RIF_TYPE_VLAN, + .rif_size = sizeof(struct mlxsw_sp_rif), + .configure = mlxsw_sp_rif_vlan_configure, + .deconfigure = mlxsw_sp_rif_vlan_deconfigure, + .fid_get = mlxsw_sp_rif_vlan_fid_get, +}; + +static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + u16 fid_index = mlxsw_sp_fid_index(rif->fid); + int err; + + err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, + true); + if (err) + return err; + + err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, + mlxsw_sp_router_port(mlxsw_sp), true); + if (err) + goto err_fid_bc_flood_set; + + return 0; + +err_fid_bc_flood_set: + mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false); + return err; +} + +static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + u16 fid_index = mlxsw_sp_fid_index(rif->fid); + + mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, + mlxsw_sp_router_port(mlxsw_sp), false); + mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false); +} + +static struct mlxsw_sp_fid * +mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif *rif) +{ + return mlxsw_sp_fid_8021d_get(rif->mlxsw_sp, rif->dev->ifindex); +} + +static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops = { + .type = MLXSW_SP_RIF_TYPE_FID, + .rif_size = sizeof(struct mlxsw_sp_rif), + .configure = mlxsw_sp_rif_fid_configure, + .deconfigure = mlxsw_sp_rif_fid_deconfigure, + .fid_get = mlxsw_sp_rif_fid_fid_get, +}; + +static const struct mlxsw_sp_rif_ops *mlxsw_sp_rif_ops_arr[] = { + [MLXSW_SP_RIF_TYPE_SUBPORT] = &mlxsw_sp_rif_subport_ops, + [MLXSW_SP_RIF_TYPE_VLAN] = &mlxsw_sp_rif_vlan_ops, + [MLXSW_SP_RIF_TYPE_FID] = &mlxsw_sp_rif_fid_ops, +}; + +static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp) +{ + u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); + + mlxsw_sp->router->rifs = kcalloc(max_rifs, + sizeof(struct mlxsw_sp_rif *), + GFP_KERNEL); + if (!mlxsw_sp->router->rifs) + return -ENOMEM; + + mlxsw_sp->router->rif_ops_arr = mlxsw_sp_rif_ops_arr; + + return 0; +} + +static void mlxsw_sp_rifs_fini(struct mlxsw_sp *mlxsw_sp) +{ + int i; + + for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) + WARN_ON_ONCE(mlxsw_sp->router->rifs[i]); + + kfree(mlxsw_sp->router->rifs); +} + static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb) { - struct mlxsw_sp *mlxsw_sp = container_of(nb, struct mlxsw_sp, fib_nb); + struct mlxsw_sp_router *router; /* Flush pending FIB notifications and then flush the device's * table before requesting another dump. The FIB notification * block is unregistered, so no need to take RTNL. */ mlxsw_core_flush_owq(); - mlxsw_sp_router_fib_flush(mlxsw_sp); + router = container_of(nb, struct mlxsw_sp_router, fib_nb); + mlxsw_sp_router_fib_flush(router->mlxsw_sp); } static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) @@ -3512,55 +3688,50 @@ static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_RIFS)) return -EIO; - max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); - mlxsw_sp->rifs = kcalloc(max_rifs, sizeof(struct mlxsw_sp_rif *), - GFP_KERNEL); - if (!mlxsw_sp->rifs) - return -ENOMEM; mlxsw_reg_rgcr_pack(rgcr_pl, true); mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, max_rifs); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); if (err) - goto err_rgcr_fail; - + return err; return 0; - -err_rgcr_fail: - kfree(mlxsw_sp->rifs); - return err; } static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) { char rgcr_pl[MLXSW_REG_RGCR_LEN]; - int i; mlxsw_reg_rgcr_pack(rgcr_pl, false); mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); - - for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) - WARN_ON_ONCE(mlxsw_sp->rifs[i]); - - kfree(mlxsw_sp->rifs); } int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) { + struct mlxsw_sp_router *router; int err; - INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_neighs_list); + router = kzalloc(sizeof(*mlxsw_sp->router), GFP_KERNEL); + if (!router) + return -ENOMEM; + mlxsw_sp->router = router; + router->mlxsw_sp = mlxsw_sp; + + INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_neighs_list); err = __mlxsw_sp_router_init(mlxsw_sp); if (err) - return err; + goto err_router_init; + + err = mlxsw_sp_rifs_init(mlxsw_sp); + if (err) + goto err_rifs_init; - err = rhashtable_init(&mlxsw_sp->router.nexthop_ht, + err = rhashtable_init(&mlxsw_sp->router->nexthop_ht, &mlxsw_sp_nexthop_ht_params); if (err) goto err_nexthop_ht_init; - err = rhashtable_init(&mlxsw_sp->router.nexthop_group_ht, + err = rhashtable_init(&mlxsw_sp->router->nexthop_group_ht, &mlxsw_sp_nexthop_group_ht_params); if (err) goto err_nexthop_group_ht_init; @@ -3577,8 +3748,8 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) if (err) goto err_neigh_init; - mlxsw_sp->fib_nb.notifier_call = mlxsw_sp_router_fib_event; - err = register_fib_notifier(&mlxsw_sp->fib_nb, + mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event; + err = register_fib_notifier(&mlxsw_sp->router->fib_nb, mlxsw_sp_router_fib_dump_flush); if (err) goto err_register_fib_notifier; @@ -3592,21 +3763,27 @@ err_neigh_init: err_vrs_init: mlxsw_sp_lpm_fini(mlxsw_sp); err_lpm_init: - rhashtable_destroy(&mlxsw_sp->router.nexthop_group_ht); + rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht); err_nexthop_group_ht_init: - rhashtable_destroy(&mlxsw_sp->router.nexthop_ht); + rhashtable_destroy(&mlxsw_sp->router->nexthop_ht); err_nexthop_ht_init: + mlxsw_sp_rifs_fini(mlxsw_sp); +err_rifs_init: __mlxsw_sp_router_fini(mlxsw_sp); +err_router_init: + kfree(mlxsw_sp->router); return err; } void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) { - unregister_fib_notifier(&mlxsw_sp->fib_nb); + unregister_fib_notifier(&mlxsw_sp->router->fib_nb); mlxsw_sp_neigh_fini(mlxsw_sp); mlxsw_sp_vrs_fini(mlxsw_sp); mlxsw_sp_lpm_fini(mlxsw_sp); - rhashtable_destroy(&mlxsw_sp->router.nexthop_group_ht); - rhashtable_destroy(&mlxsw_sp->router.nexthop_ht); + rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht); + rhashtable_destroy(&mlxsw_sp->router->nexthop_ht); + mlxsw_sp_rifs_fini(mlxsw_sp); __mlxsw_sp_router_fini(mlxsw_sp); + kfree(mlxsw_sp->router); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h index c3095fef6697..a3e8d2b25148 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h @@ -42,6 +42,8 @@ enum mlxsw_sp_rif_counter_dir { MLXSW_SP_RIF_COUNTER_EGRESS, }; +struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp, + u16 rif_index); u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif); int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif); int mlxsw_sp_rif_counter_value_get(struct mlxsw_sp *mlxsw_sp, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index f4bb0c0b7c1d..edcc273d7597 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -52,340 +52,596 @@ #include "core.h" #include "reg.h" -static u16 mlxsw_sp_port_vid_to_fid_get(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid) -{ - struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_port); - u16 fid = vid; +struct mlxsw_sp_bridge_ops; + +struct mlxsw_sp_bridge { + struct mlxsw_sp *mlxsw_sp; + struct { + struct delayed_work dw; +#define MLXSW_SP_DEFAULT_LEARNING_INTERVAL 100 + unsigned int interval; /* ms */ + } fdb_notify; +#define MLXSW_SP_MIN_AGEING_TIME 10 +#define MLXSW_SP_MAX_AGEING_TIME 1000000 +#define MLXSW_SP_DEFAULT_AGEING_TIME 300 + u32 ageing_time; + bool vlan_enabled_exists; + struct list_head bridges_list; + struct list_head mids_list; + DECLARE_BITMAP(mids_bitmap, MLXSW_SP_MID_MAX); + const struct mlxsw_sp_bridge_ops *bridge_8021q_ops; + const struct mlxsw_sp_bridge_ops *bridge_8021d_ops; +}; + +struct mlxsw_sp_bridge_device { + struct net_device *dev; + struct list_head list; + struct list_head ports_list; + u8 vlan_enabled:1, + multicast_enabled:1; + const struct mlxsw_sp_bridge_ops *ops; +}; + +struct mlxsw_sp_bridge_port { + struct net_device *dev; + struct mlxsw_sp_bridge_device *bridge_device; + struct list_head list; + struct list_head vlans_list; + unsigned int ref_count; + u8 stp_state; + unsigned long flags; + bool mrouter; + bool lagged; + union { + u16 lag_id; + u16 system_port; + }; +}; - fid = f ? f->fid : fid; +struct mlxsw_sp_bridge_vlan { + struct list_head list; + struct list_head port_vlan_list; + u16 vid; + u8 egress_untagged:1, + pvid:1; +}; + +struct mlxsw_sp_bridge_ops { + int (*port_join)(struct mlxsw_sp_bridge_device *bridge_device, + struct mlxsw_sp_bridge_port *bridge_port, + struct mlxsw_sp_port *mlxsw_sp_port); + void (*port_leave)(struct mlxsw_sp_bridge_device *bridge_device, + struct mlxsw_sp_bridge_port *bridge_port, + struct mlxsw_sp_port *mlxsw_sp_port); + struct mlxsw_sp_fid * + (*fid_get)(struct mlxsw_sp_bridge_device *bridge_device, + u16 vid); +}; + +static int +mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_bridge_port *bridge_port, + u16 fid_index); + +static struct mlxsw_sp_bridge_device * +mlxsw_sp_bridge_device_find(const struct mlxsw_sp_bridge *bridge, + const struct net_device *br_dev) +{ + struct mlxsw_sp_bridge_device *bridge_device; - if (!fid) - fid = mlxsw_sp_port->pvid; + list_for_each_entry(bridge_device, &bridge->bridges_list, list) + if (bridge_device->dev == br_dev) + return bridge_device; - return fid; + return NULL; } -static struct mlxsw_sp_port * -mlxsw_sp_port_orig_get(struct net_device *dev, - struct mlxsw_sp_port *mlxsw_sp_port) +static struct mlxsw_sp_bridge_device * +mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge, + struct net_device *br_dev) { - struct mlxsw_sp_port *mlxsw_sp_vport; - struct mlxsw_sp_fid *fid; - u16 vid; + struct device *dev = bridge->mlxsw_sp->bus_info->dev; + struct mlxsw_sp_bridge_device *bridge_device; + bool vlan_enabled = br_vlan_enabled(br_dev); - if (netif_is_bridge_master(dev)) { - fid = mlxsw_sp_vfid_find(mlxsw_sp_port->mlxsw_sp, - dev); - if (fid) { - mlxsw_sp_vport = - mlxsw_sp_port_vport_find_by_fid(mlxsw_sp_port, - fid->fid); - WARN_ON(!mlxsw_sp_vport); - return mlxsw_sp_vport; - } + if (vlan_enabled && bridge->vlan_enabled_exists) { + dev_err(dev, "Only one VLAN-aware bridge is supported\n"); + return ERR_PTR(-EINVAL); } - if (!is_vlan_dev(dev)) - return mlxsw_sp_port; + bridge_device = kzalloc(sizeof(*bridge_device), GFP_KERNEL); + if (!bridge_device) + return ERR_PTR(-ENOMEM); + + bridge_device->dev = br_dev; + bridge_device->vlan_enabled = vlan_enabled; + bridge_device->multicast_enabled = br_multicast_enabled(br_dev); + INIT_LIST_HEAD(&bridge_device->ports_list); + if (vlan_enabled) { + bridge->vlan_enabled_exists = true; + bridge_device->ops = bridge->bridge_8021q_ops; + } else { + bridge_device->ops = bridge->bridge_8021d_ops; + } + list_add(&bridge_device->list, &bridge->bridges_list); - vid = vlan_dev_vlan_id(dev); - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); - WARN_ON(!mlxsw_sp_vport); + return bridge_device; +} - return mlxsw_sp_vport; +static void +mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge *bridge, + struct mlxsw_sp_bridge_device *bridge_device) +{ + list_del(&bridge_device->list); + if (bridge_device->vlan_enabled) + bridge->vlan_enabled_exists = false; + WARN_ON(!list_empty(&bridge_device->ports_list)); + kfree(bridge_device); } -static int mlxsw_sp_port_attr_get(struct net_device *dev, - struct switchdev_attr *attr) +static struct mlxsw_sp_bridge_device * +mlxsw_sp_bridge_device_get(struct mlxsw_sp_bridge *bridge, + struct net_device *br_dev) { - struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_bridge_device *bridge_device; - mlxsw_sp_port = mlxsw_sp_port_orig_get(attr->orig_dev, mlxsw_sp_port); - if (!mlxsw_sp_port) - return -EINVAL; + bridge_device = mlxsw_sp_bridge_device_find(bridge, br_dev); + if (bridge_device) + return bridge_device; - switch (attr->id) { - case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: - attr->u.ppid.id_len = sizeof(mlxsw_sp->base_mac); - memcpy(&attr->u.ppid.id, &mlxsw_sp->base_mac, - attr->u.ppid.id_len); - break; - case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: - attr->u.brport_flags = - (mlxsw_sp_port->learning ? BR_LEARNING : 0) | - (mlxsw_sp_port->learning_sync ? BR_LEARNING_SYNC : 0) | - (mlxsw_sp_port->uc_flood ? BR_FLOOD : 0); - break; - default: - return -EOPNOTSUPP; + return mlxsw_sp_bridge_device_create(bridge, br_dev); +} + +static void +mlxsw_sp_bridge_device_put(struct mlxsw_sp_bridge *bridge, + struct mlxsw_sp_bridge_device *bridge_device) +{ + if (list_empty(&bridge_device->ports_list)) + mlxsw_sp_bridge_device_destroy(bridge, bridge_device); +} + +static struct mlxsw_sp_bridge_port * +__mlxsw_sp_bridge_port_find(const struct mlxsw_sp_bridge_device *bridge_device, + const struct net_device *brport_dev) +{ + struct mlxsw_sp_bridge_port *bridge_port; + + list_for_each_entry(bridge_port, &bridge_device->ports_list, list) { + if (bridge_port->dev == brport_dev) + return bridge_port; } - return 0; + return NULL; } -static int mlxsw_sp_port_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port, - u8 state) +static struct mlxsw_sp_bridge_port * +mlxsw_sp_bridge_port_find(struct mlxsw_sp_bridge *bridge, + struct net_device *brport_dev) { - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - enum mlxsw_reg_spms_state spms_state; - char *spms_pl; - u16 vid; + struct net_device *br_dev = netdev_master_upper_dev_get(brport_dev); + struct mlxsw_sp_bridge_device *bridge_device; + + if (!br_dev) + return NULL; + + bridge_device = mlxsw_sp_bridge_device_find(bridge, br_dev); + if (!bridge_device) + return NULL; + + return __mlxsw_sp_bridge_port_find(bridge_device, brport_dev); +} + +static struct mlxsw_sp_bridge_port * +mlxsw_sp_bridge_port_create(struct mlxsw_sp_bridge_device *bridge_device, + struct net_device *brport_dev) +{ + struct mlxsw_sp_bridge_port *bridge_port; + struct mlxsw_sp_port *mlxsw_sp_port; + + bridge_port = kzalloc(sizeof(*bridge_port), GFP_KERNEL); + if (!bridge_port) + return NULL; + + mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(brport_dev); + bridge_port->lagged = mlxsw_sp_port->lagged; + if (bridge_port->lagged) + bridge_port->lag_id = mlxsw_sp_port->lag_id; + else + bridge_port->system_port = mlxsw_sp_port->local_port; + bridge_port->dev = brport_dev; + bridge_port->bridge_device = bridge_device; + bridge_port->stp_state = BR_STATE_DISABLED; + bridge_port->flags = BR_LEARNING | BR_FLOOD | BR_LEARNING_SYNC; + INIT_LIST_HEAD(&bridge_port->vlans_list); + list_add(&bridge_port->list, &bridge_device->ports_list); + bridge_port->ref_count = 1; + + return bridge_port; +} + +static void +mlxsw_sp_bridge_port_destroy(struct mlxsw_sp_bridge_port *bridge_port) +{ + list_del(&bridge_port->list); + WARN_ON(!list_empty(&bridge_port->vlans_list)); + kfree(bridge_port); +} + +static bool +mlxsw_sp_bridge_port_should_destroy(const struct mlxsw_sp_bridge_port * + bridge_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_port->dev); + + /* In case ports were pulled from out of a bridged LAG, then + * it's possible the reference count isn't zero, yet the bridge + * port should be destroyed, as it's no longer an upper of ours. + */ + if (!mlxsw_sp && list_empty(&bridge_port->vlans_list)) + return true; + else if (bridge_port->ref_count == 0) + return true; + else + return false; +} + +static struct mlxsw_sp_bridge_port * +mlxsw_sp_bridge_port_get(struct mlxsw_sp_bridge *bridge, + struct net_device *brport_dev) +{ + struct net_device *br_dev = netdev_master_upper_dev_get(brport_dev); + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; int err; - switch (state) { - case BR_STATE_FORWARDING: - spms_state = MLXSW_REG_SPMS_STATE_FORWARDING; - break; - case BR_STATE_LEARNING: - spms_state = MLXSW_REG_SPMS_STATE_LEARNING; - break; - case BR_STATE_LISTENING: /* fall-through */ - case BR_STATE_DISABLED: /* fall-through */ - case BR_STATE_BLOCKING: - spms_state = MLXSW_REG_SPMS_STATE_DISCARDING; - break; - default: - BUG(); + bridge_port = mlxsw_sp_bridge_port_find(bridge, brport_dev); + if (bridge_port) { + bridge_port->ref_count++; + return bridge_port; } - spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL); - if (!spms_pl) - return -ENOMEM; - mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port); + bridge_device = mlxsw_sp_bridge_device_get(bridge, br_dev); + if (IS_ERR(bridge_device)) + return ERR_CAST(bridge_device); - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { - vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port); - mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state); - } else { - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) - mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state); + bridge_port = mlxsw_sp_bridge_port_create(bridge_device, brport_dev); + if (!bridge_port) { + err = -ENOMEM; + goto err_bridge_port_create; } - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl); - kfree(spms_pl); - return err; + return bridge_port; + +err_bridge_port_create: + mlxsw_sp_bridge_device_put(bridge, bridge_device); + return ERR_PTR(err); } -static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port, - struct switchdev_trans *trans, - u8 state) +static void mlxsw_sp_bridge_port_put(struct mlxsw_sp_bridge *bridge, + struct mlxsw_sp_bridge_port *bridge_port) { - if (switchdev_trans_ph_prepare(trans)) - return 0; + struct mlxsw_sp_bridge_device *bridge_device; - mlxsw_sp_port->stp_state = state; - return mlxsw_sp_port_stp_state_set(mlxsw_sp_port, state); + bridge_port->ref_count--; + if (!mlxsw_sp_bridge_port_should_destroy(bridge_port)) + return; + bridge_device = bridge_port->bridge_device; + mlxsw_sp_bridge_port_destroy(bridge_port); + mlxsw_sp_bridge_device_put(bridge, bridge_device); } -static int __mlxsw_sp_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port, - u16 idx_begin, u16 idx_end, - enum mlxsw_sp_flood_table table, - bool set) +static struct mlxsw_sp_port_vlan * +mlxsw_sp_port_vlan_find_by_bridge(struct mlxsw_sp_port *mlxsw_sp_port, + const struct mlxsw_sp_bridge_device * + bridge_device, + u16 vid) { - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - u16 local_port = mlxsw_sp_port->local_port; - enum mlxsw_flood_table_type table_type; - u16 range = idx_end - idx_begin + 1; - char *sftr_pl; - int err; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) - table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID; - else - table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST; + list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, + list) { + if (!mlxsw_sp_port_vlan->bridge_port) + continue; + if (mlxsw_sp_port_vlan->bridge_port->bridge_device != + bridge_device) + continue; + if (bridge_device->vlan_enabled && + mlxsw_sp_port_vlan->vid != vid) + continue; + return mlxsw_sp_port_vlan; + } - sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL); - if (!sftr_pl) - return -ENOMEM; + return NULL; +} - mlxsw_reg_sftr_pack(sftr_pl, table, idx_begin, - table_type, range, local_port, set); - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl); +static struct mlxsw_sp_port_vlan* +mlxsw_sp_port_vlan_find_by_fid(struct mlxsw_sp_port *mlxsw_sp_port, + u16 fid_index) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - kfree(sftr_pl); - return err; + list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, + list) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + + if (fid && mlxsw_sp_fid_index(fid) == fid_index) + return mlxsw_sp_port_vlan; + } + + return NULL; } -static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port, - u16 idx_begin, u16 idx_end, bool uc_set, - bool bc_set, bool mc_set) +static struct mlxsw_sp_bridge_vlan * +mlxsw_sp_bridge_vlan_find(const struct mlxsw_sp_bridge_port *bridge_port, + u16 vid) { - int err; + struct mlxsw_sp_bridge_vlan *bridge_vlan; - err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end, - MLXSW_SP_FLOOD_TABLE_UC, uc_set); - if (err) - return err; + list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) { + if (bridge_vlan->vid == vid) + return bridge_vlan; + } - err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end, - MLXSW_SP_FLOOD_TABLE_BC, bc_set); - if (err) - goto err_flood_bm_set; + return NULL; +} - err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end, - MLXSW_SP_FLOOD_TABLE_MC, mc_set); - if (err) - goto err_flood_mc_set; - return 0; +static struct mlxsw_sp_bridge_vlan * +mlxsw_sp_bridge_vlan_create(struct mlxsw_sp_bridge_port *bridge_port, u16 vid) +{ + struct mlxsw_sp_bridge_vlan *bridge_vlan; -err_flood_mc_set: - __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end, - MLXSW_SP_FLOOD_TABLE_BC, !bc_set); -err_flood_bm_set: - __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end, - MLXSW_SP_FLOOD_TABLE_UC, !uc_set); - return err; + bridge_vlan = kzalloc(sizeof(*bridge_vlan), GFP_KERNEL); + if (!bridge_vlan) + return NULL; + + INIT_LIST_HEAD(&bridge_vlan->port_vlan_list); + bridge_vlan->vid = vid; + list_add(&bridge_vlan->list, &bridge_port->vlans_list); + + return bridge_vlan; } -static int mlxsw_sp_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port, - enum mlxsw_sp_flood_table table, - bool set) +static void +mlxsw_sp_bridge_vlan_destroy(struct mlxsw_sp_bridge_vlan *bridge_vlan) { - struct net_device *dev = mlxsw_sp_port->dev; - u16 vid, last_visited_vid; - int err; + list_del(&bridge_vlan->list); + WARN_ON(!list_empty(&bridge_vlan->port_vlan_list)); + kfree(bridge_vlan); +} - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { - u16 fid = mlxsw_sp_vport_fid_get(mlxsw_sp_port)->fid; - u16 vfid = mlxsw_sp_fid_to_vfid(fid); +static struct mlxsw_sp_bridge_vlan * +mlxsw_sp_bridge_vlan_get(struct mlxsw_sp_bridge_port *bridge_port, u16 vid) +{ + struct mlxsw_sp_bridge_vlan *bridge_vlan; - return __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, vfid, - vfid, table, set); - } + bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid); + if (bridge_vlan) + return bridge_vlan; - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) { - err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, vid, vid, - table, set); - if (err) { - last_visited_vid = vid; - goto err_port_flood_set; - } + return mlxsw_sp_bridge_vlan_create(bridge_port, vid); +} + +static void mlxsw_sp_bridge_vlan_put(struct mlxsw_sp_bridge_vlan *bridge_vlan) +{ + if (list_empty(&bridge_vlan->port_vlan_list)) + mlxsw_sp_bridge_vlan_destroy(bridge_vlan); +} + +static void mlxsw_sp_port_bridge_flags_get(struct mlxsw_sp_bridge *bridge, + struct net_device *dev, + unsigned long *brport_flags) +{ + struct mlxsw_sp_bridge_port *bridge_port; + + bridge_port = mlxsw_sp_bridge_port_find(bridge, dev); + if (WARN_ON(!bridge_port)) + return; + + memcpy(brport_flags, &bridge_port->flags, sizeof(*brport_flags)); +} + +static int mlxsw_sp_port_attr_get(struct net_device *dev, + struct switchdev_attr *attr) +{ + struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + + switch (attr->id) { + case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: + attr->u.ppid.id_len = sizeof(mlxsw_sp->base_mac); + memcpy(&attr->u.ppid.id, &mlxsw_sp->base_mac, + attr->u.ppid.id_len); + break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: + mlxsw_sp_port_bridge_flags_get(mlxsw_sp->bridge, attr->orig_dev, + &attr->u.brport_flags); + break; + default: + return -EOPNOTSUPP; } return 0; +} -err_port_flood_set: - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, last_visited_vid) - __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, vid, vid, table, - !set); - netdev_err(dev, "Failed to configure unicast flooding\n"); - return err; +static int +mlxsw_sp_port_bridge_vlan_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_bridge_vlan *bridge_vlan, + u8 state) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list, + bridge_vlan_node) { + if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port) + continue; + return mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, + bridge_vlan->vid, state); + } + + return 0; } -static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port, - struct switchdev_trans *trans, - bool mc_disabled) +static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct switchdev_trans *trans, + struct net_device *orig_dev, + u8 state) { - int set; - int err = 0; + struct mlxsw_sp_bridge_port *bridge_port; + struct mlxsw_sp_bridge_vlan *bridge_vlan; + int err; if (switchdev_trans_ph_prepare(trans)) return 0; - if (mlxsw_sp_port->mc_router != mlxsw_sp_port->mc_flood) { - set = mc_disabled ? - mlxsw_sp_port->mc_flood : mlxsw_sp_port->mc_router; - err = mlxsw_sp_port_flood_table_set(mlxsw_sp_port, - MLXSW_SP_FLOOD_TABLE_MC, - set); + /* It's possible we failed to enslave the port, yet this + * operation is executed due to it being deferred. + */ + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge, + orig_dev); + if (!bridge_port) + return 0; + + list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) { + err = mlxsw_sp_port_bridge_vlan_stp_set(mlxsw_sp_port, + bridge_vlan, state); + if (err) + goto err_port_bridge_vlan_stp_set; } - if (!err) - mlxsw_sp_port->mc_disabled = mc_disabled; + bridge_port->stp_state = state; + return 0; + +err_port_bridge_vlan_stp_set: + list_for_each_entry_continue_reverse(bridge_vlan, + &bridge_port->vlans_list, list) + mlxsw_sp_port_bridge_vlan_stp_set(mlxsw_sp_port, bridge_vlan, + bridge_port->stp_state); return err; } -int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid, - bool set) +static int +mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_bridge_vlan *bridge_vlan, + enum mlxsw_sp_flood_type packet_type, + bool member) { - bool mc_set = set; - u16 vfid; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - /* In case of vFIDs, index into the flooding table is relative to - * the start of the vFIDs range. - */ - vfid = mlxsw_sp_fid_to_vfid(fid); - - if (set) - mc_set = mlxsw_sp_vport->mc_disabled ? - mlxsw_sp_vport->mc_flood : mlxsw_sp_vport->mc_router; + list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list, + bridge_vlan_node) { + if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port) + continue; + return mlxsw_sp_fid_flood_set(mlxsw_sp_port_vlan->fid, + packet_type, + mlxsw_sp_port->local_port, + member); + } - return __mlxsw_sp_port_flood_set(mlxsw_sp_vport, vfid, vfid, set, set, - mc_set); + return 0; } -static int mlxsw_sp_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, - bool set) +static int +mlxsw_sp_bridge_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_bridge_port *bridge_port, + enum mlxsw_sp_flood_type packet_type, + bool member) { - u16 vid; + struct mlxsw_sp_bridge_vlan *bridge_vlan; int err; - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { - vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port); + list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) { + err = mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port, + bridge_vlan, + packet_type, + member); + if (err) + goto err_port_bridge_vlan_flood_set; + } - return __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, vid, - set); + return 0; + +err_port_bridge_vlan_flood_set: + list_for_each_entry_continue_reverse(bridge_vlan, + &bridge_port->vlans_list, list) + mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port, bridge_vlan, + packet_type, !member); + return err; +} + +static int +mlxsw_sp_port_bridge_vlan_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_bridge_vlan *bridge_vlan, + bool set) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + u16 vid = bridge_vlan->vid; + + list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list, + bridge_vlan_node) { + if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port) + continue; + return mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, set); } - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) { - err = __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, vid, - set); + return 0; +} + +static int +mlxsw_sp_bridge_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_bridge_port *bridge_port, + bool set) +{ + struct mlxsw_sp_bridge_vlan *bridge_vlan; + int err; + + list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) { + err = mlxsw_sp_port_bridge_vlan_learning_set(mlxsw_sp_port, + bridge_vlan, set); if (err) - goto err_port_vid_learning_set; + goto err_port_bridge_vlan_learning_set; } return 0; -err_port_vid_learning_set: - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) - __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, vid, !set); +err_port_bridge_vlan_learning_set: + list_for_each_entry_continue_reverse(bridge_vlan, + &bridge_port->vlans_list, list) + mlxsw_sp_port_bridge_vlan_learning_set(mlxsw_sp_port, + bridge_vlan, !set); return err; } static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port, struct switchdev_trans *trans, + struct net_device *orig_dev, unsigned long brport_flags) { - unsigned long learning = mlxsw_sp_port->learning ? BR_LEARNING : 0; - unsigned long uc_flood = mlxsw_sp_port->uc_flood ? BR_FLOOD : 0; + struct mlxsw_sp_bridge_port *bridge_port; int err; - if (!mlxsw_sp_port->bridged) - return -EINVAL; - if (switchdev_trans_ph_prepare(trans)) return 0; - if ((uc_flood ^ brport_flags) & BR_FLOOD) { - err = mlxsw_sp_port_flood_table_set(mlxsw_sp_port, - MLXSW_SP_FLOOD_TABLE_UC, - !mlxsw_sp_port->uc_flood); - if (err) - return err; - } + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge, + orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; - if ((learning ^ brport_flags) & BR_LEARNING) { - err = mlxsw_sp_port_learning_set(mlxsw_sp_port, - !mlxsw_sp_port->learning); - if (err) - goto err_port_learning_set; - } + err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port, + MLXSW_SP_FLOOD_TYPE_UC, + brport_flags & BR_FLOOD); + if (err) + return err; - mlxsw_sp_port->uc_flood = brport_flags & BR_FLOOD ? 1 : 0; - mlxsw_sp_port->learning = brport_flags & BR_LEARNING ? 1 : 0; - mlxsw_sp_port->learning_sync = brport_flags & BR_LEARNING_SYNC ? 1 : 0; + err = mlxsw_sp_bridge_port_learning_set(mlxsw_sp_port, bridge_port, + brport_flags & BR_LEARNING); + if (err) + return err; - return 0; + memcpy(&bridge_port->flags, &brport_flags, sizeof(brport_flags)); -err_port_learning_set: - if ((uc_flood ^ brport_flags) & BR_FLOOD) - mlxsw_sp_port_flood_table_set(mlxsw_sp_port, - MLXSW_SP_FLOOD_TABLE_UC, - mlxsw_sp_port->uc_flood); - return err; + return 0; } static int mlxsw_sp_ageing_set(struct mlxsw_sp *mlxsw_sp, u32 ageing_time) @@ -397,7 +653,7 @@ static int mlxsw_sp_ageing_set(struct mlxsw_sp *mlxsw_sp, u32 ageing_time) err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdat), sfdat_pl); if (err) return err; - mlxsw_sp->ageing_time = ageing_time; + mlxsw_sp->bridge->ageing_time = ageing_time; return 0; } @@ -426,28 +682,77 @@ static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, bool vlan_enabled) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_bridge_device *bridge_device; - /* SWITCHDEV_TRANS_PREPARE phase */ - if ((!vlan_enabled) && (mlxsw_sp->master_bridge.dev == orig_dev)) { - netdev_err(mlxsw_sp_port->dev, "Bridge must be vlan-aware\n"); + if (!switchdev_trans_ph_prepare(trans)) + return 0; + + bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_device)) return -EINVAL; - } - return 0; + if (bridge_device->vlan_enabled == vlan_enabled) + return 0; + + netdev_err(bridge_device->dev, "VLAN filtering can't be changed for existing bridge\n"); + return -EINVAL; } static int mlxsw_sp_port_attr_mc_router_set(struct mlxsw_sp_port *mlxsw_sp_port, struct switchdev_trans *trans, + struct net_device *orig_dev, bool is_port_mc_router) { + struct mlxsw_sp_bridge_port *bridge_port; + if (switchdev_trans_ph_prepare(trans)) return 0; - mlxsw_sp_port->mc_router = is_port_mc_router; - if (!mlxsw_sp_port->mc_disabled) - return mlxsw_sp_port_flood_table_set(mlxsw_sp_port, - MLXSW_SP_FLOOD_TABLE_MC, - is_port_mc_router); + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge, + orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; + + if (!bridge_port->bridge_device->multicast_enabled) + return 0; + + return mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port, + MLXSW_SP_FLOOD_TYPE_MC, + is_port_mc_router); +} + +static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct switchdev_trans *trans, + struct net_device *orig_dev, + bool mc_disabled) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; + int err; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + /* It's possible we failed to enslave the port, yet this + * operation is executed due to it being deferred. + */ + bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev); + if (!bridge_device) + return 0; + + list_for_each_entry(bridge_port, &bridge_device->ports_list, list) { + enum mlxsw_sp_flood_type packet_type = MLXSW_SP_FLOOD_TYPE_MC; + bool member = mc_disabled ? true : bridge_port->mrouter; + + err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, + bridge_port, + packet_type, member); + if (err) + return err; + } + + bridge_device->multicast_enabled = !mc_disabled; return 0; } @@ -457,19 +762,17 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev, struct switchdev_trans *trans) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); - int err = 0; - - mlxsw_sp_port = mlxsw_sp_port_orig_get(attr->orig_dev, mlxsw_sp_port); - if (!mlxsw_sp_port) - return -EINVAL; + int err; switch (attr->id) { case SWITCHDEV_ATTR_ID_PORT_STP_STATE: err = mlxsw_sp_port_attr_stp_state_set(mlxsw_sp_port, trans, + attr->orig_dev, attr->u.stp_state); break; case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: err = mlxsw_sp_port_attr_br_flags_set(mlxsw_sp_port, trans, + attr->orig_dev, attr->u.brport_flags); break; case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: @@ -483,10 +786,12 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev, break; case SWITCHDEV_ATTR_ID_PORT_MROUTER: err = mlxsw_sp_port_attr_mc_router_set(mlxsw_sp_port, trans, + attr->orig_dev, attr->u.mrouter); break; case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED: err = mlxsw_sp_port_mc_disabled_set(mlxsw_sp_port, trans, + attr->orig_dev, attr->u.mc_disabled); break; default: @@ -497,268 +802,245 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev, return err; } -static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid, bool create) +static bool mlxsw_sp_mc_flood(const struct mlxsw_sp_bridge_port *bridge_port) { - char sfmr_pl[MLXSW_REG_SFMR_LEN]; + const struct mlxsw_sp_bridge_device *bridge_device; - mlxsw_reg_sfmr_pack(sfmr_pl, !create, fid, fid); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); + bridge_device = bridge_port->bridge_device; + return !bridge_device->multicast_enabled ? true : bridge_port->mrouter; } -static int mlxsw_sp_fid_map(struct mlxsw_sp *mlxsw_sp, u16 fid, bool valid) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID; - char svfa_pl[MLXSW_REG_SVFA_LEN]; - - mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid, fid); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); -} - -static struct mlxsw_sp_fid *mlxsw_sp_fid_alloc(u16 fid) +static int +mlxsw_sp_port_vlan_fid_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, + struct mlxsw_sp_bridge_port *bridge_port) { - struct mlxsw_sp_fid *f; - - f = kzalloc(sizeof(*f), GFP_KERNEL); - if (!f) - return NULL; + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp_bridge_device *bridge_device; + u8 local_port = mlxsw_sp_port->local_port; + u16 vid = mlxsw_sp_port_vlan->vid; + struct mlxsw_sp_fid *fid; + int err; - f->fid = fid; + bridge_device = bridge_port->bridge_device; + fid = bridge_device->ops->fid_get(bridge_device, vid); + if (IS_ERR(fid)) + return PTR_ERR(fid); - return f; -} - -struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid) -{ - struct mlxsw_sp_fid *f; - int err; + err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, + bridge_port->flags & BR_FLOOD); + if (err) + goto err_fid_uc_flood_set; - err = mlxsw_sp_fid_op(mlxsw_sp, fid, true); + err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, + mlxsw_sp_mc_flood(bridge_port)); if (err) - return ERR_PTR(err); + goto err_fid_mc_flood_set; - /* Although all the ports member in the FID might be using a - * {Port, VID} to FID mapping, we create a global VID-to-FID - * mapping. This allows a port to transition to VLAN mode, - * knowing the global mapping exists. - */ - err = mlxsw_sp_fid_map(mlxsw_sp, fid, true); + err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, + true); if (err) - goto err_fid_map; + goto err_fid_bc_flood_set; - f = mlxsw_sp_fid_alloc(fid); - if (!f) { - err = -ENOMEM; - goto err_allocate_fid; - } + err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid); + if (err) + goto err_fid_port_vid_map; - list_add(&f->list, &mlxsw_sp->fids); + mlxsw_sp_port_vlan->fid = fid; - return f; + return 0; -err_allocate_fid: - mlxsw_sp_fid_map(mlxsw_sp, fid, false); -err_fid_map: - mlxsw_sp_fid_op(mlxsw_sp, fid, false); - return ERR_PTR(err); +err_fid_port_vid_map: + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, false); +err_fid_bc_flood_set: + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, false); +err_fid_mc_flood_set: + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, false); +err_fid_uc_flood_set: + mlxsw_sp_fid_put(fid); + return err; } -void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *f) +static void +mlxsw_sp_port_vlan_fid_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { - u16 fid = f->fid; - - list_del(&f->list); - - if (f->rif) - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif); - - kfree(f); + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u8 local_port = mlxsw_sp_port->local_port; + u16 vid = mlxsw_sp_port_vlan->vid; - mlxsw_sp_fid_map(mlxsw_sp, fid, false); + mlxsw_sp_port_vlan->fid = NULL; + mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid); + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, false); + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, false); + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, false); + mlxsw_sp_fid_put(fid); +} - mlxsw_sp_fid_op(mlxsw_sp, fid, false); +static u16 +mlxsw_sp_port_pvid_determine(const struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid, bool is_pvid) +{ + if (is_pvid) + return vid; + else if (mlxsw_sp_port->pvid == vid) + return 0; /* Dis-allow untagged packets */ + else + return mlxsw_sp_port->pvid; } -static int __mlxsw_sp_port_fid_join(struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid) +static int +mlxsw_sp_port_vlan_bridge_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, + struct mlxsw_sp_bridge_port *bridge_port) { - struct mlxsw_sp_fid *f; + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp_bridge_vlan *bridge_vlan; + u16 vid = mlxsw_sp_port_vlan->vid; + int err; - if (test_bit(fid, mlxsw_sp_port->active_vlans)) + /* No need to continue if only VLAN flags were changed */ + if (mlxsw_sp_port_vlan->bridge_port) return 0; - f = mlxsw_sp_fid_find(mlxsw_sp_port->mlxsw_sp, fid); - if (!f) { - f = mlxsw_sp_fid_create(mlxsw_sp_port->mlxsw_sp, fid); - if (IS_ERR(f)) - return PTR_ERR(f); + err = mlxsw_sp_port_vlan_fid_join(mlxsw_sp_port_vlan, bridge_port); + if (err) + return err; + + err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, + bridge_port->flags & BR_LEARNING); + if (err) + goto err_port_vid_learning_set; + + err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, + bridge_port->stp_state); + if (err) + goto err_port_vid_stp_set; + + bridge_vlan = mlxsw_sp_bridge_vlan_get(bridge_port, vid); + if (!bridge_vlan) { + err = -ENOMEM; + goto err_bridge_vlan_get; } - f->ref_count++; + list_add(&mlxsw_sp_port_vlan->bridge_vlan_node, + &bridge_vlan->port_vlan_list); - netdev_dbg(mlxsw_sp_port->dev, "Joined FID=%d\n", fid); + mlxsw_sp_bridge_port_get(mlxsw_sp_port->mlxsw_sp->bridge, + bridge_port->dev); + mlxsw_sp_port_vlan->bridge_port = bridge_port; return 0; + +err_bridge_vlan_get: + mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_DISABLED); +err_port_vid_stp_set: + mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false); +err_port_vid_learning_set: + mlxsw_sp_port_vlan_fid_leave(mlxsw_sp_port_vlan); + return err; } -static void __mlxsw_sp_port_fid_leave(struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid) +void +mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { - struct mlxsw_sp_fid *f; + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + struct mlxsw_sp_bridge_vlan *bridge_vlan; + struct mlxsw_sp_bridge_port *bridge_port; + u16 vid = mlxsw_sp_port_vlan->vid; + bool last; - f = mlxsw_sp_fid_find(mlxsw_sp_port->mlxsw_sp, fid); - if (WARN_ON(!f)) + if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021Q && + mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021D)) return; - netdev_dbg(mlxsw_sp_port->dev, "Left FID=%d\n", fid); + bridge_port = mlxsw_sp_port_vlan->bridge_port; + bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid); + last = list_is_singular(&bridge_vlan->port_vlan_list); - mlxsw_sp_port_fdb_flush(mlxsw_sp_port, fid); + list_del(&mlxsw_sp_port_vlan->bridge_vlan_node); + mlxsw_sp_bridge_vlan_put(bridge_vlan); + mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_DISABLED); + mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false); + if (last) + mlxsw_sp_bridge_port_fdb_flush(mlxsw_sp_port->mlxsw_sp, + bridge_port, + mlxsw_sp_fid_index(fid)); + mlxsw_sp_port_vlan_fid_leave(mlxsw_sp_port_vlan); - if (--f->ref_count == 0) - mlxsw_sp_fid_destroy(mlxsw_sp_port->mlxsw_sp, f); + mlxsw_sp_bridge_port_put(mlxsw_sp_port->mlxsw_sp->bridge, bridge_port); + mlxsw_sp_port_vlan->bridge_port = NULL; } -static int mlxsw_sp_port_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid, - bool valid) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - - /* If port doesn't have vPorts, then it can use the global - * VID-to-FID mapping. - */ - if (list_empty(&mlxsw_sp_port->vports_list)) - return 0; - - return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, valid, fid, fid); -} +static int +mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_bridge_port *bridge_port, + u16 vid, bool is_untagged, bool is_pvid) +{ + u16 pvid = mlxsw_sp_port_pvid_determine(mlxsw_sp_port, vid, is_pvid); + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_bridge_vlan *bridge_vlan; + u16 old_pvid = mlxsw_sp_port->pvid; + int err; -static int mlxsw_sp_port_fid_join(struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid_begin, u16 fid_end) -{ - bool mc_flood; - int fid, err; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, vid); + if (IS_ERR(mlxsw_sp_port_vlan)) + return PTR_ERR(mlxsw_sp_port_vlan); - for (fid = fid_begin; fid <= fid_end; fid++) { - err = __mlxsw_sp_port_fid_join(mlxsw_sp_port, fid); - if (err) - goto err_port_fid_join; - } + err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true, + is_untagged); + if (err) + goto err_port_vlan_set; - mc_flood = mlxsw_sp_port->mc_disabled ? - mlxsw_sp_port->mc_flood : mlxsw_sp_port->mc_router; + err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, pvid); + if (err) + goto err_port_pvid_set; - err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end, - mlxsw_sp_port->uc_flood, true, - mc_flood); + err = mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port); if (err) - goto err_port_flood_set; + goto err_port_vlan_bridge_join; - for (fid = fid_begin; fid <= fid_end; fid++) { - err = mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, true); - if (err) - goto err_port_fid_map; - } + bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid); + bridge_vlan->egress_untagged = is_untagged; + bridge_vlan->pvid = is_pvid; return 0; -err_port_fid_map: - for (fid--; fid >= fid_begin; fid--) - mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, false); - __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end, false, - false, false); -err_port_flood_set: - fid = fid_end; -err_port_fid_join: - for (fid--; fid >= fid_begin; fid--) - __mlxsw_sp_port_fid_leave(mlxsw_sp_port, fid); +err_port_vlan_bridge_join: + mlxsw_sp_port_pvid_set(mlxsw_sp_port, old_pvid); +err_port_pvid_set: + mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false); +err_port_vlan_set: + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); return err; } -static void mlxsw_sp_port_fid_leave(struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid_begin, u16 fid_end) -{ - int fid; - - for (fid = fid_begin; fid <= fid_end; fid++) - mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, false); - - __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end, false, - false, false); - - for (fid = fid_begin; fid <= fid_end; fid++) - __mlxsw_sp_port_fid_leave(mlxsw_sp_port, fid); -} - -static int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - char spvid_pl[MLXSW_REG_SPVID_LEN]; - - mlxsw_reg_spvid_pack(spvid_pl, mlxsw_sp_port->local_port, vid); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl); -} - -static int mlxsw_sp_port_allow_untagged_set(struct mlxsw_sp_port *mlxsw_sp_port, - bool allow) +static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, + const struct switchdev_obj_port_vlan *vlan, + struct switchdev_trans *trans) { + bool flag_untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - char spaft_pl[MLXSW_REG_SPAFT_LEN]; - - mlxsw_reg_spaft_pack(spaft_pl, mlxsw_sp_port->local_port, allow); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spaft), spaft_pl); -} - -int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) -{ - struct net_device *dev = mlxsw_sp_port->dev; - int err; - - if (!vid) { - err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, false); - if (err) { - netdev_err(dev, "Failed to disallow untagged traffic\n"); - return err; - } - } else { - err = __mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid); - if (err) { - netdev_err(dev, "Failed to set PVID\n"); - return err; - } - - /* Only allow if not already allowed. */ - if (!mlxsw_sp_port->pvid) { - err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, - true); - if (err) { - netdev_err(dev, "Failed to allow untagged traffic\n"); - goto err_port_allow_untagged_set; - } - } - } + struct net_device *orig_dev = vlan->obj.orig_dev; + struct mlxsw_sp_bridge_port *bridge_port; + u16 vid; - mlxsw_sp_port->pvid = vid; - return 0; + if (switchdev_trans_ph_prepare(trans)) + return 0; -err_port_allow_untagged_set: - __mlxsw_sp_port_pvid_set(mlxsw_sp_port, mlxsw_sp_port->pvid); - return err; -} + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; -static int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid_begin, u16 vid_end, - bool learn_enable) -{ - u16 vid, vid_e; - int err; + if (!bridge_port->bridge_device->vlan_enabled) + return 0; - for (vid = vid_begin; vid <= vid_end; - vid += MLXSW_REG_SPVMLR_REC_MAX_COUNT) { - vid_e = min((u16) (vid + MLXSW_REG_SPVMLR_REC_MAX_COUNT - 1), - vid_end); + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + int err; - err = __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, - vid_e, learn_enable); + err = mlxsw_sp_bridge_port_vlan_add(mlxsw_sp_port, bridge_port, + vid, flag_untagged, + flag_pvid); if (err) return err; } @@ -766,102 +1048,27 @@ static int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, return 0; } -static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid_begin, u16 vid_end, - bool flag_untagged, bool flag_pvid) +static enum mlxsw_reg_sfdf_flush_type mlxsw_sp_fdb_flush_type(bool lagged) { - struct net_device *dev = mlxsw_sp_port->dev; - u16 vid, old_pvid; - int err; - - if (!mlxsw_sp_port->bridged) - return -EINVAL; - - err = mlxsw_sp_port_fid_join(mlxsw_sp_port, vid_begin, vid_end); - if (err) { - netdev_err(dev, "Failed to join FIDs\n"); - return err; - } - - err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid_begin, vid_end, - true, flag_untagged); - if (err) { - netdev_err(dev, "Unable to add VIDs %d-%d\n", vid_begin, - vid_end); - goto err_port_vlans_set; - } - - old_pvid = mlxsw_sp_port->pvid; - if (flag_pvid && old_pvid != vid_begin) { - err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid_begin); - if (err) { - netdev_err(dev, "Unable to add PVID %d\n", vid_begin); - goto err_port_pvid_set; - } - } else if (!flag_pvid && old_pvid >= vid_begin && old_pvid <= vid_end) { - err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0); - if (err) { - netdev_err(dev, "Unable to del PVID\n"); - goto err_port_pvid_set; - } - } - - err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid_begin, vid_end, - mlxsw_sp_port->learning); - if (err) { - netdev_err(dev, "Failed to set learning for VIDs %d-%d\n", - vid_begin, vid_end); - goto err_port_vid_learning_set; - } - - /* Changing activity bits only if HW operation succeded */ - for (vid = vid_begin; vid <= vid_end; vid++) { - set_bit(vid, mlxsw_sp_port->active_vlans); - if (flag_untagged) - set_bit(vid, mlxsw_sp_port->untagged_vlans); - else - clear_bit(vid, mlxsw_sp_port->untagged_vlans); - } - - /* STP state change must be done after we set active VLANs */ - err = mlxsw_sp_port_stp_state_set(mlxsw_sp_port, - mlxsw_sp_port->stp_state); - if (err) { - netdev_err(dev, "Failed to set STP state\n"); - goto err_port_stp_state_set; - } - - return 0; - -err_port_stp_state_set: - for (vid = vid_begin; vid <= vid_end; vid++) - clear_bit(vid, mlxsw_sp_port->active_vlans); - mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid_begin, vid_end, - false); -err_port_vid_learning_set: - if (old_pvid != mlxsw_sp_port->pvid) - mlxsw_sp_port_pvid_set(mlxsw_sp_port, old_pvid); -err_port_pvid_set: - mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid_begin, vid_end, - false, false); -err_port_vlans_set: - mlxsw_sp_port_fid_leave(mlxsw_sp_port, vid_begin, vid_end); - return err; + return lagged ? MLXSW_REG_SFDF_FLUSH_PER_LAG_AND_FID : + MLXSW_REG_SFDF_FLUSH_PER_PORT_AND_FID; } -static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, - const struct switchdev_obj_port_vlan *vlan, - struct switchdev_trans *trans) +static int +mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_bridge_port *bridge_port, + u16 fid_index) { - bool flag_untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; - bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; + bool lagged = bridge_port->lagged; + char sfdf_pl[MLXSW_REG_SFDF_LEN]; + u16 system_port; - if (switchdev_trans_ph_prepare(trans)) - return 0; + system_port = lagged ? bridge_port->lag_id : bridge_port->system_port; + mlxsw_reg_sfdf_pack(sfdf_pl, mlxsw_sp_fdb_flush_type(lagged)); + mlxsw_reg_sfdf_fid_set(sfdf_pl, fid_index); + mlxsw_reg_sfdf_port_fid_system_port_set(sfdf_pl, system_port); - return __mlxsw_sp_port_vlans_add(mlxsw_sp_port, - vlan->vid_begin, vlan->vid_end, - flag_untagged, flag_pvid); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl); } static enum mlxsw_reg_sfd_rec_policy mlxsw_sp_sfd_rec_policy(bool dynamic) @@ -939,24 +1146,39 @@ mlxsw_sp_port_fdb_static_add(struct mlxsw_sp_port *mlxsw_sp_port, const struct switchdev_obj_port_fdb *fdb, struct switchdev_trans *trans) { - u16 fid = mlxsw_sp_port_vid_to_fid_get(mlxsw_sp_port, fdb->vid); - u16 lag_vid = 0; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct net_device *orig_dev = fdb->obj.orig_dev; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; + u16 fid_index, vid; if (switchdev_trans_ph_prepare(trans)) return 0; - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { - lag_vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port); - } + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; + + bridge_device = bridge_port->bridge_device; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port, + bridge_device, + fdb->vid); + if (!mlxsw_sp_port_vlan) + return 0; + + fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); + vid = mlxsw_sp_port_vlan->vid; if (!mlxsw_sp_port->lagged) - return mlxsw_sp_port_fdb_uc_op(mlxsw_sp_port->mlxsw_sp, + return mlxsw_sp_port_fdb_uc_op(mlxsw_sp, mlxsw_sp_port->local_port, - fdb->addr, fid, true, false); + fdb->addr, fid_index, true, + false); else - return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp_port->mlxsw_sp, + return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, mlxsw_sp_port->lag_id, - fdb->addr, fid, lag_vid, + fdb->addr, fid_index, vid, true, false); } @@ -1006,7 +1228,7 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_get(struct mlxsw_sp *mlxsw_sp, { struct mlxsw_sp_mid *mid; - list_for_each_entry(mid, &mlxsw_sp->br_mids.list, list) { + list_for_each_entry(mid, &mlxsw_sp->bridge->mids_list, list) { if (ether_addr_equal(mid->addr, addr) && mid->fid == fid) return mid; } @@ -1020,7 +1242,7 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_mid *mid; u16 mid_idx; - mid_idx = find_first_zero_bit(mlxsw_sp->br_mids.mapped, + mid_idx = find_first_zero_bit(mlxsw_sp->bridge->mids_bitmap, MLXSW_SP_MID_MAX); if (mid_idx == MLXSW_SP_MID_MAX) return NULL; @@ -1029,12 +1251,12 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp, if (!mid) return NULL; - set_bit(mid_idx, mlxsw_sp->br_mids.mapped); + set_bit(mid_idx, mlxsw_sp->bridge->mids_bitmap); ether_addr_copy(mid->addr, addr); mid->fid = fid; mid->mid = mid_idx; mid->ref_count = 0; - list_add_tail(&mid->list, &mlxsw_sp->br_mids.list); + list_add_tail(&mid->list, &mlxsw_sp->bridge->mids_list); return mid; } @@ -1044,7 +1266,7 @@ static int __mlxsw_sp_mc_dec_ref(struct mlxsw_sp *mlxsw_sp, { if (--mid->ref_count == 0) { list_del(&mid->list); - clear_bit(mid->mid, mlxsw_sp->br_mids.mapped); + clear_bit(mid->mid, mlxsw_sp->bridge->mids_bitmap); kfree(mid); return 1; } @@ -1056,17 +1278,34 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port, struct switchdev_trans *trans) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct net_device *orig_dev = mdb->obj.orig_dev; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct net_device *dev = mlxsw_sp_port->dev; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_mid *mid; - u16 fid = mlxsw_sp_port_vid_to_fid_get(mlxsw_sp_port, mdb->vid); + u16 fid_index; int err = 0; if (switchdev_trans_ph_prepare(trans)) return 0; - mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid); + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; + + bridge_device = bridge_port->bridge_device; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port, + bridge_device, + mdb->vid); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return -EINVAL; + + fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); + + mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid_index); if (!mid) { - mid = __mlxsw_sp_mc_alloc(mlxsw_sp, mdb->addr, fid); + mid = __mlxsw_sp_mc_alloc(mlxsw_sp, mdb->addr, fid_index); if (!mid) { netdev_err(dev, "Unable to allocate MC group\n"); return -ENOMEM; @@ -1082,8 +1321,8 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port, } if (mid->ref_count == 1) { - err = mlxsw_sp_port_mdb_op(mlxsw_sp, mdb->addr, fid, mid->mid, - true); + err = mlxsw_sp_port_mdb_op(mlxsw_sp, mdb->addr, fid_index, + mid->mid, true); if (err) { netdev_err(dev, "Unable to set MC SFD\n"); goto err_out; @@ -1104,15 +1343,8 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev, struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); int err = 0; - mlxsw_sp_port = mlxsw_sp_port_orig_get(obj->orig_dev, mlxsw_sp_port); - if (!mlxsw_sp_port) - return -EINVAL; - switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_VLAN: - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) - return 0; - err = mlxsw_sp_port_vlans_add(mlxsw_sp_port, SWITCHDEV_OBJ_PORT_VLAN(obj), trans); @@ -1135,68 +1367,78 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev, return err; } -static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid_begin, u16 vid_end) +static void +mlxsw_sp_bridge_port_vlan_del(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_bridge_port *bridge_port, u16 vid) { - u16 vid, pvid; - - if (!mlxsw_sp_port->bridged) - return -EINVAL; - - mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid_begin, vid_end, - false); + u16 pvid = mlxsw_sp_port->pvid == vid ? 0 : vid; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - pvid = mlxsw_sp_port->pvid; - if (pvid >= vid_begin && pvid <= vid_end) - mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0); - - mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid_begin, vid_end, - false, false); - - mlxsw_sp_port_fid_leave(mlxsw_sp_port, vid_begin, vid_end); - - /* Changing activity bits only if HW operation succeded */ - for (vid = vid_begin; vid <= vid_end; vid++) - clear_bit(vid, mlxsw_sp_port->active_vlans); + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return; - return 0; + mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); + mlxsw_sp_port_pvid_set(mlxsw_sp_port, pvid); + mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false); + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); } static int mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port, const struct switchdev_obj_port_vlan *vlan) { - return __mlxsw_sp_port_vlans_del(mlxsw_sp_port, vlan->vid_begin, - vlan->vid_end); -} - -void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port) -{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct net_device *orig_dev = vlan->obj.orig_dev; + struct mlxsw_sp_bridge_port *bridge_port; u16 vid; - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) - __mlxsw_sp_port_vlans_del(mlxsw_sp_port, vid, vid); + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; + + if (!bridge_port->bridge_device->vlan_enabled) + return 0; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) + mlxsw_sp_bridge_port_vlan_del(mlxsw_sp_port, bridge_port, vid); + + return 0; } static int mlxsw_sp_port_fdb_static_del(struct mlxsw_sp_port *mlxsw_sp_port, const struct switchdev_obj_port_fdb *fdb) { - u16 fid = mlxsw_sp_port_vid_to_fid_get(mlxsw_sp_port, fdb->vid); - u16 lag_vid = 0; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct net_device *orig_dev = fdb->obj.orig_dev; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; + u16 fid_index, vid; + + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { - lag_vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port); - } + bridge_device = bridge_port->bridge_device; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port, + bridge_device, + fdb->vid); + if (!mlxsw_sp_port_vlan) + return 0; + + fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); + vid = mlxsw_sp_port_vlan->vid; if (!mlxsw_sp_port->lagged) - return mlxsw_sp_port_fdb_uc_op(mlxsw_sp_port->mlxsw_sp, + return mlxsw_sp_port_fdb_uc_op(mlxsw_sp, mlxsw_sp_port->local_port, - fdb->addr, fid, - false, false); + fdb->addr, fid_index, false, + false); else - return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp_port->mlxsw_sp, + return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, mlxsw_sp_port->lag_id, - fdb->addr, fid, lag_vid, + fdb->addr, fid_index, vid, false, false); } @@ -1204,13 +1446,30 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port, const struct switchdev_obj_port_mdb *mdb) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct net_device *orig_dev = mdb->obj.orig_dev; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_bridge_device *bridge_device; struct net_device *dev = mlxsw_sp_port->dev; + struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_mid *mid; - u16 fid = mlxsw_sp_port_vid_to_fid_get(mlxsw_sp_port, mdb->vid); + u16 fid_index; u16 mid_idx; int err = 0; - mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid); + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; + + bridge_device = bridge_port->bridge_device; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port, + bridge_device, + mdb->vid); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return -EINVAL; + + fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); + + mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid_index); if (!mid) { netdev_err(dev, "Unable to remove port from MC DB\n"); return -EINVAL; @@ -1222,8 +1481,8 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port, mid_idx = mid->mid; if (__mlxsw_sp_mc_dec_ref(mlxsw_sp, mid)) { - err = mlxsw_sp_port_mdb_op(mlxsw_sp, mdb->addr, fid, mid_idx, - false); + err = mlxsw_sp_port_mdb_op(mlxsw_sp, mdb->addr, fid_index, + mid_idx, false); if (err) netdev_err(dev, "Unable to remove MC SFD\n"); } @@ -1237,15 +1496,8 @@ static int mlxsw_sp_port_obj_del(struct net_device *dev, struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); int err = 0; - mlxsw_sp_port = mlxsw_sp_port_orig_get(obj->orig_dev, mlxsw_sp_port); - if (!mlxsw_sp_port) - return -EINVAL; - switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_VLAN: - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) - return 0; - err = mlxsw_sp_port_vlans_del(mlxsw_sp_port, SWITCHDEV_OBJ_PORT_VLAN(obj)); break; @@ -1284,32 +1536,32 @@ static struct mlxsw_sp_port *mlxsw_sp_lag_rep_port(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port, struct switchdev_obj_port_fdb *fdb, - switchdev_obj_dump_cb_t *cb, - struct net_device *orig_dev) + switchdev_obj_dump_cb_t *cb) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - struct mlxsw_sp_port *tmp; - struct mlxsw_sp_fid *f; - u16 vport_fid; - char *sfd_pl; + struct net_device *orig_dev = fdb->obj.orig_dev; + struct mlxsw_sp_bridge_port *bridge_port; + u16 lag_id, fid_index; char mac[ETH_ALEN]; - u16 fid; - u8 local_port; - u16 lag_id; - u8 num_rec; int stored_err = 0; - int i; + char *sfd_pl; + u8 num_rec; int err; + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (!bridge_port) + return 0; + sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); if (!sfd_pl) return -ENOMEM; - f = mlxsw_sp_vport_fid_get(mlxsw_sp_port); - vport_fid = f ? f->fid : 0; - mlxsw_reg_sfd_pack(sfd_pl, MLXSW_REG_SFD_OP_QUERY_DUMP, 0); do { + struct mlxsw_sp_port *tmp; + u8 local_port; + int i; + mlxsw_reg_sfd_num_rec_set(sfd_pl, MLXSW_REG_SFD_REC_MAX_COUNT); err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); if (err) @@ -1326,48 +1578,44 @@ static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port, for (i = 0; i < num_rec; i++) { switch (mlxsw_reg_sfd_rec_type_get(sfd_pl, i)) { case MLXSW_REG_SFD_REC_TYPE_UNICAST: - mlxsw_reg_sfd_uc_unpack(sfd_pl, i, mac, &fid, + mlxsw_reg_sfd_uc_unpack(sfd_pl, i, mac, + &fid_index, &local_port); - if (local_port == mlxsw_sp_port->local_port) { - if (vport_fid && vport_fid == fid) - fdb->vid = 0; - else if (!vport_fid && - !mlxsw_sp_fid_is_vfid(fid)) - fdb->vid = fid; - else - continue; - ether_addr_copy(fdb->addr, mac); - fdb->ndm_state = NUD_REACHABLE; - err = cb(&fdb->obj); - if (err) - stored_err = err; - } + if (bridge_port->lagged) + continue; + if (bridge_port->system_port != local_port) + continue; + if (bridge_port->bridge_device->vlan_enabled) + fdb->vid = fid_index; + else + fdb->vid = 0; + ether_addr_copy(fdb->addr, mac); + fdb->ndm_state = NUD_REACHABLE; + err = cb(&fdb->obj); + if (err) + stored_err = err; break; case MLXSW_REG_SFD_REC_TYPE_UNICAST_LAG: mlxsw_reg_sfd_uc_lag_unpack(sfd_pl, i, - mac, &fid, &lag_id); + mac, &fid_index, + &lag_id); + if (!bridge_port->lagged) + continue; + if (bridge_port->lag_id != lag_id) + continue; tmp = mlxsw_sp_lag_rep_port(mlxsw_sp, lag_id); - if (tmp && tmp->local_port == - mlxsw_sp_port->local_port) { - /* LAG records can only point to LAG - * devices or VLAN devices on top. - */ - if (!netif_is_lag_master(orig_dev) && - !is_vlan_dev(orig_dev)) - continue; - if (vport_fid && vport_fid == fid) - fdb->vid = 0; - else if (!vport_fid && - !mlxsw_sp_fid_is_vfid(fid)) - fdb->vid = fid; - else - continue; - ether_addr_copy(fdb->addr, mac); - fdb->ndm_state = NUD_REACHABLE; - err = cb(&fdb->obj); - if (err) - stored_err = err; - } + if (tmp->local_port != + mlxsw_sp_port->local_port) + continue; + if (bridge_port->bridge_device->vlan_enabled) + fdb->vid = fid_index; + else + fdb->vid = 0; + ether_addr_copy(fdb->addr, mac); + fdb->ndm_state = NUD_REACHABLE; + err = cb(&fdb->obj); + if (err) + stored_err = err; break; } } @@ -1382,28 +1630,32 @@ static int mlxsw_sp_port_vlan_dump(struct mlxsw_sp_port *mlxsw_sp_port, struct switchdev_obj_port_vlan *vlan, switchdev_obj_dump_cb_t *cb) { - u16 vid; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct net_device *orig_dev = vlan->obj.orig_dev; + struct mlxsw_sp_bridge_port *bridge_port; + struct mlxsw_sp_bridge_vlan *bridge_vlan; int err = 0; - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { - vlan->flags = 0; - vlan->vid_begin = mlxsw_sp_vport_vid_get(mlxsw_sp_port); - vlan->vid_end = mlxsw_sp_vport_vid_get(mlxsw_sp_port); - return cb(&vlan->obj); - } + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; + + if (!bridge_port->bridge_device->vlan_enabled) + return 0; - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) { + list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) { vlan->flags = 0; - if (vid == mlxsw_sp_port->pvid) + if (bridge_vlan->pvid) vlan->flags |= BRIDGE_VLAN_INFO_PVID; - if (test_bit(vid, mlxsw_sp_port->untagged_vlans)) + if (bridge_vlan->egress_untagged) vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; - vlan->vid_begin = vid; - vlan->vid_end = vid; + vlan->vid_begin = bridge_vlan->vid; + vlan->vid_end = bridge_vlan->vid; err = cb(&vlan->obj); if (err) break; } + return err; } @@ -1414,10 +1666,6 @@ static int mlxsw_sp_port_obj_dump(struct net_device *dev, struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); int err = 0; - mlxsw_sp_port = mlxsw_sp_port_orig_get(obj->orig_dev, mlxsw_sp_port); - if (!mlxsw_sp_port) - return -EINVAL; - switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_VLAN: err = mlxsw_sp_port_vlan_dump(mlxsw_sp_port, @@ -1425,8 +1673,7 @@ static int mlxsw_sp_port_obj_dump(struct net_device *dev, break; case SWITCHDEV_OBJ_ID_PORT_FDB: err = mlxsw_sp_port_fdb_dump(mlxsw_sp_port, - SWITCHDEV_OBJ_PORT_FDB(obj), cb, - obj->orig_dev); + SWITCHDEV_OBJ_PORT_FDB(obj), cb); break; default: err = -EOPNOTSUPP; @@ -1444,6 +1691,172 @@ static const struct switchdev_ops mlxsw_sp_port_switchdev_ops = { .switchdev_port_obj_dump = mlxsw_sp_port_obj_dump, }; +static int +mlxsw_sp_bridge_8021q_port_join(struct mlxsw_sp_bridge_device *bridge_device, + struct mlxsw_sp_bridge_port *bridge_port, + struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + if (is_vlan_dev(bridge_port->dev)) + return -EINVAL; + + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, 1); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return -EINVAL; + + /* Let VLAN-aware bridge take care of its own VLANs */ + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); + + return 0; +} + +static void +mlxsw_sp_bridge_8021q_port_leave(struct mlxsw_sp_bridge_device *bridge_device, + struct mlxsw_sp_bridge_port *bridge_port, + struct mlxsw_sp_port *mlxsw_sp_port) +{ + mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1); + /* Make sure untagged frames are allowed to ingress */ + mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1); +} + +static struct mlxsw_sp_fid * +mlxsw_sp_bridge_8021q_fid_get(struct mlxsw_sp_bridge_device *bridge_device, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); + + return mlxsw_sp_fid_8021q_get(mlxsw_sp, vid); +} + +static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021q_ops = { + .port_join = mlxsw_sp_bridge_8021q_port_join, + .port_leave = mlxsw_sp_bridge_8021q_port_leave, + .fid_get = mlxsw_sp_bridge_8021q_fid_get, +}; + +static bool +mlxsw_sp_port_is_br_member(const struct mlxsw_sp_port *mlxsw_sp_port, + const struct net_device *br_dev) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, + list) { + if (mlxsw_sp_port_vlan->bridge_port && + mlxsw_sp_port_vlan->bridge_port->bridge_device->dev == + br_dev) + return true; + } + + return false; +} + +static int +mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device, + struct mlxsw_sp_bridge_port *bridge_port, + struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + u16 vid; + + if (!is_vlan_dev(bridge_port->dev)) + return -EINVAL; + vid = vlan_dev_vlan_id(bridge_port->dev); + + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return -EINVAL; + + if (mlxsw_sp_port_is_br_member(mlxsw_sp_port, bridge_device->dev)) { + netdev_err(mlxsw_sp_port->dev, "Can't bridge VLAN uppers of the same port\n"); + return -EINVAL; + } + + /* Port is no longer usable as a router interface */ + if (mlxsw_sp_port_vlan->fid) + mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); + + return mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port); +} + +static void +mlxsw_sp_bridge_8021d_port_leave(struct mlxsw_sp_bridge_device *bridge_device, + struct mlxsw_sp_bridge_port *bridge_port, + struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + u16 vid = vlan_dev_vlan_id(bridge_port->dev); + + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return; + + mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); +} + +static struct mlxsw_sp_fid * +mlxsw_sp_bridge_8021d_fid_get(struct mlxsw_sp_bridge_device *bridge_device, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); + + return mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex); +} + +static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021d_ops = { + .port_join = mlxsw_sp_bridge_8021d_port_join, + .port_leave = mlxsw_sp_bridge_8021d_port_leave, + .fid_get = mlxsw_sp_bridge_8021d_fid_get, +}; + +int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, + struct net_device *brport_dev, + struct net_device *br_dev) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; + int err; + + bridge_port = mlxsw_sp_bridge_port_get(mlxsw_sp->bridge, brport_dev); + if (IS_ERR(bridge_port)) + return PTR_ERR(bridge_port); + bridge_device = bridge_port->bridge_device; + + err = bridge_device->ops->port_join(bridge_device, bridge_port, + mlxsw_sp_port); + if (err) + goto err_port_join; + + return 0; + +err_port_join: + mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port); + return err; +} + +void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, + struct net_device *brport_dev, + struct net_device *br_dev) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; + + bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); + if (!bridge_device) + return; + bridge_port = __mlxsw_sp_bridge_port_find(bridge_device, brport_dev); + if (!bridge_port) + return; + + bridge_device->ops->port_leave(bridge_device, bridge_port, + mlxsw_sp_port); + mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port); +} + static void mlxsw_sp_fdb_call_notifiers(bool learning_sync, bool adding, char *mac, u16 vid, struct net_device *dev) @@ -1463,6 +1876,9 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp, char *sfn_pl, int rec_index, bool adding) { + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_port *mlxsw_sp_port; char mac[ETH_ALEN]; u8 local_port; @@ -1477,22 +1893,21 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp, goto just_remove; } - if (mlxsw_sp_fid_is_vfid(fid)) { - struct mlxsw_sp_port *mlxsw_sp_vport; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid); + if (!mlxsw_sp_port_vlan) { + netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n"); + goto just_remove; + } - mlxsw_sp_vport = mlxsw_sp_port_vport_find_by_fid(mlxsw_sp_port, - fid); - if (!mlxsw_sp_vport) { - netdev_err(mlxsw_sp_port->dev, "Failed to find a matching vPort following FDB notification\n"); - goto just_remove; - } - vid = 0; - /* Override the physical port with the vPort. */ - mlxsw_sp_port = mlxsw_sp_vport; - } else { - vid = fid; + bridge_port = mlxsw_sp_port_vlan->bridge_port; + if (!bridge_port) { + netdev_err(mlxsw_sp_port->dev, "{Port, VID} not associated with a bridge\n"); + goto just_remove; } + bridge_device = bridge_port->bridge_device; + vid = bridge_device->vlan_enabled ? mlxsw_sp_port_vlan->vid : 0; + do_fdb_op: err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, adding, true); @@ -1503,8 +1918,8 @@ do_fdb_op: if (!do_notification) return; - mlxsw_sp_fdb_call_notifiers(mlxsw_sp_port->learning_sync, - adding, mac, vid, mlxsw_sp_port->dev); + mlxsw_sp_fdb_call_notifiers(bridge_port->flags & BR_LEARNING_SYNC, + adding, mac, vid, bridge_port->dev); return; just_remove: @@ -1517,8 +1932,10 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp, char *sfn_pl, int rec_index, bool adding) { + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_port *mlxsw_sp_port; - struct net_device *dev; char mac[ETH_ALEN]; u16 lag_vid = 0; u16 lag_id; @@ -1533,26 +1950,22 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp, goto just_remove; } - if (mlxsw_sp_fid_is_vfid(fid)) { - struct mlxsw_sp_port *mlxsw_sp_vport; - - mlxsw_sp_vport = mlxsw_sp_port_vport_find_by_fid(mlxsw_sp_port, - fid); - if (!mlxsw_sp_vport) { - netdev_err(mlxsw_sp_port->dev, "Failed to find a matching vPort following FDB notification\n"); - goto just_remove; - } + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid); + if (!mlxsw_sp_port_vlan) { + netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n"); + goto just_remove; + } - lag_vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); - dev = mlxsw_sp_vport->dev; - vid = 0; - /* Override the physical port with the vPort. */ - mlxsw_sp_port = mlxsw_sp_vport; - } else { - dev = mlxsw_sp_lag_get(mlxsw_sp, lag_id)->dev; - vid = fid; + bridge_port = mlxsw_sp_port_vlan->bridge_port; + if (!bridge_port) { + netdev_err(mlxsw_sp_port->dev, "{Port, VID} not associated with a bridge\n"); + goto just_remove; } + bridge_device = bridge_port->bridge_device; + vid = bridge_device->vlan_enabled ? mlxsw_sp_port_vlan->vid : 0; + lag_vid = mlxsw_sp_port_vlan->vid; + do_fdb_op: err = mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, lag_id, mac, fid, lag_vid, adding, true); @@ -1563,8 +1976,8 @@ do_fdb_op: if (!do_notification) return; - mlxsw_sp_fdb_call_notifiers(mlxsw_sp_port->learning_sync, adding, mac, - vid, dev); + mlxsw_sp_fdb_call_notifiers(bridge_port->flags & BR_LEARNING_SYNC, + adding, mac, vid, bridge_port->dev); return; just_remove: @@ -1598,12 +2011,15 @@ static void mlxsw_sp_fdb_notify_rec_process(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_fdb_notify_work_schedule(struct mlxsw_sp *mlxsw_sp) { - mlxsw_core_schedule_dw(&mlxsw_sp->fdb_notify.dw, - msecs_to_jiffies(mlxsw_sp->fdb_notify.interval)); + struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge; + + mlxsw_core_schedule_dw(&bridge->fdb_notify.dw, + msecs_to_jiffies(bridge->fdb_notify.interval)); } static void mlxsw_sp_fdb_notify_work(struct work_struct *work) { + struct mlxsw_sp_bridge *bridge; struct mlxsw_sp *mlxsw_sp; char *sfn_pl; u8 num_rec; @@ -1614,7 +2030,8 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work) if (!sfn_pl) return; - mlxsw_sp = container_of(work, struct mlxsw_sp, fdb_notify.dw.work); + bridge = container_of(work, struct mlxsw_sp_bridge, fdb_notify.dw.work); + mlxsw_sp = bridge->mlxsw_sp; rtnl_lock(); mlxsw_reg_sfn_pack(sfn_pl); @@ -1635,6 +2052,7 @@ out: static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp) { + struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge; int err; err = mlxsw_sp_ageing_set(mlxsw_sp, MLXSW_SP_DEFAULT_AGEING_TIME); @@ -1642,25 +2060,42 @@ static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp) dev_err(mlxsw_sp->bus_info->dev, "Failed to set default ageing time\n"); return err; } - INIT_DELAYED_WORK(&mlxsw_sp->fdb_notify.dw, mlxsw_sp_fdb_notify_work); - mlxsw_sp->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL; + INIT_DELAYED_WORK(&bridge->fdb_notify.dw, mlxsw_sp_fdb_notify_work); + bridge->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL; mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); return 0; } static void mlxsw_sp_fdb_fini(struct mlxsw_sp *mlxsw_sp) { - cancel_delayed_work_sync(&mlxsw_sp->fdb_notify.dw); + cancel_delayed_work_sync(&mlxsw_sp->bridge->fdb_notify.dw); } int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp) { + struct mlxsw_sp_bridge *bridge; + + bridge = kzalloc(sizeof(*mlxsw_sp->bridge), GFP_KERNEL); + if (!bridge) + return -ENOMEM; + mlxsw_sp->bridge = bridge; + bridge->mlxsw_sp = mlxsw_sp; + + INIT_LIST_HEAD(&mlxsw_sp->bridge->bridges_list); + INIT_LIST_HEAD(&mlxsw_sp->bridge->mids_list); + + bridge->bridge_8021q_ops = &mlxsw_sp_bridge_8021q_ops; + bridge->bridge_8021d_ops = &mlxsw_sp_bridge_8021d_ops; + return mlxsw_sp_fdb_init(mlxsw_sp); } void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp) { mlxsw_sp_fdb_fini(mlxsw_sp); + WARN_ON(!list_empty(&mlxsw_sp->bridge->mids_list)); + WARN_ON(!list_empty(&mlxsw_sp->bridge->bridges_list)); + kfree(mlxsw_sp->bridge); } void mlxsw_sp_port_switchdev_init(struct mlxsw_sp_port *mlxsw_sp_port) diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h index e008fdbed20f..12b5ed58f3eb 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/trap.h +++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h @@ -66,6 +66,7 @@ enum { MLXSW_TRAP_ID_RTR_INGRESS0 = 0x70, MLXSW_TRAP_ID_BGP_IPV4 = 0x88, MLXSW_TRAP_ID_HOST_MISS_IPV4 = 0x90, + MLXSW_TRAP_ID_ACL0 = 0x1C0, MLXSW_TRAP_ID_MAX = 0x1FF }; diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c index 20358f87de57..2fe96f1f3fe5 100644 --- a/drivers/net/ethernet/micrel/ks8851.c +++ b/drivers/net/ethernet/micrel/ks8851.c @@ -1071,7 +1071,10 @@ static int ks8851_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct ks8851_net *ks = netdev_priv(dev); - return mii_ethtool_get_link_ksettings(&ks->mii, cmd); + + mii_ethtool_get_link_ksettings(&ks->mii, cmd); + + return 0; } static int ks8851_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/micrel/ks8851_mll.c b/drivers/net/ethernet/micrel/ks8851_mll.c index 7647f7bdbcb8..f3e9dd47b56f 100644 --- a/drivers/net/ethernet/micrel/ks8851_mll.c +++ b/drivers/net/ethernet/micrel/ks8851_mll.c @@ -1315,7 +1315,10 @@ static int ks_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { struct ks_net *ks = netdev_priv(netdev); - return mii_ethtool_get_link_ksettings(&ks->mii, cmd); + + mii_ethtool_get_link_ksettings(&ks->mii, cmd); + + return 0; } static int ks_set_link_ksettings(struct net_device *netdev, diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c index 6a4310af5d97..50ea69d88480 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -3218,6 +3218,7 @@ static int vxge_hwtstamp_set(struct vxgedev *vdev, void __user *data) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: if (vdev->devh->config.hwts_en != VXGE_HW_HWTS_ENABLE) return -EFAULT; diff --git a/drivers/net/ethernet/netronome/Kconfig b/drivers/net/ethernet/netronome/Kconfig index 967d7ca8c28c..0d5a7b9203a4 100644 --- a/drivers/net/ethernet/netronome/Kconfig +++ b/drivers/net/ethernet/netronome/Kconfig @@ -19,6 +19,7 @@ config NFP tristate "Netronome(R) NFP4000/NFP6000 NIC driver" depends on PCI && PCI_MSI depends on VXLAN || VXLAN=n + depends on MAY_USE_DEVLINK ---help--- This driver supports the Netronome(R) NFP4000/NFP6000 based cards working as a advanced Ethernet NIC. It works with both diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index 4b15f0f496aa..5ad9a557f06a 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -14,17 +14,24 @@ nfp-objs := \ nfpcore/nfp_resource.o \ nfpcore/nfp_rtsym.o \ nfpcore/nfp_target.o \ + nfp_app.o \ + nfp_app_nic.o \ + nfp_devlink.o \ + nfp_hwmon.o \ nfp_main.o \ nfp_net_common.o \ nfp_net_ethtool.o \ - nfp_net_offload.o \ nfp_net_main.o \ - nfp_netvf_main.o + nfp_netvf_main.o \ + nfp_port.o \ + bpf/main.o \ + bpf/offload.o \ + nic/main.o ifeq ($(CONFIG_BPF_SYSCALL),y) nfp-objs += \ - nfp_bpf_verifier.o \ - nfp_bpf_jit.o + bpf/verifier.o \ + bpf/jit.o endif nfp-$(CONFIG_NFP_DEBUG) += nfp_net_debugfs.o diff --git a/drivers/net/ethernet/netronome/nfp/nfp_bpf_jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c index 97a8f00674d0..8e57fda6b8b5 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_bpf_jit.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c @@ -39,8 +39,8 @@ #include <linux/pkt_cls.h> #include <linux/unistd.h> -#include "nfp_asm.h" -#include "nfp_bpf.h" +#include "main.h" +#include "../nfp_asm.h" /* --- NFP prog --- */ /* Foreach "multiple" entries macros provide pos and next<n> pointers. diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c new file mode 100644 index 000000000000..afbdf5fd4e4f --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <net/pkt_cls.h> + +#include "../nfpcore/nfp_cpp.h" +#include "../nfp_app.h" +#include "../nfp_main.h" +#include "../nfp_net.h" +#include "../nfp_port.h" +#include "main.h" + +static bool nfp_net_ebpf_capable(struct nfp_net *nn) +{ + if (nn->cap & NFP_NET_CFG_CTRL_BPF && + nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI) + return true; + return false; +} + +static int +nfp_bpf_xdp_offload(struct nfp_app *app, struct nfp_net *nn, + struct bpf_prog *prog) +{ + struct tc_cls_bpf_offload cmd = { + .prog = prog, + }; + int ret; + + if (!nfp_net_ebpf_capable(nn)) + return -EINVAL; + + if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) { + if (!nn->dp.bpf_offload_xdp) + return prog ? -EBUSY : 0; + cmd.command = prog ? TC_CLSBPF_REPLACE : TC_CLSBPF_DESTROY; + } else { + if (!prog) + return 0; + cmd.command = TC_CLSBPF_ADD; + } + + ret = nfp_net_bpf_offload(nn, &cmd); + /* Stop offload if replace not possible */ + if (ret && cmd.command == TC_CLSBPF_REPLACE) + nfp_bpf_xdp_offload(app, nn, NULL); + nn->dp.bpf_offload_xdp = prog && !ret; + return ret; +} + +static const char *nfp_bpf_extra_cap(struct nfp_app *app, struct nfp_net *nn) +{ + return nfp_net_ebpf_capable(nn) ? "BPF" : ""; +} + +static int +nfp_bpf_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id) +{ + struct nfp_net_bpf_priv *priv; + int ret; + + /* Limit to single port, otherwise it's just a NIC */ + if (id > 0) { + nfp_warn(app->cpp, + "BPF NIC doesn't support more than one port right now\n"); + nn->port = nfp_port_alloc(app, NFP_PORT_INVALID, nn->dp.netdev); + return PTR_ERR_OR_ZERO(nn->port); + } + + priv = kmalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + nn->app_priv = priv; + spin_lock_init(&priv->rx_filter_lock); + setup_timer(&priv->rx_filter_stats_timer, + nfp_net_filter_stats_timer, (unsigned long)nn); + + ret = nfp_app_nic_vnic_init(app, nn, id); + if (ret) + kfree(priv); + + return ret; +} + +static void nfp_bpf_vnic_clean(struct nfp_app *app, struct nfp_net *nn) +{ + if (nn->dp.bpf_offload_xdp) + nfp_bpf_xdp_offload(app, nn, NULL); + kfree(nn->app_priv); +} + +static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev, + u32 handle, __be16 proto, struct tc_to_netdev *tc) +{ + struct nfp_net *nn = netdev_priv(netdev); + + if (TC_H_MAJ(handle) != TC_H_MAJ(TC_H_INGRESS)) + return -EOPNOTSUPP; + if (proto != htons(ETH_P_ALL)) + return -EOPNOTSUPP; + + if (tc->type == TC_SETUP_CLSBPF && nfp_net_ebpf_capable(nn)) { + if (!nn->dp.bpf_offload_xdp) + return nfp_net_bpf_offload(nn, tc->cls_bpf); + else + return -EBUSY; + } + + return -EINVAL; +} + +static bool nfp_bpf_tc_busy(struct nfp_app *app, struct nfp_net *nn) +{ + return nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF; +} + +const struct nfp_app_type app_bpf = { + .id = NFP_APP_BPF_NIC, + .name = "ebpf", + + .extra_cap = nfp_bpf_extra_cap, + + .vnic_init = nfp_bpf_vnic_init, + .vnic_clean = nfp_bpf_vnic_clean, + + .setup_tc = nfp_bpf_setup_tc, + .tc_busy = nfp_bpf_tc_busy, + .xdp_offload = nfp_bpf_xdp_offload, +}; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_bpf.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 9513c80f7be5..4051e943f363 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_bpf.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -39,6 +39,8 @@ #include <linux/list.h> #include <linux/types.h> +#include "../nfp_net.h" + /* For branch fixup logic use up-most byte of branch instruction as scratch * area. Remember to clear this before sending instructions to HW! */ @@ -198,4 +200,25 @@ nfp_bpf_jit(struct bpf_prog *filter, void *prog, enum nfp_bpf_action_type act, int nfp_prog_verify(struct nfp_prog *nfp_prog, struct bpf_prog *prog); +struct nfp_net; +struct tc_cls_bpf_offload; + +/** + * struct nfp_net_bpf_priv - per-vNIC BPF private data + * @rx_filter: Filter offload statistics - dropped packets/bytes + * @rx_filter_prev: Filter offload statistics - values from previous update + * @rx_filter_change: Jiffies when statistics last changed + * @rx_filter_stats_timer: Timer for polling filter offload statistics + * @rx_filter_lock: Lock protecting timer state changes (teardown) + */ +struct nfp_net_bpf_priv { + struct nfp_stat_pair rx_filter, rx_filter_prev; + unsigned long rx_filter_change; + struct timer_list rx_filter_stats_timer; + spinlock_t rx_filter_lock; +}; + +int nfp_net_bpf_offload(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf); +void nfp_net_filter_stats_timer(unsigned long data); + #endif diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c index cc823df12c8a..78d80a364edb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_offload.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c @@ -47,60 +47,59 @@ #include <net/tc_act/tc_gact.h> #include <net/tc_act/tc_mirred.h> -#include "nfp_bpf.h" -#include "nfp_net_ctrl.h" -#include "nfp_net.h" +#include "main.h" +#include "../nfp_net_ctrl.h" +#include "../nfp_net.h" void nfp_net_filter_stats_timer(unsigned long data) { struct nfp_net *nn = (void *)data; + struct nfp_net_bpf_priv *priv; struct nfp_stat_pair latest; - spin_lock_bh(&nn->rx_filter_lock); + priv = nn->app_priv; + + spin_lock_bh(&priv->rx_filter_lock); if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) - mod_timer(&nn->rx_filter_stats_timer, + mod_timer(&priv->rx_filter_stats_timer, jiffies + NFP_NET_STAT_POLL_IVL); - spin_unlock_bh(&nn->rx_filter_lock); + spin_unlock_bh(&priv->rx_filter_lock); latest.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES); latest.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES); - if (latest.pkts != nn->rx_filter.pkts) - nn->rx_filter_change = jiffies; + if (latest.pkts != priv->rx_filter.pkts) + priv->rx_filter_change = jiffies; - nn->rx_filter = latest; + priv->rx_filter = latest; } static void nfp_net_bpf_stats_reset(struct nfp_net *nn) { - nn->rx_filter.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES); - nn->rx_filter.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES); - nn->rx_filter_prev = nn->rx_filter; - nn->rx_filter_change = jiffies; + struct nfp_net_bpf_priv *priv = nn->app_priv; + + priv->rx_filter.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES); + priv->rx_filter.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES); + priv->rx_filter_prev = priv->rx_filter; + priv->rx_filter_change = jiffies; } static int nfp_net_bpf_stats_update(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf) { - struct tc_action *a; - LIST_HEAD(actions); + struct nfp_net_bpf_priv *priv = nn->app_priv; u64 bytes, pkts; - pkts = nn->rx_filter.pkts - nn->rx_filter_prev.pkts; - bytes = nn->rx_filter.bytes - nn->rx_filter_prev.bytes; + pkts = priv->rx_filter.pkts - priv->rx_filter_prev.pkts; + bytes = priv->rx_filter.bytes - priv->rx_filter_prev.bytes; bytes -= pkts * ETH_HLEN; - nn->rx_filter_prev = nn->rx_filter; + priv->rx_filter_prev = priv->rx_filter; - preempt_disable(); - - tcf_exts_to_list(cls_bpf->exts, &actions); - list_for_each_entry(a, &actions, list) - tcf_action_stats_update(a, bytes, pkts, nn->rx_filter_change); - - preempt_enable(); + tcf_exts_stats_update(cls_bpf->exts, + bytes, pkts, priv->rx_filter_change); return 0; } @@ -190,6 +189,7 @@ nfp_net_bpf_load_and_start(struct nfp_net *nn, u32 tc_flags, unsigned int code_sz, unsigned int n_instr, bool dense_mode) { + struct nfp_net_bpf_priv *priv = nn->app_priv; u64 bpf_addr = dma_addr; int err; @@ -216,20 +216,23 @@ nfp_net_bpf_load_and_start(struct nfp_net *nn, u32 tc_flags, dma_free_coherent(nn->dp.dev, code_sz, code, dma_addr); nfp_net_bpf_stats_reset(nn); - mod_timer(&nn->rx_filter_stats_timer, jiffies + NFP_NET_STAT_POLL_IVL); + mod_timer(&priv->rx_filter_stats_timer, + jiffies + NFP_NET_STAT_POLL_IVL); } static int nfp_net_bpf_stop(struct nfp_net *nn) { + struct nfp_net_bpf_priv *priv = nn->app_priv; + if (!(nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF)) return 0; - spin_lock_bh(&nn->rx_filter_lock); + spin_lock_bh(&priv->rx_filter_lock); nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_BPF; - spin_unlock_bh(&nn->rx_filter_lock); + spin_unlock_bh(&priv->rx_filter_lock); nn_writel(nn, NFP_NET_CFG_CTRL, nn->dp.ctrl); - del_timer_sync(&nn->rx_filter_stats_timer); + del_timer_sync(&priv->rx_filter_stats_timer); nn->dp.bpf_offload_skip_sw = 0; return nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_bpf_verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c index b3361f9b8e5c..d696ba46f70a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_bpf_verifier.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c @@ -38,7 +38,7 @@ #include <linux/kernel.h> #include <linux/pkt_cls.h> -#include "nfp_bpf.h" +#include "main.h" /* Analyzer/verifier definitions */ struct nfp_bpf_analyzer_priv { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c new file mode 100644 index 000000000000..cea2090cf063 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/slab.h> + +#include "nfpcore/nfp_cpp.h" +#include "nfp_app.h" +#include "nfp_main.h" + +static const struct nfp_app_type *apps[] = { + &app_nic, + &app_bpf, +}; + +struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id) +{ + struct nfp_app *app; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(apps); i++) + if (apps[i]->id == id) + break; + if (i == ARRAY_SIZE(apps)) { + nfp_err(pf->cpp, "failed to find app with ID 0x%02hhx\n", id); + return ERR_PTR(-EINVAL); + } + + if (WARN_ON(!apps[i]->name || !apps[i]->vnic_init)) + return ERR_PTR(-EINVAL); + + app = kzalloc(sizeof(*app), GFP_KERNEL); + if (!app) + return ERR_PTR(-ENOMEM); + + app->pf = pf; + app->cpp = pf->cpp; + app->pdev = pf->pdev; + app->type = apps[i]; + + return app; +} + +void nfp_app_free(struct nfp_app *app) +{ + kfree(app); +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h new file mode 100644 index 000000000000..13efdefffa1a --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _NFP_APP_H +#define _NFP_APP_H 1 + +struct bpf_prog; +struct net_device; +struct pci_dev; +struct tc_to_netdev; +struct nfp_app; +struct nfp_cpp; +struct nfp_pf; +struct nfp_net; + +enum nfp_app_id { + NFP_APP_CORE_NIC = 0x1, + NFP_APP_BPF_NIC = 0x2, +}; + +extern const struct nfp_app_type app_nic; +extern const struct nfp_app_type app_bpf; + +/** + * struct nfp_app_type - application definition + * @id: application ID + * @name: application name + * + * Callbacks + * @init: perform basic app checks + * @extra_cap: extra capabilities string + * @vnic_init: init vNICs (assign port types, etc.) + * @vnic_clean: clean up app's vNIC state + * @setup_tc: setup TC ndo + * @tc_busy: TC HW offload busy (rules loaded) + * @xdp_offload: offload an XDP program + */ +struct nfp_app_type { + enum nfp_app_id id; + const char *name; + + int (*init)(struct nfp_app *app); + + const char *(*extra_cap)(struct nfp_app *app, struct nfp_net *nn); + + int (*vnic_init)(struct nfp_app *app, struct nfp_net *nn, + unsigned int id); + void (*vnic_clean)(struct nfp_app *app, struct nfp_net *nn); + + int (*setup_tc)(struct nfp_app *app, struct net_device *netdev, + u32 handle, __be16 proto, struct tc_to_netdev *tc); + bool (*tc_busy)(struct nfp_app *app, struct nfp_net *nn); + int (*xdp_offload)(struct nfp_app *app, struct nfp_net *nn, + struct bpf_prog *prog); +}; + +/** + * struct nfp_app - NFP application container + * @pdev: backpointer to PCI device + * @pf: backpointer to NFP PF structure + * @cpp: pointer to the CPP handle + * @type: pointer to const application ops and info + */ +struct nfp_app { + struct pci_dev *pdev; + struct nfp_pf *pf; + struct nfp_cpp *cpp; + + const struct nfp_app_type *type; +}; + +static inline int nfp_app_init(struct nfp_app *app) +{ + if (!app->type->init) + return 0; + return app->type->init(app); +} + +static inline int nfp_app_vnic_init(struct nfp_app *app, struct nfp_net *nn, + unsigned int id) +{ + return app->type->vnic_init(app, nn, id); +} + +static inline void nfp_app_vnic_clean(struct nfp_app *app, struct nfp_net *nn) +{ + if (app->type->vnic_clean) + app->type->vnic_clean(app, nn); +} + +static inline const char *nfp_app_name(struct nfp_app *app) +{ + if (!app) + return ""; + return app->type->name; +} + +static inline const char *nfp_app_extra_cap(struct nfp_app *app, + struct nfp_net *nn) +{ + if (!app || !app->type->extra_cap) + return ""; + return app->type->extra_cap(app, nn); +} + +static inline bool nfp_app_has_tc(struct nfp_app *app) +{ + return app && app->type->setup_tc; +} + +static inline bool nfp_app_tc_busy(struct nfp_app *app, struct nfp_net *nn) +{ + if (!app || !app->type->tc_busy) + return false; + return app->type->tc_busy(app, nn); +} + +static inline int nfp_app_setup_tc(struct nfp_app *app, + struct net_device *netdev, + u32 handle, __be16 proto, + struct tc_to_netdev *tc) +{ + if (!app || !app->type->setup_tc) + return -EOPNOTSUPP; + return app->type->setup_tc(app, netdev, handle, proto, tc); +} + +static inline int nfp_app_xdp_offload(struct nfp_app *app, struct nfp_net *nn, + struct bpf_prog *prog) +{ + if (!app || !app->type->xdp_offload) + return -EOPNOTSUPP; + return app->type->xdp_offload(app, nn, prog); +} + +struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id); +void nfp_app_free(struct nfp_app *app); + +/* Callbacks shared between apps */ + +int nfp_app_nic_vnic_init(struct nfp_app *app, struct nfp_net *nn, + unsigned int id); + +#endif diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c new file mode 100644 index 000000000000..1a33ad9f4170 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nfpcore/nfp_cpp.h" +#include "nfpcore/nfp_nsp.h" +#include "nfp_app.h" +#include "nfp_main.h" +#include "nfp_net.h" +#include "nfp_port.h" + +static int +nfp_app_nic_vnic_init_phy_port(struct nfp_pf *pf, struct nfp_app *app, + struct nfp_net *nn, unsigned int id) +{ + if (!pf->eth_tbl) + return 0; + + nn->port = nfp_port_alloc(app, NFP_PORT_PHYS_PORT, nn->dp.netdev); + if (IS_ERR(nn->port)) + return PTR_ERR(nn->port); + + nn->port->eth_id = id; + nn->port->eth_port = nfp_net_find_port(pf->eth_tbl, id); + + /* Check if vNIC has external port associated and cfg is OK */ + if (!nn->port->eth_port) { + nfp_err(app->cpp, + "NSP port entries don't match vNICs (no entry for port #%d)\n", + id); + nfp_port_free(nn->port); + return -EINVAL; + } + if (nn->port->eth_port->override_changed) { + nfp_warn(app->cpp, + "Config changed for port #%d, reboot required before port will be operational\n", + id); + nn->port->type = NFP_PORT_INVALID; + return 1; + } + + return 0; +} + +int nfp_app_nic_vnic_init(struct nfp_app *app, struct nfp_net *nn, + unsigned int id) +{ + int err; + + err = nfp_app_nic_vnic_init_phy_port(app->pf, app, nn, id); + if (err) + return err < 0 ? err : 0; + + nfp_net_get_mac_addr(nn, app->cpp, id); + + return 0; +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_asm.h b/drivers/net/ethernet/netronome/nfp/nfp_asm.h index 22484b6fd3e8..d2b535739d2b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_asm.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_asm.h @@ -34,7 +34,7 @@ #ifndef __NFP_ASM_H__ #define __NFP_ASM_H__ 1 -#include "nfp_bpf.h" +#include <linux/types.h> #define REG_NONE 0 diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c new file mode 100644 index 000000000000..2609a0f28e81 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/rtnetlink.h> +#include <net/devlink.h> + +#include "nfpcore/nfp_nsp.h" +#include "nfp_app.h" +#include "nfp_main.h" +#include "nfp_port.h" + +static int +nfp_devlink_fill_eth_port(struct nfp_port *port, + struct nfp_eth_table_port *copy) +{ + struct nfp_eth_table_port *eth_port; + + eth_port = __nfp_port_get_eth_port(port); + if (!eth_port) + return -EINVAL; + + memcpy(copy, eth_port, sizeof(*eth_port)); + + return 0; +} + +static int +nfp_devlink_fill_eth_port_from_id(struct nfp_pf *pf, unsigned int port_index, + struct nfp_eth_table_port *copy) +{ + struct nfp_port *port; + + port = nfp_port_from_id(pf, NFP_PORT_PHYS_PORT, port_index); + + return nfp_devlink_fill_eth_port(port, copy); +} + +static int +nfp_devlink_set_lanes(struct nfp_pf *pf, unsigned int idx, unsigned int lanes) +{ + struct nfp_nsp *nsp; + int ret; + + nsp = nfp_eth_config_start(pf->cpp, idx); + if (IS_ERR(nsp)) + return PTR_ERR(nsp); + + ret = __nfp_eth_set_split(nsp, lanes); + if (ret) { + nfp_eth_config_cleanup_end(nsp); + return ret; + } + + ret = nfp_eth_config_commit_end(nsp); + if (ret < 0) + return ret; + if (ret) /* no change */ + return 0; + + return nfp_net_refresh_port_table_sync(pf); +} + +static int +nfp_devlink_port_split(struct devlink *devlink, unsigned int port_index, + unsigned int count) +{ + struct nfp_pf *pf = devlink_priv(devlink); + struct nfp_eth_table_port eth_port; + int ret; + + if (count < 2) + return -EINVAL; + + mutex_lock(&pf->lock); + + rtnl_lock(); + ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, ð_port); + rtnl_unlock(); + if (ret) + goto out; + + if (eth_port.is_split || eth_port.port_lanes % count) { + ret = -EINVAL; + goto out; + } + + ret = nfp_devlink_set_lanes(pf, eth_port.index, + eth_port.port_lanes / count); +out: + mutex_unlock(&pf->lock); + + return ret; +} + +static int +nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index) +{ + struct nfp_pf *pf = devlink_priv(devlink); + struct nfp_eth_table_port eth_port; + int ret; + + mutex_lock(&pf->lock); + + rtnl_lock(); + ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, ð_port); + rtnl_unlock(); + if (ret) + goto out; + + if (!eth_port.is_split) { + ret = -EINVAL; + goto out; + } + + ret = nfp_devlink_set_lanes(pf, eth_port.index, eth_port.port_lanes); +out: + mutex_unlock(&pf->lock); + + return ret; +} + +const struct devlink_ops nfp_devlink_ops = { + .port_split = nfp_devlink_port_split, + .port_unsplit = nfp_devlink_port_unsplit, +}; + +int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port) +{ + struct nfp_eth_table_port eth_port; + struct devlink *devlink; + int ret; + + rtnl_lock(); + ret = nfp_devlink_fill_eth_port(port, ð_port); + rtnl_unlock(); + if (ret) + return ret; + + devlink_port_type_eth_set(&port->dl_port, port->netdev); + if (eth_port.is_split) + devlink_port_split_set(&port->dl_port, eth_port.label_port); + + devlink = priv_to_devlink(app->pf); + + return devlink_port_register(devlink, &port->dl_port, port->eth_id); +} + +void nfp_devlink_port_unregister(struct nfp_port *port) +{ + devlink_port_unregister(&port->dl_port); +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_hwmon.c b/drivers/net/ethernet/netronome/nfp/nfp_hwmon.c new file mode 100644 index 000000000000..f0dcf45aeec1 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_hwmon.c @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/kernel.h> +#include <linux/bitops.h> +#include <linux/hwmon.h> + +#include "nfpcore/nfp_cpp.h" +#include "nfpcore/nfp_nsp.h" +#include "nfp_main.h" + +#define NFP_TEMP_MAX (95 * 1000) +#define NFP_TEMP_CRIT (105 * 1000) + +#define NFP_POWER_MAX (25 * 1000 * 1000) + +static int nfp_hwmon_sensor_id(enum hwmon_sensor_types type, int channel) +{ + if (type == hwmon_temp) + return NFP_SENSOR_CHIP_TEMPERATURE; + if (type == hwmon_power) + return NFP_SENSOR_ASSEMBLY_POWER + channel; + return -EINVAL; +} + +static int +nfp_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, long *val) +{ + static const struct { + enum hwmon_sensor_types type; + u32 attr; + long val; + } const_vals[] = { + { hwmon_temp, hwmon_temp_max, NFP_TEMP_MAX }, + { hwmon_temp, hwmon_temp_crit, NFP_TEMP_CRIT }, + { hwmon_power, hwmon_power_max, NFP_POWER_MAX }, + }; + struct nfp_pf *pf = dev_get_drvdata(dev); + enum nfp_nsp_sensor_id id; + int err, i; + + for (i = 0; i < ARRAY_SIZE(const_vals); i++) + if (const_vals[i].type == type && const_vals[i].attr == attr) { + *val = const_vals[i].val; + return 0; + } + + err = nfp_hwmon_sensor_id(type, channel); + if (err < 0) + return err; + id = err; + + if (!(pf->nspi->sensor_mask & BIT(id))) + return -EOPNOTSUPP; + + if (type == hwmon_temp && attr == hwmon_temp_input) + return nfp_hwmon_read_sensor(pf->cpp, id, val); + if (type == hwmon_power && attr == hwmon_power_input) + return nfp_hwmon_read_sensor(pf->cpp, id, val); + + return -EINVAL; +} + +static umode_t +nfp_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, + int channel) +{ + if (type == hwmon_temp) { + switch (attr) { + case hwmon_temp_input: + case hwmon_temp_crit: + case hwmon_temp_max: + return 0444; + } + } else if (type == hwmon_power) { + switch (attr) { + case hwmon_power_input: + case hwmon_power_max: + return 0444; + } + } + return 0; +} + +static u32 nfp_chip_config[] = { + HWMON_C_REGISTER_TZ, + 0 +}; + +static const struct hwmon_channel_info nfp_chip = { + .type = hwmon_chip, + .config = nfp_chip_config, +}; + +static u32 nfp_temp_config[] = { + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT, + 0 +}; + +static const struct hwmon_channel_info nfp_temp = { + .type = hwmon_temp, + .config = nfp_temp_config, +}; + +static u32 nfp_power_config[] = { + HWMON_P_INPUT | HWMON_P_MAX, + HWMON_P_INPUT, + HWMON_P_INPUT, + 0 +}; + +static const struct hwmon_channel_info nfp_power = { + .type = hwmon_power, + .config = nfp_power_config, +}; + +static const struct hwmon_channel_info *nfp_hwmon_info[] = { + &nfp_chip, + &nfp_temp, + &nfp_power, + NULL +}; + +static const struct hwmon_ops nfp_hwmon_ops = { + .is_visible = nfp_hwmon_is_visible, + .read = nfp_hwmon_read, +}; + +static const struct hwmon_chip_info nfp_chip_info = { + .ops = &nfp_hwmon_ops, + .info = nfp_hwmon_info, +}; + +int nfp_hwmon_register(struct nfp_pf *pf) +{ + if (!IS_REACHABLE(CONFIG_HWMON)) + return 0; + + if (!pf->nspi) { + nfp_warn(pf->cpp, "not registering HWMON (no NSP info)\n"); + return 0; + } + if (!pf->nspi->sensor_mask) { + nfp_info(pf->cpp, + "not registering HWMON (NSP doesn't report sensors)\n"); + return 0; + } + + pf->hwmon_dev = hwmon_device_register_with_info(&pf->pdev->dev, "nfp", + pf, &nfp_chip_info, + NULL); + return PTR_ERR_OR_ZERO(pf->hwmon_dev); +} + +void nfp_hwmon_unregister(struct nfp_pf *pf) +{ + if (!IS_REACHABLE(CONFIG_HWMON) || !pf->hwmon_dev) + return; + + hwmon_device_unregister(pf->hwmon_dev); +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index dde35dae35c5..0c2e64d217b5 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -41,9 +41,11 @@ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/pci.h> #include <linux/firmware.h> #include <linux/vermagic.h> +#include <net/devlink.h> #include "nfpcore/nfp.h" #include "nfpcore/nfp_cpp.h" @@ -71,20 +73,22 @@ static const struct pci_device_id nfp_pci_device_ids[] = { }; MODULE_DEVICE_TABLE(pci, nfp_pci_device_ids); -static void nfp_pcie_sriov_read_nfd_limit(struct nfp_pf *pf) +static int nfp_pcie_sriov_read_nfd_limit(struct nfp_pf *pf) { -#ifdef CONFIG_PCI_IOV int err; pf->limit_vfs = nfp_rtsym_read_le(pf->cpp, "nfd_vf_cfg_max_vfs", &err); if (!err) - return; + return pci_sriov_set_totalvfs(pf->pdev, pf->limit_vfs); pf->limit_vfs = ~0; + pci_sriov_set_totalvfs(pf->pdev, 0); /* 0 is unset */ /* Allow any setting for backwards compatibility if symbol not found */ - if (err != -ENOENT) - nfp_warn(pf->cpp, "Warning: VF limit read failed: %d\n", err); -#endif + if (err == -ENOENT) + return 0; + + nfp_warn(pf->cpp, "Warning: VF limit read failed: %d\n", err); + return err; } static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs) @@ -253,7 +257,6 @@ exit_release_fw: static int nfp_nsp_init(struct pci_dev *pdev, struct nfp_pf *pf) { - struct nfp_nsp_identify *nspi; struct nfp_nsp *nsp; int err; @@ -270,14 +273,13 @@ static int nfp_nsp_init(struct pci_dev *pdev, struct nfp_pf *pf) pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp); - nspi = __nfp_nsp_identify(nsp); - if (nspi) { - dev_info(&pdev->dev, "BSP: %s\n", nspi->version); - kfree(nspi); - } + pf->nspi = __nfp_nsp_identify(nsp); + if (pf->nspi) + dev_info(&pdev->dev, "BSP: %s\n", pf->nspi->version); err = nfp_fw_load(pdev, pf, nsp); if (err < 0) { + kfree(pf->nspi); kfree(pf->eth_tbl); dev_err(&pdev->dev, "Failed to load FW\n"); goto exit_close_nsp; @@ -315,6 +317,7 @@ static void nfp_fw_unload(struct nfp_pf *pf) static int nfp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { + struct devlink *devlink; struct nfp_pf *pf; int err; @@ -335,12 +338,15 @@ static int nfp_pci_probe(struct pci_dev *pdev, goto err_pci_disable; } - pf = kzalloc(sizeof(*pf), GFP_KERNEL); - if (!pf) { + devlink = devlink_alloc(&nfp_devlink_ops, sizeof(*pf)); + if (!devlink) { err = -ENOMEM; goto err_rel_regions; } + pf = devlink_priv(devlink); + INIT_LIST_HEAD(&pf->vnics); INIT_LIST_HEAD(&pf->ports); + mutex_init(&pf->lock); pci_set_drvdata(pdev, pf); pf->pdev = pdev; @@ -359,27 +365,47 @@ static int nfp_pci_probe(struct pci_dev *pdev, nfp_hwinfo_lookup(pf->cpp, "assembly.revision"), nfp_hwinfo_lookup(pf->cpp, "cpld.version")); - err = nfp_nsp_init(pdev, pf); + err = devlink_register(devlink, &pdev->dev); if (err) goto err_cpp_free; - nfp_pcie_sriov_read_nfd_limit(pf); + err = nfp_nsp_init(pdev, pf); + if (err) + goto err_devlink_unreg; - err = nfp_net_pci_probe(pf); + err = nfp_pcie_sriov_read_nfd_limit(pf); if (err) goto err_fw_unload; + err = nfp_net_pci_probe(pf); + if (err) + goto err_sriov_unlimit; + + err = nfp_hwmon_register(pf); + if (err) { + dev_err(&pdev->dev, "Failed to register hwmon info\n"); + goto err_net_remove; + } + return 0; +err_net_remove: + nfp_net_pci_remove(pf); +err_sriov_unlimit: + pci_sriov_set_totalvfs(pf->pdev, 0); err_fw_unload: if (pf->fw_loaded) nfp_fw_unload(pf); kfree(pf->eth_tbl); + kfree(pf->nspi); +err_devlink_unreg: + devlink_unregister(devlink); err_cpp_free: nfp_cpp_free(pf->cpp); err_disable_msix: pci_set_drvdata(pdev, NULL); - kfree(pf); + mutex_destroy(&pf->lock); + devlink_free(devlink); err_rel_regions: pci_release_regions(pdev); err_pci_disable: @@ -391,10 +417,18 @@ err_pci_disable: static void nfp_pci_remove(struct pci_dev *pdev) { struct nfp_pf *pf = pci_get_drvdata(pdev); + struct devlink *devlink; + + nfp_hwmon_unregister(pf); + + devlink = priv_to_devlink(pf); nfp_net_pci_remove(pf); nfp_pcie_sriov_disable(pdev); + pci_sriov_set_totalvfs(pf->pdev, 0); + + devlink_unregister(devlink); if (pf->fw_loaded) nfp_fw_unload(pf); @@ -403,7 +437,9 @@ static void nfp_pci_remove(struct pci_dev *pdev) nfp_cpp_free(pf->cpp); kfree(pf->eth_tbl); - kfree(pf); + kfree(pf->nspi); + mutex_destroy(&pf->lock); + devlink_free(devlink); pci_release_regions(pdev); pci_disable_device(pdev); } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index b57de047b002..c46d00bbf19d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -47,37 +47,47 @@ #include <linux/workqueue.h> struct dentry; +struct device; +struct devlink_ops; struct pci_dev; struct nfp_cpp; struct nfp_cpp_area; struct nfp_eth_table; +struct nfp_net; +struct nfp_nsp_identify; /** * struct nfp_pf - NFP PF-specific device structure * @pdev: Backpointer to PCI device * @cpp: Pointer to the CPP handle - * @ctrl_area: Pointer to the CPP area for the control BAR + * @app: Pointer to the APP handle + * @data_vnic_bar: Pointer to the CPP area for the data vNICs' BARs * @tx_area: Pointer to the CPP area for the TX queues * @rx_area: Pointer to the CPP area for the FL/RX queues - * @irq_entries: Array of MSI-X entries for all ports + * @irq_entries: Array of MSI-X entries for all vNICs * @limit_vfs: Number of VFs supported by firmware (~0 for PCI limit) * @num_vfs: Number of SR-IOV VFs enabled * @fw_loaded: Is the firmware loaded? * @eth_tbl: NSP ETH table + * @nspi: NSP identification info + * @hwmon_dev: pointer to hwmon device * @ddir: Per-device debugfs directory - * @num_ports: Number of adapter ports app firmware supports - * @num_netdevs: Number of netdevs spawned - * @ports: Linked list of port structures (struct nfp_net) - * @port_lock: Protects @ports, @num_ports, @num_netdevs + * @max_data_vnics: Number of data vNICs app firmware supports + * @num_vnics: Number of vNICs spawned + * @vnics: Linked list of vNIC structures (struct nfp_net) + * @ports: Linked list of port structures (struct nfp_port) * @port_refresh_work: Work entry for taking netdevs out + * @lock: Protects all fields which may change after probe */ struct nfp_pf { struct pci_dev *pdev; struct nfp_cpp *cpp; - struct nfp_cpp_area *ctrl_area; + struct nfp_app *app; + + struct nfp_cpp_area *data_vnic_bar; struct nfp_cpp_area *tx_area; struct nfp_cpp_area *rx_area; @@ -89,20 +99,34 @@ struct nfp_pf { bool fw_loaded; struct nfp_eth_table *eth_tbl; + struct nfp_nsp_identify *nspi; + + struct device *hwmon_dev; struct dentry *ddir; - unsigned int num_ports; - unsigned int num_netdevs; + unsigned int max_data_vnics; + unsigned int num_vnics; + struct list_head vnics; struct list_head ports; struct work_struct port_refresh_work; - struct mutex port_lock; + struct mutex lock; }; extern struct pci_driver nfp_netvf_pci_driver; +extern const struct devlink_ops nfp_devlink_ops; + int nfp_net_pci_probe(struct nfp_pf *pf); void nfp_net_pci_remove(struct nfp_pf *pf); +int nfp_hwmon_register(struct nfp_pf *pf); +void nfp_hwmon_unregister(struct nfp_pf *pf); + +struct nfp_eth_table_port * +nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id); +void +nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id); + #endif /* NFP_MAIN_H */ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index fcf81b3be830..2e526338f678 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -84,7 +84,7 @@ #define NFP_NET_NON_Q_VECTORS 2 #define NFP_NET_IRQ_LSC_IDX 0 #define NFP_NET_IRQ_EXN_IDX 1 -#define NFP_NET_MIN_PORT_IRQS (NFP_NET_NON_Q_VECTORS + 1) +#define NFP_NET_MIN_VNIC_IRQS (NFP_NET_NON_Q_VECTORS + 1) /* Queue/Ring definitions */ #define NFP_NET_MAX_TX_RINGS 64 /* Max. # of Tx rings per device */ @@ -102,6 +102,7 @@ #define NFP_NET_RX_DESCS_DEFAULT 4096 /* Default # of Rx descs per ring */ #define NFP_NET_FL_BATCH 16 /* Add freelist in this Batch size */ +#define NFP_NET_XDP_MAX_COMPLETE 2048 /* XDP bufs to reclaim in NAPI poll */ /* Offload definitions */ #define NFP_NET_N_VXLAN_PORTS (NFP_NET_CFG_VXLAN_SZ / sizeof(__be16)) @@ -115,6 +116,10 @@ struct nfp_cpp; struct nfp_eth_table_port; struct nfp_net; struct nfp_net_r_vector; +struct nfp_port; + +/* Convenience macro for wrapping descriptor index on ring size */ +#define D_IDX(ring, idx) ((idx) & ((ring)->cnt - 1)) /* Convenience macro for writing dma address into RX/TX descriptors */ #define nfp_desc_set_dma_addr(desc, dma_addr) \ @@ -153,10 +158,15 @@ struct nfp_net_tx_desc { __le32 dma_addr_lo; /* Low 32bit of host buf addr */ __le16 mss; /* MSS to be used for LSO */ - u8 l4_offset; /* LSO, where the L4 data starts */ + u8 lso_hdrlen; /* LSO, TCP payload offset */ u8 flags; /* TX Flags, see @PCIE_DESC_TX_* */ - - __le16 vlan; /* VLAN tag to add if indicated */ + union { + struct { + u8 l3_offset; /* L3 header offset */ + u8 l4_offset; /* L4 header offset */ + }; + __le16 vlan; /* VLAN tag to add if indicated */ + }; __le16 data_len; /* Length of frame + meta data */ } __packed; __le32 vals[4]; @@ -287,9 +297,11 @@ struct nfp_net_rx_desc { #define NFP_NET_META_FIELD_MASK GENMASK(NFP_NET_META_FIELD_SIZE - 1, 0) struct nfp_meta_parsed { - u32 hash_type; + u8 hash_type; + u8 csum_type; u32 hash; u32 mark; + __wsum csum; }; struct nfp_net_rx_hash { @@ -316,8 +328,6 @@ struct nfp_net_rx_buf { * @idx: Ring index from Linux's perspective * @fl_qcidx: Queue Controller Peripheral (QCP) queue index for the freelist * @qcp_fl: Pointer to base of the QCP freelist queue - * @wr_ptr_add: Accumulated number of buffers to add to QCP write pointer - * (used for free list batching) * @rxbufs: Array of transmitted FL/RX buffers * @rxds: Virtual address of FL/RX ring in host memory * @dma: DMA address of the FL/RX ring @@ -331,7 +341,6 @@ struct nfp_net_rx_ring { u32 rd_p; u32 idx; - u32 wr_ptr_add; int fl_qcidx; u8 __iomem *qcp_fl; @@ -508,11 +517,6 @@ struct nfp_net_dp { * @rss_cfg: RSS configuration * @rss_key: RSS secret key * @rss_itbl: RSS indirection table - * @rx_filter: Filter offload statistics - dropped packets/bytes - * @rx_filter_prev: Filter offload statistics - values from previous update - * @rx_filter_change: Jiffies when statistics last changed - * @rx_filter_stats_timer: Timer for polling filter offload statistics - * @rx_filter_lock: Lock protecting timer state changes (teardown) * @max_r_vecs: Number of allocated interrupt vectors for RX/TX * @max_tx_rings: Maximum number of TX rings supported by the Firmware * @max_rx_rings: Maximum number of RX rings supported by the Firmware @@ -531,7 +535,6 @@ struct nfp_net_dp { * @reconfig_sync_present: Some thread is performing synchronous reconfig * @reconfig_timer: Timer for async reading of reconfig results * @link_up: Is the link up? - * @link_changed: Has link state changes since last port refresh? * @link_status_lock: Protects @link_* and ensures atomicity with BAR reading * @rx_coalesce_usecs: RX interrupt moderation usecs delay parameter * @rx_coalesce_max_frames: RX interrupt moderation frame count parameter @@ -544,10 +547,11 @@ struct nfp_net_dp { * @rx_bar: Pointer to mapped FL/RX queues * @debugfs_dir: Device directory in debugfs * @ethtool_dump_flag: Ethtool dump flag - * @port_list: Entry on device port list + * @vnic_list: Entry on device vNIC list * @pdev: Backpointer to PCI device - * @cpp: CPP device handle if available - * @eth_port: Translated ETH Table port entry + * @app: APP handle if available + * @port: Pointer to nfp_port structure if vNIC is a port + * @app_priv: APP private data for this vNIC */ struct nfp_net { struct nfp_net_dp dp; @@ -562,11 +566,6 @@ struct nfp_net { u8 rss_key[NFP_NET_CFG_RSS_KEY_SZ]; u8 rss_itbl[NFP_NET_CFG_RSS_ITBL_SZ]; - struct nfp_stat_pair rx_filter, rx_filter_prev; - unsigned long rx_filter_change; - struct timer_list rx_filter_stats_timer; - spinlock_t rx_filter_lock; - unsigned int max_tx_rings; unsigned int max_rx_rings; @@ -589,7 +588,6 @@ struct nfp_net { u32 me_freq_mhz; bool link_up; - bool link_changed; spinlock_t link_status_lock; spinlock_t reconfig_lock; @@ -614,12 +612,14 @@ struct nfp_net { struct dentry *debugfs_dir; u32 ethtool_dump_flag; - struct list_head port_list; + struct list_head vnic_list; struct pci_dev *pdev; - struct nfp_cpp *cpp; + struct nfp_app *app; - struct nfp_eth_table_port *eth_port; + struct nfp_port *port; + + void *app_priv; }; /* Functions to read/write from/to a BAR @@ -791,16 +791,25 @@ static inline u32 nfp_qcp_wr_ptr_read(u8 __iomem *q) /* Globals */ extern const char nfp_driver_version[]; +extern const struct net_device_ops nfp_net_netdev_ops; + +static inline bool nfp_netdev_is_nfp_net(struct net_device *netdev) +{ + return netdev->netdev_ops == &nfp_net_netdev_ops; +} + /* Prototypes */ void nfp_net_get_fw_version(struct nfp_net_fw_version *fw_ver, void __iomem *ctrl_bar); struct nfp_net * -nfp_net_netdev_alloc(struct pci_dev *pdev, - unsigned int max_tx_rings, unsigned int max_rx_rings); -void nfp_net_netdev_free(struct nfp_net *nn); -int nfp_net_netdev_init(struct net_device *netdev); -void nfp_net_netdev_clean(struct net_device *netdev); +nfp_net_alloc(struct pci_dev *pdev, + unsigned int max_tx_rings, unsigned int max_rx_rings); +void nfp_net_free(struct nfp_net *nn); + +int nfp_net_init(struct nfp_net *nn); +void nfp_net_clean(struct nfp_net *nn); + void nfp_net_set_ethtool_ops(struct net_device *netdev); void nfp_net_info(struct nfp_net *nn); int nfp_net_reconfig(struct nfp_net *nn, u32 update); @@ -821,15 +830,11 @@ struct nfp_net_dp *nfp_net_clone_dp(struct nfp_net *nn); int nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_dp *new, struct netlink_ext_ack *extack); -bool nfp_net_link_changed_read_clear(struct nfp_net *nn); -int nfp_net_refresh_eth_port(struct nfp_net *nn); -void nfp_net_refresh_port_table(struct nfp_net *nn); - #ifdef CONFIG_NFP_DEBUG void nfp_net_debugfs_create(void); void nfp_net_debugfs_destroy(void); struct dentry *nfp_net_debugfs_device_add(struct pci_dev *pdev); -void nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id); +void nfp_net_debugfs_vnic_add(struct nfp_net *nn, struct dentry *ddir, int id); void nfp_net_debugfs_dir_clean(struct dentry **dir); #else static inline void nfp_net_debugfs_create(void) @@ -846,7 +851,7 @@ static inline struct dentry *nfp_net_debugfs_device_add(struct pci_dev *pdev) } static inline void -nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id) +nfp_net_debugfs_vnic_add(struct nfp_net *nn, struct dentry *ddir, int id) { } @@ -855,7 +860,4 @@ static inline void nfp_net_debugfs_dir_clean(struct dentry **dir) } #endif /* CONFIG_NFP_DEBUG */ -void nfp_net_filter_stats_timer(unsigned long data); -int nfp_net_bpf_offload(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf); - #endif /* _NFP_NET_H_ */ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 82bd6b0935f1..c3235d03b8eb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -64,12 +64,13 @@ #include <linux/ktime.h> -#include <net/pkt_cls.h> #include <net/vxlan.h> #include "nfpcore/nfp_nsp.h" +#include "nfp_app.h" #include "nfp_net_ctrl.h" #include "nfp_net.h" +#include "nfp_port.h" /** * nfp_net_get_fw_version() - Read and parse the FW version @@ -391,19 +392,6 @@ static irqreturn_t nfp_net_irq_rxtx(int irq, void *data) return IRQ_HANDLED; } -bool nfp_net_link_changed_read_clear(struct nfp_net *nn) -{ - unsigned long flags; - bool ret; - - spin_lock_irqsave(&nn->link_status_lock, flags); - ret = nn->link_changed; - nn->link_changed = false; - spin_unlock_irqrestore(&nn->link_status_lock, flags); - - return ret; -} - /** * nfp_net_read_link_status() - Reread link status from control BAR * @nn: NFP Network structure @@ -423,7 +411,8 @@ static void nfp_net_read_link_status(struct nfp_net *nn) goto out; nn->link_up = link_up; - nn->link_changed = true; + if (nn->port) + set_bit(NFP_PORT_CHANGED, &nn->port->flags); if (nn->link_up) { netif_carrier_on(nn->dp.netdev); @@ -516,11 +505,10 @@ nfp_net_rx_ring_init(struct nfp_net_rx_ring *rx_ring, /** * nfp_net_vecs_init() - Assign IRQs and setup rvecs. - * @netdev: netdev structure + * @nn: NFP Network structure */ -static void nfp_net_vecs_init(struct net_device *netdev) +static void nfp_net_vecs_init(struct nfp_net *nn) { - struct nfp_net *nn = netdev_priv(netdev); struct nfp_net_r_vector *r_vec; int r; @@ -667,17 +655,22 @@ static void nfp_net_tx_tso(struct nfp_net_r_vector *r_vec, if (!skb_is_gso(skb)) return; - if (!skb->encapsulation) + if (!skb->encapsulation) { + txd->l3_offset = skb_network_offset(skb); + txd->l4_offset = skb_transport_offset(skb); hdrlen = skb_transport_offset(skb) + tcp_hdrlen(skb); - else + } else { + txd->l3_offset = skb_inner_network_offset(skb); + txd->l4_offset = skb_inner_transport_offset(skb); hdrlen = skb_inner_transport_header(skb) - skb->data + inner_tcp_hdrlen(skb); + } txbuf->pkt_cnt = skb_shinfo(skb)->gso_segs; txbuf->real_len += hdrlen * (txbuf->pkt_cnt - 1); mss = skb_shinfo(skb)->gso_size & PCIE_DESC_TX_MSS_MASK; - txd->l4_offset = hdrlen; + txd->lso_hdrlen = hdrlen; txd->mss = cpu_to_le16(mss); txd->flags |= PCIE_DESC_TX_LSO; @@ -804,7 +797,7 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev) if (dma_mapping_error(dp->dev, dma_addr)) goto err_free; - wr_idx = tx_ring->wr_p & (tx_ring->cnt - 1); + wr_idx = D_IDX(tx_ring, tx_ring->wr_p); /* Stash the soft descriptor of the head then initialize it */ txbuf = &tx_ring->txbufs[wr_idx]; @@ -823,12 +816,11 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev) txd->flags = 0; txd->mss = 0; - txd->l4_offset = 0; + txd->lso_hdrlen = 0; + /* Do not reorder - tso may adjust pkt cnt, vlan may override fields */ nfp_net_tx_tso(r_vec, txbuf, txd, skb); - nfp_net_tx_csum(dp, r_vec, txbuf, txd, skb); - if (skb_vlan_tag_present(skb) && dp->ctrl & NFP_NET_CFG_CTRL_TXVLAN) { txd->flags |= PCIE_DESC_TX_VLAN; txd->vlan = cpu_to_le16(skb_vlan_tag_get(skb)); @@ -848,7 +840,7 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev) if (dma_mapping_error(dp->dev, dma_addr)) goto err_unmap; - wr_idx = (wr_idx + 1) & (tx_ring->cnt - 1); + wr_idx = D_IDX(tx_ring, wr_idx + 1); tx_ring->txbufs[wr_idx].skb = skb; tx_ring->txbufs[wr_idx].dma_addr = dma_addr; tx_ring->txbufs[wr_idx].fidx = f; @@ -936,14 +928,10 @@ static void nfp_net_tx_complete(struct nfp_net_tx_ring *tx_ring) if (qcp_rd_p == tx_ring->qcp_rd_p) return; - if (qcp_rd_p > tx_ring->qcp_rd_p) - todo = qcp_rd_p - tx_ring->qcp_rd_p; - else - todo = qcp_rd_p + tx_ring->cnt - tx_ring->qcp_rd_p; + todo = D_IDX(tx_ring, qcp_rd_p - tx_ring->qcp_rd_p); while (todo--) { - idx = tx_ring->rd_p & (tx_ring->cnt - 1); - tx_ring->rd_p++; + idx = D_IDX(tx_ring, tx_ring->rd_p++); skb = tx_ring->txbufs[idx].skb; if (!skb) @@ -997,45 +985,45 @@ static void nfp_net_tx_complete(struct nfp_net_tx_ring *tx_ring) tx_ring->rd_p, tx_ring->wr_p, tx_ring->cnt); } -static void nfp_net_xdp_complete(struct nfp_net_tx_ring *tx_ring) +static bool nfp_net_xdp_complete(struct nfp_net_tx_ring *tx_ring) { struct nfp_net_r_vector *r_vec = tx_ring->r_vec; u32 done_pkts = 0, done_bytes = 0; + bool done_all; int idx, todo; u32 qcp_rd_p; - if (tx_ring->wr_p == tx_ring->rd_p) - return; - /* Work out how many descriptors have been transmitted */ qcp_rd_p = nfp_qcp_rd_ptr_read(tx_ring->qcp_q); if (qcp_rd_p == tx_ring->qcp_rd_p) - return; + return true; - if (qcp_rd_p > tx_ring->qcp_rd_p) - todo = qcp_rd_p - tx_ring->qcp_rd_p; - else - todo = qcp_rd_p + tx_ring->cnt - tx_ring->qcp_rd_p; + todo = D_IDX(tx_ring, qcp_rd_p - tx_ring->qcp_rd_p); + + done_all = todo <= NFP_NET_XDP_MAX_COMPLETE; + todo = min(todo, NFP_NET_XDP_MAX_COMPLETE); + + tx_ring->qcp_rd_p = D_IDX(tx_ring, tx_ring->qcp_rd_p + todo); done_pkts = todo; while (todo--) { - idx = tx_ring->rd_p & (tx_ring->cnt - 1); + idx = D_IDX(tx_ring, tx_ring->rd_p); tx_ring->rd_p++; done_bytes += tx_ring->txbufs[idx].real_len; } - tx_ring->qcp_rd_p = qcp_rd_p; - u64_stats_update_begin(&r_vec->tx_sync); r_vec->tx_bytes += done_bytes; r_vec->tx_pkts += done_pkts; u64_stats_update_end(&r_vec->tx_sync); WARN_ONCE(tx_ring->wr_p - tx_ring->rd_p > tx_ring->cnt, - "TX ring corruption rd_p=%u wr_p=%u cnt=%u\n", + "XDP TX ring corruption rd_p=%u wr_p=%u cnt=%u\n", tx_ring->rd_p, tx_ring->wr_p, tx_ring->cnt); + + return done_all; } /** @@ -1056,7 +1044,7 @@ nfp_net_tx_ring_reset(struct nfp_net_dp *dp, struct nfp_net_tx_ring *tx_ring) struct sk_buff *skb; int idx, nr_frags; - idx = tx_ring->rd_p & (tx_ring->cnt - 1); + idx = D_IDX(tx_ring, tx_ring->rd_p); tx_buf = &tx_ring->txbufs[idx]; skb = tx_ring->txbufs[idx].skb; @@ -1209,7 +1197,7 @@ static void nfp_net_rx_give_one(const struct nfp_net_dp *dp, { unsigned int wr_idx; - wr_idx = rx_ring->wr_p & (rx_ring->cnt - 1); + wr_idx = D_IDX(rx_ring, rx_ring->wr_p); nfp_net_dma_sync_dev_rx(dp, dma_addr); @@ -1224,14 +1212,12 @@ static void nfp_net_rx_give_one(const struct nfp_net_dp *dp, dma_addr + dp->rx_dma_off); rx_ring->wr_p++; - rx_ring->wr_ptr_add++; - if (rx_ring->wr_ptr_add >= NFP_NET_FL_BATCH) { + if (!(rx_ring->wr_p % NFP_NET_FL_BATCH)) { /* Update write pointer of the freelist queue. Make * sure all writes are flushed before telling the hardware. */ wmb(); - nfp_qcp_wr_ptr_add(rx_ring->qcp_fl, rx_ring->wr_ptr_add); - rx_ring->wr_ptr_add = 0; + nfp_qcp_wr_ptr_add(rx_ring->qcp_fl, NFP_NET_FL_BATCH); } } @@ -1247,7 +1233,7 @@ static void nfp_net_rx_ring_reset(struct nfp_net_rx_ring *rx_ring) unsigned int wr_idx, last_idx; /* Move the empty entry to the end of the list */ - wr_idx = rx_ring->wr_p & (rx_ring->cnt - 1); + wr_idx = D_IDX(rx_ring, rx_ring->wr_p); last_idx = rx_ring->cnt - 1; rx_ring->rxbufs[wr_idx].dma_addr = rx_ring->rxbufs[last_idx].dma_addr; rx_ring->rxbufs[wr_idx].frag = rx_ring->rxbufs[last_idx].frag; @@ -1257,7 +1243,6 @@ static void nfp_net_rx_ring_reset(struct nfp_net_rx_ring *rx_ring) memset(rx_ring->rxds, 0, sizeof(*rx_ring->rxds) * rx_ring->cnt); rx_ring->wr_p = 0; rx_ring->rd_p = 0; - rx_ring->wr_ptr_add = 0; } /** @@ -1350,17 +1335,28 @@ static int nfp_net_rx_csum_has_errors(u16 flags) * @dp: NFP Net data path struct * @r_vec: per-ring structure * @rxd: Pointer to RX descriptor + * @meta: Parsed metadata prepend * @skb: Pointer to SKB */ static void nfp_net_rx_csum(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec, - struct nfp_net_rx_desc *rxd, struct sk_buff *skb) + struct nfp_net_rx_desc *rxd, + struct nfp_meta_parsed *meta, struct sk_buff *skb) { skb_checksum_none_assert(skb); if (!(dp->netdev->features & NETIF_F_RXCSUM)) return; + if (meta->csum_type) { + skb->ip_summed = meta->csum_type; + skb->csum = meta->csum; + u64_stats_update_begin(&r_vec->rx_sync); + r_vec->hw_csum_rx_ok++; + u64_stats_update_end(&r_vec->rx_sync); + return; + } + if (nfp_net_rx_csum_has_errors(le16_to_cpu(rxd->rxd.flags))) { u64_stats_update_begin(&r_vec->rx_sync); r_vec->hw_csum_rx_error++; @@ -1445,6 +1441,12 @@ nfp_net_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta, meta->mark = get_unaligned_be32(data); data += 4; break; + case NFP_NET_META_CSUM: + meta->csum_type = CHECKSUM_COMPLETE; + meta->csum = + (__force __wsum)__get_unaligned_cpu32(data); + data += 4; + break; default: return NULL; } @@ -1479,18 +1481,26 @@ static bool nfp_net_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring, struct nfp_net_tx_ring *tx_ring, struct nfp_net_rx_buf *rxbuf, unsigned int dma_off, - unsigned int pkt_len) + unsigned int pkt_len, bool *completed) { struct nfp_net_tx_buf *txbuf; struct nfp_net_tx_desc *txd; int wr_idx; if (unlikely(nfp_net_tx_full(tx_ring, 1))) { - nfp_net_rx_drop(dp, rx_ring->r_vec, rx_ring, rxbuf, NULL); - return false; + if (!*completed) { + nfp_net_xdp_complete(tx_ring); + *completed = true; + } + + if (unlikely(nfp_net_tx_full(tx_ring, 1))) { + nfp_net_rx_drop(dp, rx_ring->r_vec, rx_ring, rxbuf, + NULL); + return false; + } } - wr_idx = tx_ring->wr_p & (tx_ring->cnt - 1); + wr_idx = D_IDX(tx_ring, tx_ring->wr_p); /* Stash the soft descriptor of the head then initialize it */ txbuf = &tx_ring->txbufs[wr_idx]; @@ -1515,7 +1525,7 @@ nfp_net_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring, txd->flags = 0; txd->mss = 0; - txd->l4_offset = 0; + txd->lso_hdrlen = 0; tx_ring->wr_p++; tx_ring->wr_ptr_add++; @@ -1559,6 +1569,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) struct nfp_net_dp *dp = &r_vec->nfp_net->dp; struct nfp_net_tx_ring *tx_ring; struct bpf_prog *xdp_prog; + bool xdp_tx_cmpl = false; unsigned int true_bufsz; struct sk_buff *skb; int pkts_polled = 0; @@ -1577,7 +1588,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) dma_addr_t new_dma_addr; void *new_frag; - idx = rx_ring->rd_p & (rx_ring->cnt - 1); + idx = D_IDX(rx_ring, rx_ring->rd_p); rxd = &rx_ring->rxds[idx]; if (!(rxd->rxd.meta_len_dd & PCIE_DESC_RX_DD)) @@ -1669,14 +1680,17 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) if (unlikely(!nfp_net_tx_xdp_buf(dp, rx_ring, tx_ring, rxbuf, dma_off, - pkt_len))) + pkt_len, + &xdp_tx_cmpl))) trace_xdp_exception(dp->netdev, xdp_prog, act); continue; default: bpf_warn_invalid_xdp_action(act); + /* fall through */ case XDP_ABORTED: trace_xdp_exception(dp->netdev, xdp_prog, act); + /* fall through */ case XDP_DROP: nfp_net_rx_give_one(dp, rx_ring, rxbuf->frag, rxbuf->dma_addr); @@ -1708,7 +1722,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) skb_record_rx_queue(skb, rx_ring->idx); skb->protocol = eth_type_trans(skb, dp->netdev); - nfp_net_rx_csum(dp, r_vec, rxd, skb); + nfp_net_rx_csum(dp, r_vec, rxd, &meta, skb); if (rxd->rxd.flags & PCIE_DESC_RX_VLAN) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), @@ -1717,8 +1731,14 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) napi_gro_receive(&rx_ring->r_vec->napi, skb); } - if (xdp_prog && tx_ring->wr_ptr_add) - nfp_net_tx_xmit_more_flush(tx_ring); + if (xdp_prog) { + if (tx_ring->wr_ptr_add) + nfp_net_tx_xmit_more_flush(tx_ring); + else if (unlikely(tx_ring->wr_p != tx_ring->rd_p) && + !xdp_tx_cmpl) + if (!nfp_net_xdp_complete(tx_ring)) + pkts_polled = budget; + } rcu_read_unlock(); return pkts_polled; @@ -1739,11 +1759,8 @@ static int nfp_net_poll(struct napi_struct *napi, int budget) if (r_vec->tx_ring) nfp_net_tx_complete(r_vec->tx_ring); - if (r_vec->rx_ring) { + if (r_vec->rx_ring) pkts_polled = nfp_net_rx(r_vec->rx_ring, budget); - if (r_vec->xdp_ring) - nfp_net_xdp_complete(r_vec->xdp_ring); - } if (pkts_polled < budget) if (napi_complete_done(napi, pkts_polled)) @@ -2105,17 +2122,16 @@ void nfp_net_coalesce_write_cfg(struct nfp_net *nn) /** * nfp_net_write_mac_addr() - Write mac address to the device control BAR * @nn: NFP Net device to reconfigure + * @addr: MAC address to write * * Writes the MAC address from the netdev to the device control BAR. Does not * perform the required reconfig. We do a bit of byte swapping dance because * firmware is LE. */ -static void nfp_net_write_mac_addr(struct nfp_net *nn) +static void nfp_net_write_mac_addr(struct nfp_net *nn, const u8 *addr) { - nn_writel(nn, NFP_NET_CFG_MACADDR + 0, - get_unaligned_be32(nn->dp.netdev->dev_addr)); - nn_writew(nn, NFP_NET_CFG_MACADDR + 6, - get_unaligned_be16(nn->dp.netdev->dev_addr + 4)); + nn_writel(nn, NFP_NET_CFG_MACADDR + 0, get_unaligned_be32(addr)); + nn_writew(nn, NFP_NET_CFG_MACADDR + 6, get_unaligned_be16(addr + 4)); } static void nfp_net_vec_clear_ring_data(struct nfp_net *nn, unsigned int idx) @@ -2197,17 +2213,15 @@ static int nfp_net_set_config_and_enable(struct nfp_net *nn) new_ctrl = nn->dp.ctrl; - if (nn->cap & NFP_NET_CFG_CTRL_RSS) { + if (nn->dp.ctrl & NFP_NET_CFG_CTRL_RSS_ANY) { nfp_net_rss_write_key(nn); nfp_net_rss_write_itbl(nn); nn_writel(nn, NFP_NET_CFG_RSS_CTRL, nn->rss_cfg); update |= NFP_NET_CFG_UPDATE_RSS; } - if (nn->cap & NFP_NET_CFG_CTRL_IRQMOD) { + if (nn->dp.ctrl & NFP_NET_CFG_CTRL_IRQMOD) { nfp_net_coalesce_write_cfg(nn); - - new_ctrl |= NFP_NET_CFG_CTRL_IRQMOD; update |= NFP_NET_CFG_UPDATE_IRQMOD; } @@ -2222,7 +2236,7 @@ static int nfp_net_set_config_and_enable(struct nfp_net *nn) nn_writeq(nn, NFP_NET_CFG_RXRS_ENABLE, nn->dp.num_rx_rings == 64 ? 0xffffffffffffffffULL : ((u64)1 << nn->dp.num_rx_rings) - 1); - nfp_net_write_mac_addr(nn); + nfp_net_write_mac_addr(nn, nn->dp.netdev->dev_addr); nn_writel(nn, NFP_NET_CFG_MTU, nn->dp.netdev->mtu); @@ -2667,33 +2681,13 @@ static void nfp_net_stat64(struct net_device *netdev, } } -static bool nfp_net_ebpf_capable(struct nfp_net *nn) -{ - if (nn->cap & NFP_NET_CFG_CTRL_BPF && - nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI) - return true; - return false; -} - static int nfp_net_setup_tc(struct net_device *netdev, u32 handle, __be16 proto, struct tc_to_netdev *tc) { struct nfp_net *nn = netdev_priv(netdev); - if (TC_H_MAJ(handle) != TC_H_MAJ(TC_H_INGRESS)) - return -EOPNOTSUPP; - if (proto != htons(ETH_P_ALL)) - return -EOPNOTSUPP; - - if (tc->type == TC_SETUP_CLSBPF && nfp_net_ebpf_capable(nn)) { - if (!nn->dp.bpf_offload_xdp) - return nfp_net_bpf_offload(nn, tc->cls_bpf); - else - return -EBUSY; - } - - return -EINVAL; + return nfp_app_setup_tc(nn->app, netdev, handle, proto, tc); } static int nfp_net_set_features(struct net_device *netdev, @@ -2710,9 +2704,9 @@ static int nfp_net_set_features(struct net_device *netdev, if (changed & NETIF_F_RXCSUM) { if (features & NETIF_F_RXCSUM) - new_ctrl |= NFP_NET_CFG_CTRL_RXCSUM; + new_ctrl |= nn->cap & NFP_NET_CFG_CTRL_RXCSUM_ANY; else - new_ctrl &= ~NFP_NET_CFG_CTRL_RXCSUM; + new_ctrl &= ~NFP_NET_CFG_CTRL_RXCSUM_ANY; } if (changed & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) { @@ -2724,9 +2718,10 @@ static int nfp_net_set_features(struct net_device *netdev, if (changed & (NETIF_F_TSO | NETIF_F_TSO6)) { if (features & (NETIF_F_TSO | NETIF_F_TSO6)) - new_ctrl |= NFP_NET_CFG_CTRL_LSO; + new_ctrl |= nn->cap & NFP_NET_CFG_CTRL_LSO2 ?: + NFP_NET_CFG_CTRL_LSO; else - new_ctrl &= ~NFP_NET_CFG_CTRL_LSO; + new_ctrl &= ~NFP_NET_CFG_CTRL_LSO_ANY; } if (changed & NETIF_F_HW_VLAN_CTAG_RX) { @@ -2750,7 +2745,7 @@ static int nfp_net_set_features(struct net_device *netdev, new_ctrl &= ~NFP_NET_CFG_CTRL_GATHER; } - if (changed & NETIF_F_HW_TC && nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) { + if (changed & NETIF_F_HW_TC && nfp_app_tc_busy(nn->app, nn)) { nn_err(nn, "Cannot disable HW TC offload while in use\n"); return -EBUSY; } @@ -2818,26 +2813,6 @@ nfp_net_features_check(struct sk_buff *skb, struct net_device *dev, return features; } -static int -nfp_net_get_phys_port_name(struct net_device *netdev, char *name, size_t len) -{ - struct nfp_net *nn = netdev_priv(netdev); - int err; - - if (!nn->eth_port) - return -EOPNOTSUPP; - - if (!nn->eth_port->is_split) - err = snprintf(name, len, "p%d", nn->eth_port->label_port); - else - err = snprintf(name, len, "p%ds%d", nn->eth_port->label_port, - nn->eth_port->label_subport); - if (err >= len) - return -EINVAL; - - return 0; -} - /** * nfp_net_set_vxlan_port() - set vxlan port in SW and reconfigure HW * @nn: NFP Net device to reconfigure @@ -2919,34 +2894,6 @@ static void nfp_net_del_vxlan_port(struct net_device *netdev, nfp_net_set_vxlan_port(nn, idx, 0); } -static int nfp_net_xdp_offload(struct nfp_net *nn, struct bpf_prog *prog) -{ - struct tc_cls_bpf_offload cmd = { - .prog = prog, - }; - int ret; - - if (!nfp_net_ebpf_capable(nn)) - return -EINVAL; - - if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) { - if (!nn->dp.bpf_offload_xdp) - return prog ? -EBUSY : 0; - cmd.command = prog ? TC_CLSBPF_REPLACE : TC_CLSBPF_DESTROY; - } else { - if (!prog) - return 0; - cmd.command = TC_CLSBPF_ADD; - } - - ret = nfp_net_bpf_offload(nn, &cmd); - /* Stop offload if replace not possible */ - if (ret && cmd.command == TC_CLSBPF_REPLACE) - nfp_net_xdp_offload(nn, NULL); - nn->dp.bpf_offload_xdp = prog && !ret; - return ret; -} - static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp) { struct bpf_prog *old_prog = nn->dp.xdp_prog; @@ -2959,7 +2906,7 @@ static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp) if (prog && nn->dp.xdp_prog) { prog = xchg(&nn->dp.xdp_prog, prog); bpf_prog_put(prog); - nfp_net_xdp_offload(nn, nn->dp.xdp_prog); + nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog); return 0; } @@ -2980,7 +2927,7 @@ static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp) if (old_prog) bpf_prog_put(old_prog); - nfp_net_xdp_offload(nn, nn->dp.xdp_prog); + nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog); return 0; } @@ -3000,7 +2947,28 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp) } } -static const struct net_device_ops nfp_net_netdev_ops = { +static int nfp_net_set_mac_address(struct net_device *netdev, void *addr) +{ + struct nfp_net *nn = netdev_priv(netdev); + struct sockaddr *saddr = addr; + int err; + + err = eth_prepare_mac_addr_change(netdev, addr); + if (err) + return err; + + nfp_net_write_mac_addr(nn, saddr->sa_data); + + err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_MACADDR); + if (err) + return err; + + eth_commit_mac_addr_change(netdev, addr); + + return 0; +} + +const struct net_device_ops nfp_net_netdev_ops = { .ndo_open = nfp_net_netdev_open, .ndo_stop = nfp_net_netdev_close, .ndo_start_xmit = nfp_net_tx, @@ -3009,10 +2977,10 @@ static const struct net_device_ops nfp_net_netdev_ops = { .ndo_tx_timeout = nfp_net_tx_timeout, .ndo_set_rx_mode = nfp_net_set_rx_mode, .ndo_change_mtu = nfp_net_change_mtu, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = nfp_net_set_mac_address, .ndo_set_features = nfp_net_set_features, .ndo_features_check = nfp_net_features_check, - .ndo_get_phys_port_name = nfp_net_get_phys_port_name, + .ndo_get_phys_port_name = nfp_port_get_phys_port_name, .ndo_udp_tunnel_add = nfp_net_add_vxlan_port, .ndo_udp_tunnel_del = nfp_net_del_vxlan_port, .ndo_xdp = nfp_net_xdp, @@ -3032,7 +3000,7 @@ void nfp_net_info(struct nfp_net *nn) nn->fw_ver.resv, nn->fw_ver.class, nn->fw_ver.major, nn->fw_ver.minor, nn->max_mtu); - nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", nn->cap, nn->cap & NFP_NET_CFG_CTRL_PROMISC ? "PROMISC " : "", nn->cap & NFP_NET_CFG_CTRL_L2BC ? "L2BCFILT " : "", @@ -3043,18 +3011,23 @@ void nfp_net_info(struct nfp_net *nn) nn->cap & NFP_NET_CFG_CTRL_TXVLAN ? "TXVLAN " : "", nn->cap & NFP_NET_CFG_CTRL_SCATTER ? "SCATTER " : "", nn->cap & NFP_NET_CFG_CTRL_GATHER ? "GATHER " : "", - nn->cap & NFP_NET_CFG_CTRL_LSO ? "TSO " : "", - nn->cap & NFP_NET_CFG_CTRL_RSS ? "RSS " : "", + nn->cap & NFP_NET_CFG_CTRL_LSO ? "TSO1 " : "", + nn->cap & NFP_NET_CFG_CTRL_LSO2 ? "TSO2 " : "", + nn->cap & NFP_NET_CFG_CTRL_RSS ? "RSS1 " : "", + nn->cap & NFP_NET_CFG_CTRL_RSS2 ? "RSS2 " : "", nn->cap & NFP_NET_CFG_CTRL_L2SWITCH ? "L2SWITCH " : "", nn->cap & NFP_NET_CFG_CTRL_MSIXAUTO ? "AUTOMASK " : "", nn->cap & NFP_NET_CFG_CTRL_IRQMOD ? "IRQMOD " : "", nn->cap & NFP_NET_CFG_CTRL_VXLAN ? "VXLAN " : "", nn->cap & NFP_NET_CFG_CTRL_NVGRE ? "NVGRE " : "", - nfp_net_ebpf_capable(nn) ? "BPF " : ""); + nn->cap & NFP_NET_CFG_CTRL_CSUM_COMPLETE ? + "RXCSUM_COMPLETE " : "", + nn->cap & NFP_NET_CFG_CTRL_LIVE_ADDR ? "LIVE_ADDR " : "", + nfp_app_extra_cap(nn->app, nn)); } /** - * nfp_net_netdev_alloc() - Allocate netdev and related structure + * nfp_net_alloc() - Allocate netdev and related structure * @pdev: PCI device * @max_tx_rings: Maximum number of TX rings supported by device * @max_rx_rings: Maximum number of RX rings supported by device @@ -3064,9 +3037,9 @@ void nfp_net_info(struct nfp_net *nn) * * Return: NFP Net device structure, or ERR_PTR on error. */ -struct nfp_net *nfp_net_netdev_alloc(struct pci_dev *pdev, - unsigned int max_tx_rings, - unsigned int max_rx_rings) +struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, + unsigned int max_tx_rings, + unsigned int max_rx_rings) { struct net_device *netdev; struct nfp_net *nn; @@ -3099,22 +3072,19 @@ struct nfp_net *nfp_net_netdev_alloc(struct pci_dev *pdev, nn->dp.rxd_cnt = NFP_NET_RX_DESCS_DEFAULT; spin_lock_init(&nn->reconfig_lock); - spin_lock_init(&nn->rx_filter_lock); spin_lock_init(&nn->link_status_lock); setup_timer(&nn->reconfig_timer, nfp_net_reconfig_timer, (unsigned long)nn); - setup_timer(&nn->rx_filter_stats_timer, - nfp_net_filter_stats_timer, (unsigned long)nn); return nn; } /** - * nfp_net_netdev_free() - Undo what @nfp_net_netdev_alloc() did + * nfp_net_free() - Undo what @nfp_net_alloc() did * @nn: NFP Net device to reconfigure */ -void nfp_net_netdev_free(struct nfp_net *nn) +void nfp_net_free(struct nfp_net *nn) { free_netdev(nn->dp.netdev); } @@ -3188,25 +3158,29 @@ static void nfp_net_irqmod_init(struct nfp_net *nn) } /** - * nfp_net_netdev_init() - Initialise/finalise the netdev structure - * @netdev: netdev structure + * nfp_net_init() - Initialise/finalise the nfp_net structure + * @nn: NFP Net device structure * * Return: 0 on success or negative errno on error. */ -int nfp_net_netdev_init(struct net_device *netdev) +int nfp_net_init(struct nfp_net *nn) { - struct nfp_net *nn = netdev_priv(netdev); + struct net_device *netdev = nn->dp.netdev; int err; - nn->dp.chained_metadata_format = nn->fw_ver.major > 3; - nn->dp.rx_dma_dir = DMA_FROM_DEVICE; /* Get some of the read-only fields from the BAR */ nn->cap = nn_readl(nn, NFP_NET_CFG_CAP); nn->max_mtu = nn_readl(nn, NFP_NET_CFG_MAX_MTU); - nfp_net_write_mac_addr(nn); + /* Chained metadata is signalled by capabilities except in version 4 */ + nn->dp.chained_metadata_format = nn->fw_ver.major == 4 || + nn->cap & NFP_NET_CFG_CTRL_CHAIN_META; + if (nn->dp.chained_metadata_format && nn->fw_ver.major != 4) + nn->cap &= ~NFP_NET_CFG_CTRL_RSS; + + nfp_net_write_mac_addr(nn, nn->dp.netdev->dev_addr); /* Determine RX packet/metadata boundary offset */ if (nn->fw_ver.major >= 2) { @@ -3236,10 +3210,13 @@ int nfp_net_netdev_init(struct net_device *netdev) * and netdev->hw_features advertises which features are * supported. By default we enable most features. */ + if (nn->cap & NFP_NET_CFG_CTRL_LIVE_ADDR) + netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + netdev->hw_features = NETIF_F_HIGHDMA; - if (nn->cap & NFP_NET_CFG_CTRL_RXCSUM) { + if (nn->cap & NFP_NET_CFG_CTRL_RXCSUM_ANY) { netdev->hw_features |= NETIF_F_RXCSUM; - nn->dp.ctrl |= NFP_NET_CFG_CTRL_RXCSUM; + nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_RXCSUM_ANY; } if (nn->cap & NFP_NET_CFG_CTRL_TXCSUM) { netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; @@ -3249,14 +3226,17 @@ int nfp_net_netdev_init(struct net_device *netdev) netdev->hw_features |= NETIF_F_SG; nn->dp.ctrl |= NFP_NET_CFG_CTRL_GATHER; } - if ((nn->cap & NFP_NET_CFG_CTRL_LSO) && nn->fw_ver.major > 2) { + if ((nn->cap & NFP_NET_CFG_CTRL_LSO && nn->fw_ver.major > 2) || + nn->cap & NFP_NET_CFG_CTRL_LSO2) { netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; - nn->dp.ctrl |= NFP_NET_CFG_CTRL_LSO; + nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_LSO2 ?: + NFP_NET_CFG_CTRL_LSO; } - if (nn->cap & NFP_NET_CFG_CTRL_RSS) { + if (nn->cap & NFP_NET_CFG_CTRL_RSS_ANY) { netdev->hw_features |= NETIF_F_RXHASH; nfp_net_rss_init(nn); - nn->dp.ctrl |= NFP_NET_CFG_CTRL_RSS; + nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_RSS2 ?: + NFP_NET_CFG_CTRL_RSS; } if (nn->cap & NFP_NET_CFG_CTRL_VXLAN && nn->cap & NFP_NET_CFG_CTRL_NVGRE) { @@ -3275,17 +3255,22 @@ int nfp_net_netdev_init(struct net_device *netdev) nn->dp.ctrl |= NFP_NET_CFG_CTRL_RXVLAN; } if (nn->cap & NFP_NET_CFG_CTRL_TXVLAN) { - netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX; - nn->dp.ctrl |= NFP_NET_CFG_CTRL_TXVLAN; + if (nn->cap & NFP_NET_CFG_CTRL_LSO2) { + nn_warn(nn, "Device advertises both TSO2 and TXVLAN. Refusing to enable TXVLAN.\n"); + } else { + netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX; + nn->dp.ctrl |= NFP_NET_CFG_CTRL_TXVLAN; + } } netdev->features = netdev->hw_features; - if (nfp_net_ebpf_capable(nn)) + if (nfp_app_has_tc(nn->app)) netdev->hw_features |= NETIF_F_HW_TC; /* Advertise but disable TSO by default. */ netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_LSO_ANY; /* Allow L2 Broadcast and Multicast through by default, if supported */ if (nn->cap & NFP_NET_CFG_CTRL_L2BC) @@ -3322,23 +3307,19 @@ int nfp_net_netdev_init(struct net_device *netdev) netif_carrier_off(netdev); nfp_net_set_ethtool_ops(netdev); - nfp_net_vecs_init(netdev); + nfp_net_vecs_init(nn); return register_netdev(netdev); } /** - * nfp_net_netdev_clean() - Undo what nfp_net_netdev_init() did. - * @netdev: netdev structure + * nfp_net_clean() - Undo what nfp_net_init() did. + * @nn: NFP Net device structure */ -void nfp_net_netdev_clean(struct net_device *netdev) +void nfp_net_clean(struct nfp_net *nn) { - struct nfp_net *nn = netdev_priv(netdev); - unregister_netdev(nn->dp.netdev); if (nn->dp.xdp_prog) bpf_prog_put(nn->dp.xdp_prog); - if (nn->dp.bpf_offload_xdp) - nfp_net_xdp_offload(nn, NULL); } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index d04ccc9f6116..c8208bf370e0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -71,6 +71,7 @@ #define NFP_NET_META_FIELD_SIZE 4 #define NFP_NET_META_HASH 1 /* next field carries hash type */ #define NFP_NET_META_MARK 2 +#define NFP_NET_META_CSUM 6 /* checksum complete type */ /** * Hash type pre-pended when a RSS hash was computed @@ -119,9 +120,9 @@ #define NFP_NET_CFG_CTRL_TXVLAN (0x1 << 7) /* Enable VLAN insert */ #define NFP_NET_CFG_CTRL_SCATTER (0x1 << 8) /* Scatter DMA */ #define NFP_NET_CFG_CTRL_GATHER (0x1 << 9) /* Gather DMA */ -#define NFP_NET_CFG_CTRL_LSO (0x1 << 10) /* LSO/TSO */ +#define NFP_NET_CFG_CTRL_LSO (0x1 << 10) /* LSO/TSO (version 1) */ #define NFP_NET_CFG_CTRL_RINGCFG (0x1 << 16) /* Ring runtime changes */ -#define NFP_NET_CFG_CTRL_RSS (0x1 << 17) /* RSS */ +#define NFP_NET_CFG_CTRL_RSS (0x1 << 17) /* RSS (version 1) */ #define NFP_NET_CFG_CTRL_IRQMOD (0x1 << 18) /* Interrupt moderation */ #define NFP_NET_CFG_CTRL_RINGPRIO (0x1 << 19) /* Ring priorities */ #define NFP_NET_CFG_CTRL_MSIXAUTO (0x1 << 20) /* MSI-X auto-masking */ @@ -131,6 +132,20 @@ #define NFP_NET_CFG_CTRL_VXLAN (0x1 << 24) /* VXLAN tunnel support */ #define NFP_NET_CFG_CTRL_NVGRE (0x1 << 25) /* NVGRE tunnel support */ #define NFP_NET_CFG_CTRL_BPF (0x1 << 27) /* BPF offload capable */ +#define NFP_NET_CFG_CTRL_LSO2 (0x1 << 28) /* LSO/TSO (version 2) */ +#define NFP_NET_CFG_CTRL_RSS2 (0x1 << 29) /* RSS (version 2) */ +#define NFP_NET_CFG_CTRL_CSUM_COMPLETE (0x1 << 30) /* Checksum complete */ +#define NFP_NET_CFG_CTRL_LIVE_ADDR (0x1 << 31) /* live MAC addr change */ + +#define NFP_NET_CFG_CTRL_LSO_ANY (NFP_NET_CFG_CTRL_LSO | \ + NFP_NET_CFG_CTRL_LSO2) +#define NFP_NET_CFG_CTRL_RSS_ANY (NFP_NET_CFG_CTRL_RSS | \ + NFP_NET_CFG_CTRL_RSS2) +#define NFP_NET_CFG_CTRL_RXCSUM_ANY (NFP_NET_CFG_CTRL_RXCSUM | \ + NFP_NET_CFG_CTRL_CSUM_COMPLETE) +#define NFP_NET_CFG_CTRL_CHAIN_META (NFP_NET_CFG_CTRL_RSS2 | \ + NFP_NET_CFG_CTRL_CSUM_COMPLETE) + #define NFP_NET_CFG_UPDATE 0x0004 #define NFP_NET_CFG_UPDATE_GEN (0x1 << 0) /* General update */ #define NFP_NET_CFG_UPDATE_RING (0x1 << 1) /* Ring config change */ @@ -143,6 +158,7 @@ #define NFP_NET_CFG_UPDATE_IRQMOD (0x1 << 8) /* IRQ mod change */ #define NFP_NET_CFG_UPDATE_VXLAN (0x1 << 9) /* VXLAN port change */ #define NFP_NET_CFG_UPDATE_BPF (0x1 << 10) /* BPF program load */ +#define NFP_NET_CFG_UPDATE_MACADDR (0x1 << 11) /* MAC address change */ #define NFP_NET_CFG_UPDATE_ERR (0x1 << 31) /* A error occurred */ #define NFP_NET_CFG_TXRS_ENABLE 0x0008 #define NFP_NET_CFG_RXRS_ENABLE 0x0010 diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c index 4077c59bf782..8c52c0e8379c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c @@ -62,7 +62,7 @@ static int nfp_net_debugfs_rx_q_read(struct seq_file *file, void *data) fl_rd_p = nfp_qcp_rd_ptr_read(rx_ring->qcp_fl); fl_wr_p = nfp_qcp_wr_ptr_read(rx_ring->qcp_fl); - seq_printf(file, "RX[%02d,%02d]: cnt=%d dma=%pad host=%p H_RD=%d H_WR=%d FL_RD=%d FL_WR=%d\n", + seq_printf(file, "RX[%02d,%02d]: cnt=%u dma=%pad host=%p H_RD=%u H_WR=%u FL_RD=%u FL_WR=%u\n", rx_ring->idx, rx_ring->fl_qcidx, rx_ring->cnt, &rx_ring->dma, rx_ring->rxds, rx_ring->rd_p, rx_ring->wr_p, fl_rd_p, fl_wr_p); @@ -146,7 +146,7 @@ static int nfp_net_debugfs_tx_q_read(struct seq_file *file, void *data) d_rd_p = nfp_qcp_rd_ptr_read(tx_ring->qcp_q); d_wr_p = nfp_qcp_wr_ptr_read(tx_ring->qcp_q); - seq_printf(file, "TX[%02d,%02d%s]: cnt=%d dma=%pad host=%p H_RD=%d H_WR=%d D_RD=%d D_WR=%d\n", + seq_printf(file, "TX[%02d,%02d%s]: cnt=%u dma=%pad host=%p H_RD=%u H_WR=%u D_RD=%u D_WR=%u\n", tx_ring->idx, tx_ring->qcidx, tx_ring == r_vec->tx_ring ? "" : "xdp", tx_ring->cnt, &tx_ring->dma, tx_ring->txds, @@ -200,7 +200,7 @@ static const struct file_operations nfp_xdp_q_fops = { .llseek = seq_lseek }; -void nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id) +void nfp_net_debugfs_vnic_add(struct nfp_net *nn, struct dentry *ddir, int id) { struct dentry *queues, *tx, *rx, *xdp; char name[20]; @@ -209,7 +209,7 @@ void nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id) if (IS_ERR_OR_NULL(nfp_dir)) return; - sprintf(name, "port%d", id); + sprintf(name, "vnic%d", id); nn->debugfs_dir = debugfs_create_dir(name, ddir); if (IS_ERR_OR_NULL(nn->debugfs_dir)) return; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index abbb47e60cc3..83664ca25213 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -50,8 +50,10 @@ #include "nfpcore/nfp.h" #include "nfpcore/nfp_nsp.h" +#include "nfp_app.h" #include "nfp_net_ctrl.h" #include "nfp_net.h" +#include "nfp_port.h" enum nfp_dump_diag { NFP_DUMP_NSP_DIAG = 0, @@ -134,14 +136,14 @@ static const struct _nfp_net_et_stats nfp_net_et_stats[] = { #define NN_ET_STATS_LEN (NN_ET_GLOBAL_STATS_LEN + NN_ET_RVEC_GATHER_STATS + \ NN_ET_RVEC_STATS_LEN + NN_ET_QUEUE_STATS_LEN) -static void nfp_net_get_nspinfo(struct nfp_net *nn, char *version) +static void nfp_net_get_nspinfo(struct nfp_app *app, char *version) { struct nfp_nsp *nsp; - if (!nn->cpp) + if (!app) return; - nsp = nfp_nsp_open(nn->cpp); + nsp = nfp_nsp_open(app->cpp); if (IS_ERR(nsp)) return; @@ -162,11 +164,12 @@ static void nfp_net_get_drvinfo(struct net_device *netdev, sizeof(drvinfo->driver)); strlcpy(drvinfo->version, nfp_driver_version, sizeof(drvinfo->version)); - nfp_net_get_nspinfo(nn, nsp_version); + nfp_net_get_nspinfo(nn->app, nsp_version); snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), - "%d.%d.%d.%d %s", + "%d.%d.%d.%d %s %s", nn->fw_ver.resv, nn->fw_ver.class, - nn->fw_ver.major, nn->fw_ver.minor, nsp_version); + nn->fw_ver.major, nn->fw_ver.minor, nsp_version, + nfp_app_name(nn->app)); strlcpy(drvinfo->bus_info, pci_name(nn->pdev), sizeof(drvinfo->bus_info)); @@ -195,37 +198,38 @@ nfp_net_get_link_ksettings(struct net_device *netdev, [NFP_NET_CFG_STS_LINK_RATE_50G] = SPEED_50000, [NFP_NET_CFG_STS_LINK_RATE_100G] = SPEED_100000, }; - struct nfp_net *nn = netdev_priv(netdev); + struct nfp_eth_table_port *eth_port; + struct nfp_port *port; + struct nfp_net *nn; u32 sts, ls; + /* Init to unknowns */ ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); cmd->base.port = PORT_OTHER; cmd->base.speed = SPEED_UNKNOWN; cmd->base.duplex = DUPLEX_UNKNOWN; - if (nn->eth_port) - cmd->base.autoneg = nn->eth_port->aneg != NFP_ANEG_DISABLED ? + port = nfp_port_from_netdev(netdev); + eth_port = nfp_port_get_eth_port(port); + if (eth_port) + cmd->base.autoneg = eth_port->aneg != NFP_ANEG_DISABLED ? AUTONEG_ENABLE : AUTONEG_DISABLE; if (!netif_carrier_ok(netdev)) return 0; /* Use link speed from ETH table if available, otherwise try the BAR */ - if (nn->eth_port) { - int err; - - if (nfp_net_link_changed_read_clear(nn)) { - err = nfp_net_refresh_eth_port(nn); - if (err) - return err; - } - - cmd->base.port = nn->eth_port->port_type; - cmd->base.speed = nn->eth_port->speed; + if (eth_port) { + cmd->base.port = eth_port->port_type; + cmd->base.speed = eth_port->speed; cmd->base.duplex = DUPLEX_FULL; return 0; } + if (!nfp_netdev_is_nfp_net(netdev)) + return -EOPNOTSUPP; + nn = netdev_priv(netdev); + sts = nn_readl(nn, NFP_NET_CFG_STS); ls = FIELD_GET(NFP_NET_CFG_STS_LINK_RATE, sts); @@ -246,19 +250,22 @@ static int nfp_net_set_link_ksettings(struct net_device *netdev, const struct ethtool_link_ksettings *cmd) { - struct nfp_net *nn = netdev_priv(netdev); + struct nfp_eth_table_port *eth_port; + struct nfp_port *port; struct nfp_nsp *nsp; int err; - if (!nn->eth_port) + port = nfp_port_from_netdev(netdev); + eth_port = __nfp_port_get_eth_port(port); + if (!eth_port) return -EOPNOTSUPP; if (netif_running(netdev)) { - nn_warn(nn, "Changing settings not allowed on an active interface. It may cause the port to be disabled until reboot.\n"); + netdev_warn(netdev, "Changing settings not allowed on an active interface. It may cause the port to be disabled until reboot.\n"); return -EBUSY; } - nsp = nfp_eth_config_start(nn->cpp, nn->eth_port->index); + nsp = nfp_eth_config_start(port->app->cpp, eth_port->index); if (IS_ERR(nsp)) return PTR_ERR(nsp); @@ -267,7 +274,7 @@ nfp_net_set_link_ksettings(struct net_device *netdev, if (err) goto err_bad_set; if (cmd->base.speed != SPEED_UNKNOWN) { - u32 speed = cmd->base.speed / nn->eth_port->lanes; + u32 speed = cmd->base.speed / eth_port->lanes; err = __nfp_eth_set_speed(nsp, speed); if (err) @@ -278,7 +285,7 @@ nfp_net_set_link_ksettings(struct net_device *netdev, if (err > 0) return 0; /* no change */ - nfp_net_refresh_port_table(nn); + nfp_net_refresh_port_table(port); return err; @@ -496,7 +503,7 @@ static int nfp_net_get_rss_hash_opts(struct nfp_net *nn, cmd->data = 0; - if (!(nn->cap & NFP_NET_CFG_CTRL_RSS)) + if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY)) return -EOPNOTSUPP; nfp_rss_flag = ethtool_flow_to_nfp_flag(cmd->flow_type); @@ -533,7 +540,7 @@ static int nfp_net_set_rss_hash_opt(struct nfp_net *nn, u32 nfp_rss_flag; int err; - if (!(nn->cap & NFP_NET_CFG_CTRL_RSS)) + if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY)) return -EOPNOTSUPP; /* RSS only supports IP SA/DA and L4 src/dst ports */ @@ -595,7 +602,7 @@ static u32 nfp_net_get_rxfh_indir_size(struct net_device *netdev) { struct nfp_net *nn = netdev_priv(netdev); - if (!(nn->cap & NFP_NET_CFG_CTRL_RSS)) + if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY)) return 0; return ARRAY_SIZE(nn->rss_itbl); @@ -605,7 +612,7 @@ static u32 nfp_net_get_rxfh_key_size(struct net_device *netdev) { struct nfp_net *nn = netdev_priv(netdev); - if (!(nn->cap & NFP_NET_CFG_CTRL_RSS)) + if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY)) return -EOPNOTSUPP; return nfp_net_rss_key_sz(nn); @@ -617,7 +624,7 @@ static int nfp_net_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, struct nfp_net *nn = netdev_priv(netdev); int i; - if (!(nn->cap & NFP_NET_CFG_CTRL_RSS)) + if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY)) return -EOPNOTSUPP; if (indir) @@ -641,7 +648,7 @@ static int nfp_net_set_rxfh(struct net_device *netdev, struct nfp_net *nn = netdev_priv(netdev); int i; - if (!(nn->cap & NFP_NET_CFG_CTRL_RSS) || + if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY) || !(hfunc == ETH_RSS_HASH_NO_CHANGE || hfunc == nn->rss_hfunc)) return -EOPNOTSUPP; @@ -706,13 +713,13 @@ nfp_dump_nsp_diag(struct nfp_net *nn, struct ethtool_dump *dump, void *buffer) struct nfp_resource *res; int ret; - if (!nn->cpp) + if (!nn->app) return -EOPNOTSUPP; dump->version = 1; dump->flag = NFP_DUMP_NSP_DIAG; - res = nfp_resource_acquire(nn->cpp, NFP_RESOURCE_NSP_DIAG); + res = nfp_resource_acquire(nn->app->cpp, NFP_RESOURCE_NSP_DIAG); if (IS_ERR(res)) return PTR_ERR(res); @@ -722,7 +729,7 @@ nfp_dump_nsp_diag(struct nfp_net *nn, struct ethtool_dump *dump, void *buffer) goto exit_release; } - ret = nfp_cpp_read(nn->cpp, nfp_resource_cpp_id(res), + ret = nfp_cpp_read(nn->app->cpp, nfp_resource_cpp_id(res), nfp_resource_address(res), buffer, dump->len); if (ret != dump->len) @@ -743,7 +750,7 @@ static int nfp_net_set_dump(struct net_device *netdev, struct ethtool_dump *val) { struct nfp_net *nn = netdev_priv(netdev); - if (!nn->cpp) + if (!nn->app) return -EOPNOTSUPP; if (val->flag != NFP_DUMP_NSP_DIAG) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 8cb87cbe1120..7dd310911d9f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -43,6 +43,7 @@ #include <linux/etherdevice.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/lockdep.h> #include <linux/pci.h> #include <linux/pci_regs.h> #include <linux/msi.h> @@ -54,10 +55,11 @@ #include "nfpcore/nfp_nffw.h" #include "nfpcore/nfp_nsp.h" #include "nfpcore/nfp6000_pcie.h" - +#include "nfp_app.h" #include "nfp_net_ctrl.h" #include "nfp_net.h" #include "nfp_main.h" +#include "nfp_port.h" #define NFP_PF_CSR_SLICE_SIZE (32 * 1024) @@ -139,17 +141,19 @@ err_area: * First try to get the MAC address from NSP ETH table. If that * fails try HWInfo. As a last resort generate a random address. */ -static void +void nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id) { + struct nfp_eth_table_port *eth_port; struct nfp_net_dp *dp = &nn->dp; u8 mac_addr[ETH_ALEN]; const char *mac_str; char name[32]; - if (nn->eth_port) { - ether_addr_copy(dp->netdev->dev_addr, nn->eth_port->mac_addr); - ether_addr_copy(dp->netdev->perm_addr, nn->eth_port->mac_addr); + eth_port = __nfp_port_get_eth_port(nn->port); + if (eth_port) { + ether_addr_copy(dp->netdev->dev_addr, eth_port->mac_addr); + ether_addr_copy(dp->netdev->perm_addr, eth_port->mac_addr); return; } @@ -175,7 +179,7 @@ nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id) ether_addr_copy(dp->netdev->perm_addr, mac_addr); } -static struct nfp_eth_table_port * +struct nfp_eth_table_port * nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id) { int i; @@ -187,30 +191,38 @@ nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id) return NULL; } -static unsigned int nfp_net_pf_get_num_ports(struct nfp_pf *pf) +static int +nfp_net_pf_rtsym_read_optional(struct nfp_pf *pf, const char *format, + unsigned int default_val) { char name[256]; - u16 interface; - int pcie_pf; int err = 0; u64 val; - interface = nfp_cpp_interface(pf->cpp); - pcie_pf = NFP_CPP_INTERFACE_UNIT_of(interface); - - snprintf(name, sizeof(name), "nfd_cfg_pf%d_num_ports", pcie_pf); + snprintf(name, sizeof(name), format, nfp_cppcore_pcie_unit(pf->cpp)); val = nfp_rtsym_read_le(pf->cpp, name, &err); - /* Default to one port */ if (err) { - if (err != -ENOENT) - nfp_err(pf->cpp, "Unable to read adapter port count\n"); - val = 1; + if (err == -ENOENT) + return default_val; + nfp_err(pf->cpp, "Unable to read symbol %s\n", name); + return err; } return val; } +static int nfp_net_pf_get_num_ports(struct nfp_pf *pf) +{ + return nfp_net_pf_rtsym_read_optional(pf, "nfd_cfg_pf%u_num_ports", 1); +} + +static int nfp_net_pf_get_app_id(struct nfp_pf *pf) +{ + return nfp_net_pf_rtsym_read_optional(pf, "_pf%u_net_app_id", + NFP_APP_CORE_NIC); +} + static unsigned int nfp_net_pf_total_qcs(struct nfp_pf *pf, void __iomem *ctrl_bar, unsigned int stride, u32 start_off, u32 num_off) @@ -220,7 +232,7 @@ nfp_net_pf_total_qcs(struct nfp_pf *pf, void __iomem *ctrl_bar, min_qc = readl(ctrl_bar + start_off); max_qc = min_qc; - for (i = 0; i < pf->num_ports; i++) { + for (i = 0; i < pf->max_data_vnics; i++) { /* To make our lives simpler only accept configuration where * queues are allocated to PFs in order (queues of PFn all have * indexes lower than PFn+1). @@ -241,13 +253,9 @@ static u8 __iomem *nfp_net_pf_map_ctrl_bar(struct nfp_pf *pf) const struct nfp_rtsym *ctrl_sym; u8 __iomem *ctrl_bar; char pf_symbol[256]; - u16 interface; - int pcie_pf; - - interface = nfp_cpp_interface(pf->cpp); - pcie_pf = NFP_CPP_INTERFACE_UNIT_of(interface); - snprintf(pf_symbol, sizeof(pf_symbol), "_pf%d_net_bar0", pcie_pf); + snprintf(pf_symbol, sizeof(pf_symbol), "_pf%u_net_bar0", + nfp_cppcore_pcie_unit(pf->cpp)); ctrl_sym = nfp_rtsym_lookup(pf->cpp, pf_symbol); if (!ctrl_sym) { @@ -256,17 +264,17 @@ static u8 __iomem *nfp_net_pf_map_ctrl_bar(struct nfp_pf *pf) return NULL; } - if (ctrl_sym->size < pf->num_ports * NFP_PF_CSR_SLICE_SIZE) { + if (ctrl_sym->size < pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE) { dev_err(&pf->pdev->dev, - "PF BAR0 too small to contain %d ports\n", - pf->num_ports); + "PF BAR0 too small to contain %d vNICs\n", + pf->max_data_vnics); return NULL; } ctrl_bar = nfp_net_map_area(pf->cpp, "net.ctrl", ctrl_sym->domain, ctrl_sym->target, ctrl_sym->addr, ctrl_sym->size, - &pf->ctrl_area); + &pf->data_vnic_bar); if (IS_ERR(ctrl_bar)) { dev_err(&pf->pdev->dev, "Failed to map PF BAR0: %ld\n", PTR_ERR(ctrl_bar)); @@ -276,37 +284,43 @@ static u8 __iomem *nfp_net_pf_map_ctrl_bar(struct nfp_pf *pf) return ctrl_bar; } -static void nfp_net_pf_free_netdevs(struct nfp_pf *pf) +static void nfp_net_pf_free_vnic(struct nfp_pf *pf, struct nfp_net *nn) { - struct nfp_net *nn; + nfp_port_free(nn->port); + list_del(&nn->vnic_list); + pf->num_vnics--; + nfp_net_free(nn); +} - while (!list_empty(&pf->ports)) { - nn = list_first_entry(&pf->ports, struct nfp_net, port_list); - list_del(&nn->port_list); - pf->num_netdevs--; +static void nfp_net_pf_free_vnics(struct nfp_pf *pf) +{ + struct nfp_net *nn; - nfp_net_netdev_free(nn); + while (!list_empty(&pf->vnics)) { + nn = list_first_entry(&pf->vnics, struct nfp_net, vnic_list); + nfp_net_pf_free_vnic(pf, nn); } } static struct nfp_net * -nfp_net_pf_alloc_port_netdev(struct nfp_pf *pf, void __iomem *ctrl_bar, - void __iomem *tx_bar, void __iomem *rx_bar, - int stride, struct nfp_net_fw_version *fw_ver, - struct nfp_eth_table_port *eth_port) +nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar, + void __iomem *tx_bar, void __iomem *rx_bar, + int stride, struct nfp_net_fw_version *fw_ver, + unsigned int eth_id) { u32 n_tx_rings, n_rx_rings; struct nfp_net *nn; + int err; n_tx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_TXRINGS); n_rx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_RXRINGS); - /* Allocate and initialise the netdev */ - nn = nfp_net_netdev_alloc(pf->pdev, n_tx_rings, n_rx_rings); + /* Allocate and initialise the vNIC */ + nn = nfp_net_alloc(pf->pdev, n_tx_rings, n_rx_rings); if (IS_ERR(nn)) return nn; - nn->cpp = pf->cpp; + nn->app = pf->app; nn->fw_ver = *fw_ver; nn->dp.ctrl_bar = ctrl_bar; nn->tx_bar = tx_bar; @@ -314,44 +328,58 @@ nfp_net_pf_alloc_port_netdev(struct nfp_pf *pf, void __iomem *ctrl_bar, nn->dp.is_vf = 0; nn->stride_rx = stride; nn->stride_tx = stride; - nn->eth_port = eth_port; + + err = nfp_app_vnic_init(pf->app, nn, eth_id); + if (err) { + nfp_net_free(nn); + return ERR_PTR(err); + } + + pf->num_vnics++; + list_add_tail(&nn->vnic_list, &pf->vnics); return nn; } static int -nfp_net_pf_init_port_netdev(struct nfp_pf *pf, struct nfp_net *nn, - unsigned int id) +nfp_net_pf_init_vnic(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id) { int err; - /* Get MAC address */ - nfp_net_get_mac_addr(nn, pf->cpp, id); - /* Get ME clock frequency from ctrl BAR * XXX for now frequency is hardcoded until we figure out how * to get the value from nfp-hwinfo into ctrl bar */ nn->me_freq_mhz = 1200; - err = nfp_net_netdev_init(nn->dp.netdev); + err = nfp_net_init(nn); if (err) return err; - nfp_net_debugfs_port_add(nn, pf->ddir, id); + nfp_net_debugfs_vnic_add(nn, pf->ddir, id); + + if (nn->port) { + err = nfp_devlink_port_register(pf->app, nn->port); + if (err) + goto err_dfs_clean; + } nfp_net_info(nn); return 0; + +err_dfs_clean: + nfp_net_debugfs_dir_clean(&nn->debugfs_dir); + nfp_net_clean(nn); + return err; } static int -nfp_net_pf_alloc_netdevs(struct nfp_pf *pf, void __iomem *ctrl_bar, - void __iomem *tx_bar, void __iomem *rx_bar, - int stride, struct nfp_net_fw_version *fw_ver) +nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar, + void __iomem *tx_bar, void __iomem *rx_bar, + int stride, struct nfp_net_fw_version *fw_ver) { u32 prev_tx_base, prev_rx_base, tgt_tx_base, tgt_rx_base; - struct nfp_eth_table_port *eth_port; struct nfp_net *nn; unsigned int i; int err; @@ -359,7 +387,7 @@ nfp_net_pf_alloc_netdevs(struct nfp_pf *pf, void __iomem *ctrl_bar, prev_tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ); prev_rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ); - for (i = 0; i < pf->num_ports; i++) { + for (i = 0; i < pf->max_data_vnics; i++) { tgt_tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ); tgt_rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ); tx_bar += (tgt_tx_base - prev_tx_base) * NFP_QCP_QUEUE_ADDR_SZ; @@ -367,53 +395,60 @@ nfp_net_pf_alloc_netdevs(struct nfp_pf *pf, void __iomem *ctrl_bar, prev_tx_base = tgt_tx_base; prev_rx_base = tgt_rx_base; - eth_port = nfp_net_find_port(pf->eth_tbl, i); - if (eth_port && eth_port->override_changed) { - nfp_warn(pf->cpp, "Config changed for port #%d, reboot required before port will be operational\n", i); - } else { - nn = nfp_net_pf_alloc_port_netdev(pf, ctrl_bar, tx_bar, - rx_bar, stride, - fw_ver, eth_port); - if (IS_ERR(nn)) { - err = PTR_ERR(nn); - goto err_free_prev; - } - list_add_tail(&nn->port_list, &pf->ports); - pf->num_netdevs++; + nn = nfp_net_pf_alloc_vnic(pf, ctrl_bar, tx_bar, rx_bar, + stride, fw_ver, i); + if (IS_ERR(nn)) { + err = PTR_ERR(nn); + goto err_free_prev; } ctrl_bar += NFP_PF_CSR_SLICE_SIZE; + + /* Kill the vNIC if app init marked it as invalid */ + if (nn->port && nn->port->type == NFP_PORT_INVALID) { + nfp_net_pf_free_vnic(pf, nn); + continue; + } } - if (list_empty(&pf->ports)) + if (list_empty(&pf->vnics)) return -ENODEV; return 0; err_free_prev: - nfp_net_pf_free_netdevs(pf); + nfp_net_pf_free_vnics(pf); return err; } +static void nfp_net_pf_clean_vnic(struct nfp_pf *pf, struct nfp_net *nn) +{ + if (nn->port) + nfp_devlink_port_unregister(nn->port); + nfp_net_debugfs_dir_clean(&nn->debugfs_dir); + nfp_net_clean(nn); + nfp_app_vnic_clean(pf->app, nn); +} + static int -nfp_net_pf_spawn_netdevs(struct nfp_pf *pf, - void __iomem *ctrl_bar, void __iomem *tx_bar, - void __iomem *rx_bar, int stride, - struct nfp_net_fw_version *fw_ver) +nfp_net_pf_spawn_vnics(struct nfp_pf *pf, + void __iomem *ctrl_bar, void __iomem *tx_bar, + void __iomem *rx_bar, int stride, + struct nfp_net_fw_version *fw_ver) { - unsigned int id, wanted_irqs, num_irqs, ports_left, irqs_left; + unsigned int id, wanted_irqs, num_irqs, vnics_left, irqs_left; struct nfp_net *nn; int err; - /* Allocate the netdevs and do basic init */ - err = nfp_net_pf_alloc_netdevs(pf, ctrl_bar, tx_bar, rx_bar, - stride, fw_ver); + /* Allocate the vnics and do basic init */ + err = nfp_net_pf_alloc_vnics(pf, ctrl_bar, tx_bar, rx_bar, + stride, fw_ver); if (err) return err; /* Get MSI-X vectors */ wanted_irqs = 0; - list_for_each_entry(nn, &pf->ports, port_list) + list_for_each_entry(nn, &pf->vnics, vnic_list) wanted_irqs += NFP_NET_NON_Q_VECTORS + nn->dp.num_r_vecs; pf->irq_entries = kcalloc(wanted_irqs, sizeof(*pf->irq_entries), GFP_KERNEL); @@ -423,7 +458,7 @@ nfp_net_pf_spawn_netdevs(struct nfp_pf *pf, } num_irqs = nfp_net_irqs_alloc(pf->pdev, pf->irq_entries, - NFP_NET_MIN_PORT_IRQS * pf->num_netdevs, + NFP_NET_MIN_VNIC_IRQS * pf->num_vnics, wanted_irqs); if (!num_irqs) { nn_warn(nn, "Unable to allocate MSI-X Vectors. Exiting\n"); @@ -431,23 +466,23 @@ nfp_net_pf_spawn_netdevs(struct nfp_pf *pf, goto err_vec_free; } - /* Distribute IRQs to ports */ + /* Distribute IRQs to vNICs */ irqs_left = num_irqs; - ports_left = pf->num_netdevs; - list_for_each_entry(nn, &pf->ports, port_list) { + vnics_left = pf->num_vnics; + list_for_each_entry(nn, &pf->vnics, vnic_list) { unsigned int n; - n = DIV_ROUND_UP(irqs_left, ports_left); + n = DIV_ROUND_UP(irqs_left, vnics_left); nfp_net_irqs_assign(nn, &pf->irq_entries[num_irqs - irqs_left], n); irqs_left -= n; - ports_left--; + vnics_left--; } - /* Finish netdev init and register */ + /* Finish vNIC init and register */ id = 0; - list_for_each_entry(nn, &pf->ports, port_list) { - err = nfp_net_pf_init_port_netdev(pf, nn, id); + list_for_each_entry(nn, &pf->vnics, vnic_list) { + err = nfp_net_pf_init_vnic(pf, nn, id); if (err) goto err_prev_deinit; @@ -457,18 +492,41 @@ nfp_net_pf_spawn_netdevs(struct nfp_pf *pf, return 0; err_prev_deinit: - list_for_each_entry_continue_reverse(nn, &pf->ports, port_list) { - nfp_net_debugfs_dir_clean(&nn->debugfs_dir); - nfp_net_netdev_clean(nn->dp.netdev); - } + list_for_each_entry_continue_reverse(nn, &pf->vnics, vnic_list) + nfp_net_pf_clean_vnic(pf, nn); nfp_net_irqs_disable(pf->pdev); err_vec_free: kfree(pf->irq_entries); err_nn_free: - nfp_net_pf_free_netdevs(pf); + nfp_net_pf_free_vnics(pf); return err; } +static int nfp_net_pf_app_init(struct nfp_pf *pf) +{ + int err; + + pf->app = nfp_app_alloc(pf, nfp_net_pf_get_app_id(pf)); + if (IS_ERR(pf->app)) + return PTR_ERR(pf->app); + + err = nfp_app_init(pf->app); + if (err) + goto err_free; + + return 0; + +err_free: + nfp_app_free(pf->app); + return err; +} + +static void nfp_net_pf_app_clean(struct nfp_pf *pf) +{ + nfp_app_free(pf->app); + pf->app = NULL; +} + static void nfp_net_pci_remove_finish(struct nfp_pf *pf) { nfp_net_debugfs_dir_clean(&pf->ddir); @@ -476,99 +534,126 @@ static void nfp_net_pci_remove_finish(struct nfp_pf *pf) nfp_net_irqs_disable(pf->pdev); kfree(pf->irq_entries); + nfp_net_pf_app_clean(pf); + nfp_cpp_area_release_free(pf->rx_area); nfp_cpp_area_release_free(pf->tx_area); - nfp_cpp_area_release_free(pf->ctrl_area); + nfp_cpp_area_release_free(pf->data_vnic_bar); +} + +static int +nfp_net_eth_port_update(struct nfp_cpp *cpp, struct nfp_port *port, + struct nfp_eth_table *eth_table) +{ + struct nfp_eth_table_port *eth_port; + + ASSERT_RTNL(); + + eth_port = nfp_net_find_port(eth_table, port->eth_id); + if (!eth_port) { + set_bit(NFP_PORT_CHANGED, &port->flags); + nfp_warn(cpp, "Warning: port #%d not present after reconfig\n", + port->eth_id); + return -EIO; + } + if (eth_port->override_changed) { + nfp_warn(cpp, "Port #%d config changed, unregistering. Reboot required before port will be operational again.\n", port->eth_id); + port->type = NFP_PORT_INVALID; + } + + memcpy(port->eth_port, eth_port, sizeof(*eth_port)); + + return 0; } -static void nfp_net_refresh_netdevs(struct work_struct *work) +int nfp_net_refresh_port_table_sync(struct nfp_pf *pf) { - struct nfp_pf *pf = container_of(work, struct nfp_pf, - port_refresh_work); struct nfp_eth_table *eth_table; struct nfp_net *nn, *next; + struct nfp_port *port; - mutex_lock(&pf->port_lock); + lockdep_assert_held(&pf->lock); /* Check for nfp_net_pci_remove() racing against us */ - if (list_empty(&pf->ports)) - goto out; + if (list_empty(&pf->vnics)) + return 0; - list_for_each_entry(nn, &pf->ports, port_list) - nfp_net_link_changed_read_clear(nn); + /* Update state of all ports */ + rtnl_lock(); + list_for_each_entry(port, &pf->ports, port_list) + clear_bit(NFP_PORT_CHANGED, &port->flags); eth_table = nfp_eth_read_ports(pf->cpp); if (!eth_table) { + list_for_each_entry(port, &pf->ports, port_list) + if (__nfp_port_get_eth_port(port)) + set_bit(NFP_PORT_CHANGED, &port->flags); + rtnl_unlock(); nfp_err(pf->cpp, "Error refreshing port config!\n"); - goto out; + return -EIO; } - rtnl_lock(); - list_for_each_entry(nn, &pf->ports, port_list) { - if (!nn->eth_port) - continue; - nn->eth_port = nfp_net_find_port(eth_table, - nn->eth_port->eth_index); - } + list_for_each_entry(port, &pf->ports, port_list) + if (__nfp_port_get_eth_port(port)) + nfp_net_eth_port_update(pf->cpp, port, eth_table); rtnl_unlock(); - kfree(pf->eth_tbl); - pf->eth_tbl = eth_table; + kfree(eth_table); - list_for_each_entry_safe(nn, next, &pf->ports, port_list) { - if (!nn->eth_port) { - nfp_warn(pf->cpp, "Warning: port not present after reconfig\n"); - continue; - } - if (!nn->eth_port->override_changed) + /* Shoot off the ports which became invalid */ + list_for_each_entry_safe(nn, next, &pf->vnics, vnic_list) { + if (!nn->port || nn->port->type != NFP_PORT_INVALID) continue; - nn_warn(nn, "Port config changed, unregistering. Reboot required before port will be operational again.\n"); - - nfp_net_debugfs_dir_clean(&nn->debugfs_dir); - nfp_net_netdev_clean(nn->dp.netdev); - - list_del(&nn->port_list); - pf->num_netdevs--; - nfp_net_netdev_free(nn); + nfp_net_pf_clean_vnic(pf, nn); + nfp_net_pf_free_vnic(pf, nn); } - if (list_empty(&pf->ports)) + if (list_empty(&pf->vnics)) nfp_net_pci_remove_finish(pf); -out: - mutex_unlock(&pf->port_lock); + + return 0; } -void nfp_net_refresh_port_table(struct nfp_net *nn) +static void nfp_net_refresh_vnics(struct work_struct *work) { - struct nfp_pf *pf = pci_get_drvdata(nn->pdev); + struct nfp_pf *pf = container_of(work, struct nfp_pf, + port_refresh_work); + + mutex_lock(&pf->lock); + nfp_net_refresh_port_table_sync(pf); + mutex_unlock(&pf->lock); +} + +void nfp_net_refresh_port_table(struct nfp_port *port) +{ + struct nfp_pf *pf = port->app->pf; + + set_bit(NFP_PORT_CHANGED, &port->flags); schedule_work(&pf->port_refresh_work); } -int nfp_net_refresh_eth_port(struct nfp_net *nn) +int nfp_net_refresh_eth_port(struct nfp_port *port) { - struct nfp_eth_table_port *eth_port; + struct nfp_cpp *cpp = port->app->cpp; struct nfp_eth_table *eth_table; + int ret; - eth_table = nfp_eth_read_ports(nn->cpp); - if (!eth_table) { - nn_err(nn, "Error refreshing port state table!\n"); - return -EIO; - } + clear_bit(NFP_PORT_CHANGED, &port->flags); - eth_port = nfp_net_find_port(eth_table, nn->eth_port->eth_index); - if (!eth_port) { - nn_err(nn, "Error finding state of the port!\n"); - kfree(eth_table); + eth_table = nfp_eth_read_ports(cpp); + if (!eth_table) { + set_bit(NFP_PORT_CHANGED, &port->flags); + nfp_err(cpp, "Error refreshing port state table!\n"); return -EIO; } - memcpy(nn->eth_port, eth_port, sizeof(*eth_port)); + ret = nfp_net_eth_port_update(cpp, port, eth_table); kfree(eth_table); - return 0; + return ret; } /* @@ -584,8 +669,7 @@ int nfp_net_pci_probe(struct nfp_pf *pf) int stride; int err; - INIT_WORK(&pf->port_refresh_work, nfp_net_refresh_netdevs); - mutex_init(&pf->port_lock); + INIT_WORK(&pf->port_refresh_work, nfp_net_refresh_vnics); /* Verify that the board has completed initialization */ if (!nfp_is_ready(pf->cpp)) { @@ -593,8 +677,12 @@ int nfp_net_pci_probe(struct nfp_pf *pf) return -EINVAL; } - mutex_lock(&pf->port_lock); - pf->num_ports = nfp_net_pf_get_num_ports(pf); + mutex_lock(&pf->lock); + pf->max_data_vnics = nfp_net_pf_get_num_ports(pf); + if ((int)pf->max_data_vnics < 0) { + err = pf->max_data_vnics; + goto err_unlock; + } ctrl_bar = nfp_net_pf_map_ctrl_bar(pf); if (!ctrl_bar) { @@ -667,26 +755,32 @@ int nfp_net_pci_probe(struct nfp_pf *pf) goto err_unmap_tx; } + err = nfp_net_pf_app_init(pf); + if (err) + goto err_unmap_rx; + pf->ddir = nfp_net_debugfs_device_add(pf->pdev); - err = nfp_net_pf_spawn_netdevs(pf, ctrl_bar, tx_bar, rx_bar, - stride, &fw_ver); + err = nfp_net_pf_spawn_vnics(pf, ctrl_bar, tx_bar, rx_bar, + stride, &fw_ver); if (err) goto err_clean_ddir; - mutex_unlock(&pf->port_lock); + mutex_unlock(&pf->lock); return 0; err_clean_ddir: nfp_net_debugfs_dir_clean(&pf->ddir); + nfp_net_pf_app_clean(pf); +err_unmap_rx: nfp_cpp_area_release_free(pf->rx_area); err_unmap_tx: nfp_cpp_area_release_free(pf->tx_area); err_ctrl_unmap: - nfp_cpp_area_release_free(pf->ctrl_area); + nfp_cpp_area_release_free(pf->data_vnic_bar); err_unlock: - mutex_unlock(&pf->port_lock); + mutex_unlock(&pf->lock); return err; } @@ -694,21 +788,18 @@ void nfp_net_pci_remove(struct nfp_pf *pf) { struct nfp_net *nn; - mutex_lock(&pf->port_lock); - if (list_empty(&pf->ports)) + mutex_lock(&pf->lock); + if (list_empty(&pf->vnics)) goto out; - list_for_each_entry(nn, &pf->ports, port_list) { - nfp_net_debugfs_dir_clean(&nn->debugfs_dir); - - nfp_net_netdev_clean(nn->dp.netdev); - } + list_for_each_entry(nn, &pf->vnics, vnic_list) + nfp_net_pf_clean_vnic(pf, nn); - nfp_net_pf_free_netdevs(pf); + nfp_net_pf_free_vnics(pf); nfp_net_pci_remove_finish(pf); out: - mutex_unlock(&pf->port_lock); + mutex_unlock(&pf->lock); cancel_work_sync(&pf->port_refresh_work); } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c index 86e61be6f35c..3f1c7f0f392e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c @@ -202,7 +202,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev, rx_bar_off = NFP_PCIE_QUEUE(startq); /* Allocate and initialise the netdev */ - nn = nfp_net_netdev_alloc(pdev, max_tx_rings, max_rx_rings); + nn = nfp_net_alloc(pdev, max_tx_rings, max_rx_rings); if (IS_ERR(nn)) { err = PTR_ERR(nn); goto err_ctrl_unmap; @@ -267,7 +267,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev, nfp_netvf_get_mac_addr(nn); num_irqs = nfp_net_irqs_alloc(pdev, vf->irq_entries, - NFP_NET_MIN_PORT_IRQS, + NFP_NET_MIN_VNIC_IRQS, NFP_NET_NON_Q_VECTORS + nn->dp.num_r_vecs); if (!num_irqs) { @@ -283,13 +283,13 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev, */ nn->me_freq_mhz = 1200; - err = nfp_net_netdev_init(nn->dp.netdev); + err = nfp_net_init(nn); if (err) goto err_irqs_disable; nfp_net_info(nn); vf->ddir = nfp_net_debugfs_device_add(pdev); - nfp_net_debugfs_port_add(nn, vf->ddir, 0); + nfp_net_debugfs_vnic_add(nn, vf->ddir, 0); return 0; @@ -304,7 +304,7 @@ err_unmap_tx: else iounmap(vf->q_bar); err_netdev_free: - nfp_net_netdev_free(nn); + nfp_net_free(nn); err_ctrl_unmap: iounmap(ctrl_bar); err_pci_regions: @@ -328,7 +328,7 @@ static void nfp_netvf_pci_remove(struct pci_dev *pdev) nfp_net_debugfs_dir_clean(&nn->debugfs_dir); nfp_net_debugfs_dir_clean(&vf->ddir); - nfp_net_netdev_clean(nn->dp.netdev); + nfp_net_clean(nn); nfp_net_irqs_disable(pdev); @@ -340,7 +340,7 @@ static void nfp_netvf_pci_remove(struct pci_dev *pdev) } iounmap(nn->dp.ctrl_bar); - nfp_net_netdev_free(nn); + nfp_net_free(nn); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c new file mode 100644 index 000000000000..a17410ac01ab --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/lockdep.h> + +#include "nfpcore/nfp_nsp.h" +#include "nfp_app.h" +#include "nfp_main.h" +#include "nfp_net.h" +#include "nfp_port.h" + +struct nfp_port *nfp_port_from_netdev(struct net_device *netdev) +{ + struct nfp_net *nn; + + if (WARN_ON(!nfp_netdev_is_nfp_net(netdev))) + return NULL; + nn = netdev_priv(netdev); + + return nn->port; +} + +struct nfp_port * +nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id) +{ + struct nfp_port *port; + + lockdep_assert_held(&pf->lock); + + if (type != NFP_PORT_PHYS_PORT) + return NULL; + + list_for_each_entry(port, &pf->ports, port_list) + if (port->eth_id == id) + return port; + + return NULL; +} + +struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port) +{ + if (!port) + return NULL; + if (port->type != NFP_PORT_PHYS_PORT) + return NULL; + + return port->eth_port; +} + +struct nfp_eth_table_port *nfp_port_get_eth_port(struct nfp_port *port) +{ + if (!__nfp_port_get_eth_port(port)) + return NULL; + + if (test_bit(NFP_PORT_CHANGED, &port->flags)) + if (nfp_net_refresh_eth_port(port)) + return NULL; + + return __nfp_port_get_eth_port(port); +} + +int +nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len) +{ + struct nfp_eth_table_port *eth_port; + struct nfp_port *port; + int n; + + port = nfp_port_from_netdev(netdev); + eth_port = __nfp_port_get_eth_port(port); + if (!eth_port) + return -EOPNOTSUPP; + + if (!eth_port->is_split) + n = snprintf(name, len, "p%d", eth_port->label_port); + else + n = snprintf(name, len, "p%ds%d", eth_port->label_port, + eth_port->label_subport); + if (n >= len) + return -EINVAL; + + return 0; +} + +struct nfp_port * +nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type, + struct net_device *netdev) +{ + struct nfp_port *port; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return ERR_PTR(-ENOMEM); + + port->netdev = netdev; + port->type = type; + port->app = app; + + list_add_tail(&port->port_list, &app->pf->ports); + + return port; +} + +void nfp_port_free(struct nfp_port *port) +{ + if (!port) + return; + list_del(&port->port_list); + kfree(port); +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h new file mode 100644 index 000000000000..4d1a9b3fed41 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _NFP_PORT_H_ +#define _NFP_PORT_H_ + +#include <net/devlink.h> + +struct net_device; +struct nfp_app; +struct nfp_pf; +struct nfp_port; + +/** + * enum nfp_port_type - type of port NFP can switch traffic to + * @NFP_PORT_INVALID: port is invalid, %NFP_PORT_PHYS_PORT transitions to this + * state when port disappears because of FW fault or config + * change + * @NFP_PORT_PHYS_PORT: external NIC port + */ +enum nfp_port_type { + NFP_PORT_INVALID, + NFP_PORT_PHYS_PORT, +}; + +/** + * enum nfp_port_flags - port flags (can be type-specific) + * @NFP_PORT_CHANGED: port state has changed since last eth table refresh; + * for NFP_PORT_PHYS_PORT, never set otherwise; must hold + * rtnl_lock to clear + */ +enum nfp_port_flags { + NFP_PORT_CHANGED = 0, +}; + +/** + * struct nfp_port - structure representing NFP port + * @netdev: backpointer to associated netdev + * @type: what port type does the entity represent + * @flags: port flags + * @app: backpointer to the app structure + * @dl_port: devlink port structure + * @eth_id: for %NFP_PORT_PHYS_PORT port ID in NFP enumeration scheme + * @eth_port: for %NFP_PORT_PHYS_PORT translated ETH Table port entry + * @port_list: entry on pf's list of ports + */ +struct nfp_port { + struct net_device *netdev; + enum nfp_port_type type; + + unsigned long flags; + + struct nfp_app *app; + + struct devlink_port dl_port; + + unsigned int eth_id; + struct nfp_eth_table_port *eth_port; + + struct list_head port_list; +}; + +struct nfp_port *nfp_port_from_netdev(struct net_device *netdev); +struct nfp_port * +nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id); +struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port); +struct nfp_eth_table_port *nfp_port_get_eth_port(struct nfp_port *port); + +int +nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len); + +struct nfp_port * +nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type, + struct net_device *netdev); +void nfp_port_free(struct nfp_port *port); + +int nfp_net_refresh_eth_port(struct nfp_port *port); +void nfp_net_refresh_port_table(struct nfp_port *port); +int nfp_net_refresh_port_table_sync(struct nfp_pf *pf); + +int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port); +void nfp_devlink_port_unregister(struct nfp_port *port); + +#endif diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h index 4df2ce261b3f..94641b4c2c55 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h @@ -64,6 +64,8 @@ int nfp_nsp_read_eth_table(struct nfp_nsp *state, void *buf, unsigned int size); int nfp_nsp_write_eth_table(struct nfp_nsp *state, const void *buf, unsigned int size); int nfp_nsp_read_identify(struct nfp_nsp *state, void *buf, unsigned int size); +int nfp_nsp_read_sensors(struct nfp_nsp *state, unsigned int sensor_mask, + void *buf, unsigned int size); /* Implemented in nfp_resource.c */ diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c index 43dc68e01274..cd678323bacb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c @@ -119,6 +119,11 @@ #define NFP_PCIE_EM 0x020000 #define NFP_PCIE_SRAM 0x000000 +/* Minimal size of the PCIe cfg memory we depend on being mapped, + * queue controller and DMA controller don't have to be covered. + */ +#define NFP_PCI_MIN_MAP_SIZE 0x080000 + #define NFP_PCIE_P2C_FIXED_SIZE(bar) (1 << (bar)->bitsize) #define NFP_PCIE_P2C_BULK_SIZE(bar) (1 << (bar)->bitsize) #define NFP_PCIE_P2C_GENERAL_TARGET_OFFSET(bar, x) ((x) << ((bar)->bitsize - 2)) @@ -583,9 +588,15 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) NFP_PCIE_BAR_PCIE2CPP_MapType( NFP_PCIE_BAR_PCIE2CPP_MapType_EXPLICIT3), }; + char status_msg[196] = {}; struct nfp_bar *bar; int i, bars_free; int expl_groups; + char *msg, *end; + + msg = status_msg + + snprintf(status_msg, sizeof(status_msg) - 1, "RESERVED BARs: "); + end = status_msg + sizeof(status_msg) - 1; bar = &nfp->bar[0]; for (i = 0; i < ARRAY_SIZE(nfp->bar); i++, bar++) { @@ -628,34 +639,38 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) /* Configure, and lock, BAR0.0 for General Target use (MSI-X SRAM) */ bar = &nfp->bar[0]; - bar->iomem = ioremap_nocache(nfp_bar_resource_start(bar), - nfp_bar_resource_len(bar)); + if (nfp_bar_resource_len(bar) >= NFP_PCI_MIN_MAP_SIZE) + bar->iomem = ioremap_nocache(nfp_bar_resource_start(bar), + nfp_bar_resource_len(bar)); if (bar->iomem) { - dev_info(nfp->dev, - "BAR0.0 RESERVED: General Mapping/MSI-X SRAM\n"); + msg += snprintf(msg, end - msg, "0.0: General/MSI-X SRAM, "); atomic_inc(&bar->refcnt); bars_free--; nfp6000_bar_write(nfp, bar, barcfg_msix_general); nfp->expl.data = bar->iomem + NFP_PCIE_SRAM + 0x1000; + + if (nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP4000 || + nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000) { + nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(0); + } else { + int pf = nfp->pdev->devfn & 7; + + nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(pf); + } + nfp->iomem.em = bar->iomem + NFP_PCIE_EM; } if (nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP4000 || - nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000) { - nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(0); + nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000) expl_groups = 4; - } else { - int pf = nfp->pdev->devfn & 7; - - nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(pf); + else expl_groups = 1; - } - nfp->iomem.em = bar->iomem + NFP_PCIE_EM; /* Configure, and lock, BAR0.1 for PCIe XPB (MSI-X PBA) */ bar = &nfp->bar[1]; - dev_info(nfp->dev, "BAR0.1 RESERVED: PCIe XPB/MSI-X PBA\n"); + msg += snprintf(msg, end - msg, "0.1: PCIe XPB/MSI-X PBA, "); atomic_inc(&bar->refcnt); bars_free--; @@ -674,9 +689,8 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) bar->iomem = ioremap_nocache(nfp_bar_resource_start(bar), nfp_bar_resource_len(bar)); if (bar->iomem) { - dev_info(nfp->dev, - "BAR0.%d RESERVED: Explicit%d Mapping\n", - 4 + i, i); + msg += snprintf(msg, end - msg, + "0.%d: Explicit%d, ", 4 + i, i); atomic_inc(&bar->refcnt); bars_free--; @@ -694,8 +708,7 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) sort(&nfp->bar[0], nfp->bars, sizeof(nfp->bar[0]), bar_cmp, NULL); - dev_info(nfp->dev, "%d NFP PCI2CPP BARs, %d free\n", - nfp->bars, bars_free); + dev_info(nfp->dev, "%sfree: %d/%d\n", status_msg, bars_free, nfp->bars); return 0; } diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index edecc0a27485..0a46c0984e68 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -42,6 +42,7 @@ #include <linux/ctype.h> #include <linux/types.h> +#include <linux/sizes.h> #ifndef NFP_SUBSYS #define NFP_SUBSYS "nfp" @@ -59,6 +60,13 @@ #define PCI_64BIT_BAR_COUNT 3 #define NFP_CPP_NUM_TARGETS 16 +/* Max size of area it should be safe to request */ +#define NFP_CPP_SAFE_AREA_SIZE SZ_2M + +/* NFP_MUTEX_WAIT_* are timeouts in seconds when waiting for a mutex */ +#define NFP_MUTEX_WAIT_FIRST_WARN 15 +#define NFP_MUTEX_WAIT_NEXT_WARN 5 +#define NFP_MUTEX_WAIT_ERROR 60 struct device; @@ -289,6 +297,17 @@ int nfp_cpp_mutex_lock(struct nfp_cpp_mutex *mutex); int nfp_cpp_mutex_unlock(struct nfp_cpp_mutex *mutex); int nfp_cpp_mutex_trylock(struct nfp_cpp_mutex *mutex); +/** + * nfp_cppcore_pcie_unit() - Get PCI Unit of a CPP handle + * @cpp: CPP handle + * + * Return: PCI unit for the NFP CPP handle + */ +static inline u8 nfp_cppcore_pcie_unit(struct nfp_cpp *cpp) +{ + return NFP_CPP_INTERFACE_UNIT_of(nfp_cpp_interface(cpp)); +} + struct nfp_cpp_explicit; struct nfp_cpp_explicit_command { diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c index e2abba4c3a3f..5672d309d07d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c @@ -924,18 +924,9 @@ area_cache_put(struct nfp_cpp *cpp, struct nfp_cpp_area_cache *cache) mutex_unlock(&cpp->area_cache_mutex); } -/** - * nfp_cpp_read() - read from CPP target - * @cpp: CPP handle - * @destination: CPP id - * @address: offset into CPP target - * @kernel_vaddr: kernel buffer for result - * @length: number of bytes to read - * - * Return: length of io, or -ERRNO - */ -int nfp_cpp_read(struct nfp_cpp *cpp, u32 destination, - unsigned long long address, void *kernel_vaddr, size_t length) +static int __nfp_cpp_read(struct nfp_cpp *cpp, u32 destination, + unsigned long long address, void *kernel_vaddr, + size_t length) { struct nfp_cpp_area_cache *cache; struct nfp_cpp_area *area; @@ -968,18 +959,43 @@ int nfp_cpp_read(struct nfp_cpp *cpp, u32 destination, } /** - * nfp_cpp_write() - write to CPP target + * nfp_cpp_read() - read from CPP target * @cpp: CPP handle * @destination: CPP id * @address: offset into CPP target - * @kernel_vaddr: kernel buffer to read from - * @length: number of bytes to write + * @kernel_vaddr: kernel buffer for result + * @length: number of bytes to read * * Return: length of io, or -ERRNO */ -int nfp_cpp_write(struct nfp_cpp *cpp, u32 destination, - unsigned long long address, - const void *kernel_vaddr, size_t length) +int nfp_cpp_read(struct nfp_cpp *cpp, u32 destination, + unsigned long long address, void *kernel_vaddr, + size_t length) +{ + size_t n, offset; + int ret; + + for (offset = 0; offset < length; offset += n) { + unsigned long long r_addr = address + offset; + + /* make first read smaller to align to safe window */ + n = min_t(size_t, length - offset, + ALIGN(r_addr + 1, NFP_CPP_SAFE_AREA_SIZE) - r_addr); + + ret = __nfp_cpp_read(cpp, destination, address + offset, + kernel_vaddr + offset, n); + if (ret < 0) + return ret; + if (ret != n) + return offset + n; + } + + return length; +} + +static int __nfp_cpp_write(struct nfp_cpp *cpp, u32 destination, + unsigned long long address, + const void *kernel_vaddr, size_t length) { struct nfp_cpp_area_cache *cache; struct nfp_cpp_area *area; @@ -1011,6 +1027,41 @@ int nfp_cpp_write(struct nfp_cpp *cpp, u32 destination, return err; } +/** + * nfp_cpp_write() - write to CPP target + * @cpp: CPP handle + * @destination: CPP id + * @address: offset into CPP target + * @kernel_vaddr: kernel buffer to read from + * @length: number of bytes to write + * + * Return: length of io, or -ERRNO + */ +int nfp_cpp_write(struct nfp_cpp *cpp, u32 destination, + unsigned long long address, + const void *kernel_vaddr, size_t length) +{ + size_t n, offset; + int ret; + + for (offset = 0; offset < length; offset += n) { + unsigned long long w_addr = address + offset; + + /* make first write smaller to align to safe window */ + n = min_t(size_t, length - offset, + ALIGN(w_addr + 1, NFP_CPP_SAFE_AREA_SIZE) - w_addr); + + ret = __nfp_cpp_write(cpp, destination, address + offset, + kernel_vaddr + offset, n); + if (ret < 0) + return ret; + if (ret != n) + return offset + n; + } + + return length; +} + /* Return the correct CPP address, and fixup xpb_addr as needed. */ static u32 nfp_xpb_to_cpp(struct nfp_cpp *cpp, u32 *xpb_addr) { diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c index 8a99c189efa8..f7b958181126 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c @@ -195,7 +195,8 @@ void nfp_cpp_mutex_free(struct nfp_cpp_mutex *mutex) */ int nfp_cpp_mutex_lock(struct nfp_cpp_mutex *mutex) { - unsigned long warn_at = jiffies + 15 * HZ; + unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ; + unsigned long err_at = jiffies + NFP_MUTEX_WAIT_ERROR * HZ; unsigned int timeout_ms = 1; int err; @@ -214,12 +215,16 @@ int nfp_cpp_mutex_lock(struct nfp_cpp_mutex *mutex) return -ERESTARTSYS; if (time_is_before_eq_jiffies(warn_at)) { - warn_at = jiffies + 60 * HZ; + warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ; nfp_warn(mutex->cpp, "Warning: waiting for NFP mutex [depth:%hd target:%d addr:%llx key:%08x]\n", mutex->depth, mutex->target, mutex->address, mutex->key); } + if (time_is_before_eq_jiffies(err_at)) { + nfp_err(mutex->cpp, "Error: mutex wait timed out\n"); + return -EBUSY; + } } return err; diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c index 2fa9247bb23d..eefdb756d74e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c @@ -93,6 +93,7 @@ enum nfp_nsp_cmd { SPCODE_FW_LOAD = 6, /* Load fw from buffer, len in option */ SPCODE_ETH_RESCAN = 7, /* Rescan ETHs, write ETH_TABLE to buf */ SPCODE_ETH_CONTROL = 8, /* Update media config from buffer */ + SPCODE_NSP_SENSORS = 12, /* Read NSP sensor(s) */ SPCODE_NSP_IDENTIFY = 13, /* Read NSP version */ }; @@ -419,6 +420,14 @@ static int nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option, if (err < 0) return err; } + /* Zero out remaining part of the buffer */ + if (out_buf && out_size && out_size > in_size) { + memset(out_buf, 0, out_size - in_size); + err = nfp_cpp_write(cpp, cpp_id, cpp_buf + in_size, + out_buf, out_size - in_size); + if (err < 0) + return err; + } ret = nfp_nsp_command(nsp, code, option, cpp_id, cpp_buf); if (ret < 0) @@ -498,3 +507,10 @@ int nfp_nsp_read_identify(struct nfp_nsp *state, void *buf, unsigned int size) return nfp_nsp_command_buf(state, SPCODE_NSP_IDENTIFY, size, NULL, 0, buf, size); } + +int nfp_nsp_read_sensors(struct nfp_nsp *state, unsigned int sensor_mask, + void *buf, unsigned int size) +{ + return nfp_nsp_command_buf(state, SPCODE_NSP_SENSORS, sensor_mask, + NULL, 0, buf, size); +} diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h index 36b21e4dc56d..26d7dcea4fd9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h @@ -96,6 +96,7 @@ enum nfp_eth_aneg { * @override_changed: is media reconfig pending? * * @port_type: one of %PORT_* defines for ethtool + * @port_lanes: total number of lanes on the port (sum of lanes of all subports) * @is_split: is interface part of a split port */ struct nfp_eth_table { @@ -127,6 +128,8 @@ struct nfp_eth_table { /* Computed fields */ u8 port_type; + unsigned int port_lanes; + bool is_split; } ports[0]; }; @@ -157,6 +160,7 @@ int __nfp_eth_set_split(struct nfp_nsp *nsp, unsigned int lanes); * @primary: version of primarary bootloader * @secondary: version id of secondary bootloader * @nsp: version id of NSP + * @sensor_mask: mask of present sensors available on NIC */ struct nfp_nsp_identify { char version[40]; @@ -167,8 +171,19 @@ struct nfp_nsp_identify { u16 primary; u16 secondary; u16 nsp; + u64 sensor_mask; }; struct nfp_nsp_identify *__nfp_nsp_identify(struct nfp_nsp *nsp); +enum nfp_nsp_sensor_id { + NFP_SENSOR_CHIP_TEMPERATURE, + NFP_SENSOR_ASSEMBLY_POWER, + NFP_SENSOR_ASSEMBLY_12V_POWER, + NFP_SENSOR_ASSEMBLY_3V3_POWER, +}; + +int nfp_hwmon_read_sensor(struct nfp_cpp *cpp, enum nfp_nsp_sensor_id id, + long *val); + #endif diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c index e7a263de3731..5d362f87af08 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c @@ -46,7 +46,8 @@ struct nsp_identify { __le16 primary; __le16 secondary; __le16 nsp; - __le16 reserved; + u8 reserved[6]; + __le64 sensor_mask; }; struct nfp_nsp_identify *__nfp_nsp_identify(struct nfp_nsp *nsp) @@ -82,8 +83,52 @@ struct nfp_nsp_identify *__nfp_nsp_identify(struct nfp_nsp *nsp) nspi->primary = le16_to_cpu(ni->primary); nspi->secondary = le16_to_cpu(ni->secondary); nspi->nsp = le16_to_cpu(ni->nsp); + nspi->sensor_mask = le64_to_cpu(ni->sensor_mask); exit_free: kfree(ni); return nspi; } + +struct nfp_sensors { + __le32 chip_temp; + __le32 assembly_power; + __le32 assembly_12v_power; + __le32 assembly_3v3_power; +}; + +int nfp_hwmon_read_sensor(struct nfp_cpp *cpp, enum nfp_nsp_sensor_id id, + long *val) +{ + struct nfp_sensors s; + struct nfp_nsp *nsp; + int ret; + + nsp = nfp_nsp_open(cpp); + if (IS_ERR(nsp)) + return PTR_ERR(nsp); + + ret = nfp_nsp_read_sensors(nsp, BIT(id), &s, sizeof(s)); + nfp_nsp_close(nsp); + + if (ret < 0) + return ret; + + switch (id) { + case NFP_SENSOR_CHIP_TEMPERATURE: + *val = le32_to_cpu(s.chip_temp); + break; + case NFP_SENSOR_ASSEMBLY_POWER: + *val = le32_to_cpu(s.assembly_power); + break; + case NFP_SENSOR_ASSEMBLY_12V_POWER: + *val = le32_to_cpu(s.assembly_12v_power); + break; + case NFP_SENSOR_ASSEMBLY_3V3_POWER: + *val = le32_to_cpu(s.assembly_3v3_power); + break; + default: + return -EINVAL; + } + return 0; +} diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c index 639438d8313a..b0f8785c064f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c @@ -186,17 +186,19 @@ nfp_eth_port_translate(struct nfp_nsp *nsp, const union eth_table_entry *src, } static void -nfp_eth_mark_split_ports(struct nfp_cpp *cpp, struct nfp_eth_table *table) +nfp_eth_calc_port_geometry(struct nfp_cpp *cpp, struct nfp_eth_table *table) { unsigned int i, j; for (i = 0; i < table->count; i++) for (j = 0; j < table->count; j++) { - if (i == j) - continue; if (table->ports[i].label_port != table->ports[j].label_port) continue; + table->ports[i].port_lanes += table->ports[j].lanes; + + if (i == j) + continue; if (table->ports[i].label_subport == table->ports[j].label_subport) nfp_warn(cpp, @@ -205,7 +207,6 @@ nfp_eth_mark_split_ports(struct nfp_cpp *cpp, struct nfp_eth_table *table) table->ports[i].label_subport); table->ports[i].is_split = true; - break; } } @@ -289,7 +290,7 @@ __nfp_eth_read_ports(struct nfp_cpp *cpp, struct nfp_nsp *nsp) nfp_eth_port_translate(nsp, &entries[i], i, &table->ports[j++]); - nfp_eth_mark_split_ports(cpp, table); + nfp_eth_calc_port_geometry(cpp, table); for (i = 0; i < table->count; i++) nfp_eth_calc_port_type(cpp, &table->ports[i]); diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c index 2d15a7c9d0de..072612263dab 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c @@ -181,7 +181,8 @@ err_unlock_dev: struct nfp_resource * nfp_resource_acquire(struct nfp_cpp *cpp, const char *name) { - unsigned long warn_at = jiffies + 15 * HZ; + unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ; + unsigned long err_at = jiffies + NFP_MUTEX_WAIT_ERROR * HZ; struct nfp_cpp_mutex *dev_mutex; struct nfp_resource *res; int err; @@ -214,10 +215,15 @@ nfp_resource_acquire(struct nfp_cpp *cpp, const char *name) } if (time_is_before_eq_jiffies(warn_at)) { - warn_at = jiffies + 60 * HZ; + warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ; nfp_warn(cpp, "Warning: waiting for NFP resource %s\n", name); } + if (time_is_before_eq_jiffies(err_at)) { + nfp_err(cpp, "Error: resource %s timed out\n", name); + err = -EBUSY; + goto err_free; + } } nfp_cpp_mutex_free(dev_mutex); diff --git a/drivers/net/ethernet/netronome/nfp/nic/main.c b/drivers/net/ethernet/netronome/nfp/nic/main.c new file mode 100644 index 000000000000..520684242b7d --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nic/main.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../nfpcore/nfp_cpp.h" +#include "../nfpcore/nfp_nsp.h" +#include "../nfp_app.h" +#include "../nfp_main.h" + +static int nfp_nic_init(struct nfp_app *app) +{ + struct nfp_pf *pf = app->pf; + + if (pf->eth_tbl && pf->max_data_vnics != pf->eth_tbl->count) { + nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n", + pf->max_data_vnics, pf->eth_tbl->count); + return -EINVAL; + } + + return 0; +} + +const struct nfp_app_type app_nic = { + .id = NFP_APP_CORE_NIC, + .name = "nic", + + .init = nfp_nic_init, + .vnic_init = nfp_app_nic_vnic_init, +}; diff --git a/drivers/net/ethernet/nuvoton/w90p910_ether.c b/drivers/net/ethernet/nuvoton/w90p910_ether.c index 159564d8dcdb..89ab786da25f 100644 --- a/drivers/net/ethernet/nuvoton/w90p910_ether.c +++ b/drivers/net/ethernet/nuvoton/w90p910_ether.c @@ -868,7 +868,10 @@ static int w90p910_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct w90p910_ether *ether = netdev_priv(dev); - return mii_ethtool_get_link_ksettings(ðer->mii, cmd); + + mii_ethtool_get_link_ksettings(ðer->mii, cmd); + + return 0; } static int w90p910_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c index 21093276d2b7..731ce1e419e4 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c @@ -85,9 +85,8 @@ static int pch_gbe_get_link_ksettings(struct net_device *netdev, { struct pch_gbe_adapter *adapter = netdev_priv(netdev); u32 supported, advertising; - int ret; - ret = mii_ethtool_get_link_ksettings(&adapter->mii, ecmd); + mii_ethtool_get_link_ksettings(&adapter->mii, ecmd); ethtool_convert_link_mode_to_legacy_u32(&supported, ecmd->link_modes.supported); @@ -104,7 +103,8 @@ static int pch_gbe_get_link_ksettings(struct net_device *netdev, if (!netif_carrier_ok(adapter->netdev)) ecmd->base.speed = SPEED_UNKNOWN; - return ret; + + return 0; } /** diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c index a996801d442d..66ff15d08bad 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c @@ -21,6 +21,7 @@ * */ +#include <linux/io-64-nonatomic-lo-hi.h> #include <linux/slab.h> #include "netxen_nic.h" #include "netxen_nic_hw.h" @@ -44,20 +45,6 @@ static void netxen_nic_io_write_128M(struct netxen_adapter *adapter, void __iomem *addr, u32 data); static u32 netxen_nic_io_read_128M(struct netxen_adapter *adapter, void __iomem *addr); -#ifndef readq -static inline u64 readq(void __iomem *addr) -{ - return readl(addr) | (((u64) readl(addr + 4)) << 32LL); -} -#endif - -#ifndef writeq -static inline void writeq(u64 val, void __iomem *addr) -{ - writel(((u32) (val)), (addr)); - writel(((u32) (val >> 32)), (addr + 4)); -} -#endif #define PCI_OFFSET_FIRST_RANGE(adapter, off) \ ((adapter)->ahw.pci_base0 + (off)) diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index 2ab1aab7c3fe..d7afc42f766c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -54,7 +54,7 @@ extern const struct qed_common_ops qed_common_ops_pass; #define QED_MAJOR_VERSION 8 #define QED_MINOR_VERSION 10 -#define QED_REVISION_VERSION 10 +#define QED_REVISION_VERSION 11 #define QED_ENGINEERING_VERSION 21 #define QED_VERSION \ @@ -92,7 +92,7 @@ enum qed_mcp_protocol_type; #define QED_MFW_SET_FIELD(name, field, value) \ do { \ - (name) &= ~((field ## _MASK) << (field ## _SHIFT)); \ + (name) &= ~(field ## _MASK); \ (name) |= (((value) << (field ## _SHIFT)) & (field ## _MASK));\ } while (0) @@ -412,6 +412,11 @@ struct qed_fw_data { u32 init_ops_size; }; +enum BAR_ID { + BAR_ID_0, /* used for GRC */ + BAR_ID_1 /* Used for doorbells */ +}; + #define DRV_MODULE_VERSION \ __stringify(QED_MAJOR_VERSION) "." \ __stringify(QED_MINOR_VERSION) "." \ @@ -495,10 +500,6 @@ struct qed_hwfn { bool b_rdma_enabled_in_prs; u32 rdma_prs_search_reg; - /* Array of sb_info of all status blocks */ - struct qed_sb_info *sbs_info[MAX_SB_PER_PF_MIMD]; - u16 num_sbs; - struct qed_cxt_mngr *p_cxt_mngr; /* Flag indicating whether interrupts are enabled or not*/ @@ -537,6 +538,9 @@ struct qed_hwfn { u8 dcbx_no_edpm; u8 db_bar_no_edpm; + /* L2-related */ + struct qed_l2_info *p_l2_info; + struct qed_ptt *p_arfs_ptt; struct qed_simd_fp_handler simd_proto_handler[64]; @@ -598,16 +602,11 @@ struct qed_dev { enum qed_dev_type type; /* Translate type/revision combo into the proper conditions */ #define QED_IS_BB(dev) ((dev)->type == QED_DEV_TYPE_BB) -#define QED_IS_BB_A0(dev) (QED_IS_BB(dev) && \ - CHIP_REV_IS_A0(dev)) #define QED_IS_BB_B0(dev) (QED_IS_BB(dev) && \ CHIP_REV_IS_B0(dev)) #define QED_IS_AH(dev) ((dev)->type == QED_DEV_TYPE_AH) #define QED_IS_K2(dev) QED_IS_AH(dev) -#define QED_GET_TYPE(dev) (QED_IS_BB_A0(dev) ? CHIP_BB_A0 : \ - QED_IS_BB_B0(dev) ? CHIP_BB_B0 : CHIP_K2) - u16 vendor_id; u16 device_id; #define QED_DEV_ID_MASK 0xff00 @@ -621,7 +620,6 @@ struct qed_dev { u16 chip_rev; #define CHIP_REV_MASK 0xf #define CHIP_REV_SHIFT 12 -#define CHIP_REV_IS_A0(_cdev) (!(_cdev)->chip_rev) #define CHIP_REV_IS_B0(_cdev) ((_cdev)->chip_rev == 1) u16 chip_metal; @@ -633,7 +631,7 @@ struct qed_dev { #define CHIP_BOND_ID_SHIFT 0 u8 num_engines; - u8 num_ports_in_engines; + u8 num_ports_in_engine; u8 num_funcs_in_port; u8 path_id; @@ -644,7 +642,6 @@ struct qed_dev { int pcie_width; int pcie_speed; - u8 ver_str[VER_SIZE]; /* Add MF related configuration */ u8 mcp_rev; diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index 694845793af2..e201214764db 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -135,7 +135,6 @@ struct qed_tid_seg { struct qed_conn_type_cfg { u32 cid_count; - u32 cid_start; u32 cids_per_vf; struct qed_tid_seg tid_seg[TASK_SEGMENTS]; }; @@ -222,6 +221,9 @@ struct qed_cxt_mngr { /* Acquired CIDs */ struct qed_cid_acquired_map acquired[MAX_CONN_TYPES]; + struct qed_cid_acquired_map + acquired_vf[MAX_CONN_TYPES][MAX_NUM_VFS]; + /* ILT shadow table */ struct qed_dma_mem *ilt_shadow; u32 pf_start_line; @@ -1121,45 +1123,76 @@ ilt_shadow_fail: static void qed_cid_map_free(struct qed_hwfn *p_hwfn) { struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; - u32 type; + u32 type, vf; for (type = 0; type < MAX_CONN_TYPES; type++) { kfree(p_mngr->acquired[type].cid_map); p_mngr->acquired[type].max_count = 0; p_mngr->acquired[type].start_cid = 0; + + for (vf = 0; vf < MAX_NUM_VFS; vf++) { + kfree(p_mngr->acquired_vf[type][vf].cid_map); + p_mngr->acquired_vf[type][vf].max_count = 0; + p_mngr->acquired_vf[type][vf].start_cid = 0; + } } } +static int +qed_cid_map_alloc_single(struct qed_hwfn *p_hwfn, + u32 type, + u32 cid_start, + u32 cid_count, struct qed_cid_acquired_map *p_map) +{ + u32 size; + + if (!cid_count) + return 0; + + size = DIV_ROUND_UP(cid_count, + sizeof(unsigned long) * BITS_PER_BYTE) * + sizeof(unsigned long); + p_map->cid_map = kzalloc(size, GFP_KERNEL); + if (!p_map->cid_map) + return -ENOMEM; + + p_map->max_count = cid_count; + p_map->start_cid = cid_start; + + DP_VERBOSE(p_hwfn, QED_MSG_CXT, + "Type %08x start: %08x count %08x\n", + type, p_map->start_cid, p_map->max_count); + + return 0; +} + static int qed_cid_map_alloc(struct qed_hwfn *p_hwfn) { struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; - u32 start_cid = 0; - u32 type; + u32 start_cid = 0, vf_start_cid = 0; + u32 type, vf; for (type = 0; type < MAX_CONN_TYPES; type++) { - u32 cid_cnt = p_hwfn->p_cxt_mngr->conn_cfg[type].cid_count; - u32 size; - - if (cid_cnt == 0) - continue; + struct qed_conn_type_cfg *p_cfg = &p_mngr->conn_cfg[type]; + struct qed_cid_acquired_map *p_map; - size = DIV_ROUND_UP(cid_cnt, - sizeof(unsigned long) * BITS_PER_BYTE) * - sizeof(unsigned long); - p_mngr->acquired[type].cid_map = kzalloc(size, GFP_KERNEL); - if (!p_mngr->acquired[type].cid_map) + /* Handle PF maps */ + p_map = &p_mngr->acquired[type]; + if (qed_cid_map_alloc_single(p_hwfn, type, start_cid, + p_cfg->cid_count, p_map)) goto cid_map_fail; - p_mngr->acquired[type].max_count = cid_cnt; - p_mngr->acquired[type].start_cid = start_cid; - - p_hwfn->p_cxt_mngr->conn_cfg[type].cid_start = start_cid; + /* Handle VF maps */ + for (vf = 0; vf < MAX_NUM_VFS; vf++) { + p_map = &p_mngr->acquired_vf[type][vf]; + if (qed_cid_map_alloc_single(p_hwfn, type, + vf_start_cid, + p_cfg->cids_per_vf, p_map)) + goto cid_map_fail; + } - DP_VERBOSE(p_hwfn, QED_MSG_CXT, - "Type %08x start: %08x count %08x\n", - type, p_mngr->acquired[type].start_cid, - p_mngr->acquired[type].max_count); - start_cid += cid_cnt; + start_cid += p_cfg->cid_count; + vf_start_cid += p_cfg->cids_per_vf; } return 0; @@ -1265,19 +1298,36 @@ void qed_cxt_mngr_free(struct qed_hwfn *p_hwfn) void qed_cxt_mngr_setup(struct qed_hwfn *p_hwfn) { struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct qed_cid_acquired_map *p_map; + struct qed_conn_type_cfg *p_cfg; int type; + u32 len; /* Reset acquired cids */ for (type = 0; type < MAX_CONN_TYPES; type++) { - u32 cid_cnt = p_hwfn->p_cxt_mngr->conn_cfg[type].cid_count; + u32 vf; + + p_cfg = &p_mngr->conn_cfg[type]; + if (p_cfg->cid_count) { + p_map = &p_mngr->acquired[type]; + len = DIV_ROUND_UP(p_map->max_count, + sizeof(unsigned long) * + BITS_PER_BYTE) * + sizeof(unsigned long); + memset(p_map->cid_map, 0, len); + } - if (cid_cnt == 0) + if (!p_cfg->cids_per_vf) continue; - memset(p_mngr->acquired[type].cid_map, 0, - DIV_ROUND_UP(cid_cnt, - sizeof(unsigned long) * BITS_PER_BYTE) * - sizeof(unsigned long)); + for (vf = 0; vf < MAX_NUM_VFS; vf++) { + p_map = &p_mngr->acquired_vf[type][vf]; + len = DIV_ROUND_UP(p_map->max_count, + sizeof(unsigned long) * + BITS_PER_BYTE) * + sizeof(unsigned long); + memset(p_map->cid_map, 0, len); + } } } @@ -1841,91 +1891,145 @@ void qed_cxt_hw_init_pf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) qed_prs_init_pf(p_hwfn); } -int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn, - enum protocol_type type, u32 *p_cid) +int _qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn, + enum protocol_type type, u32 *p_cid, u8 vfid) { struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct qed_cid_acquired_map *p_map; u32 rel_cid; - if (type >= MAX_CONN_TYPES || !p_mngr->acquired[type].cid_map) { + if (type >= MAX_CONN_TYPES) { DP_NOTICE(p_hwfn, "Invalid protocol type %d", type); return -EINVAL; } - rel_cid = find_first_zero_bit(p_mngr->acquired[type].cid_map, - p_mngr->acquired[type].max_count); + if (vfid >= MAX_NUM_VFS && vfid != QED_CXT_PF_CID) { + DP_NOTICE(p_hwfn, "VF [%02x] is out of range\n", vfid); + return -EINVAL; + } - if (rel_cid >= p_mngr->acquired[type].max_count) { + /* Determine the right map to take this CID from */ + if (vfid == QED_CXT_PF_CID) + p_map = &p_mngr->acquired[type]; + else + p_map = &p_mngr->acquired_vf[type][vfid]; + + if (!p_map->cid_map) { + DP_NOTICE(p_hwfn, "Invalid protocol type %d", type); + return -EINVAL; + } + + rel_cid = find_first_zero_bit(p_map->cid_map, p_map->max_count); + + if (rel_cid >= p_map->max_count) { DP_NOTICE(p_hwfn, "no CID available for protocol %d\n", type); return -EINVAL; } - __set_bit(rel_cid, p_mngr->acquired[type].cid_map); + __set_bit(rel_cid, p_map->cid_map); - *p_cid = rel_cid + p_mngr->acquired[type].start_cid; + *p_cid = rel_cid + p_map->start_cid; + + DP_VERBOSE(p_hwfn, QED_MSG_CXT, + "Acquired cid 0x%08x [rel. %08x] vfid %02x type %d\n", + *p_cid, rel_cid, vfid, type); return 0; } +int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn, + enum protocol_type type, u32 *p_cid) +{ + return _qed_cxt_acquire_cid(p_hwfn, type, p_cid, QED_CXT_PF_CID); +} + static bool qed_cxt_test_cid_acquired(struct qed_hwfn *p_hwfn, - u32 cid, enum protocol_type *p_type) + u32 cid, + u8 vfid, + enum protocol_type *p_type, + struct qed_cid_acquired_map **pp_map) { struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; - struct qed_cid_acquired_map *p_map; - enum protocol_type p; u32 rel_cid; /* Iterate over protocols and find matching cid range */ - for (p = 0; p < MAX_CONN_TYPES; p++) { - p_map = &p_mngr->acquired[p]; + for (*p_type = 0; *p_type < MAX_CONN_TYPES; (*p_type)++) { + if (vfid == QED_CXT_PF_CID) + *pp_map = &p_mngr->acquired[*p_type]; + else + *pp_map = &p_mngr->acquired_vf[*p_type][vfid]; - if (!p_map->cid_map) + if (!((*pp_map)->cid_map)) continue; - if (cid >= p_map->start_cid && - cid < p_map->start_cid + p_map->max_count) + if (cid >= (*pp_map)->start_cid && + cid < (*pp_map)->start_cid + (*pp_map)->max_count) break; } - *p_type = p; - if (p == MAX_CONN_TYPES) { - DP_NOTICE(p_hwfn, "Invalid CID %d", cid); - return false; + if (*p_type == MAX_CONN_TYPES) { + DP_NOTICE(p_hwfn, "Invalid CID %d vfid %02x", cid, vfid); + goto fail; } - rel_cid = cid - p_map->start_cid; - if (!test_bit(rel_cid, p_map->cid_map)) { - DP_NOTICE(p_hwfn, "CID %d not acquired", cid); - return false; + rel_cid = cid - (*pp_map)->start_cid; + if (!test_bit(rel_cid, (*pp_map)->cid_map)) { + DP_NOTICE(p_hwfn, "CID %d [vifd %02x] not acquired", + cid, vfid); + goto fail; } + return true; +fail: + *p_type = MAX_CONN_TYPES; + *pp_map = NULL; + return false; } -void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid) +void _qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid, u8 vfid) { - struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct qed_cid_acquired_map *p_map = NULL; enum protocol_type type; bool b_acquired; u32 rel_cid; + if (vfid != QED_CXT_PF_CID && vfid > MAX_NUM_VFS) { + DP_NOTICE(p_hwfn, + "Trying to return incorrect CID belonging to VF %02x\n", + vfid); + return; + } + /* Test acquired and find matching per-protocol map */ - b_acquired = qed_cxt_test_cid_acquired(p_hwfn, cid, &type); + b_acquired = qed_cxt_test_cid_acquired(p_hwfn, cid, vfid, + &type, &p_map); if (!b_acquired) return; - rel_cid = cid - p_mngr->acquired[type].start_cid; - __clear_bit(rel_cid, p_mngr->acquired[type].cid_map); + rel_cid = cid - p_map->start_cid; + clear_bit(rel_cid, p_map->cid_map); + + DP_VERBOSE(p_hwfn, QED_MSG_CXT, + "Released CID 0x%08x [rel. %08x] vfid %02x type %d\n", + cid, rel_cid, vfid, type); +} + +void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid) +{ + _qed_cxt_release_cid(p_hwfn, cid, QED_CXT_PF_CID); } int qed_cxt_get_cid_info(struct qed_hwfn *p_hwfn, struct qed_cxt_info *p_info) { struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct qed_cid_acquired_map *p_map = NULL; u32 conn_cxt_size, hw_p_size, cxts_per_p, line; enum protocol_type type; bool b_acquired; /* Test acquired and find matching per-protocol map */ - b_acquired = qed_cxt_test_cid_acquired(p_hwfn, p_info->iid, &type); + b_acquired = qed_cxt_test_cid_acquired(p_hwfn, p_info->iid, + QED_CXT_PF_CID, &type, &p_map); if (!b_acquired) return -EINVAL; @@ -2012,8 +2116,12 @@ int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn, u32 rdma_tasks) struct qed_eth_pf_params *p_params = &p_hwfn->pf_params.eth_pf_params; - qed_cxt_set_proto_cid_count(p_hwfn, PROTOCOLID_ETH, - p_params->num_cons, 1); + if (!p_params->num_vf_cons) + p_params->num_vf_cons = + ETH_PF_PARAMS_VF_CONS_DEFAULT; + qed_cxt_set_proto_cid_count(p_hwfn, PROTOCOLID_ETH, + p_params->num_cons, + p_params->num_vf_cons); p_hwfn->p_cxt_mngr->arfs_count = p_params->num_arfs_filters; break; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.h b/drivers/net/ethernet/qlogic/qed/qed_cxt.h index 53ad532dc212..17836349a274 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.h +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.h @@ -54,19 +54,6 @@ struct qed_tid_mem { }; /** - * @brief qed_cxt_acquire - Acquire a new cid of a specific protocol type - * - * @param p_hwfn - * @param type - * @param p_cid - * - * @return int - */ -int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn, - enum protocol_type type, - u32 *p_cid); - -/** * @brief qedo_cid_get_cxt_info - Returns the context info for a specific cid * * @@ -195,14 +182,51 @@ void qed_qm_init_pf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); */ int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); +#define QED_CXT_PF_CID (0xff) + /** * @brief qed_cxt_release - Release a cid * * @param p_hwfn * @param cid */ -void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, - u32 cid); +void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid); + +/** + * @brief qed_cxt_release - Release a cid belonging to a vf-queue + * + * @param p_hwfn + * @param cid + * @param vfid - engine relative index. QED_CXT_PF_CID if belongs to PF + */ +void _qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid, u8 vfid); + +/** + * @brief qed_cxt_acquire - Acquire a new cid of a specific protocol type + * + * @param p_hwfn + * @param type + * @param p_cid + * + * @return int + */ +int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn, + enum protocol_type type, u32 *p_cid); + +/** + * @brief _qed_cxt_acquire - Acquire a new cid of a specific protocol type + * for a vf-queue + * + * @param p_hwfn + * @param type + * @param p_cid + * @param vfid - engine relative index. QED_CXT_PF_CID if belongs to PF + * + * @return int + */ +int _qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn, + enum protocol_type type, u32 *p_cid, u8 vfid); + int qed_cxt_dynamic_ilt_alloc(struct qed_hwfn *p_hwfn, enum qed_cxt_elem_type elem_type, u32 iid); u32 qed_cxt_get_proto_tid_count(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index d883ad5bec6d..e2a62c091b80 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -191,17 +191,19 @@ static void qed_dcbx_set_params(struct qed_dcbx_results *p_data, struct qed_hw_info *p_info, bool enable, - bool update, u8 prio, u8 tc, enum dcbx_protocol_type type, enum qed_pci_personality personality) { /* PF update ramrod data */ - p_data->arr[type].update = update; p_data->arr[type].enable = enable; p_data->arr[type].priority = prio; p_data->arr[type].tc = tc; + if (enable) + p_data->arr[type].update = UPDATE_DCB; + else + p_data->arr[type].update = DONT_UPDATE_DCB_DSCP; /* QM reconf data */ if (p_info->personality == personality) @@ -213,7 +215,6 @@ static void qed_dcbx_update_app_info(struct qed_dcbx_results *p_data, struct qed_hwfn *p_hwfn, bool enable, - bool update, u8 prio, u8 tc, enum dcbx_protocol_type type) { struct qed_hw_info *p_info = &p_hwfn->hw_info; @@ -231,7 +232,7 @@ qed_dcbx_update_app_info(struct qed_dcbx_results *p_data, personality = qed_dcbx_app_update[i].personality; name = qed_dcbx_app_update[i].name; - qed_dcbx_set_params(p_data, p_info, enable, update, + qed_dcbx_set_params(p_data, p_info, enable, prio, tc, type, personality); } } @@ -304,22 +305,11 @@ qed_dcbx_process_tlv(struct qed_hwfn *p_hwfn, */ enable = !(type == DCBX_PROTOCOL_ETH); - qed_dcbx_update_app_info(p_data, p_hwfn, enable, true, + qed_dcbx_update_app_info(p_data, p_hwfn, enable, priority, tc, type); } } - /* If RoCE-V2 TLV is not detected, driver need to use RoCE app - * data for RoCE-v2 not the default app data. - */ - if (!p_data->arr[DCBX_PROTOCOL_ROCE_V2].update && - p_data->arr[DCBX_PROTOCOL_ROCE].update) { - tc = p_data->arr[DCBX_PROTOCOL_ROCE].tc; - priority = p_data->arr[DCBX_PROTOCOL_ROCE].priority; - qed_dcbx_update_app_info(p_data, p_hwfn, true, true, - priority, tc, DCBX_PROTOCOL_ROCE_V2); - } - /* Update ramrod protocol data and hw_info fields * with default info when corresponding APP TLV's are not detected. * The enabled field has a different logic for ethernet as only for @@ -332,8 +322,8 @@ qed_dcbx_process_tlv(struct qed_hwfn *p_hwfn, if (p_data->arr[type].update) continue; - enable = !(type == DCBX_PROTOCOL_ETH); - qed_dcbx_update_app_info(p_data, p_hwfn, enable, true, + enable = (type == DCBX_PROTOCOL_ETH) ? false : !!dcbx_version; + qed_dcbx_update_app_info(p_data, p_hwfn, enable, priority, tc, type); } @@ -923,6 +913,7 @@ int qed_dcbx_info_alloc(struct qed_hwfn *p_hwfn) void qed_dcbx_info_free(struct qed_hwfn *p_hwfn) { kfree(p_hwfn->p_dcbx_info); + p_hwfn->p_dcbx_info = NULL; } static void qed_dcbx_update_protocol_data(struct protocol_dcb_data *p_data, @@ -944,17 +935,18 @@ void qed_dcbx_set_pf_update_params(struct qed_dcbx_results *p_src, p_dest->pf_id = p_src->pf_id; update_flag = p_src->arr[DCBX_PROTOCOL_FCOE].update; - p_dest->update_fcoe_dcb_data_flag = update_flag; + p_dest->update_fcoe_dcb_data_mode = update_flag; update_flag = p_src->arr[DCBX_PROTOCOL_ROCE].update; - p_dest->update_roce_dcb_data_flag = update_flag; + p_dest->update_roce_dcb_data_mode = update_flag; + update_flag = p_src->arr[DCBX_PROTOCOL_ROCE_V2].update; - p_dest->update_roce_dcb_data_flag = update_flag; + p_dest->update_rroce_dcb_data_mode = update_flag; update_flag = p_src->arr[DCBX_PROTOCOL_ISCSI].update; - p_dest->update_iscsi_dcb_data_flag = update_flag; + p_dest->update_iscsi_dcb_data_mode = update_flag; update_flag = p_src->arr[DCBX_PROTOCOL_ETH].update; - p_dest->update_eth_dcb_data_flag = update_flag; + p_dest->update_eth_dcb_data_mode = update_flag; p_dcb_data = &p_dest->fcoe_dcb_data; qed_dcbx_update_protocol_data(p_dcb_data, p_src, DCBX_PROTOCOL_FCOE); @@ -1458,7 +1450,7 @@ static u8 qed_dcbnl_getcap(struct qed_dev *cdev, int capid, u8 *cap) break; case DCB_CAP_ATTR_DCBX: *cap = (DCB_CAP_DCBX_LLD_MANAGED | DCB_CAP_DCBX_VER_CEE | - DCB_CAP_DCBX_VER_IEEE); + DCB_CAP_DCBX_VER_IEEE | DCB_CAP_DCBX_STATIC); break; default: *cap = false; @@ -1532,6 +1524,8 @@ static u8 qed_dcbnl_getdcbx(struct qed_dev *cdev) mode |= DCB_CAP_DCBX_VER_IEEE; if (dcbx_info->operational.cee) mode |= DCB_CAP_DCBX_VER_CEE; + if (dcbx_info->operational.local) + mode |= DCB_CAP_DCBX_STATIC; DP_VERBOSE(hwfn, QED_MSG_DCB, "dcb mode = %d\n", mode); kfree(dcbx_info); diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.h b/drivers/net/ethernet/qlogic/qed/qed_dcbx.h index 414e26268f3a..5feb90e049e0 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.h +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.h @@ -52,7 +52,7 @@ enum qed_mib_read_type { struct qed_dcbx_app_data { bool enable; /* DCB enabled */ - bool update; /* Update indication */ + u8 update; /* Update indication */ u8 priority; /* Priority */ u8 tc; /* Traffic Class */ }; diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.c b/drivers/net/ethernet/qlogic/qed/qed_debug.c index 483241b4b05d..03c3cf77aaff 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_debug.c +++ b/drivers/net/ethernet/qlogic/qed/qed_debug.c @@ -15,13 +15,6 @@ #include "qed_mcp.h" #include "qed_reg_addr.h" -/* Chip IDs enum */ -enum chip_ids { - CHIP_BB_B0, - CHIP_K2, - MAX_CHIP_IDS -}; - /* Memory groups enum */ enum mem_groups { MEM_GROUP_PXP_MEM, @@ -33,7 +26,6 @@ enum mem_groups { MEM_GROUP_BRB_MEM, MEM_GROUP_PRS_MEM, MEM_GROUP_SDM_MEM, - MEM_GROUP_PBUF, MEM_GROUP_IOR, MEM_GROUP_RAM, MEM_GROUP_BTB_RAM, @@ -45,6 +37,7 @@ enum mem_groups { MEM_GROUP_CAU_PI, MEM_GROUP_CAU_MEM, MEM_GROUP_PXP_ILT, + MEM_GROUP_PBUF, MEM_GROUP_MULD_MEM, MEM_GROUP_BTB_MEM, MEM_GROUP_IGU_MEM, @@ -66,7 +59,6 @@ static const char * const s_mem_group_names[] = { "BRB_MEM", "PRS_MEM", "SDM_MEM", - "PBUF", "IOR", "RAM", "BTB_RAM", @@ -78,6 +70,7 @@ static const char * const s_mem_group_names[] = { "CAU_PI", "CAU_MEM", "PXP_ILT", + "PBUF", "MULD_MEM", "BTB_MEM", "IGU_MEM", @@ -88,48 +81,59 @@ static const char * const s_mem_group_names[] = { }; /* Idle check conditions */ -static u32 cond4(const u32 *r, const u32 *imm) + +static u32 cond5(const u32 *r, const u32 *imm) { return ((r[0] & imm[0]) != imm[1]) && ((r[1] & imm[2]) != imm[3]); } -static u32 cond6(const u32 *r, const u32 *imm) +static u32 cond7(const u32 *r, const u32 *imm) { return ((r[0] >> imm[0]) & imm[1]) != imm[2]; } -static u32 cond5(const u32 *r, const u32 *imm) +static u32 cond14(const u32 *r, const u32 *imm) +{ + return (r[0] != imm[0]) && (((r[1] >> imm[1]) & imm[2]) == imm[3]); +} + +static u32 cond6(const u32 *r, const u32 *imm) { return (r[0] & imm[0]) != imm[1]; } -static u32 cond8(const u32 *r, const u32 *imm) +static u32 cond9(const u32 *r, const u32 *imm) { return ((r[0] & imm[0]) >> imm[1]) != (((r[0] & imm[2]) >> imm[3]) | ((r[1] & imm[4]) << imm[5])); } -static u32 cond9(const u32 *r, const u32 *imm) +static u32 cond10(const u32 *r, const u32 *imm) { return ((r[0] & imm[0]) >> imm[1]) != (r[0] & imm[2]); } -static u32 cond1(const u32 *r, const u32 *imm) +static u32 cond4(const u32 *r, const u32 *imm) { return (r[0] & ~imm[0]) != imm[1]; } static u32 cond0(const u32 *r, const u32 *imm) { + return (r[0] & ~r[1]) != imm[0]; +} + +static u32 cond1(const u32 *r, const u32 *imm) +{ return r[0] != imm[0]; } -static u32 cond10(const u32 *r, const u32 *imm) +static u32 cond11(const u32 *r, const u32 *imm) { return r[0] != r[1] && r[2] == imm[0]; } -static u32 cond11(const u32 *r, const u32 *imm) +static u32 cond12(const u32 *r, const u32 *imm) { return r[0] != r[1] && r[2] > imm[0]; } @@ -139,12 +143,12 @@ static u32 cond3(const u32 *r, const u32 *imm) return r[0] != r[1]; } -static u32 cond12(const u32 *r, const u32 *imm) +static u32 cond13(const u32 *r, const u32 *imm) { return r[0] & imm[0]; } -static u32 cond7(const u32 *r, const u32 *imm) +static u32 cond8(const u32 *r, const u32 *imm) { return r[0] < (r[1] - imm[0]); } @@ -169,6 +173,8 @@ static u32(*cond_arr[]) (const u32 *r, const u32 *imm) = { cond10, cond11, cond12, + cond13, + cond14, }; /******************************* Data Types **********************************/ @@ -181,11 +187,6 @@ enum platform_ids { MAX_PLATFORM_IDS }; -struct dbg_array { - const u32 *ptr; - u32 size_in_dwords; -}; - struct chip_platform_defs { u8 num_ports; u8 num_pfs; @@ -204,7 +205,9 @@ struct platform_defs { u32 delay_factor; }; -/* Storm constant definitions */ +/* Storm constant definitions. + * Addresses are in bytes, sizes are in quad-regs. + */ struct storm_defs { char letter; enum block_id block_id; @@ -218,13 +221,13 @@ struct storm_defs { u32 sem_sync_dbg_empty_addr; u32 sem_slow_dbg_empty_addr; u32 cm_ctx_wr_addr; - u32 cm_conn_ag_ctx_lid_size; /* In quad-regs */ + u32 cm_conn_ag_ctx_lid_size; u32 cm_conn_ag_ctx_rd_addr; - u32 cm_conn_st_ctx_lid_size; /* In quad-regs */ + u32 cm_conn_st_ctx_lid_size; u32 cm_conn_st_ctx_rd_addr; - u32 cm_task_ag_ctx_lid_size; /* In quad-regs */ + u32 cm_task_ag_ctx_lid_size; u32 cm_task_ag_ctx_rd_addr; - u32 cm_task_st_ctx_lid_size; /* In quad-regs */ + u32 cm_task_st_ctx_lid_size; u32 cm_task_st_ctx_rd_addr; }; @@ -233,17 +236,23 @@ struct block_defs { const char *name; bool has_dbg_bus[MAX_CHIP_IDS]; bool associated_to_storm; - u32 storm_id; /* Valid only if associated_to_storm is true */ + + /* Valid only if associated_to_storm is true */ + u32 storm_id; enum dbg_bus_clients dbg_client_id[MAX_CHIP_IDS]; u32 dbg_select_addr; - u32 dbg_cycle_enable_addr; + u32 dbg_enable_addr; u32 dbg_shift_addr; u32 dbg_force_valid_addr; u32 dbg_force_frame_addr; bool has_reset_bit; - bool unreset; /* If true, the block is taken out of reset before dump */ + + /* If true, block is taken out of reset before dump */ + bool unreset; enum dbg_reset_regs reset_reg; - u8 reset_bit_offset; /* Bit offset in reset register */ + + /* Bit offset in reset register */ + u8 reset_bit_offset; }; /* Reset register definitions */ @@ -262,12 +271,13 @@ struct grc_param_defs { u32 crash_preset_val; }; +/* Address is in 128b units. Width is in bits. */ struct rss_mem_defs { const char *mem_name; const char *type_name; - u32 addr; /* In 128b units */ + u32 addr; u32 num_entries[MAX_CHIP_IDS]; - u32 entry_width[MAX_CHIP_IDS]; /* In bits */ + u32 entry_width[MAX_CHIP_IDS]; }; struct vfc_ram_defs { @@ -289,10 +299,20 @@ struct big_ram_defs { struct phy_defs { const char *phy_name; + + /* PHY base GRC address */ u32 base_addr; + + /* Relative address of indirect TBUS address register (bits 0..7) */ u32 tbus_addr_lo_addr; + + /* Relative address of indirect TBUS address register (bits 8..10) */ u32 tbus_addr_hi_addr; + + /* Relative address of indirect TBUS data register (bits 0..7) */ u32 tbus_data_lo_addr; + + /* Relative address of indirect TBUS data register (bits 8..11) */ u32 tbus_data_hi_addr; }; @@ -300,9 +320,11 @@ struct phy_defs { #define MAX_LCIDS 320 #define MAX_LTIDS 320 + #define NUM_IOR_SETS 2 #define IORS_PER_SET 176 #define IOR_SET_OFFSET(set_id) ((set_id) * 256) + #define BYTES_IN_DWORD sizeof(u32) /* In the macros below, size and offset are specified in bits */ @@ -315,6 +337,7 @@ struct phy_defs { #define FIELD_BIT_MASK(type, field) \ (((1 << FIELD_BIT_SIZE(type, field)) - 1) << \ FIELD_DWORD_SHIFT(type, field)) + #define SET_VAR_FIELD(var, type, field, val) \ do { \ var[FIELD_DWORD_OFFSET(type, field)] &= \ @@ -322,31 +345,51 @@ struct phy_defs { var[FIELD_DWORD_OFFSET(type, field)] |= \ (val) << FIELD_DWORD_SHIFT(type, field); \ } while (0) + #define ARR_REG_WR(dev, ptt, addr, arr, arr_size) \ do { \ for (i = 0; i < (arr_size); i++) \ qed_wr(dev, ptt, addr, (arr)[i]); \ } while (0) + #define ARR_REG_RD(dev, ptt, addr, arr, arr_size) \ do { \ for (i = 0; i < (arr_size); i++) \ (arr)[i] = qed_rd(dev, ptt, addr); \ } while (0) +#ifndef DWORDS_TO_BYTES #define DWORDS_TO_BYTES(dwords) ((dwords) * BYTES_IN_DWORD) +#endif +#ifndef BYTES_TO_DWORDS #define BYTES_TO_DWORDS(bytes) ((bytes) / BYTES_IN_DWORD) +#endif + +/* extra lines include a signature line + optional latency events line */ +#ifndef NUM_DBG_LINES +#define NUM_EXTRA_DBG_LINES(block_desc) \ + (1 + ((block_desc)->has_latency_events ? 1 : 0)) +#define NUM_DBG_LINES(block_desc) \ + ((block_desc)->num_of_lines + NUM_EXTRA_DBG_LINES(block_desc)) +#endif + #define RAM_LINES_TO_DWORDS(lines) ((lines) * 2) #define RAM_LINES_TO_BYTES(lines) \ DWORDS_TO_BYTES(RAM_LINES_TO_DWORDS(lines)) + #define REG_DUMP_LEN_SHIFT 24 #define MEM_DUMP_ENTRY_SIZE_DWORDS \ BYTES_TO_DWORDS(sizeof(struct dbg_dump_mem)) + #define IDLE_CHK_RULE_SIZE_DWORDS \ BYTES_TO_DWORDS(sizeof(struct dbg_idle_chk_rule)) + #define IDLE_CHK_RESULT_HDR_DWORDS \ BYTES_TO_DWORDS(sizeof(struct dbg_idle_chk_result_hdr)) + #define IDLE_CHK_RESULT_REG_HDR_DWORDS \ BYTES_TO_DWORDS(sizeof(struct dbg_idle_chk_result_reg_hdr)) + #define IDLE_CHK_MAX_ENTRIES_SIZE 32 /* The sizes and offsets below are specified in bits */ @@ -363,62 +406,92 @@ struct phy_defs { #define VFC_RAM_ADDR_ROW_OFFSET 2 #define VFC_RAM_ADDR_ROW_SIZE 10 #define VFC_RAM_RESP_STRUCT_SIZE 256 + #define VFC_CAM_CMD_DWORDS CEIL_DWORDS(VFC_CAM_CMD_STRUCT_SIZE) #define VFC_CAM_ADDR_DWORDS CEIL_DWORDS(VFC_CAM_ADDR_STRUCT_SIZE) #define VFC_CAM_RESP_DWORDS CEIL_DWORDS(VFC_CAM_RESP_STRUCT_SIZE) #define VFC_RAM_CMD_DWORDS VFC_CAM_CMD_DWORDS #define VFC_RAM_ADDR_DWORDS CEIL_DWORDS(VFC_RAM_ADDR_STRUCT_SIZE) #define VFC_RAM_RESP_DWORDS CEIL_DWORDS(VFC_RAM_RESP_STRUCT_SIZE) + #define NUM_VFC_RAM_TYPES 4 + #define VFC_CAM_NUM_ROWS 512 + #define VFC_OPCODE_CAM_RD 14 #define VFC_OPCODE_RAM_RD 0 + #define NUM_RSS_MEM_TYPES 5 + #define NUM_BIG_RAM_TYPES 3 #define BIG_RAM_BLOCK_SIZE_BYTES 128 #define BIG_RAM_BLOCK_SIZE_DWORDS \ BYTES_TO_DWORDS(BIG_RAM_BLOCK_SIZE_BYTES) + #define NUM_PHY_TBUS_ADDRESSES 2048 #define PHY_DUMP_SIZE_DWORDS (NUM_PHY_TBUS_ADDRESSES / 2) + #define RESET_REG_UNRESET_OFFSET 4 + #define STALL_DELAY_MS 500 + #define STATIC_DEBUG_LINE_DWORDS 9 -#define NUM_DBG_BUS_LINES 256 + #define NUM_COMMON_GLOBAL_PARAMS 8 + #define FW_IMG_MAIN 1 -#define REG_FIFO_DEPTH_ELEMENTS 32 + +#ifndef REG_FIFO_ELEMENT_DWORDS #define REG_FIFO_ELEMENT_DWORDS 2 +#endif +#define REG_FIFO_DEPTH_ELEMENTS 32 #define REG_FIFO_DEPTH_DWORDS \ (REG_FIFO_ELEMENT_DWORDS * REG_FIFO_DEPTH_ELEMENTS) -#define IGU_FIFO_DEPTH_ELEMENTS 64 + +#ifndef IGU_FIFO_ELEMENT_DWORDS #define IGU_FIFO_ELEMENT_DWORDS 4 +#endif +#define IGU_FIFO_DEPTH_ELEMENTS 64 #define IGU_FIFO_DEPTH_DWORDS \ (IGU_FIFO_ELEMENT_DWORDS * IGU_FIFO_DEPTH_ELEMENTS) -#define PROTECTION_OVERRIDE_DEPTH_ELEMENTS 20 + +#ifndef PROTECTION_OVERRIDE_ELEMENT_DWORDS #define PROTECTION_OVERRIDE_ELEMENT_DWORDS 2 +#endif +#define PROTECTION_OVERRIDE_DEPTH_ELEMENTS 20 #define PROTECTION_OVERRIDE_DEPTH_DWORDS \ (PROTECTION_OVERRIDE_DEPTH_ELEMENTS * \ PROTECTION_OVERRIDE_ELEMENT_DWORDS) + #define MCP_SPAD_TRACE_OFFSIZE_ADDR \ (MCP_REG_SCRATCH + \ offsetof(struct static_init, sections[SPAD_SECTION_TRACE])) -#define MCP_TRACE_META_IMAGE_SIGNATURE 0x669955aa + #define EMPTY_FW_VERSION_STR "???_???_???_???" #define EMPTY_FW_IMAGE_STR "???????????????" /***************************** Constant Arrays *******************************/ +struct dbg_array { + const u32 *ptr; + u32 size_in_dwords; +}; + /* Debug arrays */ -static struct dbg_array s_dbg_arrays[MAX_BIN_DBG_BUFFER_TYPE] = { {0} }; +static struct dbg_array s_dbg_arrays[MAX_BIN_DBG_BUFFER_TYPE] = { {NULL} }; /* Chip constant definitions array */ static struct chip_defs s_chip_defs[MAX_CHIP_IDS] = { - { "bb_b0", - { {MAX_NUM_PORTS_BB, MAX_NUM_PFS_BB, MAX_NUM_VFS_BB}, {0, 0, 0}, - {0, 0, 0}, {0, 0, 0} } }, - { "k2", - { {MAX_NUM_PORTS_K2, MAX_NUM_PFS_K2, MAX_NUM_VFS_K2}, {0, 0, 0}, - {0, 0, 0}, {0, 0, 0} } } + { "bb", + {{MAX_NUM_PORTS_BB, MAX_NUM_PFS_BB, MAX_NUM_VFS_BB}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0} } }, + { "ah", + {{MAX_NUM_PORTS_K2, MAX_NUM_PFS_K2, MAX_NUM_VFS_K2}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0} } } }; /* Storm constant definitions array */ @@ -427,69 +500,74 @@ static struct storm_defs s_storm_defs[] = { {'T', BLOCK_TSEM, {DBG_BUS_CLIENT_RBCT, DBG_BUS_CLIENT_RBCT}, true, TSEM_REG_FAST_MEMORY, - TSEM_REG_DBG_FRAME_MODE, TSEM_REG_SLOW_DBG_ACTIVE, - TSEM_REG_SLOW_DBG_MODE, TSEM_REG_DBG_MODE1_CFG, - TSEM_REG_SYNC_DBG_EMPTY, TSEM_REG_SLOW_DBG_EMPTY, + TSEM_REG_DBG_FRAME_MODE_BB_K2, TSEM_REG_SLOW_DBG_ACTIVE_BB_K2, + TSEM_REG_SLOW_DBG_MODE_BB_K2, TSEM_REG_DBG_MODE1_CFG_BB_K2, + TSEM_REG_SYNC_DBG_EMPTY, TSEM_REG_SLOW_DBG_EMPTY_BB_K2, TCM_REG_CTX_RBC_ACCS, 4, TCM_REG_AGG_CON_CTX, 16, TCM_REG_SM_CON_CTX, 2, TCM_REG_AGG_TASK_CTX, 4, TCM_REG_SM_TASK_CTX}, + /* Mstorm */ {'M', BLOCK_MSEM, {DBG_BUS_CLIENT_RBCT, DBG_BUS_CLIENT_RBCM}, false, MSEM_REG_FAST_MEMORY, - MSEM_REG_DBG_FRAME_MODE, MSEM_REG_SLOW_DBG_ACTIVE, - MSEM_REG_SLOW_DBG_MODE, MSEM_REG_DBG_MODE1_CFG, - MSEM_REG_SYNC_DBG_EMPTY, MSEM_REG_SLOW_DBG_EMPTY, + MSEM_REG_DBG_FRAME_MODE_BB_K2, MSEM_REG_SLOW_DBG_ACTIVE_BB_K2, + MSEM_REG_SLOW_DBG_MODE_BB_K2, MSEM_REG_DBG_MODE1_CFG_BB_K2, + MSEM_REG_SYNC_DBG_EMPTY, MSEM_REG_SLOW_DBG_EMPTY_BB_K2, MCM_REG_CTX_RBC_ACCS, 1, MCM_REG_AGG_CON_CTX, 10, MCM_REG_SM_CON_CTX, 2, MCM_REG_AGG_TASK_CTX, 7, MCM_REG_SM_TASK_CTX}, + /* Ustorm */ {'U', BLOCK_USEM, {DBG_BUS_CLIENT_RBCU, DBG_BUS_CLIENT_RBCU}, false, USEM_REG_FAST_MEMORY, - USEM_REG_DBG_FRAME_MODE, USEM_REG_SLOW_DBG_ACTIVE, - USEM_REG_SLOW_DBG_MODE, USEM_REG_DBG_MODE1_CFG, - USEM_REG_SYNC_DBG_EMPTY, USEM_REG_SLOW_DBG_EMPTY, + USEM_REG_DBG_FRAME_MODE_BB_K2, USEM_REG_SLOW_DBG_ACTIVE_BB_K2, + USEM_REG_SLOW_DBG_MODE_BB_K2, USEM_REG_DBG_MODE1_CFG_BB_K2, + USEM_REG_SYNC_DBG_EMPTY, USEM_REG_SLOW_DBG_EMPTY_BB_K2, UCM_REG_CTX_RBC_ACCS, 2, UCM_REG_AGG_CON_CTX, 13, UCM_REG_SM_CON_CTX, 3, UCM_REG_AGG_TASK_CTX, 3, UCM_REG_SM_TASK_CTX}, + /* Xstorm */ {'X', BLOCK_XSEM, {DBG_BUS_CLIENT_RBCX, DBG_BUS_CLIENT_RBCX}, false, XSEM_REG_FAST_MEMORY, - XSEM_REG_DBG_FRAME_MODE, XSEM_REG_SLOW_DBG_ACTIVE, - XSEM_REG_SLOW_DBG_MODE, XSEM_REG_DBG_MODE1_CFG, - XSEM_REG_SYNC_DBG_EMPTY, XSEM_REG_SLOW_DBG_EMPTY, + XSEM_REG_DBG_FRAME_MODE_BB_K2, XSEM_REG_SLOW_DBG_ACTIVE_BB_K2, + XSEM_REG_SLOW_DBG_MODE_BB_K2, XSEM_REG_DBG_MODE1_CFG_BB_K2, + XSEM_REG_SYNC_DBG_EMPTY, XSEM_REG_SLOW_DBG_EMPTY_BB_K2, XCM_REG_CTX_RBC_ACCS, 9, XCM_REG_AGG_CON_CTX, 15, XCM_REG_SM_CON_CTX, 0, 0, 0, 0}, + /* Ystorm */ {'Y', BLOCK_YSEM, {DBG_BUS_CLIENT_RBCX, DBG_BUS_CLIENT_RBCY}, false, YSEM_REG_FAST_MEMORY, - YSEM_REG_DBG_FRAME_MODE, YSEM_REG_SLOW_DBG_ACTIVE, - YSEM_REG_SLOW_DBG_MODE, YSEM_REG_DBG_MODE1_CFG, - YSEM_REG_SYNC_DBG_EMPTY, TSEM_REG_SLOW_DBG_EMPTY, + YSEM_REG_DBG_FRAME_MODE_BB_K2, YSEM_REG_SLOW_DBG_ACTIVE_BB_K2, + YSEM_REG_SLOW_DBG_MODE_BB_K2, YSEM_REG_DBG_MODE1_CFG_BB_K2, + YSEM_REG_SYNC_DBG_EMPTY, TSEM_REG_SLOW_DBG_EMPTY_BB_K2, YCM_REG_CTX_RBC_ACCS, 2, YCM_REG_AGG_CON_CTX, 3, YCM_REG_SM_CON_CTX, 2, YCM_REG_AGG_TASK_CTX, 12, YCM_REG_SM_TASK_CTX}, + /* Pstorm */ {'P', BLOCK_PSEM, {DBG_BUS_CLIENT_RBCS, DBG_BUS_CLIENT_RBCS}, true, PSEM_REG_FAST_MEMORY, - PSEM_REG_DBG_FRAME_MODE, PSEM_REG_SLOW_DBG_ACTIVE, - PSEM_REG_SLOW_DBG_MODE, PSEM_REG_DBG_MODE1_CFG, - PSEM_REG_SYNC_DBG_EMPTY, PSEM_REG_SLOW_DBG_EMPTY, + PSEM_REG_DBG_FRAME_MODE_BB_K2, PSEM_REG_SLOW_DBG_ACTIVE_BB_K2, + PSEM_REG_SLOW_DBG_MODE_BB_K2, PSEM_REG_DBG_MODE1_CFG_BB_K2, + PSEM_REG_SYNC_DBG_EMPTY, PSEM_REG_SLOW_DBG_EMPTY_BB_K2, PCM_REG_CTX_RBC_ACCS, 0, 0, 10, PCM_REG_SM_CON_CTX, @@ -498,6 +576,7 @@ static struct storm_defs s_storm_defs[] = { }; /* Block definitions array */ + static struct block_defs block_grc_defs = { "grc", {true, true}, false, 0, @@ -587,9 +666,11 @@ static struct block_defs block_pcie_defs = { "pcie", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCH}, - PCIE_REG_DBG_COMMON_SELECT, PCIE_REG_DBG_COMMON_DWORD_ENABLE, - PCIE_REG_DBG_COMMON_SHIFT, PCIE_REG_DBG_COMMON_FORCE_VALID, - PCIE_REG_DBG_COMMON_FORCE_FRAME, + PCIE_REG_DBG_COMMON_SELECT_K2, + PCIE_REG_DBG_COMMON_DWORD_ENABLE_K2, + PCIE_REG_DBG_COMMON_SHIFT_K2, + PCIE_REG_DBG_COMMON_FORCE_VALID_K2, + PCIE_REG_DBG_COMMON_FORCE_FRAME_K2, false, false, MAX_DBG_RESET_REGS, 0 }; @@ -691,9 +772,9 @@ static struct block_defs block_pglcs_defs = { "pglcs", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCH}, - PGLCS_REG_DBG_SELECT, PGLCS_REG_DBG_DWORD_ENABLE, - PGLCS_REG_DBG_SHIFT, PGLCS_REG_DBG_FORCE_VALID, - PGLCS_REG_DBG_FORCE_FRAME, + PGLCS_REG_DBG_SELECT_K2, PGLCS_REG_DBG_DWORD_ENABLE_K2, + PGLCS_REG_DBG_SHIFT_K2, PGLCS_REG_DBG_FORCE_VALID_K2, + PGLCS_REG_DBG_FORCE_FRAME_K2, true, false, DBG_RESET_REG_MISCS_PL_HV, 2 }; @@ -991,10 +1072,11 @@ static struct block_defs block_yuld_defs = { "yuld", {true, true}, false, 0, {DBG_BUS_CLIENT_RBCU, DBG_BUS_CLIENT_RBCU}, - YULD_REG_DBG_SELECT, YULD_REG_DBG_DWORD_ENABLE, - YULD_REG_DBG_SHIFT, YULD_REG_DBG_FORCE_VALID, - YULD_REG_DBG_FORCE_FRAME, - true, true, DBG_RESET_REG_MISC_PL_PDA_VMAIN_2, 15 + YULD_REG_DBG_SELECT_BB_K2, YULD_REG_DBG_DWORD_ENABLE_BB_K2, + YULD_REG_DBG_SHIFT_BB_K2, YULD_REG_DBG_FORCE_VALID_BB_K2, + YULD_REG_DBG_FORCE_FRAME_BB_K2, + true, true, DBG_RESET_REG_MISC_PL_PDA_VMAIN_2, + 15 }; static struct block_defs block_xyld_defs = { @@ -1143,9 +1225,9 @@ static struct block_defs block_umac_defs = { "umac", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCZ}, - UMAC_REG_DBG_SELECT, UMAC_REG_DBG_DWORD_ENABLE, - UMAC_REG_DBG_SHIFT, UMAC_REG_DBG_FORCE_VALID, - UMAC_REG_DBG_FORCE_FRAME, + UMAC_REG_DBG_SELECT_K2, UMAC_REG_DBG_DWORD_ENABLE_K2, + UMAC_REG_DBG_SHIFT_K2, UMAC_REG_DBG_FORCE_VALID_K2, + UMAC_REG_DBG_FORCE_FRAME_K2, true, false, DBG_RESET_REG_MISCS_PL_HV, 6 }; @@ -1177,9 +1259,9 @@ static struct block_defs block_wol_defs = { "wol", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCZ}, - WOL_REG_DBG_SELECT, WOL_REG_DBG_DWORD_ENABLE, - WOL_REG_DBG_SHIFT, WOL_REG_DBG_FORCE_VALID, - WOL_REG_DBG_FORCE_FRAME, + WOL_REG_DBG_SELECT_K2, WOL_REG_DBG_DWORD_ENABLE_K2, + WOL_REG_DBG_SHIFT_K2, WOL_REG_DBG_FORCE_VALID_K2, + WOL_REG_DBG_FORCE_FRAME_K2, true, true, DBG_RESET_REG_MISC_PL_PDA_VAUX, 7 }; @@ -1187,9 +1269,9 @@ static struct block_defs block_bmbn_defs = { "bmbn", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCB}, - BMBN_REG_DBG_SELECT, BMBN_REG_DBG_DWORD_ENABLE, - BMBN_REG_DBG_SHIFT, BMBN_REG_DBG_FORCE_VALID, - BMBN_REG_DBG_FORCE_FRAME, + BMBN_REG_DBG_SELECT_K2, BMBN_REG_DBG_DWORD_ENABLE_K2, + BMBN_REG_DBG_SHIFT_K2, BMBN_REG_DBG_FORCE_VALID_K2, + BMBN_REG_DBG_FORCE_FRAME_K2, false, false, MAX_DBG_RESET_REGS, 0 }; @@ -1204,9 +1286,9 @@ static struct block_defs block_nwm_defs = { "nwm", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCW}, - NWM_REG_DBG_SELECT, NWM_REG_DBG_DWORD_ENABLE, - NWM_REG_DBG_SHIFT, NWM_REG_DBG_FORCE_VALID, - NWM_REG_DBG_FORCE_FRAME, + NWM_REG_DBG_SELECT_K2, NWM_REG_DBG_DWORD_ENABLE_K2, + NWM_REG_DBG_SHIFT_K2, NWM_REG_DBG_FORCE_VALID_K2, + NWM_REG_DBG_FORCE_FRAME_K2, true, false, DBG_RESET_REG_MISCS_PL_HV_2, 0 }; @@ -1214,9 +1296,9 @@ static struct block_defs block_nws_defs = { "nws", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCW}, - NWS_REG_DBG_SELECT, NWS_REG_DBG_DWORD_ENABLE, - NWS_REG_DBG_SHIFT, NWS_REG_DBG_FORCE_VALID, - NWS_REG_DBG_FORCE_FRAME, + NWS_REG_DBG_SELECT_K2, NWS_REG_DBG_DWORD_ENABLE_K2, + NWS_REG_DBG_SHIFT_K2, NWS_REG_DBG_FORCE_VALID_K2, + NWS_REG_DBG_FORCE_FRAME_K2, true, false, DBG_RESET_REG_MISCS_PL_HV, 12 }; @@ -1224,9 +1306,9 @@ static struct block_defs block_ms_defs = { "ms", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCZ}, - MS_REG_DBG_SELECT, MS_REG_DBG_DWORD_ENABLE, - MS_REG_DBG_SHIFT, MS_REG_DBG_FORCE_VALID, - MS_REG_DBG_FORCE_FRAME, + MS_REG_DBG_SELECT_K2, MS_REG_DBG_DWORD_ENABLE_K2, + MS_REG_DBG_SHIFT_K2, MS_REG_DBG_FORCE_VALID_K2, + MS_REG_DBG_FORCE_FRAME_K2, true, false, DBG_RESET_REG_MISCS_PL_HV, 13 }; @@ -1234,9 +1316,11 @@ static struct block_defs block_phy_pcie_defs = { "phy_pcie", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCH}, - PCIE_REG_DBG_COMMON_SELECT, PCIE_REG_DBG_COMMON_DWORD_ENABLE, - PCIE_REG_DBG_COMMON_SHIFT, PCIE_REG_DBG_COMMON_FORCE_VALID, - PCIE_REG_DBG_COMMON_FORCE_FRAME, + PCIE_REG_DBG_COMMON_SELECT_K2, + PCIE_REG_DBG_COMMON_DWORD_ENABLE_K2, + PCIE_REG_DBG_COMMON_SHIFT_K2, + PCIE_REG_DBG_COMMON_FORCE_VALID_K2, + PCIE_REG_DBG_COMMON_FORCE_FRAME_K2, false, false, MAX_DBG_RESET_REGS, 0 }; @@ -1261,6 +1345,13 @@ static struct block_defs block_rgfs_defs = { false, false, MAX_DBG_RESET_REGS, 0 }; +static struct block_defs block_rgsrc_defs = { + "rgsrc", {false, false}, false, 0, + {MAX_DBG_BUS_CLIENTS, MAX_DBG_BUS_CLIENTS}, + 0, 0, 0, 0, 0, + false, false, MAX_DBG_RESET_REGS, 0 +}; + static struct block_defs block_tgfs_defs = { "tgfs", {false, false}, false, 0, {MAX_DBG_BUS_CLIENTS, MAX_DBG_BUS_CLIENTS}, @@ -1268,6 +1359,13 @@ static struct block_defs block_tgfs_defs = { false, false, MAX_DBG_RESET_REGS, 0 }; +static struct block_defs block_tgsrc_defs = { + "tgsrc", {false, false}, false, 0, + {MAX_DBG_BUS_CLIENTS, MAX_DBG_BUS_CLIENTS}, + 0, 0, 0, 0, 0, + false, false, MAX_DBG_RESET_REGS, 0 +}; + static struct block_defs block_ptld_defs = { "ptld", {false, false}, false, 0, {MAX_DBG_BUS_CLIENTS, MAX_DBG_BUS_CLIENTS}, @@ -1350,6 +1448,8 @@ static struct block_defs *s_block_defs[MAX_BLOCK_ID] = { &block_muld_defs, &block_yuld_defs, &block_xyld_defs, + &block_ptld_defs, + &block_ypld_defs, &block_prm_defs, &block_pbf_pb1_defs, &block_pbf_pb2_defs, @@ -1363,6 +1463,10 @@ static struct block_defs *s_block_defs[MAX_BLOCK_ID] = { &block_tcfc_defs, &block_igu_defs, &block_cau_defs, + &block_rgfs_defs, + &block_rgsrc_defs, + &block_tgfs_defs, + &block_tgsrc_defs, &block_umac_defs, &block_xmac_defs, &block_dbg_defs, @@ -1376,10 +1480,6 @@ static struct block_defs *s_block_defs[MAX_BLOCK_ID] = { &block_phy_pcie_defs, &block_led_defs, &block_avs_wrap_defs, - &block_rgfs_defs, - &block_tgfs_defs, - &block_ptld_defs, - &block_ypld_defs, &block_misc_aeu_defs, &block_bar0_map_defs, }; @@ -1392,66 +1492,151 @@ static struct platform_defs s_platform_defs[] = { }; static struct grc_param_defs s_grc_param_defs[] = { - {{1, 1}, 0, 1, false, 1, 1}, /* DBG_GRC_PARAM_DUMP_TSTORM */ - {{1, 1}, 0, 1, false, 1, 1}, /* DBG_GRC_PARAM_DUMP_MSTORM */ - {{1, 1}, 0, 1, false, 1, 1}, /* DBG_GRC_PARAM_DUMP_USTORM */ - {{1, 1}, 0, 1, false, 1, 1}, /* DBG_GRC_PARAM_DUMP_XSTORM */ - {{1, 1}, 0, 1, false, 1, 1}, /* DBG_GRC_PARAM_DUMP_YSTORM */ - {{1, 1}, 0, 1, false, 1, 1}, /* DBG_GRC_PARAM_DUMP_PSTORM */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_REGS */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_RAM */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_PBUF */ - {{0, 0}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_IOR */ - {{0, 0}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_VFC */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_CM_CTX */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_ILT */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_RSS */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_CAU */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_QM */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_MCP */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_RESERVED */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_CFC */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_IGU */ - {{0, 0}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_BRB */ - {{0, 0}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_BTB */ - {{0, 0}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_BMB */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_NIG */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_MULD */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_PRS */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_DMAE */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_TM */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_SDM */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_DIF */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_STATIC */ - {{0, 0}, 0, 1, false, 0, 0}, /* DBG_GRC_PARAM_UNSTALL */ + /* DBG_GRC_PARAM_DUMP_TSTORM */ + {{1, 1}, 0, 1, false, 1, 1}, + + /* DBG_GRC_PARAM_DUMP_MSTORM */ + {{1, 1}, 0, 1, false, 1, 1}, + + /* DBG_GRC_PARAM_DUMP_USTORM */ + {{1, 1}, 0, 1, false, 1, 1}, + + /* DBG_GRC_PARAM_DUMP_XSTORM */ + {{1, 1}, 0, 1, false, 1, 1}, + + /* DBG_GRC_PARAM_DUMP_YSTORM */ + {{1, 1}, 0, 1, false, 1, 1}, + + /* DBG_GRC_PARAM_DUMP_PSTORM */ + {{1, 1}, 0, 1, false, 1, 1}, + + /* DBG_GRC_PARAM_DUMP_REGS */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_RAM */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_PBUF */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_IOR */ + {{0, 0}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_VFC */ + {{0, 0}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_CM_CTX */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_ILT */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_RSS */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_CAU */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_QM */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_MCP */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_RESERVED */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_CFC */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_IGU */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_BRB */ + {{0, 0}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_BTB */ + {{0, 0}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_BMB */ + {{0, 0}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_NIG */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_MULD */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_PRS */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_DMAE */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_TM */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_SDM */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_DIF */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_STATIC */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_UNSTALL */ + {{0, 0}, 0, 1, false, 0, 0}, + + /* DBG_GRC_PARAM_NUM_LCIDS */ {{MAX_LCIDS, MAX_LCIDS}, 1, MAX_LCIDS, false, MAX_LCIDS, - MAX_LCIDS}, /* DBG_GRC_PARAM_NUM_LCIDS */ + MAX_LCIDS}, + + /* DBG_GRC_PARAM_NUM_LTIDS */ {{MAX_LTIDS, MAX_LTIDS}, 1, MAX_LTIDS, false, MAX_LTIDS, - MAX_LTIDS}, /* DBG_GRC_PARAM_NUM_LTIDS */ - {{0, 0}, 0, 1, true, 0, 0}, /* DBG_GRC_PARAM_EXCLUDE_ALL */ - {{0, 0}, 0, 1, true, 0, 0}, /* DBG_GRC_PARAM_CRASH */ - {{0, 0}, 0, 1, false, 1, 0}, /* DBG_GRC_PARAM_PARITY_SAFE */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_CM */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_PHY */ - {{0, 0}, 0, 1, false, 0, 0}, /* DBG_GRC_PARAM_NO_MCP */ - {{0, 0}, 0, 1, false, 0, 0} /* DBG_GRC_PARAM_NO_FW_VER */ + MAX_LTIDS}, + + /* DBG_GRC_PARAM_EXCLUDE_ALL */ + {{0, 0}, 0, 1, true, 0, 0}, + + /* DBG_GRC_PARAM_CRASH */ + {{0, 0}, 0, 1, true, 0, 0}, + + /* DBG_GRC_PARAM_PARITY_SAFE */ + {{0, 0}, 0, 1, false, 1, 0}, + + /* DBG_GRC_PARAM_DUMP_CM */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_PHY */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_NO_MCP */ + {{0, 0}, 0, 1, false, 0, 0}, + + /* DBG_GRC_PARAM_NO_FW_VER */ + {{0, 0}, 0, 1, false, 0, 0} }; static struct rss_mem_defs s_rss_mem_defs[] = { { "rss_mem_cid", "rss_cid", 0, {256, 320}, {32, 32} }, + { "rss_mem_key_msb", "rss_key", 1024, {128, 208}, {256, 256} }, + { "rss_mem_key_lsb", "rss_key", 2048, {128, 208}, {64, 64} }, + { "rss_mem_info", "rss_info", 3072, {128, 208}, {16, 16} }, + { "rss_mem_ind", "rss_ind", 4096, - {(128 * 128), (128 * 208)}, + {16384, 26624}, {16, 16} } }; @@ -1466,50 +1651,71 @@ static struct big_ram_defs s_big_ram_defs[] = { { "BRB", MEM_GROUP_BRB_MEM, MEM_GROUP_BRB_RAM, DBG_GRC_PARAM_DUMP_BRB, BRB_REG_BIG_RAM_ADDRESS, BRB_REG_BIG_RAM_DATA, {4800, 5632} }, + { "BTB", MEM_GROUP_BTB_MEM, MEM_GROUP_BTB_RAM, DBG_GRC_PARAM_DUMP_BTB, BTB_REG_BIG_RAM_ADDRESS, BTB_REG_BIG_RAM_DATA, {2880, 3680} }, + { "BMB", MEM_GROUP_BMB_MEM, MEM_GROUP_BMB_RAM, DBG_GRC_PARAM_DUMP_BMB, BMB_REG_BIG_RAM_ADDRESS, BMB_REG_BIG_RAM_DATA, {1152, 1152} } }; static struct reset_reg_defs s_reset_regs_defs[] = { + /* DBG_RESET_REG_MISCS_PL_UA */ { MISCS_REG_RESET_PL_UA, 0x0, - {true, true} }, /* DBG_RESET_REG_MISCS_PL_UA */ + {true, true} }, + + /* DBG_RESET_REG_MISCS_PL_HV */ { MISCS_REG_RESET_PL_HV, 0x0, - {true, true} }, /* DBG_RESET_REG_MISCS_PL_HV */ - { MISCS_REG_RESET_PL_HV_2, 0x0, - {false, true} }, /* DBG_RESET_REG_MISCS_PL_HV_2 */ + {true, true} }, + + /* DBG_RESET_REG_MISCS_PL_HV_2 */ + { MISCS_REG_RESET_PL_HV_2_K2, 0x0, + {false, true} }, + + /* DBG_RESET_REG_MISC_PL_UA */ { MISC_REG_RESET_PL_UA, 0x0, - {true, true} }, /* DBG_RESET_REG_MISC_PL_UA */ + {true, true} }, + + /* DBG_RESET_REG_MISC_PL_HV */ { MISC_REG_RESET_PL_HV, 0x0, - {true, true} }, /* DBG_RESET_REG_MISC_PL_HV */ + {true, true} }, + + /* DBG_RESET_REG_MISC_PL_PDA_VMAIN_1 */ { MISC_REG_RESET_PL_PDA_VMAIN_1, 0x4404040, - {true, true} }, /* DBG_RESET_REG_MISC_PL_PDA_VMAIN_1 */ + {true, true} }, + + /* DBG_RESET_REG_MISC_PL_PDA_VMAIN_2 */ { MISC_REG_RESET_PL_PDA_VMAIN_2, 0x7c00007, - {true, true} }, /* DBG_RESET_REG_MISC_PL_PDA_VMAIN_2 */ + {true, true} }, + + /* DBG_RESET_REG_MISC_PL_PDA_VAUX */ { MISC_REG_RESET_PL_PDA_VAUX, 0x2, - {true, true} }, /* DBG_RESET_REG_MISC_PL_PDA_VAUX */ + {true, true} }, }; static struct phy_defs s_phy_defs[] = { - {"nw_phy", NWS_REG_NWS_CMU, PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_7_0, - PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_15_8, - PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_7_0, - PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_11_8}, - {"sgmii_phy", MS_REG_MS_CMU, PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X132, - PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X133, - PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X130, - PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X131}, - {"pcie_phy0", PHY_PCIE_REG_PHY0, PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X132, - PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X133, - PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X130, - PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X131}, - {"pcie_phy1", PHY_PCIE_REG_PHY1, PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X132, - PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X133, - PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X130, - PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X131}, + {"nw_phy", NWS_REG_NWS_CMU_K2, + PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_7_0_K2, + PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_15_8_K2, + PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_7_0_K2, + PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_11_8_K2}, + {"sgmii_phy", MS_REG_MS_CMU_K2, + PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X132_K2, + PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X133_K2, + PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X130_K2, + PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X131_K2}, + {"pcie_phy0", PHY_PCIE_REG_PHY0_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X132_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X133_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X130_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X131_K2}, + {"pcie_phy1", PHY_PCIE_REG_PHY1_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X132_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X133_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X130_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X131_K2}, }; /**************************** Private Functions ******************************/ @@ -1556,7 +1762,7 @@ static enum dbg_status qed_dbg_dev_init(struct qed_hwfn *p_hwfn, dev_data->chip_id = CHIP_K2; dev_data->mode_enable[MODE_K2] = 1; } else if (QED_IS_BB_B0(p_hwfn->cdev)) { - dev_data->chip_id = CHIP_BB_B0; + dev_data->chip_id = CHIP_BB; dev_data->mode_enable[MODE_BB] = 1; } else { return DBG_STATUS_UNKNOWN_CHIP; @@ -1569,9 +1775,20 @@ static enum dbg_status qed_dbg_dev_init(struct qed_hwfn *p_hwfn, qed_dbg_grc_init_params(p_hwfn); dev_data->initialized = true; + return DBG_STATUS_OK; } +static struct dbg_bus_block *get_dbg_bus_block_desc(struct qed_hwfn *p_hwfn, + enum block_id block_id) +{ + struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; + + return (struct dbg_bus_block *)&dbg_bus_blocks[block_id * + MAX_CHIP_IDS + + dev_data->chip_id]; +} + /* Reads the FW info structure for the specified Storm from the chip, * and writes it to the specified fw_info pointer. */ @@ -1579,25 +1796,28 @@ static void qed_read_fw_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u8 storm_id, struct fw_info *fw_info) { - /* Read first the address that points to fw_info location. - * The address is located in the last line of the Storm RAM. - */ - u32 addr = s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_INT_RAM + - DWORDS_TO_BYTES(SEM_FAST_REG_INT_RAM_SIZE) - - sizeof(struct fw_info_location); + struct storm_defs *storm = &s_storm_defs[storm_id]; struct fw_info_location fw_info_location; - u32 *dest = (u32 *)&fw_info_location; - u32 i; + u32 addr, i, *dest; memset(&fw_info_location, 0, sizeof(fw_info_location)); memset(fw_info, 0, sizeof(*fw_info)); + + /* Read first the address that points to fw_info location. + * The address is located in the last line of the Storm RAM. + */ + addr = storm->sem_fast_mem_addr + SEM_FAST_REG_INT_RAM + + DWORDS_TO_BYTES(SEM_FAST_REG_INT_RAM_SIZE) - + sizeof(fw_info_location); + dest = (u32 *)&fw_info_location; + for (i = 0; i < BYTES_TO_DWORDS(sizeof(fw_info_location)); i++, addr += BYTES_IN_DWORD) dest[i] = qed_rd(p_hwfn, p_ptt, addr); + + /* Read FW version info from Storm RAM */ if (fw_info_location.size > 0 && fw_info_location.size <= sizeof(*fw_info)) { - /* Read FW version info from Storm RAM */ addr = fw_info_location.grc_addr; dest = (u32 *)fw_info; for (i = 0; i < BYTES_TO_DWORDS(fw_info_location.size); @@ -1606,27 +1826,30 @@ static void qed_read_fw_info(struct qed_hwfn *p_hwfn, } } -/* Dumps the specified string to the specified buffer. Returns the dumped size - * in bytes (actual length + 1 for the null character termination). +/* Dumps the specified string to the specified buffer. + * Returns the dumped size in bytes. */ static u32 qed_dump_str(char *dump_buf, bool dump, const char *str) { if (dump) strcpy(dump_buf, str); + return (u32)strlen(str) + 1; } -/* Dumps zeros to align the specified buffer to dwords. Returns the dumped size - * in bytes. +/* Dumps zeros to align the specified buffer to dwords. + * Returns the dumped size in bytes. */ static u32 qed_dump_align(char *dump_buf, bool dump, u32 byte_offset) { - u8 offset_in_dword = (u8)(byte_offset & 0x3), align_size; + u8 offset_in_dword, align_size; + offset_in_dword = (u8)(byte_offset & 0x3); align_size = offset_in_dword ? BYTES_IN_DWORD - offset_in_dword : 0; if (dump && align_size) memset(dump_buf, 0, align_size); + return align_size; } @@ -1653,6 +1876,7 @@ static u32 qed_dump_str_param(u32 *dump_buf, /* Align buffer to next dword */ offset += qed_dump_align(char_buf + offset, dump, offset); + return BYTES_TO_DWORDS(offset); } @@ -1681,6 +1905,7 @@ static u32 qed_dump_num_param(u32 *dump_buf, if (dump) *(dump_buf + offset) = param_val; offset++; + return offset; } @@ -1695,7 +1920,6 @@ static u32 qed_dump_fw_ver_param(struct qed_hwfn *p_hwfn, char fw_ver_str[16] = EMPTY_FW_VERSION_STR; char fw_img_str[16] = EMPTY_FW_IMAGE_STR; struct fw_info fw_info = { {0}, {0} }; - int printed_chars; u32 offset = 0; if (dump && !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_FW_VER)) { @@ -1705,37 +1929,32 @@ static u32 qed_dump_fw_ver_param(struct qed_hwfn *p_hwfn, for (storm_id = 0; storm_id < MAX_DBG_STORMS && !found; storm_id++) { - /* Read FW version/image */ - if (!dev_data->block_in_reset - [s_storm_defs[storm_id].block_id]) { - /* read FW info for the current Storm */ - qed_read_fw_info(p_hwfn, - p_ptt, storm_id, &fw_info); - - /* Create FW version/image strings */ - printed_chars = - snprintf(fw_ver_str, - sizeof(fw_ver_str), - "%d_%d_%d_%d", - fw_info.ver.num.major, - fw_info.ver.num.minor, - fw_info.ver.num.rev, - fw_info.ver.num.eng); - if (printed_chars < 0 || printed_chars >= - sizeof(fw_ver_str)) - DP_NOTICE(p_hwfn, - "Unexpected debug error: invalid FW version string\n"); - switch (fw_info.ver.image_id) { - case FW_IMG_MAIN: - strcpy(fw_img_str, "main"); - break; - default: - strcpy(fw_img_str, "unknown"); - break; - } + struct storm_defs *storm = &s_storm_defs[storm_id]; - found = true; + /* Read FW version/image */ + if (dev_data->block_in_reset[storm->block_id]) + continue; + + /* Read FW info for the current Storm */ + qed_read_fw_info(p_hwfn, p_ptt, storm_id, &fw_info); + + /* Create FW version/image strings */ + if (snprintf(fw_ver_str, sizeof(fw_ver_str), + "%d_%d_%d_%d", fw_info.ver.num.major, + fw_info.ver.num.minor, fw_info.ver.num.rev, + fw_info.ver.num.eng) < 0) + DP_NOTICE(p_hwfn, + "Unexpected debug error: invalid FW version string\n"); + switch (fw_info.ver.image_id) { + case FW_IMG_MAIN: + strcpy(fw_img_str, "main"); + break; + default: + strcpy(fw_img_str, "unknown"); + break; } + + found = true; } } @@ -1747,6 +1966,7 @@ static u32 qed_dump_fw_ver_param(struct qed_hwfn *p_hwfn, offset += qed_dump_num_param(dump_buf + offset, dump, "fw-timestamp", fw_info.ver.timestamp); + return offset; } @@ -1759,17 +1979,18 @@ static u32 qed_dump_mfw_ver_param(struct qed_hwfn *p_hwfn, { char mfw_ver_str[16] = EMPTY_FW_VERSION_STR; - if (dump && !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_FW_VER)) { + if (dump && + !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_FW_VER)) { u32 global_section_offsize, global_section_addr, mfw_ver; u32 public_data_addr, global_section_offsize_addr; - int printed_chars; - /* Find MCP public data GRC address. - * Needs to be ORed with MCP_REG_SCRATCH due to a HW bug. + /* Find MCP public data GRC address. Needs to be ORed with + * MCP_REG_SCRATCH due to a HW bug. */ - public_data_addr = qed_rd(p_hwfn, p_ptt, + public_data_addr = qed_rd(p_hwfn, + p_ptt, MISC_REG_SHARED_MEM_ADDR) | - MCP_REG_SCRATCH; + MCP_REG_SCRATCH; /* Find MCP public global section offset */ global_section_offsize_addr = public_data_addr + @@ -1778,9 +1999,9 @@ static u32 qed_dump_mfw_ver_param(struct qed_hwfn *p_hwfn, sizeof(offsize_t) * PUBLIC_GLOBAL; global_section_offsize = qed_rd(p_hwfn, p_ptt, global_section_offsize_addr); - global_section_addr = MCP_REG_SCRATCH + - (global_section_offsize & - OFFSIZE_OFFSET_MASK) * 4; + global_section_addr = + MCP_REG_SCRATCH + + (global_section_offsize & OFFSIZE_OFFSET_MASK) * 4; /* Read MFW version from MCP public global section */ mfw_ver = qed_rd(p_hwfn, p_ptt, @@ -1788,13 +2009,9 @@ static u32 qed_dump_mfw_ver_param(struct qed_hwfn *p_hwfn, offsetof(struct public_global, mfw_ver)); /* Dump MFW version param */ - printed_chars = snprintf(mfw_ver_str, sizeof(mfw_ver_str), - "%d_%d_%d_%d", - (u8) (mfw_ver >> 24), - (u8) (mfw_ver >> 16), - (u8) (mfw_ver >> 8), - (u8) mfw_ver); - if (printed_chars < 0 || printed_chars >= sizeof(mfw_ver_str)) + if (snprintf(mfw_ver_str, sizeof(mfw_ver_str), "%d_%d_%d_%d", + (u8)(mfw_ver >> 24), (u8)(mfw_ver >> 16), + (u8)(mfw_ver >> 8), (u8)mfw_ver) < 0) DP_NOTICE(p_hwfn, "Unexpected debug error: invalid MFW version string\n"); } @@ -1820,11 +2037,12 @@ static u32 qed_dump_common_global_params(struct qed_hwfn *p_hwfn, bool dump, u8 num_specific_global_params) { - u8 num_params = NUM_COMMON_GLOBAL_PARAMS + num_specific_global_params; struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; u32 offset = 0; + u8 num_params; - /* Find platform string and dump global params section header */ + /* Dump global params section header */ + num_params = NUM_COMMON_GLOBAL_PARAMS + num_specific_global_params; offset += qed_dump_section_hdr(dump_buf + offset, dump, "global_params", num_params); @@ -1846,25 +2064,29 @@ static u32 qed_dump_common_global_params(struct qed_hwfn *p_hwfn, offset += qed_dump_num_param(dump_buf + offset, dump, "pci-func", p_hwfn->abs_pf_id); + return offset; } -/* Writes the last section to the specified buffer at the given offset. - * Returns the dumped size in dwords. +/* Writes the "last" section (including CRC) to the specified buffer at the + * given offset. Returns the dumped size in dwords. */ -static u32 qed_dump_last_section(u32 *dump_buf, u32 offset, bool dump) +static u32 qed_dump_last_section(struct qed_hwfn *p_hwfn, + u32 *dump_buf, u32 offset, bool dump) { - u32 start_offset = offset, crc = ~0; + u32 start_offset = offset; /* Dump CRC section header */ offset += qed_dump_section_hdr(dump_buf + offset, dump, "last", 0); - /* Calculate CRC32 and add it to the dword following the "last" section. - */ + /* Calculate CRC32 and add it to the dword after the "last" section */ if (dump) - *(dump_buf + offset) = ~crc32(crc, (u8 *)dump_buf, + *(dump_buf + offset) = ~crc32(0xffffffff, + (u8 *)dump_buf, DWORDS_TO_BYTES(offset)); + offset++; + return offset - start_offset; } @@ -1883,11 +2105,12 @@ static void qed_update_blocks_reset_state(struct qed_hwfn *p_hwfn, p_ptt, s_reset_regs_defs[i].addr); /* Check if blocks are in reset */ - for (i = 0; i < MAX_BLOCK_ID; i++) - dev_data->block_in_reset[i] = - s_block_defs[i]->has_reset_bit && - !(reg_val[s_block_defs[i]->reset_reg] & - BIT(s_block_defs[i]->reset_bit_offset)); + for (i = 0; i < MAX_BLOCK_ID; i++) { + struct block_defs *block = s_block_defs[i]; + + dev_data->block_in_reset[i] = block->has_reset_bit && + !(reg_val[block->reset_reg] & BIT(block->reset_bit_offset)); + } } /* Enable / disable the Debug block */ @@ -1902,12 +2125,12 @@ static void qed_bus_reset_dbg_block(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { u32 dbg_reset_reg_addr, old_reset_reg_val, new_reset_reg_val; + struct block_defs *dbg_block = s_block_defs[BLOCK_DBG]; - dbg_reset_reg_addr = - s_reset_regs_defs[s_block_defs[BLOCK_DBG]->reset_reg].addr; + dbg_reset_reg_addr = s_reset_regs_defs[dbg_block->reset_reg].addr; old_reset_reg_val = qed_rd(p_hwfn, p_ptt, dbg_reset_reg_addr); - new_reset_reg_val = old_reset_reg_val & - ~BIT(s_block_defs[BLOCK_DBG]->reset_bit_offset); + new_reset_reg_val = + old_reset_reg_val & ~BIT(dbg_block->reset_bit_offset); qed_wr(p_hwfn, p_ptt, dbg_reset_reg_addr, new_reset_reg_val); qed_wr(p_hwfn, p_ptt, dbg_reset_reg_addr, old_reset_reg_val); @@ -1920,8 +2143,8 @@ static void qed_bus_set_framing_mode(struct qed_hwfn *p_hwfn, qed_wr(p_hwfn, p_ptt, DBG_REG_FRAMING_MODE, (u8)mode); } -/* Enable / disable Debug Bus clients according to the specified mask. - * (1 = enable, 0 = disable) +/* Enable / disable Debug Bus clients according to the specified mask + * (1 = enable, 0 = disable). */ static void qed_bus_enable_clients(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 client_mask) @@ -1931,10 +2154,14 @@ static void qed_bus_enable_clients(struct qed_hwfn *p_hwfn, static bool qed_is_mode_match(struct qed_hwfn *p_hwfn, u16 *modes_buf_offset) { - const u32 *ptr = s_dbg_arrays[BIN_BUF_DBG_MODE_TREE].ptr; struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; - u8 tree_val = ((u8 *)ptr)[(*modes_buf_offset)++]; bool arg1, arg2; + const u32 *ptr; + u8 tree_val; + + /* Get next element from modes tree buffer */ + ptr = s_dbg_arrays[BIN_BUF_DBG_MODE_TREE].ptr; + tree_val = ((u8 *)ptr)[(*modes_buf_offset)++]; switch (tree_val) { case INIT_MODE_OP_NOT: @@ -1974,75 +2201,81 @@ static bool qed_grc_is_storm_included(struct qed_hwfn *p_hwfn, static bool qed_grc_is_mem_included(struct qed_hwfn *p_hwfn, enum block_id block_id, u8 mem_group_id) { + struct block_defs *block = s_block_defs[block_id]; u8 i; /* Check Storm match */ - if (s_block_defs[block_id]->associated_to_storm && + if (block->associated_to_storm && !qed_grc_is_storm_included(p_hwfn, - (enum dbg_storms)s_block_defs[block_id]->storm_id)) + (enum dbg_storms)block->storm_id)) return false; - for (i = 0; i < NUM_BIG_RAM_TYPES; i++) - if (mem_group_id == s_big_ram_defs[i].mem_group_id || - mem_group_id == s_big_ram_defs[i].ram_mem_group_id) - return qed_grc_is_included(p_hwfn, - s_big_ram_defs[i].grc_param); - if (mem_group_id == MEM_GROUP_PXP_ILT || mem_group_id == - MEM_GROUP_PXP_MEM) + for (i = 0; i < NUM_BIG_RAM_TYPES; i++) { + struct big_ram_defs *big_ram = &s_big_ram_defs[i]; + + if (mem_group_id == big_ram->mem_group_id || + mem_group_id == big_ram->ram_mem_group_id) + return qed_grc_is_included(p_hwfn, big_ram->grc_param); + } + + switch (mem_group_id) { + case MEM_GROUP_PXP_ILT: + case MEM_GROUP_PXP_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_PXP); - if (mem_group_id == MEM_GROUP_RAM) + case MEM_GROUP_RAM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_RAM); - if (mem_group_id == MEM_GROUP_PBUF) + case MEM_GROUP_PBUF: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_PBUF); - if (mem_group_id == MEM_GROUP_CAU_MEM || - mem_group_id == MEM_GROUP_CAU_SB || - mem_group_id == MEM_GROUP_CAU_PI) + case MEM_GROUP_CAU_MEM: + case MEM_GROUP_CAU_SB: + case MEM_GROUP_CAU_PI: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_CAU); - if (mem_group_id == MEM_GROUP_QM_MEM) + case MEM_GROUP_QM_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_QM); - if (mem_group_id == MEM_GROUP_CONN_CFC_MEM || - mem_group_id == MEM_GROUP_TASK_CFC_MEM) + case MEM_GROUP_CFC_MEM: + case MEM_GROUP_CONN_CFC_MEM: + case MEM_GROUP_TASK_CFC_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_CFC); - if (mem_group_id == MEM_GROUP_IGU_MEM || mem_group_id == - MEM_GROUP_IGU_MSIX) + case MEM_GROUP_IGU_MEM: + case MEM_GROUP_IGU_MSIX: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_IGU); - if (mem_group_id == MEM_GROUP_MULD_MEM) + case MEM_GROUP_MULD_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_MULD); - if (mem_group_id == MEM_GROUP_PRS_MEM) + case MEM_GROUP_PRS_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_PRS); - if (mem_group_id == MEM_GROUP_DMAE_MEM) + case MEM_GROUP_DMAE_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_DMAE); - if (mem_group_id == MEM_GROUP_TM_MEM) + case MEM_GROUP_TM_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_TM); - if (mem_group_id == MEM_GROUP_SDM_MEM) + case MEM_GROUP_SDM_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_SDM); - if (mem_group_id == MEM_GROUP_TDIF_CTX || mem_group_id == - MEM_GROUP_RDIF_CTX) + case MEM_GROUP_TDIF_CTX: + case MEM_GROUP_RDIF_CTX: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_DIF); - if (mem_group_id == MEM_GROUP_CM_MEM) + case MEM_GROUP_CM_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_CM); - if (mem_group_id == MEM_GROUP_IOR) + case MEM_GROUP_IOR: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_IOR); - - return true; + default: + return true; + } } /* Stalls all Storms */ static void qed_grc_stall_storms(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool stall) { - u8 reg_val = stall ? 1 : 0; + u32 reg_addr; u8 storm_id; for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) { - if (qed_grc_is_storm_included(p_hwfn, - (enum dbg_storms)storm_id)) { - u32 reg_addr = - s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_STALL_0; + if (!qed_grc_is_storm_included(p_hwfn, + (enum dbg_storms)storm_id)) + continue; - qed_wr(p_hwfn, p_ptt, reg_addr, reg_val); - } + reg_addr = s_storm_defs[storm_id].sem_fast_mem_addr + + SEM_FAST_REG_STALL_0_BB_K2; + qed_wr(p_hwfn, p_ptt, reg_addr, stall ? 1 : 0); } msleep(STALL_DELAY_MS); @@ -2054,24 +2287,29 @@ static void qed_grc_unreset_blocks(struct qed_hwfn *p_hwfn, { struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; u32 reg_val[MAX_DBG_RESET_REGS] = { 0 }; - u32 i; + u32 block_id, i; /* Fill reset regs values */ - for (i = 0; i < MAX_BLOCK_ID; i++) - if (s_block_defs[i]->has_reset_bit && s_block_defs[i]->unreset) - reg_val[s_block_defs[i]->reset_reg] |= - BIT(s_block_defs[i]->reset_bit_offset); + for (block_id = 0; block_id < MAX_BLOCK_ID; block_id++) { + struct block_defs *block = s_block_defs[block_id]; + + if (block->has_reset_bit && block->unreset) + reg_val[block->reset_reg] |= + BIT(block->reset_bit_offset); + } /* Write reset registers */ for (i = 0; i < MAX_DBG_RESET_REGS; i++) { - if (s_reset_regs_defs[i].exists[dev_data->chip_id]) { - reg_val[i] |= s_reset_regs_defs[i].unreset_val; - if (reg_val[i]) - qed_wr(p_hwfn, - p_ptt, - s_reset_regs_defs[i].addr + - RESET_REG_UNRESET_OFFSET, reg_val[i]); - } + if (!s_reset_regs_defs[i].exists[dev_data->chip_id]) + continue; + + reg_val[i] |= s_reset_regs_defs[i].unreset_val; + + if (reg_val[i]) + qed_wr(p_hwfn, + p_ptt, + s_reset_regs_defs[i].addr + + RESET_REG_UNRESET_OFFSET, reg_val[i]); } } @@ -2095,6 +2333,7 @@ qed_get_block_attn_regs(enum block_id block_id, enum dbg_attn_type attn_type, qed_get_block_attn_data(block_id, attn_type); *num_attn_regs = block_type_data->num_regs; + return &((const struct dbg_attn_reg *) s_dbg_arrays[BIN_BUF_DBG_ATTN_REGS].ptr)[block_type_data-> regs_offset]; @@ -2105,34 +2344,34 @@ static void qed_grc_clear_all_prty(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; + const struct dbg_attn_reg *attn_reg_arr; u8 reg_idx, num_attn_regs; u32 block_id; for (block_id = 0; block_id < MAX_BLOCK_ID; block_id++) { - const struct dbg_attn_reg *attn_reg_arr; - if (dev_data->block_in_reset[block_id]) continue; attn_reg_arr = qed_get_block_attn_regs((enum block_id)block_id, ATTN_TYPE_PARITY, &num_attn_regs); + for (reg_idx = 0; reg_idx < num_attn_regs; reg_idx++) { const struct dbg_attn_reg *reg_data = &attn_reg_arr[reg_idx]; + u16 modes_buf_offset; + bool eval_mode; /* Check mode */ - bool eval_mode = GET_FIELD(reg_data->mode.data, - DBG_MODE_HDR_EVAL_MODE) > 0; - u16 modes_buf_offset = + eval_mode = GET_FIELD(reg_data->mode.data, + DBG_MODE_HDR_EVAL_MODE) > 0; + modes_buf_offset = GET_FIELD(reg_data->mode.data, DBG_MODE_HDR_MODES_BUF_OFFSET); + /* If Mode match: clear parity status */ if (!eval_mode || qed_is_mode_match(p_hwfn, &modes_buf_offset)) - /* Mode match - read parity status read-clear - * register. - */ qed_rd(p_hwfn, p_ptt, DWORDS_TO_BYTES(reg_data-> sts_clr_address)); @@ -2142,11 +2381,11 @@ static void qed_grc_clear_all_prty(struct qed_hwfn *p_hwfn, /* Dumps GRC registers section header. Returns the dumped size in dwords. * The following parameters are dumped: - * - 'count' = num_dumped_entries - * - 'split' = split_type - * - 'id' = split_id (dumped only if split_id >= 0) - * - 'param_name' = param_val (user param, dumped only if param_name != NULL and - * param_val != NULL) + * - count: no. of dumped entries + * - split: split type + * - id: split ID (dumped only if split_id >= 0) + * - param_name: user parameter value (dumped only if param_name != NULL + * and param_val != NULL). */ static u32 qed_grc_dump_regs_hdr(u32 *dump_buf, bool dump, @@ -2170,84 +2409,100 @@ static u32 qed_grc_dump_regs_hdr(u32 *dump_buf, if (param_name && param_val) offset += qed_dump_str_param(dump_buf + offset, dump, param_name, param_val); + return offset; } /* Dumps the GRC registers in the specified address range. * Returns the dumped size in dwords. + * The addr and len arguments are specified in dwords. */ static u32 qed_grc_dump_addr_range(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, u32 *dump_buf, - bool dump, u32 addr, u32 len) + struct qed_ptt *p_ptt, + u32 *dump_buf, + bool dump, u32 addr, u32 len, bool wide_bus) { u32 byte_addr = DWORDS_TO_BYTES(addr), offset = 0, i; - if (dump) - for (i = 0; i < len; i++, byte_addr += BYTES_IN_DWORD, offset++) - *(dump_buf + offset) = qed_rd(p_hwfn, p_ptt, byte_addr); - else - offset += len; + if (!dump) + return len; + + for (i = 0; i < len; i++, byte_addr += BYTES_IN_DWORD, offset++) + *(dump_buf + offset) = qed_rd(p_hwfn, p_ptt, byte_addr); + return offset; } -/* Dumps GRC registers sequence header. Returns the dumped size in dwords. */ -static u32 qed_grc_dump_reg_entry_hdr(u32 *dump_buf, bool dump, u32 addr, - u32 len) +/* Dumps GRC registers sequence header. Returns the dumped size in dwords. + * The addr and len arguments are specified in dwords. + */ +static u32 qed_grc_dump_reg_entry_hdr(u32 *dump_buf, + bool dump, u32 addr, u32 len) { if (dump) *dump_buf = addr | (len << REG_DUMP_LEN_SHIFT); + return 1; } -/* Dumps GRC registers sequence. Returns the dumped size in dwords. */ +/* Dumps GRC registers sequence. Returns the dumped size in dwords. + * The addr and len arguments are specified in dwords. + */ static u32 qed_grc_dump_reg_entry(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, u32 *dump_buf, - bool dump, u32 addr, u32 len) + struct qed_ptt *p_ptt, + u32 *dump_buf, + bool dump, u32 addr, u32 len, bool wide_bus) { u32 offset = 0; offset += qed_grc_dump_reg_entry_hdr(dump_buf, dump, addr, len); offset += qed_grc_dump_addr_range(p_hwfn, p_ptt, - dump_buf + offset, dump, addr, len); + dump_buf + offset, + dump, addr, len, wide_bus); + return offset; } /* Dumps GRC registers sequence with skip cycle. * Returns the dumped size in dwords. + * - addr: start GRC address in dwords + * - total_len: total no. of dwords to dump + * - read_len: no. consecutive dwords to read + * - skip_len: no. of dwords to skip (and fill with zeros) */ static u32 qed_grc_dump_reg_entry_skip(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, u32 *dump_buf, - bool dump, u32 addr, u32 total_len, + struct qed_ptt *p_ptt, + u32 *dump_buf, + bool dump, + u32 addr, + u32 total_len, u32 read_len, u32 skip_len) { u32 offset = 0, reg_offset = 0; offset += qed_grc_dump_reg_entry_hdr(dump_buf, dump, addr, total_len); - if (dump) { - while (reg_offset < total_len) { - u32 curr_len = min_t(u32, - read_len, - total_len - reg_offset); - offset += qed_grc_dump_addr_range(p_hwfn, - p_ptt, - dump_buf + offset, - dump, addr, curr_len); + + if (!dump) + return offset + total_len; + + while (reg_offset < total_len) { + u32 curr_len = min_t(u32, read_len, total_len - reg_offset); + + offset += qed_grc_dump_addr_range(p_hwfn, + p_ptt, + dump_buf + offset, + dump, addr, curr_len, false); + reg_offset += curr_len; + addr += curr_len; + + if (reg_offset < total_len) { + curr_len = min_t(u32, skip_len, total_len - skip_len); + memset(dump_buf + offset, 0, DWORDS_TO_BYTES(curr_len)); + offset += curr_len; reg_offset += curr_len; addr += curr_len; - if (reg_offset < total_len) { - curr_len = min_t(u32, - skip_len, - total_len - skip_len); - memset(dump_buf + offset, 0, - DWORDS_TO_BYTES(curr_len)); - offset += curr_len; - reg_offset += curr_len; - addr += curr_len; - } } - } else { - offset += total_len; } return offset; @@ -2266,43 +2521,48 @@ static u32 qed_grc_dump_regs_entries(struct qed_hwfn *p_hwfn, bool mode_match = true; *num_dumped_reg_entries = 0; + while (input_offset < input_regs_arr.size_in_dwords) { const struct dbg_dump_cond_hdr *cond_hdr = (const struct dbg_dump_cond_hdr *) &input_regs_arr.ptr[input_offset++]; - bool eval_mode = GET_FIELD(cond_hdr->mode.data, - DBG_MODE_HDR_EVAL_MODE) > 0; + u16 modes_buf_offset; + bool eval_mode; /* Check mode/block */ + eval_mode = GET_FIELD(cond_hdr->mode.data, + DBG_MODE_HDR_EVAL_MODE) > 0; if (eval_mode) { - u16 modes_buf_offset = + modes_buf_offset = GET_FIELD(cond_hdr->mode.data, DBG_MODE_HDR_MODES_BUF_OFFSET); mode_match = qed_is_mode_match(p_hwfn, &modes_buf_offset); } - if (mode_match && block_enable[cond_hdr->block_id]) { - for (i = 0; i < cond_hdr->data_size; - i++, input_offset++) { - const struct dbg_dump_reg *reg = - (const struct dbg_dump_reg *) - &input_regs_arr.ptr[input_offset]; - u32 addr, len; - - addr = GET_FIELD(reg->data, - DBG_DUMP_REG_ADDRESS); - len = GET_FIELD(reg->data, DBG_DUMP_REG_LENGTH); - offset += - qed_grc_dump_reg_entry(p_hwfn, p_ptt, - dump_buf + offset, - dump, - addr, - len); - (*num_dumped_reg_entries)++; - } - } else { + if (!mode_match || !block_enable[cond_hdr->block_id]) { input_offset += cond_hdr->data_size; + continue; + } + + for (i = 0; i < cond_hdr->data_size; i++, input_offset++) { + const struct dbg_dump_reg *reg = + (const struct dbg_dump_reg *) + &input_regs_arr.ptr[input_offset]; + u32 addr, len; + bool wide_bus; + + addr = GET_FIELD(reg->data, DBG_DUMP_REG_ADDRESS); + len = GET_FIELD(reg->data, DBG_DUMP_REG_LENGTH); + wide_bus = GET_FIELD(reg->data, DBG_DUMP_REG_WIDE_BUS); + offset += qed_grc_dump_reg_entry(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + addr, + len, + wide_bus); + (*num_dumped_reg_entries)++; } } @@ -2350,8 +2610,8 @@ static u32 qed_grc_dump_split_data(struct qed_hwfn *p_hwfn, return num_dumped_reg_entries > 0 ? offset : 0; } -/* Dumps registers according to the input registers array. - * Returns the dumped size in dwords. +/* Dumps registers according to the input registers array. Returns the dumped + * size in dwords. */ static u32 qed_grc_dump_registers(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, @@ -2361,29 +2621,37 @@ static u32 qed_grc_dump_registers(struct qed_hwfn *p_hwfn, const char *param_name, const char *param_val) { struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; - struct chip_platform_defs *p_platform_defs; + struct chip_platform_defs *chip_platform; u32 offset = 0, input_offset = 0; - struct chip_defs *p_chip_defs; + struct chip_defs *chip; u8 port_id, pf_id, vf_id; u16 fid; - p_chip_defs = &s_chip_defs[dev_data->chip_id]; - p_platform_defs = &p_chip_defs->per_platform[dev_data->platform_id]; + chip = &s_chip_defs[dev_data->chip_id]; + chip_platform = &chip->per_platform[dev_data->platform_id]; if (dump) DP_VERBOSE(p_hwfn, QED_MSG_DEBUG, "Dumping registers...\n"); + while (input_offset < s_dbg_arrays[BIN_BUF_DBG_DUMP_REG].size_in_dwords) { - const struct dbg_dump_split_hdr *split_hdr = + const struct dbg_dump_split_hdr *split_hdr; + struct dbg_array curr_input_regs_arr; + u32 split_data_size; + u8 split_type_id; + + split_hdr = (const struct dbg_dump_split_hdr *) &s_dbg_arrays[BIN_BUF_DBG_DUMP_REG].ptr[input_offset++]; - u8 split_type_id = GET_FIELD(split_hdr->hdr, - DBG_DUMP_SPLIT_HDR_SPLIT_TYPE_ID); - u32 split_data_size = GET_FIELD(split_hdr->hdr, - DBG_DUMP_SPLIT_HDR_DATA_SIZE); - struct dbg_array curr_input_regs_arr = { - &s_dbg_arrays[BIN_BUF_DBG_DUMP_REG].ptr[input_offset], - split_data_size}; + split_type_id = + GET_FIELD(split_hdr->hdr, + DBG_DUMP_SPLIT_HDR_SPLIT_TYPE_ID); + split_data_size = + GET_FIELD(split_hdr->hdr, + DBG_DUMP_SPLIT_HDR_DATA_SIZE); + curr_input_regs_arr.ptr = + &s_dbg_arrays[BIN_BUF_DBG_DUMP_REG].ptr[input_offset]; + curr_input_regs_arr.size_in_dwords = split_data_size; switch (split_type_id) { case SPLIT_TYPE_NONE: @@ -2398,8 +2666,9 @@ static u32 qed_grc_dump_registers(struct qed_hwfn *p_hwfn, param_name, param_val); break; + case SPLIT_TYPE_PORT: - for (port_id = 0; port_id < p_platform_defs->num_ports; + for (port_id = 0; port_id < chip_platform->num_ports; port_id++) { if (dump) qed_port_pretend(p_hwfn, p_ptt, @@ -2414,9 +2683,10 @@ static u32 qed_grc_dump_registers(struct qed_hwfn *p_hwfn, param_val); } break; + case SPLIT_TYPE_PF: case SPLIT_TYPE_PORT_PF: - for (pf_id = 0; pf_id < p_platform_defs->num_pfs; + for (pf_id = 0; pf_id < chip_platform->num_pfs; pf_id++) { u8 pfid_shift = PXP_PRETEND_CONCRETE_FID_PFID_SHIFT; @@ -2427,17 +2697,21 @@ static u32 qed_grc_dump_registers(struct qed_hwfn *p_hwfn, } offset += - qed_grc_dump_split_data(p_hwfn, p_ptt, + qed_grc_dump_split_data(p_hwfn, + p_ptt, curr_input_regs_arr, dump_buf + offset, - dump, block_enable, - "pf", pf_id, + dump, + block_enable, + "pf", + pf_id, param_name, param_val); } break; + case SPLIT_TYPE_VF: - for (vf_id = 0; vf_id < p_platform_defs->num_vfs; + for (vf_id = 0; vf_id < chip_platform->num_vfs; vf_id++) { u8 vfvalid_shift = PXP_PRETEND_CONCRETE_FID_VFVALID_SHIFT; @@ -2460,6 +2734,7 @@ static u32 qed_grc_dump_registers(struct qed_hwfn *p_hwfn, param_val); } break; + default: break; } @@ -2490,35 +2765,37 @@ static u32 qed_grc_dump_reset_regs(struct qed_hwfn *p_hwfn, /* Write reset registers */ for (i = 0; i < MAX_DBG_RESET_REGS; i++) { - if (s_reset_regs_defs[i].exists[dev_data->chip_id]) { - u32 addr = BYTES_TO_DWORDS(s_reset_regs_defs[i].addr); + if (!s_reset_regs_defs[i].exists[dev_data->chip_id]) + continue; - offset += qed_grc_dump_reg_entry(p_hwfn, - p_ptt, - dump_buf + offset, - dump, - addr, - 1); - num_regs++; - } + offset += qed_grc_dump_reg_entry(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + BYTES_TO_DWORDS + (s_reset_regs_defs[i].addr), 1, + false); + num_regs++; } /* Write header */ if (dump) qed_grc_dump_regs_hdr(dump_buf, true, num_regs, "eng", -1, NULL, NULL); + return offset; } -/* Dump registers that are modified during GRC Dump and therefore must be dumped - * first. Returns the dumped size in dwords. +/* Dump registers that are modified during GRC Dump and therefore must be + * dumped first. Returns the dumped size in dwords. */ static u32 qed_grc_dump_modified_regs(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *dump_buf, bool dump) { struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; - u32 offset = 0, num_reg_entries = 0, block_id; + u32 block_id, offset = 0, num_reg_entries = 0; + const struct dbg_attn_reg *attn_reg_arr; u8 storm_id, reg_idx, num_attn_regs; /* Calculate header size */ @@ -2527,14 +2804,13 @@ static u32 qed_grc_dump_modified_regs(struct qed_hwfn *p_hwfn, /* Write parity registers */ for (block_id = 0; block_id < MAX_BLOCK_ID; block_id++) { - const struct dbg_attn_reg *attn_reg_arr; - if (dev_data->block_in_reset[block_id] && dump) continue; attn_reg_arr = qed_get_block_attn_regs((enum block_id)block_id, ATTN_TYPE_PARITY, &num_attn_regs); + for (reg_idx = 0; reg_idx < num_attn_regs; reg_idx++) { const struct dbg_attn_reg *reg_data = &attn_reg_arr[reg_idx]; @@ -2548,37 +2824,36 @@ static u32 qed_grc_dump_modified_regs(struct qed_hwfn *p_hwfn, modes_buf_offset = GET_FIELD(reg_data->mode.data, DBG_MODE_HDR_MODES_BUF_OFFSET); - if (!eval_mode || - qed_is_mode_match(p_hwfn, &modes_buf_offset)) { - /* Mode match - read and dump registers */ - addr = reg_data->mask_address; - offset += - qed_grc_dump_reg_entry(p_hwfn, - p_ptt, - dump_buf + offset, - dump, - addr, - 1); - addr = GET_FIELD(reg_data->data, - DBG_ATTN_REG_STS_ADDRESS); - offset += - qed_grc_dump_reg_entry(p_hwfn, - p_ptt, - dump_buf + offset, - dump, - addr, - 1); - num_reg_entries += 2; - } + if (eval_mode && + !qed_is_mode_match(p_hwfn, &modes_buf_offset)) + continue; + + /* Mode match: read & dump registers */ + addr = reg_data->mask_address; + offset += qed_grc_dump_reg_entry(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + addr, + 1, false); + addr = GET_FIELD(reg_data->data, + DBG_ATTN_REG_STS_ADDRESS); + offset += qed_grc_dump_reg_entry(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + addr, + 1, false); + num_reg_entries += 2; } } - /* Write storm stall status registers */ + /* Write Storm stall status registers */ for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) { + struct storm_defs *storm = &s_storm_defs[storm_id]; u32 addr; - if (dev_data->block_in_reset[s_storm_defs[storm_id].block_id] && - dump) + if (dev_data->block_in_reset[storm->block_id] && dump) continue; addr = @@ -2589,7 +2864,8 @@ static u32 qed_grc_dump_modified_regs(struct qed_hwfn *p_hwfn, dump_buf + offset, dump, addr, - 1); + 1, + false); num_reg_entries++; } @@ -2598,6 +2874,7 @@ static u32 qed_grc_dump_modified_regs(struct qed_hwfn *p_hwfn, qed_grc_dump_regs_hdr(dump_buf, true, num_reg_entries, "eng", -1, NULL, NULL); + return offset; } @@ -2637,17 +2914,17 @@ static u32 qed_grc_dump_special_regs(struct qed_hwfn *p_hwfn, return offset; } -/* Dumps a GRC memory header (section and params). - * The following parameters are dumped: - * name - name is dumped only if it's not NULL. - * addr - addr is dumped only if name is NULL. - * len - len is always dumped. - * width - bit_width is dumped if it's not zero. - * packed - packed=1 is dumped if it's not false. - * mem_group - mem_group is always dumped. - * is_storm - true only if the memory is related to a Storm. - * storm_letter - storm letter (valid only if is_storm is true). - * Returns the dumped size in dwords. +/* Dumps a GRC memory header (section and params). Returns the dumped size in + * dwords. The following parameters are dumped: + * - name: dumped only if it's not NULL. + * - addr: in dwords, dumped only if name is NULL. + * - len: in dwords, always dumped. + * - width: dumped if it's not zero. + * - packed: dumped only if it's not false. + * - mem_group: always dumped. + * - is_storm: true only if the memory is related to a Storm. + * - storm_letter: valid only if is_storm is true. + * */ static u32 qed_grc_dump_mem_hdr(struct qed_hwfn *p_hwfn, u32 *dump_buf, @@ -2667,6 +2944,7 @@ static u32 qed_grc_dump_mem_hdr(struct qed_hwfn *p_hwfn, if (!len) DP_NOTICE(p_hwfn, "Unexpected GRC Dump error: dumped memory size must be non-zero\n"); + if (bit_width) num_params++; if (packed) @@ -2675,6 +2953,7 @@ static u32 qed_grc_dump_mem_hdr(struct qed_hwfn *p_hwfn, /* Dump section header */ offset += qed_dump_section_hdr(dump_buf + offset, dump, "grc_mem", num_params); + if (name) { /* Dump name */ if (is_storm) { @@ -2694,14 +2973,15 @@ static u32 qed_grc_dump_mem_hdr(struct qed_hwfn *p_hwfn, len, buf); } else { /* Dump address */ + u32 addr_in_bytes = DWORDS_TO_BYTES(addr); + offset += qed_dump_num_param(dump_buf + offset, - dump, "addr", - DWORDS_TO_BYTES(addr)); + dump, "addr", addr_in_bytes); if (dump && len > 64) DP_VERBOSE(p_hwfn, QED_MSG_DEBUG, "Dumping %d registers from address 0x%x...\n", - len, (u32)DWORDS_TO_BYTES(addr)); + len, addr_in_bytes); } /* Dump len */ @@ -2727,11 +3007,13 @@ static u32 qed_grc_dump_mem_hdr(struct qed_hwfn *p_hwfn, } offset += qed_dump_str_param(dump_buf + offset, dump, "type", buf); + return offset; } /* Dumps a single GRC memory. If name is NULL, the memory is stored by address. * Returns the dumped size in dwords. + * The addr and len arguments are specified in dwords. */ static u32 qed_grc_dump_mem(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, @@ -2740,6 +3022,7 @@ static u32 qed_grc_dump_mem(struct qed_hwfn *p_hwfn, const char *name, u32 addr, u32 len, + bool wide_bus, u32 bit_width, bool packed, const char *mem_group, @@ -2758,7 +3041,9 @@ static u32 qed_grc_dump_mem(struct qed_hwfn *p_hwfn, mem_group, is_storm, storm_letter); offset += qed_grc_dump_addr_range(p_hwfn, p_ptt, - dump_buf + offset, dump, addr, len); + dump_buf + offset, + dump, addr, len, wide_bus); + return offset; } @@ -2773,20 +3058,21 @@ static u32 qed_grc_dump_mem_entries(struct qed_hwfn *p_hwfn, while (input_offset < input_mems_arr.size_in_dwords) { const struct dbg_dump_cond_hdr *cond_hdr; + u16 modes_buf_offset; u32 num_entries; bool eval_mode; cond_hdr = (const struct dbg_dump_cond_hdr *) &input_mems_arr.ptr[input_offset++]; - eval_mode = GET_FIELD(cond_hdr->mode.data, - DBG_MODE_HDR_EVAL_MODE) > 0; + num_entries = cond_hdr->data_size / MEM_DUMP_ENTRY_SIZE_DWORDS; /* Check required mode */ + eval_mode = GET_FIELD(cond_hdr->mode.data, + DBG_MODE_HDR_EVAL_MODE) > 0; if (eval_mode) { - u16 modes_buf_offset = + modes_buf_offset = GET_FIELD(cond_hdr->mode.data, DBG_MODE_HDR_MODES_BUF_OFFSET); - mode_match = qed_is_mode_match(p_hwfn, &modes_buf_offset); } @@ -2796,81 +3082,87 @@ static u32 qed_grc_dump_mem_entries(struct qed_hwfn *p_hwfn, continue; } - num_entries = cond_hdr->data_size / MEM_DUMP_ENTRY_SIZE_DWORDS; for (i = 0; i < num_entries; i++, input_offset += MEM_DUMP_ENTRY_SIZE_DWORDS) { const struct dbg_dump_mem *mem = (const struct dbg_dump_mem *) &input_mems_arr.ptr[input_offset]; - u8 mem_group_id; + u8 mem_group_id = GET_FIELD(mem->dword0, + DBG_DUMP_MEM_MEM_GROUP_ID); + bool is_storm = false, mem_wide_bus; + enum dbg_grc_params grc_param; + char storm_letter = 'a'; + enum block_id block_id; + u32 mem_addr, mem_len; - mem_group_id = GET_FIELD(mem->dword0, - DBG_DUMP_MEM_MEM_GROUP_ID); if (mem_group_id >= MEM_GROUPS_NUM) { DP_NOTICE(p_hwfn, "Invalid mem_group_id\n"); return 0; } - if (qed_grc_is_mem_included(p_hwfn, - (enum block_id)cond_hdr->block_id, - mem_group_id)) { - u32 mem_addr = GET_FIELD(mem->dword0, - DBG_DUMP_MEM_ADDRESS); - u32 mem_len = GET_FIELD(mem->dword1, - DBG_DUMP_MEM_LENGTH); - enum dbg_grc_params grc_param; - char storm_letter = 'a'; - bool is_storm = false; - - /* Update memory length for CCFC/TCFC memories - * according to number of LCIDs/LTIDs. - */ - if (mem_group_id == MEM_GROUP_CONN_CFC_MEM) { - if (mem_len % MAX_LCIDS != 0) { - DP_NOTICE(p_hwfn, - "Invalid CCFC connection memory size\n"); - return 0; - } - - grc_param = DBG_GRC_PARAM_NUM_LCIDS; - mem_len = qed_grc_get_param(p_hwfn, - grc_param) * - (mem_len / MAX_LCIDS); - } else if (mem_group_id == - MEM_GROUP_TASK_CFC_MEM) { - if (mem_len % MAX_LTIDS != 0) { - DP_NOTICE(p_hwfn, - "Invalid TCFC task memory size\n"); - return 0; - } - - grc_param = DBG_GRC_PARAM_NUM_LTIDS; - mem_len = qed_grc_get_param(p_hwfn, - grc_param) * - (mem_len / MAX_LTIDS); + block_id = (enum block_id)cond_hdr->block_id; + if (!qed_grc_is_mem_included(p_hwfn, + block_id, + mem_group_id)) + continue; + + mem_addr = GET_FIELD(mem->dword0, DBG_DUMP_MEM_ADDRESS); + mem_len = GET_FIELD(mem->dword1, DBG_DUMP_MEM_LENGTH); + mem_wide_bus = GET_FIELD(mem->dword1, + DBG_DUMP_MEM_WIDE_BUS); + + /* Update memory length for CCFC/TCFC memories + * according to number of LCIDs/LTIDs. + */ + if (mem_group_id == MEM_GROUP_CONN_CFC_MEM) { + if (mem_len % MAX_LCIDS) { + DP_NOTICE(p_hwfn, + "Invalid CCFC connection memory size\n"); + return 0; } - /* If memory is associated with Storm, update - * Storm details. - */ - if (s_block_defs[cond_hdr->block_id]-> - associated_to_storm) { - is_storm = true; - storm_letter = - s_storm_defs[s_block_defs[ - cond_hdr->block_id]-> - storm_id].letter; + grc_param = DBG_GRC_PARAM_NUM_LCIDS; + mem_len = qed_grc_get_param(p_hwfn, grc_param) * + (mem_len / MAX_LCIDS); + } else if (mem_group_id == MEM_GROUP_TASK_CFC_MEM) { + if (mem_len % MAX_LTIDS) { + DP_NOTICE(p_hwfn, + "Invalid TCFC task memory size\n"); + return 0; } - /* Dump memory */ - offset += qed_grc_dump_mem(p_hwfn, p_ptt, - dump_buf + offset, dump, NULL, - mem_addr, mem_len, 0, + grc_param = DBG_GRC_PARAM_NUM_LTIDS; + mem_len = qed_grc_get_param(p_hwfn, grc_param) * + (mem_len / MAX_LTIDS); + } + + /* If memory is associated with Storm, update Storm + * details. + */ + if (s_block_defs + [cond_hdr->block_id]->associated_to_storm) { + is_storm = true; + storm_letter = + s_storm_defs[s_block_defs + [cond_hdr->block_id]-> + storm_id].letter; + } + + /* Dump memory */ + offset += qed_grc_dump_mem(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + NULL, + mem_addr, + mem_len, + mem_wide_bus, + 0, false, s_mem_group_names[mem_group_id], - is_storm, storm_letter); - } - } + is_storm, + storm_letter); + } } return offset; @@ -2887,16 +3179,22 @@ static u32 qed_grc_dump_memories(struct qed_hwfn *p_hwfn, while (input_offset < s_dbg_arrays[BIN_BUF_DBG_DUMP_MEM].size_in_dwords) { - const struct dbg_dump_split_hdr *split_hdr = - (const struct dbg_dump_split_hdr *) + const struct dbg_dump_split_hdr *split_hdr; + struct dbg_array curr_input_mems_arr; + u32 split_data_size; + u8 split_type_id; + + split_hdr = (const struct dbg_dump_split_hdr *) &s_dbg_arrays[BIN_BUF_DBG_DUMP_MEM].ptr[input_offset++]; - u8 split_type_id = GET_FIELD(split_hdr->hdr, - DBG_DUMP_SPLIT_HDR_SPLIT_TYPE_ID); - u32 split_data_size = GET_FIELD(split_hdr->hdr, - DBG_DUMP_SPLIT_HDR_DATA_SIZE); - struct dbg_array curr_input_mems_arr = { - &s_dbg_arrays[BIN_BUF_DBG_DUMP_MEM].ptr[input_offset], - split_data_size}; + split_type_id = + GET_FIELD(split_hdr->hdr, + DBG_DUMP_SPLIT_HDR_SPLIT_TYPE_ID); + split_data_size = + GET_FIELD(split_hdr->hdr, + DBG_DUMP_SPLIT_HDR_DATA_SIZE); + curr_input_mems_arr.ptr = + &s_dbg_arrays[BIN_BUF_DBG_DUMP_MEM].ptr[input_offset]; + curr_input_mems_arr.size_in_dwords = split_data_size; switch (split_type_id) { case SPLIT_TYPE_NONE: @@ -2906,6 +3204,7 @@ static u32 qed_grc_dump_memories(struct qed_hwfn *p_hwfn, dump_buf + offset, dump); break; + default: DP_NOTICE(p_hwfn, "Dumping split memories is currently not supported\n"); @@ -2920,6 +3219,7 @@ static u32 qed_grc_dump_memories(struct qed_hwfn *p_hwfn, /* Dumps GRC context data for the specified Storm. * Returns the dumped size in dwords. + * The lid_size argument is specified in quad-regs. */ static u32 qed_grc_dump_ctx_data(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, @@ -2931,13 +3231,15 @@ static u32 qed_grc_dump_ctx_data(struct qed_hwfn *p_hwfn, u32 rd_reg_addr, u8 storm_id) { - u32 i, lid, total_size; - u32 offset = 0; + struct storm_defs *storm = &s_storm_defs[storm_id]; + u32 i, lid, total_size, offset = 0; if (!lid_size) return 0; + lid_size *= BYTES_IN_DWORD; total_size = num_lids * lid_size; + offset += qed_grc_dump_mem_hdr(p_hwfn, dump_buf + offset, dump, @@ -2945,25 +3247,19 @@ static u32 qed_grc_dump_ctx_data(struct qed_hwfn *p_hwfn, 0, total_size, lid_size * 32, - false, - name, - true, s_storm_defs[storm_id].letter); + false, name, true, storm->letter); + + if (!dump) + return offset + total_size; /* Dump context data */ - if (dump) { - for (lid = 0; lid < num_lids; lid++) { - for (i = 0; i < lid_size; i++, offset++) { - qed_wr(p_hwfn, - p_ptt, - s_storm_defs[storm_id].cm_ctx_wr_addr, - BIT(9) | lid); - *(dump_buf + offset) = qed_rd(p_hwfn, - p_ptt, - rd_reg_addr); - } + for (lid = 0; lid < num_lids; lid++) { + for (i = 0; i < lid_size; i++, offset++) { + qed_wr(p_hwfn, + p_ptt, storm->cm_ctx_wr_addr, (i << 9) | lid); + *(dump_buf + offset) = qed_rd(p_hwfn, + p_ptt, rd_reg_addr); } - } else { - offset += total_size; } return offset; @@ -2973,15 +3269,19 @@ static u32 qed_grc_dump_ctx_data(struct qed_hwfn *p_hwfn, static u32 qed_grc_dump_ctx(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *dump_buf, bool dump) { + enum dbg_grc_params grc_param; u32 offset = 0; u8 storm_id; for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) { + struct storm_defs *storm = &s_storm_defs[storm_id]; + if (!qed_grc_is_storm_included(p_hwfn, (enum dbg_storms)storm_id)) continue; /* Dump Conn AG context size */ + grc_param = DBG_GRC_PARAM_NUM_LCIDS; offset += qed_grc_dump_ctx_data(p_hwfn, p_ptt, @@ -2989,14 +3289,13 @@ static u32 qed_grc_dump_ctx(struct qed_hwfn *p_hwfn, dump, "CONN_AG_CTX", qed_grc_get_param(p_hwfn, - DBG_GRC_PARAM_NUM_LCIDS), - s_storm_defs[storm_id]. - cm_conn_ag_ctx_lid_size, - s_storm_defs[storm_id]. - cm_conn_ag_ctx_rd_addr, + grc_param), + storm->cm_conn_ag_ctx_lid_size, + storm->cm_conn_ag_ctx_rd_addr, storm_id); /* Dump Conn ST context size */ + grc_param = DBG_GRC_PARAM_NUM_LCIDS; offset += qed_grc_dump_ctx_data(p_hwfn, p_ptt, @@ -3004,14 +3303,13 @@ static u32 qed_grc_dump_ctx(struct qed_hwfn *p_hwfn, dump, "CONN_ST_CTX", qed_grc_get_param(p_hwfn, - DBG_GRC_PARAM_NUM_LCIDS), - s_storm_defs[storm_id]. - cm_conn_st_ctx_lid_size, - s_storm_defs[storm_id]. - cm_conn_st_ctx_rd_addr, + grc_param), + storm->cm_conn_st_ctx_lid_size, + storm->cm_conn_st_ctx_rd_addr, storm_id); /* Dump Task AG context size */ + grc_param = DBG_GRC_PARAM_NUM_LTIDS; offset += qed_grc_dump_ctx_data(p_hwfn, p_ptt, @@ -3019,14 +3317,13 @@ static u32 qed_grc_dump_ctx(struct qed_hwfn *p_hwfn, dump, "TASK_AG_CTX", qed_grc_get_param(p_hwfn, - DBG_GRC_PARAM_NUM_LTIDS), - s_storm_defs[storm_id]. - cm_task_ag_ctx_lid_size, - s_storm_defs[storm_id]. - cm_task_ag_ctx_rd_addr, + grc_param), + storm->cm_task_ag_ctx_lid_size, + storm->cm_task_ag_ctx_rd_addr, storm_id); /* Dump Task ST context size */ + grc_param = DBG_GRC_PARAM_NUM_LTIDS; offset += qed_grc_dump_ctx_data(p_hwfn, p_ptt, @@ -3034,11 +3331,9 @@ static u32 qed_grc_dump_ctx(struct qed_hwfn *p_hwfn, dump, "TASK_ST_CTX", qed_grc_get_param(p_hwfn, - DBG_GRC_PARAM_NUM_LTIDS), - s_storm_defs[storm_id]. - cm_task_st_ctx_lid_size, - s_storm_defs[storm_id]. - cm_task_st_ctx_rd_addr, + grc_param), + storm->cm_task_st_ctx_lid_size, + storm->cm_task_st_ctx_rd_addr, storm_id); } @@ -3050,8 +3345,8 @@ static u32 qed_grc_dump_iors(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *dump_buf, bool dump) { char buf[10] = "IOR_SET_?"; + u32 addr, offset = 0; u8 storm_id, set_id; - u32 offset = 0; for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) { struct storm_defs *storm = &s_storm_defs[storm_id]; @@ -3061,11 +3356,9 @@ static u32 qed_grc_dump_iors(struct qed_hwfn *p_hwfn, continue; for (set_id = 0; set_id < NUM_IOR_SETS; set_id++) { - u32 dwords, addr; - - dwords = storm->sem_fast_mem_addr + - SEM_FAST_REG_STORM_REG_FILE; - addr = BYTES_TO_DWORDS(dwords) + IOR_SET_OFFSET(set_id); + addr = BYTES_TO_DWORDS(storm->sem_fast_mem_addr + + SEM_FAST_REG_STORM_REG_FILE) + + IOR_SET_OFFSET(set_id); buf[strlen(buf) - 1] = '0' + set_id; offset += qed_grc_dump_mem(p_hwfn, p_ptt, @@ -3074,6 +3367,7 @@ static u32 qed_grc_dump_iors(struct qed_hwfn *p_hwfn, buf, addr, IORS_PER_SET, + false, 32, false, "ior", @@ -3091,10 +3385,10 @@ static u32 qed_grc_dump_vfc_cam(struct qed_hwfn *p_hwfn, u32 *dump_buf, bool dump, u8 storm_id) { u32 total_size = VFC_CAM_NUM_ROWS * VFC_CAM_RESP_DWORDS; + struct storm_defs *storm = &s_storm_defs[storm_id]; u32 cam_addr[VFC_CAM_ADDR_DWORDS] = { 0 }; u32 cam_cmd[VFC_CAM_CMD_DWORDS] = { 0 }; - u32 offset = 0; - u32 row, i; + u32 row, i, offset = 0; offset += qed_grc_dump_mem_hdr(p_hwfn, dump_buf + offset, @@ -3103,38 +3397,34 @@ static u32 qed_grc_dump_vfc_cam(struct qed_hwfn *p_hwfn, 0, total_size, 256, - false, - "vfc_cam", - true, s_storm_defs[storm_id].letter); - if (dump) { - /* Prepare CAM address */ - SET_VAR_FIELD(cam_addr, VFC_CAM_ADDR, OP, VFC_OPCODE_CAM_RD); - for (row = 0; row < VFC_CAM_NUM_ROWS; - row++, offset += VFC_CAM_RESP_DWORDS) { - /* Write VFC CAM command */ - SET_VAR_FIELD(cam_cmd, VFC_CAM_CMD, ROW, row); - ARR_REG_WR(p_hwfn, - p_ptt, - s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_VFC_DATA_WR, - cam_cmd, VFC_CAM_CMD_DWORDS); + false, "vfc_cam", true, storm->letter); - /* Write VFC CAM address */ - ARR_REG_WR(p_hwfn, - p_ptt, - s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_VFC_ADDR, - cam_addr, VFC_CAM_ADDR_DWORDS); + if (!dump) + return offset + total_size; - /* Read VFC CAM read response */ - ARR_REG_RD(p_hwfn, - p_ptt, - s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_VFC_DATA_RD, - dump_buf + offset, VFC_CAM_RESP_DWORDS); - } - } else { - offset += total_size; + /* Prepare CAM address */ + SET_VAR_FIELD(cam_addr, VFC_CAM_ADDR, OP, VFC_OPCODE_CAM_RD); + + for (row = 0; row < VFC_CAM_NUM_ROWS; + row++, offset += VFC_CAM_RESP_DWORDS) { + /* Write VFC CAM command */ + SET_VAR_FIELD(cam_cmd, VFC_CAM_CMD, ROW, row); + ARR_REG_WR(p_hwfn, + p_ptt, + storm->sem_fast_mem_addr + SEM_FAST_REG_VFC_DATA_WR, + cam_cmd, VFC_CAM_CMD_DWORDS); + + /* Write VFC CAM address */ + ARR_REG_WR(p_hwfn, + p_ptt, + storm->sem_fast_mem_addr + SEM_FAST_REG_VFC_ADDR, + cam_addr, VFC_CAM_ADDR_DWORDS); + + /* Read VFC CAM read response */ + ARR_REG_RD(p_hwfn, + p_ptt, + storm->sem_fast_mem_addr + SEM_FAST_REG_VFC_DATA_RD, + dump_buf + offset, VFC_CAM_RESP_DWORDS); } return offset; @@ -3148,10 +3438,10 @@ static u32 qed_grc_dump_vfc_ram(struct qed_hwfn *p_hwfn, u8 storm_id, struct vfc_ram_defs *ram_defs) { u32 total_size = ram_defs->num_rows * VFC_RAM_RESP_DWORDS; + struct storm_defs *storm = &s_storm_defs[storm_id]; u32 ram_addr[VFC_RAM_ADDR_DWORDS] = { 0 }; u32 ram_cmd[VFC_RAM_CMD_DWORDS] = { 0 }; - u32 offset = 0; - u32 row, i; + u32 row, i, offset = 0; offset += qed_grc_dump_mem_hdr(p_hwfn, dump_buf + offset, @@ -3162,7 +3452,7 @@ static u32 qed_grc_dump_vfc_ram(struct qed_hwfn *p_hwfn, 256, false, ram_defs->type_name, - true, s_storm_defs[storm_id].letter); + true, storm->letter); /* Prepare RAM address */ SET_VAR_FIELD(ram_addr, VFC_RAM_ADDR, OP, VFC_OPCODE_RAM_RD); @@ -3176,23 +3466,20 @@ static u32 qed_grc_dump_vfc_ram(struct qed_hwfn *p_hwfn, /* Write VFC RAM command */ ARR_REG_WR(p_hwfn, p_ptt, - s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_VFC_DATA_WR, + storm->sem_fast_mem_addr + SEM_FAST_REG_VFC_DATA_WR, ram_cmd, VFC_RAM_CMD_DWORDS); /* Write VFC RAM address */ SET_VAR_FIELD(ram_addr, VFC_RAM_ADDR, ROW, row); ARR_REG_WR(p_hwfn, p_ptt, - s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_VFC_ADDR, + storm->sem_fast_mem_addr + SEM_FAST_REG_VFC_ADDR, ram_addr, VFC_RAM_ADDR_DWORDS); /* Read VFC RAM read response */ ARR_REG_RD(p_hwfn, p_ptt, - s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_VFC_DATA_RD, + storm->sem_fast_mem_addr + SEM_FAST_REG_VFC_DATA_RD, dump_buf + offset, VFC_RAM_RESP_DWORDS); } @@ -3208,28 +3495,27 @@ static u32 qed_grc_dump_vfc(struct qed_hwfn *p_hwfn, u32 offset = 0; for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) { - if (qed_grc_is_storm_included(p_hwfn, - (enum dbg_storms)storm_id) && - s_storm_defs[storm_id].has_vfc && - (storm_id != DBG_PSTORM_ID || - dev_data->platform_id == PLATFORM_ASIC)) { - /* Read CAM */ - offset += qed_grc_dump_vfc_cam(p_hwfn, + if (!qed_grc_is_storm_included(p_hwfn, + (enum dbg_storms)storm_id) || + !s_storm_defs[storm_id].has_vfc || + (storm_id == DBG_PSTORM_ID && dev_data->platform_id != + PLATFORM_ASIC)) + continue; + + /* Read CAM */ + offset += qed_grc_dump_vfc_cam(p_hwfn, + p_ptt, + dump_buf + offset, + dump, storm_id); + + /* Read RAM */ + for (i = 0; i < NUM_VFC_RAM_TYPES; i++) + offset += qed_grc_dump_vfc_ram(p_hwfn, p_ptt, dump_buf + offset, - dump, storm_id); - - /* Read RAM */ - for (i = 0; i < NUM_VFC_RAM_TYPES; i++) - offset += qed_grc_dump_vfc_ram(p_hwfn, - p_ptt, - dump_buf + - offset, - dump, - storm_id, - &s_vfc_ram_defs - [i]); - } + dump, + storm_id, + &s_vfc_ram_defs[i]); } return offset; @@ -3244,14 +3530,17 @@ static u32 qed_grc_dump_rss(struct qed_hwfn *p_hwfn, u8 rss_mem_id; for (rss_mem_id = 0; rss_mem_id < NUM_RSS_MEM_TYPES; rss_mem_id++) { - struct rss_mem_defs *rss_defs = &s_rss_mem_defs[rss_mem_id]; - u32 num_entries = rss_defs->num_entries[dev_data->chip_id]; - u32 entry_width = rss_defs->entry_width[dev_data->chip_id]; - u32 total_dwords = (num_entries * entry_width) / 32; - u32 size = RSS_REG_RSS_RAM_DATA_SIZE; - bool packed = (entry_width == 16); - u32 rss_addr = rss_defs->addr; - u32 i, addr; + u32 rss_addr, num_entries, entry_width, total_dwords, i; + struct rss_mem_defs *rss_defs; + u32 addr, size; + bool packed; + + rss_defs = &s_rss_mem_defs[rss_mem_id]; + rss_addr = rss_defs->addr; + num_entries = rss_defs->num_entries[dev_data->chip_id]; + entry_width = rss_defs->entry_width[dev_data->chip_id]; + total_dwords = (num_entries * entry_width) / 32; + packed = (entry_width == 16); offset += qed_grc_dump_mem_hdr(p_hwfn, dump_buf + offset, @@ -3263,23 +3552,23 @@ static u32 qed_grc_dump_rss(struct qed_hwfn *p_hwfn, packed, rss_defs->type_name, false, 0); + /* Dump RSS data */ if (!dump) { offset += total_dwords; continue; } - /* Dump RSS data */ - for (i = 0; i < total_dwords; - i += RSS_REG_RSS_RAM_DATA_SIZE, rss_addr++) { - addr = BYTES_TO_DWORDS(RSS_REG_RSS_RAM_DATA); + addr = BYTES_TO_DWORDS(RSS_REG_RSS_RAM_DATA); + size = RSS_REG_RSS_RAM_DATA_SIZE; + for (i = 0; i < total_dwords; i += size, rss_addr++) { qed_wr(p_hwfn, p_ptt, RSS_REG_RSS_RAM_ADDR, rss_addr); - offset += qed_grc_dump_addr_range(p_hwfn, - p_ptt, - dump_buf + - offset, - dump, - addr, - size); + offset += qed_grc_dump_addr_range(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + addr, + size, + false); } } @@ -3316,10 +3605,11 @@ static u32 qed_grc_dump_big_ram(struct qed_hwfn *p_hwfn, BIG_RAM_BLOCK_SIZE_BYTES * 8, false, type_name, false, 0); + /* Read and dump Big RAM data */ if (!dump) return offset + ram_size; - /* Read and dump Big RAM data */ + /* Dump Big RAM */ for (i = 0; i < total_blocks / 2; i++) { u32 addr, len; @@ -3331,7 +3621,8 @@ static u32 qed_grc_dump_big_ram(struct qed_hwfn *p_hwfn, dump_buf + offset, dump, addr, - len); + len, + false); } return offset; @@ -3359,7 +3650,7 @@ static u32 qed_grc_dump_mcp(struct qed_hwfn *p_hwfn, NULL, BYTES_TO_DWORDS(MCP_REG_SCRATCH), MCP_REG_SCRATCH_SIZE, - 0, false, "MCP", false, 0); + false, 0, false, "MCP", false, 0); /* Dump MCP cpu_reg_file */ offset += qed_grc_dump_mem(p_hwfn, @@ -3369,7 +3660,7 @@ static u32 qed_grc_dump_mcp(struct qed_hwfn *p_hwfn, NULL, BYTES_TO_DWORDS(MCP_REG_CPU_REG_FILE), MCP_REG_CPU_REG_FILE_SIZE, - 0, false, "MCP", false, 0); + false, 0, false, "MCP", false, 0); /* Dump MCP registers */ block_enable[BLOCK_MCP] = true; @@ -3387,11 +3678,13 @@ static u32 qed_grc_dump_mcp(struct qed_hwfn *p_hwfn, dump_buf + offset, dump, addr, - 1); + 1, + false); /* Release MCP */ if (halted && qed_mcp_resume(p_hwfn, p_ptt)) DP_NOTICE(p_hwfn, "Failed to resume MCP after halt!\n"); + return offset; } @@ -3404,14 +3697,26 @@ static u32 qed_grc_dump_phy(struct qed_hwfn *p_hwfn, u8 phy_id; for (phy_id = 0; phy_id < ARRAY_SIZE(s_phy_defs); phy_id++) { - struct phy_defs *phy_defs = &s_phy_defs[phy_id]; - int printed_chars; - - printed_chars = snprintf(mem_name, sizeof(mem_name), "tbus_%s", - phy_defs->phy_name); - if (printed_chars < 0 || printed_chars >= sizeof(mem_name)) + u32 addr_lo_addr, addr_hi_addr, data_lo_addr, data_hi_addr; + struct phy_defs *phy_defs; + u8 *bytes_buf; + + phy_defs = &s_phy_defs[phy_id]; + addr_lo_addr = phy_defs->base_addr + + phy_defs->tbus_addr_lo_addr; + addr_hi_addr = phy_defs->base_addr + + phy_defs->tbus_addr_hi_addr; + data_lo_addr = phy_defs->base_addr + + phy_defs->tbus_data_lo_addr; + data_hi_addr = phy_defs->base_addr + + phy_defs->tbus_data_hi_addr; + bytes_buf = (u8 *)(dump_buf + offset); + + if (snprintf(mem_name, sizeof(mem_name), "tbus_%s", + phy_defs->phy_name) < 0) DP_NOTICE(p_hwfn, "Unexpected debug error: invalid PHY memory name\n"); + offset += qed_grc_dump_mem_hdr(p_hwfn, dump_buf + offset, dump, @@ -3419,34 +3724,26 @@ static u32 qed_grc_dump_phy(struct qed_hwfn *p_hwfn, 0, PHY_DUMP_SIZE_DWORDS, 16, true, mem_name, false, 0); - if (dump) { - u32 addr_lo_addr = phy_defs->base_addr + - phy_defs->tbus_addr_lo_addr; - u32 addr_hi_addr = phy_defs->base_addr + - phy_defs->tbus_addr_hi_addr; - u32 data_lo_addr = phy_defs->base_addr + - phy_defs->tbus_data_lo_addr; - u32 data_hi_addr = phy_defs->base_addr + - phy_defs->tbus_data_hi_addr; - u8 *bytes_buf = (u8 *)(dump_buf + offset); - - for (tbus_hi_offset = 0; - tbus_hi_offset < (NUM_PHY_TBUS_ADDRESSES >> 8); - tbus_hi_offset++) { + + if (!dump) { + offset += PHY_DUMP_SIZE_DWORDS; + continue; + } + + for (tbus_hi_offset = 0; + tbus_hi_offset < (NUM_PHY_TBUS_ADDRESSES >> 8); + tbus_hi_offset++) { + qed_wr(p_hwfn, p_ptt, addr_hi_addr, tbus_hi_offset); + for (tbus_lo_offset = 0; tbus_lo_offset < 256; + tbus_lo_offset++) { qed_wr(p_hwfn, - p_ptt, addr_hi_addr, tbus_hi_offset); - for (tbus_lo_offset = 0; tbus_lo_offset < 256; - tbus_lo_offset++) { - qed_wr(p_hwfn, - p_ptt, - addr_lo_addr, tbus_lo_offset); - *(bytes_buf++) = - (u8)qed_rd(p_hwfn, p_ptt, - data_lo_addr); - *(bytes_buf++) = - (u8)qed_rd(p_hwfn, p_ptt, - data_hi_addr); - } + p_ptt, addr_lo_addr, tbus_lo_offset); + *(bytes_buf++) = (u8)qed_rd(p_hwfn, + p_ptt, + data_lo_addr); + *(bytes_buf++) = (u8)qed_rd(p_hwfn, + p_ptt, + data_hi_addr); } } @@ -3460,16 +3757,17 @@ static void qed_config_dbg_line(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, enum block_id block_id, u8 line_id, - u8 cycle_en, - u8 right_shift, u8 force_valid, u8 force_frame) + u8 enable_mask, + u8 right_shift, + u8 force_valid_mask, u8 force_frame_mask) { - struct block_defs *p_block_defs = s_block_defs[block_id]; + struct block_defs *block = s_block_defs[block_id]; - qed_wr(p_hwfn, p_ptt, p_block_defs->dbg_select_addr, line_id); - qed_wr(p_hwfn, p_ptt, p_block_defs->dbg_cycle_enable_addr, cycle_en); - qed_wr(p_hwfn, p_ptt, p_block_defs->dbg_shift_addr, right_shift); - qed_wr(p_hwfn, p_ptt, p_block_defs->dbg_force_valid_addr, force_valid); - qed_wr(p_hwfn, p_ptt, p_block_defs->dbg_force_frame_addr, force_frame); + qed_wr(p_hwfn, p_ptt, block->dbg_select_addr, line_id); + qed_wr(p_hwfn, p_ptt, block->dbg_enable_addr, enable_mask); + qed_wr(p_hwfn, p_ptt, block->dbg_shift_addr, right_shift); + qed_wr(p_hwfn, p_ptt, block->dbg_force_valid_addr, force_valid_mask); + qed_wr(p_hwfn, p_ptt, block->dbg_force_frame_addr, force_frame_mask); } /* Dumps Static Debug data. Returns the dumped size in dwords. */ @@ -3477,10 +3775,12 @@ static u32 qed_grc_dump_static_debug(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *dump_buf, bool dump) { - u32 block_dwords = NUM_DBG_BUS_LINES * STATIC_DEBUG_LINE_DWORDS; struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; - u32 offset = 0, block_id, line_id; - struct block_defs *p_block_defs; + u32 block_id, line_id, offset = 0; + + /* Skip static debug if a debug bus recording is in progress */ + if (qed_rd(p_hwfn, p_ptt, DBG_REG_DBG_BLOCK_ON)) + return 0; if (dump) { DP_VERBOSE(p_hwfn, @@ -3488,11 +3788,11 @@ static u32 qed_grc_dump_static_debug(struct qed_hwfn *p_hwfn, /* Disable all blocks debug output */ for (block_id = 0; block_id < MAX_BLOCK_ID; block_id++) { - p_block_defs = s_block_defs[block_id]; + struct block_defs *block = s_block_defs[block_id]; - if (p_block_defs->has_dbg_bus[dev_data->chip_id]) - qed_wr(p_hwfn, p_ptt, - p_block_defs->dbg_cycle_enable_addr, 0); + if (block->has_dbg_bus[dev_data->chip_id]) + qed_wr(p_hwfn, p_ptt, block->dbg_enable_addr, + 0); } qed_bus_reset_dbg_block(p_hwfn, p_ptt); @@ -3506,59 +3806,71 @@ static u32 qed_grc_dump_static_debug(struct qed_hwfn *p_hwfn, /* Dump all static debug lines for each relevant block */ for (block_id = 0; block_id < MAX_BLOCK_ID; block_id++) { - p_block_defs = s_block_defs[block_id]; + struct block_defs *block = s_block_defs[block_id]; + struct dbg_bus_block *block_desc; + u32 block_dwords, addr, len; + u8 dbg_client_id; - if (!p_block_defs->has_dbg_bus[dev_data->chip_id]) + if (!block->has_dbg_bus[dev_data->chip_id]) continue; + block_desc = + get_dbg_bus_block_desc(p_hwfn, + (enum block_id)block_id); + block_dwords = NUM_DBG_LINES(block_desc) * + STATIC_DEBUG_LINE_DWORDS; + /* Dump static section params */ offset += qed_grc_dump_mem_hdr(p_hwfn, dump_buf + offset, dump, - p_block_defs->name, 0, - block_dwords, 32, false, - "STATIC", false, 0); - - if (dump && !dev_data->block_in_reset[block_id]) { - u8 dbg_client_id = - p_block_defs->dbg_client_id[dev_data->chip_id]; - u32 addr = BYTES_TO_DWORDS(DBG_REG_CALENDAR_OUT_DATA); - u32 len = STATIC_DEBUG_LINE_DWORDS; - - /* Enable block's client */ - qed_bus_enable_clients(p_hwfn, p_ptt, - BIT(dbg_client_id)); - - for (line_id = 0; line_id < NUM_DBG_BUS_LINES; - line_id++) { - /* Configure debug line ID */ - qed_config_dbg_line(p_hwfn, - p_ptt, - (enum block_id)block_id, - (u8)line_id, - 0xf, 0, 0, 0); + block->name, + 0, + block_dwords, + 32, false, "STATIC", false, 0); - /* Read debug line info */ - offset += - qed_grc_dump_addr_range(p_hwfn, - p_ptt, - dump_buf + offset, - dump, - addr, - len); - } + if (!dump) { + offset += block_dwords; + continue; + } - /* Disable block's client and debug output */ - qed_bus_enable_clients(p_hwfn, p_ptt, 0); - qed_wr(p_hwfn, p_ptt, - p_block_defs->dbg_cycle_enable_addr, 0); - } else { - /* All lines are invalid - dump zeros */ - if (dump) - memset(dump_buf + offset, 0, - DWORDS_TO_BYTES(block_dwords)); + /* If all lines are invalid - dump zeros */ + if (dev_data->block_in_reset[block_id]) { + memset(dump_buf + offset, 0, + DWORDS_TO_BYTES(block_dwords)); offset += block_dwords; + continue; } + + /* Enable block's client */ + dbg_client_id = block->dbg_client_id[dev_data->chip_id]; + qed_bus_enable_clients(p_hwfn, + p_ptt, + BIT(dbg_client_id)); + + addr = BYTES_TO_DWORDS(DBG_REG_CALENDAR_OUT_DATA); + len = STATIC_DEBUG_LINE_DWORDS; + for (line_id = 0; line_id < (u32)NUM_DBG_LINES(block_desc); + line_id++) { + /* Configure debug line ID */ + qed_config_dbg_line(p_hwfn, + p_ptt, + (enum block_id)block_id, + (u8)line_id, 0xf, 0, 0, 0); + + /* Read debug line info */ + offset += qed_grc_dump_addr_range(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + addr, + len, + true); + } + + /* Disable block's client and debug output */ + qed_bus_enable_clients(p_hwfn, p_ptt, 0); + qed_wr(p_hwfn, p_ptt, block->dbg_enable_addr, 0); } if (dump) { @@ -3584,8 +3896,8 @@ static enum dbg_status qed_grc_dump(struct qed_hwfn *p_hwfn, *num_dumped_dwords = 0; - /* Find port mode */ if (dump) { + /* Find port mode */ switch (qed_rd(p_hwfn, p_ptt, MISC_REG_PORT_MODE)) { case 0: port_mode = 1; @@ -3597,11 +3909,10 @@ static enum dbg_status qed_grc_dump(struct qed_hwfn *p_hwfn, port_mode = 4; break; } - } - /* Update reset state */ - if (dump) + /* Update reset state */ qed_update_blocks_reset_state(p_hwfn, p_ptt); + } /* Dump global params */ offset += qed_dump_common_global_params(p_hwfn, @@ -3635,7 +3946,8 @@ static enum dbg_status qed_grc_dump(struct qed_hwfn *p_hwfn, } /* Disable all parities using MFW command */ - if (dump && !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_MCP)) { + if (dump && + !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_MCP)) { parities_masked = !qed_mcp_mask_parities(p_hwfn, p_ptt, 1); if (!parities_masked) { DP_NOTICE(p_hwfn, @@ -3661,9 +3973,9 @@ static enum dbg_status qed_grc_dump(struct qed_hwfn *p_hwfn, /* Dump all regs */ if (qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_REGS)) { - /* Dump all blocks except MCP */ bool block_enable[MAX_BLOCK_ID]; + /* Dump all blocks except MCP */ for (i = 0; i < MAX_BLOCK_ID; i++) block_enable[i] = true; block_enable[BLOCK_MCP] = false; @@ -3732,7 +4044,8 @@ static enum dbg_status qed_grc_dump(struct qed_hwfn *p_hwfn, dump_buf + offset, dump); /* Dump last section */ - offset += qed_dump_last_section(dump_buf, offset, dump); + offset += qed_dump_last_section(p_hwfn, dump_buf, offset, dump); + if (dump) { /* Unstall storms */ if (qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_UNSTALL)) @@ -3763,19 +4076,20 @@ static u32 qed_idle_chk_dump_failure(struct qed_hwfn *p_hwfn, const struct dbg_idle_chk_rule *rule, u16 fail_entry_id, u32 *cond_reg_values) { - const union dbg_idle_chk_reg *regs = &((const union dbg_idle_chk_reg *) - s_dbg_arrays - [BIN_BUF_DBG_IDLE_CHK_REGS]. - ptr)[rule->reg_offset]; - const struct dbg_idle_chk_cond_reg *cond_regs = ®s[0].cond_reg; struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; - struct dbg_idle_chk_result_hdr *hdr = - (struct dbg_idle_chk_result_hdr *)dump_buf; - const struct dbg_idle_chk_info_reg *info_regs = - ®s[rule->num_cond_regs].info_reg; - u32 next_reg_offset = 0, i, offset = 0; + const struct dbg_idle_chk_cond_reg *cond_regs; + const struct dbg_idle_chk_info_reg *info_regs; + u32 i, next_reg_offset = 0, offset = 0; + struct dbg_idle_chk_result_hdr *hdr; + const union dbg_idle_chk_reg *regs; u8 reg_id; + hdr = (struct dbg_idle_chk_result_hdr *)dump_buf; + regs = &((const union dbg_idle_chk_reg *) + s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_REGS].ptr)[rule->reg_offset]; + cond_regs = ®s[0].cond_reg; + info_regs = ®s[rule->num_cond_regs].info_reg; + /* Dump rule data */ if (dump) { memset(hdr, 0, sizeof(*hdr)); @@ -3790,33 +4104,31 @@ static u32 qed_idle_chk_dump_failure(struct qed_hwfn *p_hwfn, /* Dump condition register values */ for (reg_id = 0; reg_id < rule->num_cond_regs; reg_id++) { const struct dbg_idle_chk_cond_reg *reg = &cond_regs[reg_id]; + struct dbg_idle_chk_result_reg_hdr *reg_hdr; - /* Write register header */ - if (dump) { - struct dbg_idle_chk_result_reg_hdr *reg_hdr = - (struct dbg_idle_chk_result_reg_hdr *)(dump_buf - + offset); - offset += IDLE_CHK_RESULT_REG_HDR_DWORDS; - memset(reg_hdr, 0, - sizeof(struct dbg_idle_chk_result_reg_hdr)); - reg_hdr->start_entry = reg->start_entry; - reg_hdr->size = reg->entry_size; - SET_FIELD(reg_hdr->data, - DBG_IDLE_CHK_RESULT_REG_HDR_IS_MEM, - reg->num_entries > 1 || reg->start_entry > 0 - ? 1 : 0); - SET_FIELD(reg_hdr->data, - DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID, reg_id); + reg_hdr = (struct dbg_idle_chk_result_reg_hdr *) + (dump_buf + offset); - /* Write register values */ - for (i = 0; i < reg_hdr->size; - i++, next_reg_offset++, offset++) - dump_buf[offset] = - cond_reg_values[next_reg_offset]; - } else { + /* Write register header */ + if (!dump) { offset += IDLE_CHK_RESULT_REG_HDR_DWORDS + reg->entry_size; + continue; } + + offset += IDLE_CHK_RESULT_REG_HDR_DWORDS; + memset(reg_hdr, 0, sizeof(*reg_hdr)); + reg_hdr->start_entry = reg->start_entry; + reg_hdr->size = reg->entry_size; + SET_FIELD(reg_hdr->data, + DBG_IDLE_CHK_RESULT_REG_HDR_IS_MEM, + reg->num_entries > 1 || reg->start_entry > 0 ? 1 : 0); + SET_FIELD(reg_hdr->data, + DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID, reg_id); + + /* Write register values */ + for (i = 0; i < reg_hdr->size; i++, next_reg_offset++, offset++) + dump_buf[offset] = cond_reg_values[next_reg_offset]; } /* Dump info register values */ @@ -3824,12 +4136,12 @@ static u32 qed_idle_chk_dump_failure(struct qed_hwfn *p_hwfn, const struct dbg_idle_chk_info_reg *reg = &info_regs[reg_id]; u32 block_id; + /* Check if register's block is in reset */ if (!dump) { offset += IDLE_CHK_RESULT_REG_HDR_DWORDS + reg->size; continue; } - /* Check if register's block is in reset */ block_id = GET_FIELD(reg->data, DBG_IDLE_CHK_INFO_REG_BLOCK_ID); if (block_id >= MAX_BLOCK_ID) { DP_NOTICE(p_hwfn, "Invalid block_id\n"); @@ -3837,47 +4149,50 @@ static u32 qed_idle_chk_dump_failure(struct qed_hwfn *p_hwfn, } if (!dev_data->block_in_reset[block_id]) { - bool eval_mode = GET_FIELD(reg->mode.data, - DBG_MODE_HDR_EVAL_MODE) > 0; - bool mode_match = true; + struct dbg_idle_chk_result_reg_hdr *reg_hdr; + bool wide_bus, eval_mode, mode_match = true; + u16 modes_buf_offset; + u32 addr; + + reg_hdr = (struct dbg_idle_chk_result_reg_hdr *) + (dump_buf + offset); /* Check mode */ + eval_mode = GET_FIELD(reg->mode.data, + DBG_MODE_HDR_EVAL_MODE) > 0; if (eval_mode) { - u16 modes_buf_offset = - GET_FIELD(reg->mode.data, - DBG_MODE_HDR_MODES_BUF_OFFSET); + modes_buf_offset = + GET_FIELD(reg->mode.data, + DBG_MODE_HDR_MODES_BUF_OFFSET); mode_match = qed_is_mode_match(p_hwfn, &modes_buf_offset); } - if (mode_match) { - u32 addr = - GET_FIELD(reg->data, - DBG_IDLE_CHK_INFO_REG_ADDRESS); - - /* Write register header */ - struct dbg_idle_chk_result_reg_hdr *reg_hdr = - (struct dbg_idle_chk_result_reg_hdr *) - (dump_buf + offset); - - offset += IDLE_CHK_RESULT_REG_HDR_DWORDS; - hdr->num_dumped_info_regs++; - memset(reg_hdr, 0, sizeof(*reg_hdr)); - reg_hdr->size = reg->size; - SET_FIELD(reg_hdr->data, - DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID, - rule->num_cond_regs + reg_id); - - /* Write register values */ - offset += - qed_grc_dump_addr_range(p_hwfn, - p_ptt, - dump_buf + offset, - dump, - addr, - reg->size); - } + if (!mode_match) + continue; + + addr = GET_FIELD(reg->data, + DBG_IDLE_CHK_INFO_REG_ADDRESS); + wide_bus = GET_FIELD(reg->data, + DBG_IDLE_CHK_INFO_REG_WIDE_BUS); + + /* Write register header */ + offset += IDLE_CHK_RESULT_REG_HDR_DWORDS; + hdr->num_dumped_info_regs++; + memset(reg_hdr, 0, sizeof(*reg_hdr)); + reg_hdr->size = reg->size; + SET_FIELD(reg_hdr->data, + DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID, + rule->num_cond_regs + reg_id); + + /* Write register values */ + offset += qed_grc_dump_addr_range(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + addr, + reg->size, wide_bus); } } @@ -3898,6 +4213,7 @@ qed_idle_chk_dump_rule_entries(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u8 reg_id; *num_failing_rules = 0; + for (i = 0; i < num_input_rules; i++) { const struct dbg_idle_chk_cond_reg *cond_regs; const struct dbg_idle_chk_rule *rule; @@ -3920,8 +4236,9 @@ qed_idle_chk_dump_rule_entries(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, */ for (reg_id = 0; reg_id < rule->num_cond_regs && check_rule; reg_id++) { - u32 block_id = GET_FIELD(cond_regs[reg_id].data, - DBG_IDLE_CHK_COND_REG_BLOCK_ID); + u32 block_id = + GET_FIELD(cond_regs[reg_id].data, + DBG_IDLE_CHK_COND_REG_BLOCK_ID); if (block_id >= MAX_BLOCK_ID) { DP_NOTICE(p_hwfn, "Invalid block_id\n"); @@ -3936,48 +4253,47 @@ qed_idle_chk_dump_rule_entries(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, if (!check_rule && dump) continue; - if (!dump) { - u32 entry_dump_size = - qed_idle_chk_dump_failure(p_hwfn, - p_ptt, - dump_buf + offset, - false, - rule->rule_id, - rule, - 0, - NULL); - - offset += num_reg_entries * entry_dump_size; - (*num_failing_rules) += num_reg_entries; - continue; - } - /* Go over all register entries (number of entries is the same * for all condition registers). */ for (entry_id = 0; entry_id < num_reg_entries; entry_id++) { - /* Read current entry of all condition registers */ u32 next_reg_offset = 0; + if (!dump) { + offset += qed_idle_chk_dump_failure(p_hwfn, + p_ptt, + dump_buf + offset, + false, + rule->rule_id, + rule, + entry_id, + NULL); + (*num_failing_rules)++; + break; + } + + /* Read current entry of all condition registers */ for (reg_id = 0; reg_id < rule->num_cond_regs; reg_id++) { const struct dbg_idle_chk_cond_reg *reg = - &cond_regs[reg_id]; + &cond_regs[reg_id]; + u32 padded_entry_size, addr; + bool wide_bus; - /* Find GRC address (if it's a memory,the + /* Find GRC address (if it's a memory, the * address of the specific entry is calculated). */ - u32 addr = + addr = GET_FIELD(reg->data, + DBG_IDLE_CHK_COND_REG_ADDRESS); + wide_bus = GET_FIELD(reg->data, - DBG_IDLE_CHK_COND_REG_ADDRESS); - + DBG_IDLE_CHK_COND_REG_WIDE_BUS); if (reg->num_entries > 1 || reg->start_entry > 0) { - u32 padded_entry_size = - reg->entry_size > 1 ? - roundup_pow_of_two(reg->entry_size) : - 1; - + padded_entry_size = + reg->entry_size > 1 ? + roundup_pow_of_two(reg->entry_size) + : 1; addr += (reg->start_entry + entry_id) * padded_entry_size; } @@ -3991,28 +4307,27 @@ qed_idle_chk_dump_rule_entries(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, } next_reg_offset += - qed_grc_dump_addr_range(p_hwfn, - p_ptt, + qed_grc_dump_addr_range(p_hwfn, p_ptt, cond_reg_values + next_reg_offset, dump, addr, - reg->entry_size); + reg->entry_size, + wide_bus); } - /* Call rule's condition function - a return value of - * true indicates failure. + /* Call rule condition function. + * If returns true, it's a failure. */ - if ((*cond_arr[rule->cond_id])(cond_reg_values, - imm_values)) { - offset += - qed_idle_chk_dump_failure(p_hwfn, - p_ptt, - dump_buf + offset, - dump, - rule->rule_id, - rule, - entry_id, - cond_reg_values); + if ((*cond_arr[rule->cond_id]) (cond_reg_values, + imm_values)) { + offset += qed_idle_chk_dump_failure(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + rule->rule_id, + rule, + entry_id, + cond_reg_values); (*num_failing_rules)++; break; } @@ -4028,8 +4343,8 @@ qed_idle_chk_dump_rule_entries(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, static u32 qed_idle_chk_dump(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *dump_buf, bool dump) { - u32 offset = 0, input_offset = 0, num_failing_rules = 0; - u32 num_failing_rules_offset; + u32 num_failing_rules_offset, offset = 0, input_offset = 0; + u32 num_failing_rules = 0; /* Dump global params */ offset += qed_dump_common_global_params(p_hwfn, @@ -4042,29 +4357,29 @@ static u32 qed_idle_chk_dump(struct qed_hwfn *p_hwfn, offset += qed_dump_section_hdr(dump_buf + offset, dump, "idle_chk", 1); num_failing_rules_offset = offset; offset += qed_dump_num_param(dump_buf + offset, dump, "num_rules", 0); + while (input_offset < s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_RULES].size_in_dwords) { const struct dbg_idle_chk_cond_hdr *cond_hdr = (const struct dbg_idle_chk_cond_hdr *) &s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_RULES].ptr [input_offset++]; - bool eval_mode = GET_FIELD(cond_hdr->mode.data, - DBG_MODE_HDR_EVAL_MODE) > 0; - bool mode_match = true; + bool eval_mode, mode_match = true; + u32 curr_failing_rules; + u16 modes_buf_offset; /* Check mode */ + eval_mode = GET_FIELD(cond_hdr->mode.data, + DBG_MODE_HDR_EVAL_MODE) > 0; if (eval_mode) { - u16 modes_buf_offset = + modes_buf_offset = GET_FIELD(cond_hdr->mode.data, DBG_MODE_HDR_MODES_BUF_OFFSET); - mode_match = qed_is_mode_match(p_hwfn, &modes_buf_offset); } if (mode_match) { - u32 curr_failing_rules; - offset += qed_idle_chk_dump_rule_entries(p_hwfn, p_ptt, @@ -4086,10 +4401,13 @@ static u32 qed_idle_chk_dump(struct qed_hwfn *p_hwfn, qed_dump_num_param(dump_buf + num_failing_rules_offset, dump, "num_rules", num_failing_rules); + /* Dump last section */ + offset += qed_dump_last_section(p_hwfn, dump_buf, offset, dump); + return offset; } -/* Finds the meta data image in NVRAM. */ +/* Finds the meta data image in NVRAM */ static enum dbg_status qed_find_nvram_image(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 image_type, @@ -4098,16 +4416,16 @@ static enum dbg_status qed_find_nvram_image(struct qed_hwfn *p_hwfn, { u32 ret_mcp_resp, ret_mcp_param, ret_txn_size; struct mcp_file_att file_att; + int nvm_result; /* Call NVRAM get file command */ - int nvm_result = qed_mcp_nvm_rd_cmd(p_hwfn, - p_ptt, - DRV_MSG_CODE_NVM_GET_FILE_ATT, - image_type, - &ret_mcp_resp, - &ret_mcp_param, - &ret_txn_size, - (u32 *)&file_att); + nvm_result = qed_mcp_nvm_rd_cmd(p_hwfn, + p_ptt, + DRV_MSG_CODE_NVM_GET_FILE_ATT, + image_type, + &ret_mcp_resp, + &ret_mcp_param, + &ret_txn_size, (u32 *)&file_att); /* Check response */ if (nvm_result || @@ -4117,6 +4435,7 @@ static enum dbg_status qed_find_nvram_image(struct qed_hwfn *p_hwfn, /* Update return values */ *nvram_offset_bytes = file_att.nvm_start_addr; *nvram_size_bytes = file_att.len; + DP_VERBOSE(p_hwfn, QED_MSG_DEBUG, "find_nvram_image: found NVRAM image of type %d in NVRAM offset %d bytes with size %d bytes\n", @@ -4125,22 +4444,25 @@ static enum dbg_status qed_find_nvram_image(struct qed_hwfn *p_hwfn, /* Check alignment */ if (*nvram_size_bytes & 0x3) return DBG_STATUS_NON_ALIGNED_NVRAM_IMAGE; + return DBG_STATUS_OK; } +/* Reads data from NVRAM */ static enum dbg_status qed_nvram_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 nvram_offset_bytes, u32 nvram_size_bytes, u32 *ret_buf) { - u32 ret_mcp_resp, ret_mcp_param, ret_read_size; - u32 bytes_to_copy, read_offset = 0; + u32 ret_mcp_resp, ret_mcp_param, ret_read_size, bytes_to_copy; s32 bytes_left = nvram_size_bytes; + u32 read_offset = 0; DP_VERBOSE(p_hwfn, QED_MSG_DEBUG, "nvram_read: reading image of size %d bytes from NVRAM\n", nvram_size_bytes); + do { bytes_to_copy = (bytes_left > @@ -4155,8 +4477,7 @@ static enum dbg_status qed_nvram_read(struct qed_hwfn *p_hwfn, DRV_MB_PARAM_NVM_LEN_SHIFT), &ret_mcp_resp, &ret_mcp_param, &ret_read_size, - (u32 *)((u8 *)ret_buf + - read_offset)) != 0) + (u32 *)((u8 *)ret_buf + read_offset))) return DBG_STATUS_NVRAM_READ_FAILED; /* Check response */ @@ -4172,24 +4493,20 @@ static enum dbg_status qed_nvram_read(struct qed_hwfn *p_hwfn, } /* Get info on the MCP Trace data in the scratchpad: - * - trace_data_grc_addr - the GRC address of the trace data - * - trace_data_size_bytes - the size in bytes of the MCP Trace data (without - * the header) + * - trace_data_grc_addr (OUT): trace data GRC address in bytes + * - trace_data_size (OUT): trace data size in bytes (without the header) */ static enum dbg_status qed_mcp_trace_get_data_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *trace_data_grc_addr, - u32 *trace_data_size_bytes) + u32 *trace_data_size) { - /* Read MCP trace section offsize structure from MCP scratchpad */ - u32 spad_trace_offsize = qed_rd(p_hwfn, - p_ptt, - MCP_SPAD_TRACE_OFFSIZE_ADDR); - u32 signature; + u32 spad_trace_offsize, signature; - /* Extract MCP trace section GRC address from offsize structure (within - * scratchpad). - */ + /* Read trace section offsize structure from MCP scratchpad */ + spad_trace_offsize = qed_rd(p_hwfn, p_ptt, MCP_SPAD_TRACE_OFFSIZE_ADDR); + + /* Extract trace section address from offsize (in scratchpad) */ *trace_data_grc_addr = MCP_REG_SCRATCH + SECTION_OFFSET(spad_trace_offsize); @@ -4197,42 +4514,41 @@ static enum dbg_status qed_mcp_trace_get_data_info(struct qed_hwfn *p_hwfn, signature = qed_rd(p_hwfn, p_ptt, *trace_data_grc_addr + offsetof(struct mcp_trace, signature)); + if (signature != MFW_TRACE_SIGNATURE) return DBG_STATUS_INVALID_TRACE_SIGNATURE; /* Read trace size from MCP trace section */ - *trace_data_size_bytes = qed_rd(p_hwfn, - p_ptt, - *trace_data_grc_addr + - offsetof(struct mcp_trace, size)); + *trace_data_size = qed_rd(p_hwfn, + p_ptt, + *trace_data_grc_addr + + offsetof(struct mcp_trace, size)); + return DBG_STATUS_OK; } -/* Reads MCP trace meta data image from NVRAM. - * - running_bundle_id (OUT) - the running bundle ID (invalid when loaded from - * file) - * - trace_meta_offset_bytes (OUT) - the NVRAM offset in bytes in which the MCP - * Trace meta data starts (invalid when loaded from file) - * - trace_meta_size_bytes (OUT) - the size in bytes of the MCP Trace meta data +/* Reads MCP trace meta data image from NVRAM + * - running_bundle_id (OUT): running bundle ID (invalid when loaded from file) + * - trace_meta_offset (OUT): trace meta offset in NVRAM in bytes (invalid when + * loaded from file). + * - trace_meta_size (OUT): size in bytes of the trace meta data. */ static enum dbg_status qed_mcp_trace_get_meta_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 trace_data_size_bytes, u32 *running_bundle_id, - u32 *trace_meta_offset_bytes, - u32 *trace_meta_size_bytes) + u32 *trace_meta_offset, + u32 *trace_meta_size) { + u32 spad_trace_offsize, nvram_image_type, running_mfw_addr; + /* Read MCP trace section offsize structure from MCP scratchpad */ - u32 spad_trace_offsize = qed_rd(p_hwfn, - p_ptt, - MCP_SPAD_TRACE_OFFSIZE_ADDR); + spad_trace_offsize = qed_rd(p_hwfn, p_ptt, MCP_SPAD_TRACE_OFFSIZE_ADDR); /* Find running bundle ID */ - u32 running_mfw_addr = + running_mfw_addr = MCP_REG_SCRATCH + SECTION_OFFSET(spad_trace_offsize) + QED_SECTION_SIZE(spad_trace_offsize) + trace_data_size_bytes; - u32 nvram_image_type; - *running_bundle_id = qed_rd(p_hwfn, p_ptt, running_mfw_addr); if (*running_bundle_id > 1) return DBG_STATUS_INVALID_NVRAM_BUNDLE; @@ -4241,40 +4557,33 @@ static enum dbg_status qed_mcp_trace_get_meta_info(struct qed_hwfn *p_hwfn, nvram_image_type = (*running_bundle_id == DIR_ID_1) ? NVM_TYPE_MFW_TRACE1 : NVM_TYPE_MFW_TRACE2; - return qed_find_nvram_image(p_hwfn, p_ptt, nvram_image_type, - trace_meta_offset_bytes, - trace_meta_size_bytes); + trace_meta_offset, trace_meta_size); } -/* Reads the MCP Trace meta data (from NVRAM or buffer) into the specified - * buffer. - */ +/* Reads the MCP Trace meta data from NVRAM into the specified buffer */ static enum dbg_status qed_mcp_trace_read_meta(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 nvram_offset_in_bytes, u32 size_in_bytes, u32 *buf) { - u8 *byte_buf = (u8 *)buf; - u8 modules_num, i; + u8 modules_num, module_len, i, *byte_buf = (u8 *)buf; + enum dbg_status status; u32 signature; /* Read meta data from NVRAM */ - enum dbg_status status = qed_nvram_read(p_hwfn, - p_ptt, - nvram_offset_in_bytes, - size_in_bytes, - buf); - + status = qed_nvram_read(p_hwfn, + p_ptt, + nvram_offset_in_bytes, size_in_bytes, buf); if (status != DBG_STATUS_OK) return status; /* Extract and check first signature */ signature = qed_read_unaligned_dword(byte_buf); - byte_buf += sizeof(u32); - if (signature != MCP_TRACE_META_IMAGE_SIGNATURE) + byte_buf += sizeof(signature); + if (signature != NVM_MAGIC_VALUE) return DBG_STATUS_INVALID_TRACE_SIGNATURE; /* Extract number of modules */ @@ -4282,16 +4591,16 @@ static enum dbg_status qed_mcp_trace_read_meta(struct qed_hwfn *p_hwfn, /* Skip all modules */ for (i = 0; i < modules_num; i++) { - u8 module_len = *(byte_buf++); - + module_len = *(byte_buf++); byte_buf += module_len; } /* Extract and check second signature */ signature = qed_read_unaligned_dword(byte_buf); - byte_buf += sizeof(u32); - if (signature != MCP_TRACE_META_IMAGE_SIGNATURE) + byte_buf += sizeof(signature); + if (signature != NVM_MAGIC_VALUE) return DBG_STATUS_INVALID_TRACE_SIGNATURE; + return DBG_STATUS_OK; } @@ -4308,10 +4617,10 @@ static enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn, bool mcp_access; int halted = 0; - mcp_access = !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_MCP); - *num_dumped_dwords = 0; + mcp_access = !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_MCP); + /* Get trace data info */ status = qed_mcp_trace_get_data_info(p_hwfn, p_ptt, @@ -4328,7 +4637,7 @@ static enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn, dump, "dump-type", "mcp-trace"); /* Halt MCP while reading from scratchpad so the read data will be - * consistent if halt fails, MCP trace is taken anyway, with a small + * consistent. if halt fails, MCP trace is taken anyway, with a small * risk that it may be corrupt. */ if (dump && mcp_access) { @@ -4339,8 +4648,8 @@ static enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn, /* Find trace data size */ trace_data_size_dwords = - DIV_ROUND_UP(trace_data_size_bytes + sizeof(struct mcp_trace), - BYTES_IN_DWORD); + DIV_ROUND_UP(trace_data_size_bytes + sizeof(struct mcp_trace), + BYTES_IN_DWORD); /* Dump trace data section header and param */ offset += qed_dump_section_hdr(dump_buf + offset, @@ -4354,17 +4663,17 @@ static enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn, dump_buf + offset, dump, BYTES_TO_DWORDS(trace_data_grc_addr), - trace_data_size_dwords); + trace_data_size_dwords, false); /* Resume MCP (only if halt succeeded) */ - if (halted && qed_mcp_resume(p_hwfn, p_ptt) != 0) + if (halted && qed_mcp_resume(p_hwfn, p_ptt)) DP_NOTICE(p_hwfn, "Failed to resume MCP after halt!\n"); /* Dump trace meta section header */ offset += qed_dump_section_hdr(dump_buf + offset, dump, "mcp_trace_meta", 1); - /* Read trace meta info */ + /* Read trace meta info (trace_meta_size_bytes is dword-aligned) */ if (mcp_access) { status = qed_mcp_trace_get_meta_info(p_hwfn, p_ptt, @@ -4391,6 +4700,9 @@ static enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn, if (status == DBG_STATUS_OK) offset += trace_meta_size_dwords; + /* Dump last section */ + offset += qed_dump_last_section(p_hwfn, dump_buf, offset, dump); + *num_dumped_dwords = offset; /* If no mcp access, indicate that the dump doesn't contain the meta @@ -4405,7 +4717,7 @@ static enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, bool dump, u32 *num_dumped_dwords) { - u32 offset = 0, dwords_read, size_param_offset; + u32 dwords_read, size_param_offset, offset = 0; bool fifo_has_data; *num_dumped_dwords = 0; @@ -4417,8 +4729,8 @@ static enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn, offset += qed_dump_str_param(dump_buf + offset, dump, "dump-type", "reg-fifo"); - /* Dump fifo data section header and param. The size param is 0 for now, - * and is overwritten after reading the FIFO. + /* Dump fifo data section header and param. The size param is 0 for + * now, and is overwritten after reading the FIFO. */ offset += qed_dump_section_hdr(dump_buf + offset, dump, "reg_fifo_data", 1); @@ -4430,8 +4742,7 @@ static enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn, * test how much data is available, except for reading it. */ offset += REG_FIFO_DEPTH_DWORDS; - *num_dumped_dwords = offset; - return DBG_STATUS_OK; + goto out; } fifo_has_data = qed_rd(p_hwfn, p_ptt, @@ -4456,8 +4767,12 @@ static enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn, qed_dump_num_param(dump_buf + size_param_offset, dump, "size", dwords_read); +out: + /* Dump last section */ + offset += qed_dump_last_section(p_hwfn, dump_buf, offset, dump); *num_dumped_dwords = offset; + return DBG_STATUS_OK; } @@ -4467,7 +4782,7 @@ static enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, bool dump, u32 *num_dumped_dwords) { - u32 offset = 0, dwords_read, size_param_offset; + u32 dwords_read, size_param_offset, offset = 0; bool fifo_has_data; *num_dumped_dwords = 0; @@ -4479,8 +4794,8 @@ static enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn, offset += qed_dump_str_param(dump_buf + offset, dump, "dump-type", "igu-fifo"); - /* Dump fifo data section header and param. The size param is 0 for now, - * and is overwritten after reading the FIFO. + /* Dump fifo data section header and param. The size param is 0 for + * now, and is overwritten after reading the FIFO. */ offset += qed_dump_section_hdr(dump_buf + offset, dump, "igu_fifo_data", 1); @@ -4492,8 +4807,7 @@ static enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn, * test how much data is available, except for reading it. */ offset += IGU_FIFO_DEPTH_DWORDS; - *num_dumped_dwords = offset; - return DBG_STATUS_OK; + goto out; } fifo_has_data = qed_rd(p_hwfn, p_ptt, @@ -4519,8 +4833,12 @@ static enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn, qed_dump_num_param(dump_buf + size_param_offset, dump, "size", dwords_read); +out: + /* Dump last section */ + offset += qed_dump_last_section(p_hwfn, dump_buf, offset, dump); *num_dumped_dwords = offset; + return DBG_STATUS_OK; } @@ -4531,7 +4849,7 @@ static enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn, bool dump, u32 *num_dumped_dwords) { - u32 offset = 0, size_param_offset, override_window_dwords; + u32 size_param_offset, override_window_dwords, offset = 0; *num_dumped_dwords = 0; @@ -4542,8 +4860,8 @@ static enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn, offset += qed_dump_str_param(dump_buf + offset, dump, "dump-type", "protection-override"); - /* Dump data section header and param. The size param is 0 for now, and - * is overwritten after reading the data. + /* Dump data section header and param. The size param is 0 for now, + * and is overwritten after reading the data. */ offset += qed_dump_section_hdr(dump_buf + offset, dump, "protection_override_data", 1); @@ -4552,8 +4870,7 @@ static enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn, if (!dump) { offset += PROTECTION_OVERRIDE_DEPTH_DWORDS; - *num_dumped_dwords = offset; - return DBG_STATUS_OK; + goto out; } /* Add override window info to buffer */ @@ -4569,8 +4886,12 @@ static enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn, offset += override_window_dwords; qed_dump_num_param(dump_buf + size_param_offset, dump, "size", override_window_dwords); +out: + /* Dump last section */ + offset += qed_dump_last_section(p_hwfn, dump_buf, offset, dump); *num_dumped_dwords = offset; + return DBG_STATUS_OK; } @@ -4593,11 +4914,14 @@ static u32 qed_fw_asserts_dump(struct qed_hwfn *p_hwfn, dump_buf + offset, dump, 1); offset += qed_dump_str_param(dump_buf + offset, dump, "dump-type", "fw-asserts"); + + /* Find Storm dump size */ for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) { u32 fw_asserts_section_addr, next_list_idx_addr, next_list_idx; + struct storm_defs *storm = &s_storm_defs[storm_id]; u32 last_list_idx, addr; - if (dev_data->block_in_reset[s_storm_defs[storm_id].block_id]) + if (dev_data->block_in_reset[storm->block_id]) continue; /* Read FW info for the current Storm */ @@ -4606,26 +4930,26 @@ static u32 qed_fw_asserts_dump(struct qed_hwfn *p_hwfn, asserts = &fw_info.fw_asserts_section; /* Dump FW Asserts section header and params */ - storm_letter_str[0] = s_storm_defs[storm_id].letter; - offset += qed_dump_section_hdr(dump_buf + offset, dump, - "fw_asserts", 2); - offset += qed_dump_str_param(dump_buf + offset, dump, "storm", - storm_letter_str); - offset += qed_dump_num_param(dump_buf + offset, dump, "size", + storm_letter_str[0] = storm->letter; + offset += qed_dump_section_hdr(dump_buf + offset, + dump, "fw_asserts", 2); + offset += qed_dump_str_param(dump_buf + offset, + dump, "storm", storm_letter_str); + offset += qed_dump_num_param(dump_buf + offset, + dump, + "size", asserts->list_element_dword_size); + /* Read and dump FW Asserts data */ if (!dump) { offset += asserts->list_element_dword_size; continue; } - /* Read and dump FW Asserts data */ - fw_asserts_section_addr = - s_storm_defs[storm_id].sem_fast_mem_addr + + fw_asserts_section_addr = storm->sem_fast_mem_addr + SEM_FAST_REG_INT_RAM + RAM_LINES_TO_BYTES(asserts->section_ram_line_offset); - next_list_idx_addr = - fw_asserts_section_addr + + next_list_idx_addr = fw_asserts_section_addr + DWORDS_TO_BYTES(asserts->list_next_index_dword_offset); next_list_idx = qed_rd(p_hwfn, p_ptt, next_list_idx_addr); last_list_idx = (next_list_idx > 0 @@ -4638,11 +4962,13 @@ static u32 qed_fw_asserts_dump(struct qed_hwfn *p_hwfn, qed_grc_dump_addr_range(p_hwfn, p_ptt, dump_buf + offset, dump, addr, - asserts->list_element_dword_size); + asserts->list_element_dword_size, + false); } /* Dump last section */ - offset += qed_dump_section_hdr(dump_buf + offset, dump, "last", 0); + offset += qed_dump_last_section(p_hwfn, dump_buf, offset, dump); + return offset; } @@ -4650,10 +4976,10 @@ static u32 qed_fw_asserts_dump(struct qed_hwfn *p_hwfn, enum dbg_status qed_dbg_set_bin_ptr(const u8 * const bin_ptr) { - /* Convert binary data to debug arrays */ struct bin_buffer_hdr *buf_array = (struct bin_buffer_hdr *)bin_ptr; u8 buf_id; + /* convert binary data to debug arrays */ for (buf_id = 0; buf_id < MAX_BIN_DBG_BUFFER_TYPE; buf_id++) { s_dbg_arrays[buf_id].ptr = (u32 *)(bin_ptr + buf_array[buf_id].offset); @@ -4682,14 +5008,17 @@ enum dbg_status qed_dbg_grc_get_dump_buf_size(struct qed_hwfn *p_hwfn, enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); *buf_size = 0; + if (status != DBG_STATUS_OK) return status; + if (!s_dbg_arrays[BIN_BUF_DBG_MODE_TREE].ptr || !s_dbg_arrays[BIN_BUF_DBG_DUMP_REG].ptr || !s_dbg_arrays[BIN_BUF_DBG_DUMP_MEM].ptr || !s_dbg_arrays[BIN_BUF_DBG_ATTN_BLOCKS].ptr || !s_dbg_arrays[BIN_BUF_DBG_ATTN_REGS].ptr) return DBG_STATUS_DBG_ARRAY_NOT_SET; + return qed_grc_dump(p_hwfn, p_ptt, NULL, false, buf_size); } @@ -4702,12 +5031,14 @@ enum dbg_status qed_dbg_grc_dump(struct qed_hwfn *p_hwfn, u32 needed_buf_size_in_dwords; enum dbg_status status; - status = qed_dbg_grc_get_dump_buf_size(p_hwfn, p_ptt, - &needed_buf_size_in_dwords); - *num_dumped_dwords = 0; + + status = qed_dbg_grc_get_dump_buf_size(p_hwfn, + p_ptt, + &needed_buf_size_in_dwords); if (status != DBG_STATUS_OK) return status; + if (buf_size_in_dwords < needed_buf_size_in_dwords) return DBG_STATUS_DUMP_BUF_TOO_SMALL; @@ -4724,25 +5055,31 @@ enum dbg_status qed_dbg_idle_chk_get_dump_buf_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *buf_size) { - enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; + struct idle_chk_data *idle_chk; + enum dbg_status status; + idle_chk = &dev_data->idle_chk; *buf_size = 0; + + status = qed_dbg_dev_init(p_hwfn, p_ptt); if (status != DBG_STATUS_OK) return status; + if (!s_dbg_arrays[BIN_BUF_DBG_MODE_TREE].ptr || !s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_REGS].ptr || !s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_IMMS].ptr || !s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_RULES].ptr) return DBG_STATUS_DBG_ARRAY_NOT_SET; - if (!dev_data->idle_chk.buf_size_set) { - dev_data->idle_chk.buf_size = qed_idle_chk_dump(p_hwfn, - p_ptt, - NULL, false); - dev_data->idle_chk.buf_size_set = true; + + if (!idle_chk->buf_size_set) { + idle_chk->buf_size = qed_idle_chk_dump(p_hwfn, + p_ptt, NULL, false); + idle_chk->buf_size_set = true; } - *buf_size = dev_data->idle_chk.buf_size; + *buf_size = idle_chk->buf_size; + return DBG_STATUS_OK; } @@ -4755,12 +5092,14 @@ enum dbg_status qed_dbg_idle_chk_dump(struct qed_hwfn *p_hwfn, u32 needed_buf_size_in_dwords; enum dbg_status status; - status = qed_dbg_idle_chk_get_dump_buf_size(p_hwfn, p_ptt, - &needed_buf_size_in_dwords); - *num_dumped_dwords = 0; + + status = qed_dbg_idle_chk_get_dump_buf_size(p_hwfn, + p_ptt, + &needed_buf_size_in_dwords); if (status != DBG_STATUS_OK) return status; + if (buf_size_in_dwords < needed_buf_size_in_dwords) return DBG_STATUS_DUMP_BUF_TOO_SMALL; @@ -4783,8 +5122,10 @@ enum dbg_status qed_dbg_mcp_trace_get_dump_buf_size(struct qed_hwfn *p_hwfn, enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); *buf_size = 0; + if (status != DBG_STATUS_OK) return status; + return qed_mcp_trace_dump(p_hwfn, p_ptt, NULL, false, buf_size); } @@ -4797,13 +5138,12 @@ enum dbg_status qed_dbg_mcp_trace_dump(struct qed_hwfn *p_hwfn, u32 needed_buf_size_in_dwords; enum dbg_status status; - /* validate buffer size */ status = - qed_dbg_mcp_trace_get_dump_buf_size(p_hwfn, p_ptt, - &needed_buf_size_in_dwords); - - if (status != DBG_STATUS_OK && - status != DBG_STATUS_NVRAM_GET_IMAGE_FAILED) + qed_dbg_mcp_trace_get_dump_buf_size(p_hwfn, + p_ptt, + &needed_buf_size_in_dwords); + if (status != DBG_STATUS_OK && status != + DBG_STATUS_NVRAM_GET_IMAGE_FAILED) return status; if (buf_size_in_dwords < needed_buf_size_in_dwords) @@ -4829,8 +5169,10 @@ enum dbg_status qed_dbg_reg_fifo_get_dump_buf_size(struct qed_hwfn *p_hwfn, enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); *buf_size = 0; + if (status != DBG_STATUS_OK) return status; + return qed_reg_fifo_dump(p_hwfn, p_ptt, NULL, false, buf_size); } @@ -4843,12 +5185,14 @@ enum dbg_status qed_dbg_reg_fifo_dump(struct qed_hwfn *p_hwfn, u32 needed_buf_size_in_dwords; enum dbg_status status; - status = qed_dbg_reg_fifo_get_dump_buf_size(p_hwfn, p_ptt, - &needed_buf_size_in_dwords); - *num_dumped_dwords = 0; + + status = qed_dbg_reg_fifo_get_dump_buf_size(p_hwfn, + p_ptt, + &needed_buf_size_in_dwords); if (status != DBG_STATUS_OK) return status; + if (buf_size_in_dwords < needed_buf_size_in_dwords) return DBG_STATUS_DUMP_BUF_TOO_SMALL; @@ -4871,8 +5215,10 @@ enum dbg_status qed_dbg_igu_fifo_get_dump_buf_size(struct qed_hwfn *p_hwfn, enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); *buf_size = 0; + if (status != DBG_STATUS_OK) return status; + return qed_igu_fifo_dump(p_hwfn, p_ptt, NULL, false, buf_size); } @@ -4885,12 +5231,14 @@ enum dbg_status qed_dbg_igu_fifo_dump(struct qed_hwfn *p_hwfn, u32 needed_buf_size_in_dwords; enum dbg_status status; - status = qed_dbg_igu_fifo_get_dump_buf_size(p_hwfn, p_ptt, - &needed_buf_size_in_dwords); - *num_dumped_dwords = 0; + + status = qed_dbg_igu_fifo_get_dump_buf_size(p_hwfn, + p_ptt, + &needed_buf_size_in_dwords); if (status != DBG_STATUS_OK) return status; + if (buf_size_in_dwords < needed_buf_size_in_dwords) return DBG_STATUS_DUMP_BUF_TOO_SMALL; @@ -4913,8 +5261,10 @@ qed_dbg_protection_override_get_dump_buf_size(struct qed_hwfn *p_hwfn, enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); *buf_size = 0; + if (status != DBG_STATUS_OK) return status; + return qed_protection_override_dump(p_hwfn, p_ptt, NULL, false, buf_size); } @@ -4925,15 +5275,18 @@ enum dbg_status qed_dbg_protection_override_dump(struct qed_hwfn *p_hwfn, u32 buf_size_in_dwords, u32 *num_dumped_dwords) { - u32 needed_buf_size_in_dwords; + u32 needed_buf_size_in_dwords, *p_size = &needed_buf_size_in_dwords; enum dbg_status status; - status = qed_dbg_protection_override_get_dump_buf_size(p_hwfn, p_ptt, - &needed_buf_size_in_dwords); - *num_dumped_dwords = 0; + + status = + qed_dbg_protection_override_get_dump_buf_size(p_hwfn, + p_ptt, + p_size); if (status != DBG_STATUS_OK) return status; + if (buf_size_in_dwords < needed_buf_size_in_dwords) return DBG_STATUS_DUMP_BUF_TOO_SMALL; @@ -4958,12 +5311,15 @@ enum dbg_status qed_dbg_fw_asserts_get_dump_buf_size(struct qed_hwfn *p_hwfn, enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); *buf_size = 0; + if (status != DBG_STATUS_OK) return status; /* Update reset state */ qed_update_blocks_reset_state(p_hwfn, p_ptt); + *buf_size = qed_fw_asserts_dump(p_hwfn, p_ptt, NULL, false); + return DBG_STATUS_OK; } @@ -4973,24 +5329,108 @@ enum dbg_status qed_dbg_fw_asserts_dump(struct qed_hwfn *p_hwfn, u32 buf_size_in_dwords, u32 *num_dumped_dwords) { - u32 needed_buf_size_in_dwords; + u32 needed_buf_size_in_dwords, *p_size = &needed_buf_size_in_dwords; enum dbg_status status; - status = qed_dbg_fw_asserts_get_dump_buf_size(p_hwfn, p_ptt, - &needed_buf_size_in_dwords); - *num_dumped_dwords = 0; + + status = + qed_dbg_fw_asserts_get_dump_buf_size(p_hwfn, + p_ptt, + p_size); if (status != DBG_STATUS_OK) return status; + if (buf_size_in_dwords < needed_buf_size_in_dwords) return DBG_STATUS_DUMP_BUF_TOO_SMALL; *num_dumped_dwords = qed_fw_asserts_dump(p_hwfn, p_ptt, dump_buf, true); + + /* Revert GRC params to their default */ + qed_dbg_grc_set_params_default(p_hwfn); + + return DBG_STATUS_OK; +} + +enum dbg_status qed_dbg_read_attn(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum block_id block_id, + enum dbg_attn_type attn_type, + bool clear_status, + struct dbg_attn_block_result *results) +{ + enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); + u8 reg_idx, num_attn_regs, num_result_regs = 0; + const struct dbg_attn_reg *attn_reg_arr; + + if (status != DBG_STATUS_OK) + return status; + + if (!s_dbg_arrays[BIN_BUF_DBG_MODE_TREE].ptr || + !s_dbg_arrays[BIN_BUF_DBG_ATTN_BLOCKS].ptr || + !s_dbg_arrays[BIN_BUF_DBG_ATTN_REGS].ptr) + return DBG_STATUS_DBG_ARRAY_NOT_SET; + + attn_reg_arr = qed_get_block_attn_regs(block_id, + attn_type, &num_attn_regs); + + for (reg_idx = 0; reg_idx < num_attn_regs; reg_idx++) { + const struct dbg_attn_reg *reg_data = &attn_reg_arr[reg_idx]; + struct dbg_attn_reg_result *reg_result; + u32 sts_addr, sts_val; + u16 modes_buf_offset; + bool eval_mode; + + /* Check mode */ + eval_mode = GET_FIELD(reg_data->mode.data, + DBG_MODE_HDR_EVAL_MODE) > 0; + modes_buf_offset = GET_FIELD(reg_data->mode.data, + DBG_MODE_HDR_MODES_BUF_OFFSET); + if (eval_mode && !qed_is_mode_match(p_hwfn, &modes_buf_offset)) + continue; + + /* Mode match - read attention status register */ + sts_addr = DWORDS_TO_BYTES(clear_status ? + reg_data->sts_clr_address : + GET_FIELD(reg_data->data, + DBG_ATTN_REG_STS_ADDRESS)); + sts_val = qed_rd(p_hwfn, p_ptt, sts_addr); + if (!sts_val) + continue; + + /* Non-zero attention status - add to results */ + reg_result = &results->reg_results[num_result_regs]; + SET_FIELD(reg_result->data, + DBG_ATTN_REG_RESULT_STS_ADDRESS, sts_addr); + SET_FIELD(reg_result->data, + DBG_ATTN_REG_RESULT_NUM_REG_ATTN, + GET_FIELD(reg_data->data, DBG_ATTN_REG_NUM_REG_ATTN)); + reg_result->block_attn_offset = reg_data->block_attn_offset; + reg_result->sts_val = sts_val; + reg_result->mask_val = qed_rd(p_hwfn, + p_ptt, + DWORDS_TO_BYTES + (reg_data->mask_address)); + num_result_regs++; + } + + results->block_id = (u8)block_id; + results->names_offset = + qed_get_block_attn_data(block_id, attn_type)->names_offset; + SET_FIELD(results->data, DBG_ATTN_BLOCK_RESULT_ATTN_TYPE, attn_type); + SET_FIELD(results->data, + DBG_ATTN_BLOCK_RESULT_NUM_REGS, num_result_regs); + return DBG_STATUS_OK; } /******************************* Data Types **********************************/ +struct block_info { + const char *name; + enum block_id id; +}; + struct mcp_trace_format { u32 data; #define MCP_TRACE_FORMAT_MODULE_MASK 0x0000ffff @@ -5005,9 +5445,14 @@ struct mcp_trace_format { #define MCP_TRACE_FORMAT_P3_SIZE_SHIFT 22 #define MCP_TRACE_FORMAT_LEN_MASK 0xff000000 #define MCP_TRACE_FORMAT_LEN_SHIFT 24 + char *format_str; }; +/* Meta data structure, generated by a perl script during MFW build. therefore, + * the structs mcp_trace_meta and mcp_trace_format are duplicated in the perl + * script. + */ struct mcp_trace_meta { u32 modules_num; char **modules; @@ -5015,7 +5460,7 @@ struct mcp_trace_meta { struct mcp_trace_format *formats; }; -/* Reg fifo element */ +/* REG fifo element */ struct reg_fifo_element { u64 data; #define REG_FIFO_ELEMENT_ADDRESS_SHIFT 0 @@ -5140,12 +5585,15 @@ struct igu_fifo_addr_data { /******************************** Constants **********************************/ #define MAX_MSG_LEN 1024 + #define MCP_TRACE_MAX_MODULE_LEN 8 #define MCP_TRACE_FORMAT_MAX_PARAMS 3 #define MCP_TRACE_FORMAT_PARAM_WIDTH \ (MCP_TRACE_FORMAT_P2_SIZE_SHIFT - MCP_TRACE_FORMAT_P1_SIZE_SHIFT) + #define REG_FIFO_ELEMENT_ADDR_FACTOR 4 #define REG_FIFO_ELEMENT_IS_PF_VF_VAL 127 + #define PROTECTION_OVERRIDE_ELEMENT_ADDR_FACTOR 4 /********************************* Macros ************************************/ @@ -5154,59 +5602,269 @@ struct igu_fifo_addr_data { /***************************** Constant Arrays *******************************/ +struct user_dbg_array { + const u32 *ptr; + u32 size_in_dwords; +}; + +/* Debug arrays */ +static struct user_dbg_array +s_user_dbg_arrays[MAX_BIN_DBG_BUFFER_TYPE] = { {NULL} }; + +/* Block names array */ +static struct block_info s_block_info_arr[] = { + {"grc", BLOCK_GRC}, + {"miscs", BLOCK_MISCS}, + {"misc", BLOCK_MISC}, + {"dbu", BLOCK_DBU}, + {"pglue_b", BLOCK_PGLUE_B}, + {"cnig", BLOCK_CNIG}, + {"cpmu", BLOCK_CPMU}, + {"ncsi", BLOCK_NCSI}, + {"opte", BLOCK_OPTE}, + {"bmb", BLOCK_BMB}, + {"pcie", BLOCK_PCIE}, + {"mcp", BLOCK_MCP}, + {"mcp2", BLOCK_MCP2}, + {"pswhst", BLOCK_PSWHST}, + {"pswhst2", BLOCK_PSWHST2}, + {"pswrd", BLOCK_PSWRD}, + {"pswrd2", BLOCK_PSWRD2}, + {"pswwr", BLOCK_PSWWR}, + {"pswwr2", BLOCK_PSWWR2}, + {"pswrq", BLOCK_PSWRQ}, + {"pswrq2", BLOCK_PSWRQ2}, + {"pglcs", BLOCK_PGLCS}, + {"ptu", BLOCK_PTU}, + {"dmae", BLOCK_DMAE}, + {"tcm", BLOCK_TCM}, + {"mcm", BLOCK_MCM}, + {"ucm", BLOCK_UCM}, + {"xcm", BLOCK_XCM}, + {"ycm", BLOCK_YCM}, + {"pcm", BLOCK_PCM}, + {"qm", BLOCK_QM}, + {"tm", BLOCK_TM}, + {"dorq", BLOCK_DORQ}, + {"brb", BLOCK_BRB}, + {"src", BLOCK_SRC}, + {"prs", BLOCK_PRS}, + {"tsdm", BLOCK_TSDM}, + {"msdm", BLOCK_MSDM}, + {"usdm", BLOCK_USDM}, + {"xsdm", BLOCK_XSDM}, + {"ysdm", BLOCK_YSDM}, + {"psdm", BLOCK_PSDM}, + {"tsem", BLOCK_TSEM}, + {"msem", BLOCK_MSEM}, + {"usem", BLOCK_USEM}, + {"xsem", BLOCK_XSEM}, + {"ysem", BLOCK_YSEM}, + {"psem", BLOCK_PSEM}, + {"rss", BLOCK_RSS}, + {"tmld", BLOCK_TMLD}, + {"muld", BLOCK_MULD}, + {"yuld", BLOCK_YULD}, + {"xyld", BLOCK_XYLD}, + {"ptld", BLOCK_PTLD}, + {"ypld", BLOCK_YPLD}, + {"prm", BLOCK_PRM}, + {"pbf_pb1", BLOCK_PBF_PB1}, + {"pbf_pb2", BLOCK_PBF_PB2}, + {"rpb", BLOCK_RPB}, + {"btb", BLOCK_BTB}, + {"pbf", BLOCK_PBF}, + {"rdif", BLOCK_RDIF}, + {"tdif", BLOCK_TDIF}, + {"cdu", BLOCK_CDU}, + {"ccfc", BLOCK_CCFC}, + {"tcfc", BLOCK_TCFC}, + {"igu", BLOCK_IGU}, + {"cau", BLOCK_CAU}, + {"rgfs", BLOCK_RGFS}, + {"rgsrc", BLOCK_RGSRC}, + {"tgfs", BLOCK_TGFS}, + {"tgsrc", BLOCK_TGSRC}, + {"umac", BLOCK_UMAC}, + {"xmac", BLOCK_XMAC}, + {"dbg", BLOCK_DBG}, + {"nig", BLOCK_NIG}, + {"wol", BLOCK_WOL}, + {"bmbn", BLOCK_BMBN}, + {"ipc", BLOCK_IPC}, + {"nwm", BLOCK_NWM}, + {"nws", BLOCK_NWS}, + {"ms", BLOCK_MS}, + {"phy_pcie", BLOCK_PHY_PCIE}, + {"led", BLOCK_LED}, + {"avs_wrap", BLOCK_AVS_WRAP}, + {"misc_aeu", BLOCK_MISC_AEU}, + {"bar0_map", BLOCK_BAR0_MAP} +}; + /* Status string array */ static const char * const s_status_str[] = { + /* DBG_STATUS_OK */ "Operation completed successfully", + + /* DBG_STATUS_APP_VERSION_NOT_SET */ "Debug application version wasn't set", + + /* DBG_STATUS_UNSUPPORTED_APP_VERSION */ "Unsupported debug application version", + + /* DBG_STATUS_DBG_BLOCK_NOT_RESET */ "The debug block wasn't reset since the last recording", + + /* DBG_STATUS_INVALID_ARGS */ "Invalid arguments", + + /* DBG_STATUS_OUTPUT_ALREADY_SET */ "The debug output was already set", + + /* DBG_STATUS_INVALID_PCI_BUF_SIZE */ "Invalid PCI buffer size", + + /* DBG_STATUS_PCI_BUF_ALLOC_FAILED */ "PCI buffer allocation failed", + + /* DBG_STATUS_PCI_BUF_NOT_ALLOCATED */ "A PCI buffer wasn't allocated", + + /* DBG_STATUS_TOO_MANY_INPUTS */ "Too many inputs were enabled. Enabled less inputs, or set 'unifyInputs' to true", - "GRC/Timestamp input overlap in cycle dword 0", + + /* DBG_STATUS_INPUT_OVERLAP */ + "Overlapping debug bus inputs", + + /* DBG_STATUS_HW_ONLY_RECORDING */ "Cannot record Storm data since the entire recording cycle is used by HW", + + /* DBG_STATUS_STORM_ALREADY_ENABLED */ "The Storm was already enabled", + + /* DBG_STATUS_STORM_NOT_ENABLED */ "The specified Storm wasn't enabled", + + /* DBG_STATUS_BLOCK_ALREADY_ENABLED */ "The block was already enabled", + + /* DBG_STATUS_BLOCK_NOT_ENABLED */ "The specified block wasn't enabled", + + /* DBG_STATUS_NO_INPUT_ENABLED */ "No input was enabled for recording", + + /* DBG_STATUS_NO_FILTER_TRIGGER_64B */ "Filters and triggers are not allowed when recording in 64b units", + + /* DBG_STATUS_FILTER_ALREADY_ENABLED */ "The filter was already enabled", + + /* DBG_STATUS_TRIGGER_ALREADY_ENABLED */ "The trigger was already enabled", + + /* DBG_STATUS_TRIGGER_NOT_ENABLED */ "The trigger wasn't enabled", + + /* DBG_STATUS_CANT_ADD_CONSTRAINT */ "A constraint can be added only after a filter was enabled or a trigger state was added", + + /* DBG_STATUS_TOO_MANY_TRIGGER_STATES */ "Cannot add more than 3 trigger states", + + /* DBG_STATUS_TOO_MANY_CONSTRAINTS */ "Cannot add more than 4 constraints per filter or trigger state", + + /* DBG_STATUS_RECORDING_NOT_STARTED */ "The recording wasn't started", + + /* DBG_STATUS_DATA_DIDNT_TRIGGER */ "A trigger was configured, but it didn't trigger", + + /* DBG_STATUS_NO_DATA_RECORDED */ "No data was recorded", + + /* DBG_STATUS_DUMP_BUF_TOO_SMALL */ "Dump buffer is too small", + + /* DBG_STATUS_DUMP_NOT_CHUNK_ALIGNED */ "Dumped data is not aligned to chunks", + + /* DBG_STATUS_UNKNOWN_CHIP */ "Unknown chip", + + /* DBG_STATUS_VIRT_MEM_ALLOC_FAILED */ "Failed allocating virtual memory", + + /* DBG_STATUS_BLOCK_IN_RESET */ "The input block is in reset", + + /* DBG_STATUS_INVALID_TRACE_SIGNATURE */ "Invalid MCP trace signature found in NVRAM", + + /* DBG_STATUS_INVALID_NVRAM_BUNDLE */ "Invalid bundle ID found in NVRAM", + + /* DBG_STATUS_NVRAM_GET_IMAGE_FAILED */ "Failed getting NVRAM image", + + /* DBG_STATUS_NON_ALIGNED_NVRAM_IMAGE */ "NVRAM image is not dword-aligned", + + /* DBG_STATUS_NVRAM_READ_FAILED */ "Failed reading from NVRAM", + + /* DBG_STATUS_IDLE_CHK_PARSE_FAILED */ "Idle check parsing failed", + + /* DBG_STATUS_MCP_TRACE_BAD_DATA */ "MCP Trace data is corrupt", - "Dump doesn't contain meta data - it must be provided in an image file", + + /* DBG_STATUS_MCP_TRACE_NO_META */ + "Dump doesn't contain meta data - it must be provided in image file", + + /* DBG_STATUS_MCP_COULD_NOT_HALT */ "Failed to halt MCP", + + /* DBG_STATUS_MCP_COULD_NOT_RESUME */ "Failed to resume MCP after halt", + + /* DBG_STATUS_DMAE_FAILED */ "DMAE transaction failed", + + /* DBG_STATUS_SEMI_FIFO_NOT_EMPTY */ "Failed to empty SEMI sync FIFO", + + /* DBG_STATUS_IGU_FIFO_BAD_DATA */ "IGU FIFO data is corrupt", + + /* DBG_STATUS_MCP_COULD_NOT_MASK_PRTY */ "MCP failed to mask parities", + + /* DBG_STATUS_FW_ASSERTS_PARSE_FAILED */ "FW Asserts parsing failed", + + /* DBG_STATUS_REG_FIFO_BAD_DATA */ "GRC FIFO data is corrupt", + + /* DBG_STATUS_PROTECTION_OVERRIDE_BAD_DATA */ "Protection Override data is corrupt", + + /* DBG_STATUS_DBG_ARRAY_NOT_SET */ "Debug arrays were not set (when using binary files, dbg_set_bin_ptr must be called)", - "When a block is filtered, no other blocks can be recorded unless inputs are unified (due to a HW bug)" + + /* DBG_STATUS_FILTER_BUG */ + "Debug Bus filtering requires the -unifyInputs option (due to a HW bug)", + + /* DBG_STATUS_NON_MATCHING_LINES */ + "Non-matching debug lines - all lines must be of the same type (either 128b or 256b)", + + /* DBG_STATUS_INVALID_TRIGGER_DWORD_OFFSET */ + "The selected trigger dword offset wasn't enabled in the recorded HW block", + + /* DBG_STATUS_DBG_BUS_IN_USE */ + "The debug bus is in use" }; /* Idle check severity names array */ @@ -5223,12 +5881,13 @@ static const char * const s_mcp_trace_level_str[] = { "DEBUG" }; -/* Parsing strings */ +/* Access type names array */ static const char * const s_access_strs[] = { "read", "write" }; +/* Privilege type names array */ static const char * const s_privilege_strs[] = { "VF", "PDA", @@ -5236,6 +5895,7 @@ static const char * const s_privilege_strs[] = { "UA" }; +/* Protection type names array */ static const char * const s_protection_strs[] = { "(default)", "(default)", @@ -5247,6 +5907,7 @@ static const char * const s_protection_strs[] = { "override UA" }; +/* Master type names array */ static const char * const s_master_strs[] = { "???", "pxp", @@ -5266,6 +5927,7 @@ static const char * const s_master_strs[] = { "???" }; +/* REG FIFO error messages array */ static const char * const s_reg_fifo_error_strs[] = { "grc timeout", "address doesn't belong to any block", @@ -5274,6 +5936,7 @@ static const char * const s_reg_fifo_error_strs[] = { "path isolation error" }; +/* IGU FIFO sources array */ static const char * const s_igu_fifo_source_strs[] = { "TSTORM", "MSTORM", @@ -5288,6 +5951,7 @@ static const char * const s_igu_fifo_source_strs[] = { "GRC", }; +/* IGU FIFO error messages */ static const char * const s_igu_fifo_error_strs[] = { "no error", "length error", @@ -5308,13 +5972,18 @@ static const char * const s_igu_fifo_error_strs[] = { /* IGU FIFO address data */ static const struct igu_fifo_addr_data s_igu_fifo_addr_data[] = { - {0x0, 0x101, "MSI-X Memory", NULL, IGU_ADDR_TYPE_MSIX_MEM}, - {0x102, 0x1ff, "reserved", NULL, IGU_ADDR_TYPE_RESERVED}, - {0x200, 0x200, "Write PBA[0:63]", NULL, IGU_ADDR_TYPE_WRITE_PBA}, + {0x0, 0x101, "MSI-X Memory", NULL, + IGU_ADDR_TYPE_MSIX_MEM}, + {0x102, 0x1ff, "reserved", NULL, + IGU_ADDR_TYPE_RESERVED}, + {0x200, 0x200, "Write PBA[0:63]", NULL, + IGU_ADDR_TYPE_WRITE_PBA}, {0x201, 0x201, "Write PBA[64:127]", "reserved", IGU_ADDR_TYPE_WRITE_PBA}, - {0x202, 0x202, "Write PBA[128]", "reserved", IGU_ADDR_TYPE_WRITE_PBA}, - {0x203, 0x3ff, "reserved", NULL, IGU_ADDR_TYPE_RESERVED}, + {0x202, 0x202, "Write PBA[128]", "reserved", + IGU_ADDR_TYPE_WRITE_PBA}, + {0x203, 0x3ff, "reserved", NULL, + IGU_ADDR_TYPE_RESERVED}, {0x400, 0x5ef, "Write interrupt acknowledgment", NULL, IGU_ADDR_TYPE_WRITE_INT_ACK}, {0x5f0, 0x5f0, "Attention bits update", NULL, @@ -5331,8 +6000,10 @@ static const struct igu_fifo_addr_data s_igu_fifo_addr_data[] = { IGU_ADDR_TYPE_READ_INT}, {0x5f6, 0x5f6, "Read interrupt 0:63 without mask", NULL, IGU_ADDR_TYPE_READ_INT}, - {0x5f7, 0x5ff, "reserved", NULL, IGU_ADDR_TYPE_RESERVED}, - {0x600, 0x7ff, "Producer update", NULL, IGU_ADDR_TYPE_WRITE_PROD_UPDATE} + {0x5f7, 0x5ff, "reserved", NULL, + IGU_ADDR_TYPE_RESERVED}, + {0x600, 0x7ff, "Producer update", NULL, + IGU_ADDR_TYPE_WRITE_PROD_UPDATE} }; /******************************** Variables **********************************/ @@ -5340,28 +6011,12 @@ static const struct igu_fifo_addr_data s_igu_fifo_addr_data[] = { /* MCP Trace meta data - used in case the dump doesn't contain the meta data * (e.g. due to no NVRAM access). */ -static struct dbg_array s_mcp_trace_meta = { NULL, 0 }; +static struct user_dbg_array s_mcp_trace_meta = { NULL, 0 }; /* Temporary buffer, used for print size calculations */ static char s_temp_buf[MAX_MSG_LEN]; -/***************************** Public Functions *******************************/ - -enum dbg_status qed_dbg_user_set_bin_ptr(const u8 * const bin_ptr) -{ - /* Convert binary data to debug arrays */ - struct bin_buffer_hdr *buf_array = (struct bin_buffer_hdr *)bin_ptr; - u8 buf_id; - - for (buf_id = 0; buf_id < MAX_BIN_DBG_BUFFER_TYPE; buf_id++) { - s_dbg_arrays[buf_id].ptr = - (u32 *)(bin_ptr + buf_array[buf_id].offset); - s_dbg_arrays[buf_id].size_in_dwords = - BYTES_TO_DWORDS(buf_array[buf_id].length); - } - - return DBG_STATUS_OK; -} +/**************************** Private Functions ******************************/ static u32 qed_cyclic_add(u32 a, u32 b, u32 size) { @@ -5381,10 +6036,8 @@ static u32 qed_read_from_cyclic_buf(void *buf, u32 *offset, u32 buf_size, u8 num_bytes_to_read) { - u8 *bytes_buf = (u8 *)buf; - u8 *val_ptr; + u8 i, *val_ptr, *bytes_buf = (u8 *)buf; u32 val = 0; - u8 i; val_ptr = (u8 *)&val; @@ -5412,6 +6065,7 @@ static u32 qed_read_dword_from_buf(void *buf, u32 *offset) u32 dword_val = *(u32 *)&((u8 *)buf)[*offset]; *offset += 4; + return dword_val; } @@ -5445,7 +6099,7 @@ static u32 qed_read_param(u32 *dump_buf, const char **param_str_val, u32 *param_num_val) { char *char_buf = (char *)dump_buf; - u32 offset = 0; /* In bytes */ + size_t offset = 0; /* Extract param name */ *param_name = char_buf; @@ -5493,37 +6147,31 @@ static u32 qed_print_section_params(u32 *dump_buf, u32 i, dump_offset = 0, results_offset = 0; for (i = 0; i < num_section_params; i++) { - const char *param_name; - const char *param_str_val; + const char *param_name, *param_str_val; u32 param_num_val = 0; dump_offset += qed_read_param(dump_buf + dump_offset, ¶m_name, ¶m_str_val, ¶m_num_val); + if (param_str_val) - /* String param */ results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), "%s: %s\n", param_name, param_str_val); else if (strcmp(param_name, "fw-timestamp")) - /* Numeric param */ results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), "%s: %d\n", param_name, param_num_val); } - results_offset += - sprintf(qed_get_buf_ptr(results_buf, results_offset), "\n"); + results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), + "\n"); + *num_chars_printed = results_offset; - return dump_offset; -} -const char *qed_dbg_get_status_str(enum dbg_status status) -{ - return (status < - MAX_DBG_STATUS) ? s_status_str[status] : "Invalid debug status"; + return dump_offset; } /* Parses the idle check rules and returns the number of characters printed. @@ -5537,7 +6185,10 @@ static u32 qed_parse_idle_chk_dump_rules(struct qed_hwfn *p_hwfn, char *results_buf, u32 *num_errors, u32 *num_warnings) { - u32 rule_idx, results_offset = 0; /* Offset in results_buf in bytes */ + /* Offset in results_buf in bytes */ + u32 results_offset = 0; + + u32 rule_idx; u16 i, j; *num_errors = 0; @@ -5548,16 +6199,15 @@ static u32 qed_parse_idle_chk_dump_rules(struct qed_hwfn *p_hwfn, rule_idx++) { const struct dbg_idle_chk_rule_parsing_data *rule_parsing_data; struct dbg_idle_chk_result_hdr *hdr; - const char *parsing_str; + const char *parsing_str, *lsi_msg; u32 parsing_str_offset; - const char *lsi_msg; - u8 curr_reg_id = 0; bool has_fw_msg; + u8 curr_reg_id; hdr = (struct dbg_idle_chk_result_hdr *)dump_buf; rule_parsing_data = (const struct dbg_idle_chk_rule_parsing_data *) - &s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_PARSING_DATA]. + &s_user_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_PARSING_DATA]. ptr[hdr->rule_id]; parsing_str_offset = GET_FIELD(rule_parsing_data->data, @@ -5565,16 +6215,18 @@ static u32 qed_parse_idle_chk_dump_rules(struct qed_hwfn *p_hwfn, has_fw_msg = GET_FIELD(rule_parsing_data->data, DBG_IDLE_CHK_RULE_PARSING_DATA_HAS_FW_MSG) > 0; - parsing_str = &((const char *) - s_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr) - [parsing_str_offset]; + parsing_str = + &((const char *) + s_user_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr) + [parsing_str_offset]; lsi_msg = parsing_str; + curr_reg_id = 0; if (hdr->severity >= MAX_DBG_IDLE_CHK_SEVERITY_TYPES) return 0; /* Skip rule header */ - dump_buf += (sizeof(struct dbg_idle_chk_result_hdr) / 4); + dump_buf += BYTES_TO_DWORDS(sizeof(*hdr)); /* Update errors/warnings count */ if (hdr->severity == IDLE_CHK_SEVERITY_ERROR || @@ -5606,19 +6258,19 @@ static u32 qed_parse_idle_chk_dump_rules(struct qed_hwfn *p_hwfn, for (i = 0; i < hdr->num_dumped_cond_regs + hdr->num_dumped_info_regs; i++) { - struct dbg_idle_chk_result_reg_hdr *reg_hdr - = (struct dbg_idle_chk_result_reg_hdr *) - dump_buf; - bool is_mem = - GET_FIELD(reg_hdr->data, - DBG_IDLE_CHK_RESULT_REG_HDR_IS_MEM); - u8 reg_id = - GET_FIELD(reg_hdr->data, - DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID); + struct dbg_idle_chk_result_reg_hdr *reg_hdr; + bool is_mem; + u8 reg_id; + + reg_hdr = + (struct dbg_idle_chk_result_reg_hdr *)dump_buf; + is_mem = GET_FIELD(reg_hdr->data, + DBG_IDLE_CHK_RESULT_REG_HDR_IS_MEM); + reg_id = GET_FIELD(reg_hdr->data, + DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID); /* Skip reg header */ - dump_buf += - (sizeof(struct dbg_idle_chk_result_reg_hdr) / 4); + dump_buf += BYTES_TO_DWORDS(sizeof(*reg_hdr)); /* Skip register names until the required reg_id is * reached. @@ -5660,6 +6312,7 @@ static u32 qed_parse_idle_chk_dump_rules(struct qed_hwfn *p_hwfn, /* Check if end of dump buffer was exceeded */ if (dump_buf > dump_buf_end) return 0; + return results_offset; } @@ -5680,13 +6333,16 @@ static enum dbg_status qed_parse_idle_chk_dump(struct qed_hwfn *p_hwfn, const char *section_name, *param_name, *param_str_val; u32 *dump_buf_end = dump_buf + num_dumped_dwords; u32 num_section_params = 0, num_rules; - u32 results_offset = 0; /* Offset in results_buf in bytes */ + + /* Offset in results_buf in bytes */ + u32 results_offset = 0; *parsed_results_bytes = 0; *num_errors = 0; *num_warnings = 0; - if (!s_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr || - !s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_PARSING_DATA].ptr) + + if (!s_user_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr || + !s_user_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_PARSING_DATA].ptr) return DBG_STATUS_DBG_ARRAY_NOT_SET; /* Read global_params section */ @@ -5705,10 +6361,9 @@ static enum dbg_status qed_parse_idle_chk_dump(struct qed_hwfn *p_hwfn, §ion_name, &num_section_params); if (strcmp(section_name, "idle_chk") || num_section_params != 1) return DBG_STATUS_IDLE_CHK_PARSE_FAILED; - dump_buf += qed_read_param(dump_buf, ¶m_name, ¶m_str_val, &num_rules); - if (strcmp(param_name, "num_rules") != 0) + if (strcmp(param_name, "num_rules")) return DBG_STATUS_IDLE_CHK_PARSE_FAILED; if (num_rules) { @@ -5728,7 +6383,7 @@ static enum dbg_status qed_parse_idle_chk_dump(struct qed_hwfn *p_hwfn, results_offset : NULL, num_errors, num_warnings); results_offset += rules_print_size; - if (rules_print_size == 0) + if (!rules_print_size) return DBG_STATUS_IDLE_CHK_PARSE_FAILED; /* Print LSI output */ @@ -5745,64 +6400,33 @@ static enum dbg_status qed_parse_idle_chk_dump(struct qed_hwfn *p_hwfn, results_offset : NULL, num_errors, num_warnings); results_offset += rules_print_size; - if (rules_print_size == 0) + if (!rules_print_size) return DBG_STATUS_IDLE_CHK_PARSE_FAILED; } /* Print errors/warnings count */ - if (*num_errors) { + if (*num_errors) results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), "\nIdle Check failed!!! (with %d errors and %d warnings)\n", *num_errors, *num_warnings); - } else if (*num_warnings) { + else if (*num_warnings) results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), - "\nIdle Check completed successfuly (with %d warnings)\n", + "\nIdle Check completed successfully (with %d warnings)\n", *num_warnings); - } else { + else results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), - "\nIdle Check completed successfuly\n"); - } + "\nIdle Check completed successfully\n"); /* Add 1 for string NULL termination */ *parsed_results_bytes = results_offset + 1; - return DBG_STATUS_OK; -} -enum dbg_status qed_get_idle_chk_results_buf_size(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - u32 *results_buf_size) -{ - u32 num_errors, num_warnings; - - return qed_parse_idle_chk_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - NULL, - results_buf_size, - &num_errors, &num_warnings); -} - -enum dbg_status qed_print_idle_chk_results(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - char *results_buf, - u32 *num_errors, u32 *num_warnings) -{ - u32 parsed_buf_size; - - return qed_parse_idle_chk_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - results_buf, - &parsed_buf_size, - num_errors, num_warnings); + return DBG_STATUS_OK; } /* Frees the specified MCP Trace meta data */ @@ -5841,12 +6465,10 @@ static enum dbg_status qed_mcp_trace_alloc_meta(struct qed_hwfn *p_hwfn, /* Read first signature */ signature = qed_read_dword_from_buf(meta_buf_bytes, &offset); - if (signature != MCP_TRACE_META_IMAGE_SIGNATURE) + if (signature != NVM_MAGIC_VALUE) return DBG_STATUS_INVALID_TRACE_SIGNATURE; - /* Read number of modules and allocate memory for all the modules - * pointers. - */ + /* Read no. of modules and allocate memory for their pointers */ meta->modules_num = qed_read_byte_from_buf(meta_buf_bytes, &offset); meta->modules = kzalloc(meta->modules_num * sizeof(char *), GFP_KERNEL); if (!meta->modules) @@ -5871,7 +6493,7 @@ static enum dbg_status qed_mcp_trace_alloc_meta(struct qed_hwfn *p_hwfn, /* Read second signature */ signature = qed_read_dword_from_buf(meta_buf_bytes, &offset); - if (signature != MCP_TRACE_META_IMAGE_SIGNATURE) + if (signature != NVM_MAGIC_VALUE) return DBG_STATUS_INVALID_TRACE_SIGNATURE; /* Read number of formats and allocate memory for all formats */ @@ -5919,10 +6541,10 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, char *results_buf, u32 *parsed_results_bytes) { - u32 results_offset = 0, param_mask, param_shift, param_num_val; - u32 num_section_params, offset, end_offset, bytes_left; + u32 end_offset, bytes_left, trace_data_dwords, trace_meta_dwords; + u32 param_mask, param_shift, param_num_val, num_section_params; const char *section_name, *param_name, *param_str_val; - u32 trace_data_dwords, trace_meta_dwords; + u32 offset, results_offset = 0; struct mcp_trace_meta meta; struct mcp_trace *trace; enum dbg_status status; @@ -5955,7 +6577,7 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, /* Prepare trace info */ trace = (struct mcp_trace *)dump_buf; - trace_buf = (u8 *)dump_buf + sizeof(struct mcp_trace); + trace_buf = (u8 *)dump_buf + sizeof(*trace); offset = trace->trace_oldest; end_offset = trace->trace_prod; bytes_left = qed_cyclic_sub(end_offset, offset, trace->size); @@ -5968,7 +6590,7 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, return DBG_STATUS_MCP_TRACE_BAD_DATA; dump_buf += qed_read_param(dump_buf, ¶m_name, ¶m_str_val, ¶m_num_val); - if (strcmp(param_name, "size") != 0) + if (strcmp(param_name, "size")) return DBG_STATUS_MCP_TRACE_BAD_DATA; trace_meta_dwords = param_num_val; @@ -6028,6 +6650,7 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, } format_ptr = &meta.formats[format_idx]; + for (i = 0, param_mask = MCP_TRACE_FORMAT_P1_SIZE_MASK, param_shift = MCP_TRACE_FORMAT_P1_SIZE_SHIFT; @@ -6050,6 +6673,7 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, */ if (param_size == 3) param_size = 4; + if (bytes_left < param_size) { status = DBG_STATUS_MCP_TRACE_BAD_DATA; goto free_mem; @@ -6059,13 +6683,14 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, &offset, trace->size, param_size); + bytes_left -= param_size; } format_level = (u8)((format_ptr->data & MCP_TRACE_FORMAT_LEVEL_MASK) >> - MCP_TRACE_FORMAT_LEVEL_SHIFT); + MCP_TRACE_FORMAT_LEVEL_SHIFT); format_module = (u8)((format_ptr->data & MCP_TRACE_FORMAT_MODULE_MASK) >> @@ -6094,30 +6719,6 @@ free_mem: return status; } -enum dbg_status qed_get_mcp_trace_results_buf_size(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - u32 *results_buf_size) -{ - return qed_parse_mcp_trace_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - NULL, results_buf_size); -} - -enum dbg_status qed_print_mcp_trace_results(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - char *results_buf) -{ - u32 parsed_buf_size; - - return qed_parse_mcp_trace_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - results_buf, &parsed_buf_size); -} - /* Parses a Reg FIFO dump buffer. * If result_buf is not NULL, the Reg FIFO results are printed to it. * In any case, the required results buffer size is assigned to @@ -6130,10 +6731,11 @@ static enum dbg_status qed_parse_reg_fifo_dump(struct qed_hwfn *p_hwfn, char *results_buf, u32 *parsed_results_bytes) { - u32 results_offset = 0, param_num_val, num_section_params, num_elements; const char *section_name, *param_name, *param_str_val; + u32 param_num_val, num_section_params, num_elements; struct reg_fifo_element *elements; u8 i, j, err_val, vf_val; + u32 results_offset = 0; char vf_str[4]; /* Read global_params section */ @@ -6179,17 +6781,17 @@ static enum dbg_status qed_parse_reg_fifo_dump(struct qed_hwfn *p_hwfn, "raw: 0x%016llx, address: 0x%07x, access: %-5s, pf: %2d, vf: %s, port: %d, privilege: %-3s, protection: %-12s, master: %-4s, errors: ", elements[i].data, (u32)GET_FIELD(elements[i].data, - REG_FIFO_ELEMENT_ADDRESS) * - REG_FIFO_ELEMENT_ADDR_FACTOR, - s_access_strs[GET_FIELD(elements[i].data, + REG_FIFO_ELEMENT_ADDRESS) * + REG_FIFO_ELEMENT_ADDR_FACTOR, + s_access_strs[GET_FIELD(elements[i].data, REG_FIFO_ELEMENT_ACCESS)], (u32)GET_FIELD(elements[i].data, - REG_FIFO_ELEMENT_PF), vf_str, + REG_FIFO_ELEMENT_PF), + vf_str, (u32)GET_FIELD(elements[i].data, - REG_FIFO_ELEMENT_PORT), - s_privilege_strs[GET_FIELD(elements[i]. - data, - REG_FIFO_ELEMENT_PRIVILEGE)], + REG_FIFO_ELEMENT_PORT), + s_privilege_strs[GET_FIELD(elements[i].data, + REG_FIFO_ELEMENT_PRIVILEGE)], s_protection_strs[GET_FIELD(elements[i].data, REG_FIFO_ELEMENT_PROTECTION)], s_master_strs[GET_FIELD(elements[i].data, @@ -6201,18 +6803,18 @@ static enum dbg_status qed_parse_reg_fifo_dump(struct qed_hwfn *p_hwfn, REG_FIFO_ELEMENT_ERROR); j < ARRAY_SIZE(s_reg_fifo_error_strs); j++, err_val >>= 1) { - if (!(err_val & 0x1)) - continue; - if (err_printed) + if (err_val & 0x1) { + if (err_printed) + results_offset += + sprintf(qed_get_buf_ptr + (results_buf, + results_offset), ", "); results_offset += - sprintf(qed_get_buf_ptr(results_buf, - results_offset), - ", "); - results_offset += - sprintf(qed_get_buf_ptr(results_buf, - results_offset), "%s", - s_reg_fifo_error_strs[j]); - err_printed = true; + sprintf(qed_get_buf_ptr + (results_buf, results_offset), "%s", + s_reg_fifo_error_strs[j]); + err_printed = true; + } } results_offset += @@ -6225,31 +6827,140 @@ static enum dbg_status qed_parse_reg_fifo_dump(struct qed_hwfn *p_hwfn, /* Add 1 for string NULL termination */ *parsed_results_bytes = results_offset + 1; + return DBG_STATUS_OK; } -enum dbg_status qed_get_reg_fifo_results_buf_size(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - u32 *results_buf_size) +static enum dbg_status qed_parse_igu_fifo_element(struct igu_fifo_element + *element, char + *results_buf, + u32 *results_offset, + u32 *parsed_results_bytes) { - return qed_parse_reg_fifo_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - NULL, results_buf_size); -} + const struct igu_fifo_addr_data *found_addr = NULL; + u8 source, err_type, i, is_cleanup; + char parsed_addr_data[32]; + char parsed_wr_data[256]; + u32 wr_data, prod_cons; + bool is_wr_cmd, is_pf; + u16 cmd_addr; + u64 dword12; -enum dbg_status qed_print_reg_fifo_results(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - char *results_buf) -{ - u32 parsed_buf_size; + /* Dword12 (dword index 1 and 2) contains bits 32..95 of the + * FIFO element. + */ + dword12 = ((u64)element->dword2 << 32) | element->dword1; + is_wr_cmd = GET_FIELD(dword12, IGU_FIFO_ELEMENT_DWORD12_IS_WR_CMD); + is_pf = GET_FIELD(element->dword0, IGU_FIFO_ELEMENT_DWORD0_IS_PF); + cmd_addr = GET_FIELD(element->dword0, IGU_FIFO_ELEMENT_DWORD0_CMD_ADDR); + source = GET_FIELD(element->dword0, IGU_FIFO_ELEMENT_DWORD0_SOURCE); + err_type = GET_FIELD(element->dword0, IGU_FIFO_ELEMENT_DWORD0_ERR_TYPE); + + if (source >= ARRAY_SIZE(s_igu_fifo_source_strs)) + return DBG_STATUS_IGU_FIFO_BAD_DATA; + if (err_type >= ARRAY_SIZE(s_igu_fifo_error_strs)) + return DBG_STATUS_IGU_FIFO_BAD_DATA; - return qed_parse_reg_fifo_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - results_buf, &parsed_buf_size); + /* Find address data */ + for (i = 0; i < ARRAY_SIZE(s_igu_fifo_addr_data) && !found_addr; i++) { + const struct igu_fifo_addr_data *curr_addr = + &s_igu_fifo_addr_data[i]; + + if (cmd_addr >= curr_addr->start_addr && cmd_addr <= + curr_addr->end_addr) + found_addr = curr_addr; + } + + if (!found_addr) + return DBG_STATUS_IGU_FIFO_BAD_DATA; + + /* Prepare parsed address data */ + switch (found_addr->type) { + case IGU_ADDR_TYPE_MSIX_MEM: + sprintf(parsed_addr_data, " vector_num = 0x%x", cmd_addr / 2); + break; + case IGU_ADDR_TYPE_WRITE_INT_ACK: + case IGU_ADDR_TYPE_WRITE_PROD_UPDATE: + sprintf(parsed_addr_data, + " SB = 0x%x", cmd_addr - found_addr->start_addr); + break; + default: + parsed_addr_data[0] = '\0'; + } + + if (!is_wr_cmd) { + parsed_wr_data[0] = '\0'; + goto out; + } + + /* Prepare parsed write data */ + wr_data = GET_FIELD(dword12, IGU_FIFO_ELEMENT_DWORD12_WR_DATA); + prod_cons = GET_FIELD(wr_data, IGU_FIFO_WR_DATA_PROD_CONS); + is_cleanup = GET_FIELD(wr_data, IGU_FIFO_WR_DATA_CMD_TYPE); + + if (source == IGU_SRC_ATTN) { + sprintf(parsed_wr_data, "prod: 0x%x, ", prod_cons); + } else { + if (is_cleanup) { + u8 cleanup_val, cleanup_type; + + cleanup_val = + GET_FIELD(wr_data, + IGU_FIFO_CLEANUP_WR_DATA_CLEANUP_VAL); + cleanup_type = + GET_FIELD(wr_data, + IGU_FIFO_CLEANUP_WR_DATA_CLEANUP_TYPE); + + sprintf(parsed_wr_data, + "cmd_type: cleanup, cleanup_val: %s, cleanup_type : %d, ", + cleanup_val ? "set" : "clear", + cleanup_type); + } else { + u8 update_flag, en_dis_int_for_sb, segment; + u8 timer_mask; + + update_flag = GET_FIELD(wr_data, + IGU_FIFO_WR_DATA_UPDATE_FLAG); + en_dis_int_for_sb = + GET_FIELD(wr_data, + IGU_FIFO_WR_DATA_EN_DIS_INT_FOR_SB); + segment = GET_FIELD(wr_data, + IGU_FIFO_WR_DATA_SEGMENT); + timer_mask = GET_FIELD(wr_data, + IGU_FIFO_WR_DATA_TIMER_MASK); + + sprintf(parsed_wr_data, + "cmd_type: prod/cons update, prod/cons: 0x%x, update_flag: %s, en_dis_int_for_sb : %s, segment : %s, timer_mask = %d, ", + prod_cons, + update_flag ? "update" : "nop", + en_dis_int_for_sb + ? (en_dis_int_for_sb == 1 ? "disable" : "nop") + : "enable", + segment ? "attn" : "regular", + timer_mask); + } + } +out: + /* Add parsed element to parsed buffer */ + *results_offset += sprintf(qed_get_buf_ptr(results_buf, + *results_offset), + "raw: 0x%01x%08x%08x, %s: %d, source : %s, type : %s, cmd_addr : 0x%x(%s%s), %serror: %s\n", + element->dword2, element->dword1, + element->dword0, + is_pf ? "pf" : "vf", + GET_FIELD(element->dword0, + IGU_FIFO_ELEMENT_DWORD0_FID), + s_igu_fifo_source_strs[source], + is_wr_cmd ? "wr" : "rd", + cmd_addr, + (!is_pf && found_addr->vf_desc) + ? found_addr->vf_desc + : found_addr->desc, + parsed_addr_data, + parsed_wr_data, + s_igu_fifo_error_strs[err_type]); + + return DBG_STATUS_OK; } /* Parses an IGU FIFO dump buffer. @@ -6264,12 +6975,12 @@ static enum dbg_status qed_parse_igu_fifo_dump(struct qed_hwfn *p_hwfn, char *results_buf, u32 *parsed_results_bytes) { - u32 results_offset = 0, param_num_val, num_section_params, num_elements; const char *section_name, *param_name, *param_str_val; + u32 param_num_val, num_section_params, num_elements; struct igu_fifo_element *elements; - char parsed_addr_data[32]; - char parsed_wr_data[256]; - u8 i, j; + enum dbg_status status; + u32 results_offset = 0; + u8 i; /* Read global_params section */ dump_buf += qed_read_section_hdr(dump_buf, @@ -6298,118 +7009,12 @@ static enum dbg_status qed_parse_igu_fifo_dump(struct qed_hwfn *p_hwfn, /* Decode elements */ for (i = 0; i < num_elements; i++) { - /* dword12 (dword index 1 and 2) contains bits 32..95 of the - * FIFO element. - */ - u64 dword12 = - ((u64)elements[i].dword2 << 32) | elements[i].dword1; - bool is_wr_cmd = GET_FIELD(dword12, - IGU_FIFO_ELEMENT_DWORD12_IS_WR_CMD); - bool is_pf = GET_FIELD(elements[i].dword0, - IGU_FIFO_ELEMENT_DWORD0_IS_PF); - u16 cmd_addr = GET_FIELD(elements[i].dword0, - IGU_FIFO_ELEMENT_DWORD0_CMD_ADDR); - u8 source = GET_FIELD(elements[i].dword0, - IGU_FIFO_ELEMENT_DWORD0_SOURCE); - u8 err_type = GET_FIELD(elements[i].dword0, - IGU_FIFO_ELEMENT_DWORD0_ERR_TYPE); - const struct igu_fifo_addr_data *addr_data = NULL; - - if (source >= ARRAY_SIZE(s_igu_fifo_source_strs)) - return DBG_STATUS_IGU_FIFO_BAD_DATA; - if (err_type >= ARRAY_SIZE(s_igu_fifo_error_strs)) - return DBG_STATUS_IGU_FIFO_BAD_DATA; - - /* Find address data */ - for (j = 0; j < ARRAY_SIZE(s_igu_fifo_addr_data) && !addr_data; - j++) - if (cmd_addr >= s_igu_fifo_addr_data[j].start_addr && - cmd_addr <= s_igu_fifo_addr_data[j].end_addr) - addr_data = &s_igu_fifo_addr_data[j]; - if (!addr_data) - return DBG_STATUS_IGU_FIFO_BAD_DATA; - - /* Prepare parsed address data */ - switch (addr_data->type) { - case IGU_ADDR_TYPE_MSIX_MEM: - sprintf(parsed_addr_data, - " vector_num=0x%x", cmd_addr / 2); - break; - case IGU_ADDR_TYPE_WRITE_INT_ACK: - case IGU_ADDR_TYPE_WRITE_PROD_UPDATE: - sprintf(parsed_addr_data, - " SB=0x%x", cmd_addr - addr_data->start_addr); - break; - default: - parsed_addr_data[0] = '\0'; - } - - /* Prepare parsed write data */ - if (is_wr_cmd) { - u32 wr_data = GET_FIELD(dword12, - IGU_FIFO_ELEMENT_DWORD12_WR_DATA); - u32 prod_cons = GET_FIELD(wr_data, - IGU_FIFO_WR_DATA_PROD_CONS); - u8 is_cleanup = GET_FIELD(wr_data, - IGU_FIFO_WR_DATA_CMD_TYPE); - - if (source == IGU_SRC_ATTN) { - sprintf(parsed_wr_data, - "prod: 0x%x, ", prod_cons); - } else { - if (is_cleanup) { - u8 cleanup_val = GET_FIELD(wr_data, - IGU_FIFO_CLEANUP_WR_DATA_CLEANUP_VAL); - u8 cleanup_type = GET_FIELD(wr_data, - IGU_FIFO_CLEANUP_WR_DATA_CLEANUP_TYPE); - - sprintf(parsed_wr_data, - "cmd_type: cleanup, cleanup_val: %s, cleanup_type: %d, ", - cleanup_val ? "set" : "clear", - cleanup_type); - } else { - u8 update_flag = GET_FIELD(wr_data, - IGU_FIFO_WR_DATA_UPDATE_FLAG); - u8 en_dis_int_for_sb = - GET_FIELD(wr_data, - IGU_FIFO_WR_DATA_EN_DIS_INT_FOR_SB); - u8 segment = GET_FIELD(wr_data, - IGU_FIFO_WR_DATA_SEGMENT); - u8 timer_mask = GET_FIELD(wr_data, - IGU_FIFO_WR_DATA_TIMER_MASK); - - sprintf(parsed_wr_data, - "cmd_type: prod/cons update, prod/cons: 0x%x, update_flag: %s, en_dis_int_for_sb: %s, segment: %s, timer_mask=%d, ", - prod_cons, - update_flag ? "update" : "nop", - en_dis_int_for_sb - ? (en_dis_int_for_sb == - 1 ? "disable" : "nop") : - "enable", - segment ? "attn" : "regular", - timer_mask); - } - } - } else { - parsed_wr_data[0] = '\0'; - } - - /* Add parsed element to parsed buffer */ - results_offset += - sprintf(qed_get_buf_ptr(results_buf, - results_offset), - "raw: 0x%01x%08x%08x, %s: %d, source: %s, type: %s, cmd_addr: 0x%x (%s%s), %serror: %s\n", - elements[i].dword2, elements[i].dword1, - elements[i].dword0, - is_pf ? "pf" : "vf", - GET_FIELD(elements[i].dword0, - IGU_FIFO_ELEMENT_DWORD0_FID), - s_igu_fifo_source_strs[source], - is_wr_cmd ? "wr" : "rd", cmd_addr, - (!is_pf && addr_data->vf_desc) - ? addr_data->vf_desc : addr_data->desc, - parsed_addr_data, parsed_wr_data, - s_igu_fifo_error_strs[err_type]); + status = qed_parse_igu_fifo_element(&elements[i], + results_buf, + &results_offset, + parsed_results_bytes); + if (status != DBG_STATUS_OK) + return status; } results_offset += sprintf(qed_get_buf_ptr(results_buf, @@ -6418,31 +7023,8 @@ static enum dbg_status qed_parse_igu_fifo_dump(struct qed_hwfn *p_hwfn, /* Add 1 for string NULL termination */ *parsed_results_bytes = results_offset + 1; - return DBG_STATUS_OK; -} - -enum dbg_status qed_get_igu_fifo_results_buf_size(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - u32 *results_buf_size) -{ - return qed_parse_igu_fifo_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - NULL, results_buf_size); -} - -enum dbg_status qed_print_igu_fifo_results(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - char *results_buf) -{ - u32 parsed_buf_size; - return qed_parse_igu_fifo_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - results_buf, &parsed_buf_size); + return DBG_STATUS_OK; } static enum dbg_status @@ -6452,9 +7034,10 @@ qed_parse_protection_override_dump(struct qed_hwfn *p_hwfn, char *results_buf, u32 *parsed_results_bytes) { - u32 results_offset = 0, param_num_val, num_section_params, num_elements; const char *section_name, *param_name, *param_str_val; + u32 param_num_val, num_section_params, num_elements; struct protection_override_element *elements; + u32 results_offset = 0; u8 i; /* Read global_params section */ @@ -6477,7 +7060,7 @@ qed_parse_protection_override_dump(struct qed_hwfn *p_hwfn, ¶m_name, ¶m_str_val, ¶m_num_val); if (strcmp(param_name, "size")) return DBG_STATUS_PROTECTION_OVERRIDE_BAD_DATA; - if (param_num_val % PROTECTION_OVERRIDE_ELEMENT_DWORDS != 0) + if (param_num_val % PROTECTION_OVERRIDE_ELEMENT_DWORDS) return DBG_STATUS_PROTECTION_OVERRIDE_BAD_DATA; num_elements = param_num_val / PROTECTION_OVERRIDE_ELEMENT_DWORDS; elements = (struct protection_override_element *)dump_buf; @@ -6486,7 +7069,7 @@ qed_parse_protection_override_dump(struct qed_hwfn *p_hwfn, for (i = 0; i < num_elements; i++) { u32 address = GET_FIELD(elements[i].data, PROTECTION_OVERRIDE_ELEMENT_ADDRESS) * - PROTECTION_OVERRIDE_ELEMENT_ADDR_FACTOR; + PROTECTION_OVERRIDE_ELEMENT_ADDR_FACTOR; results_offset += sprintf(qed_get_buf_ptr(results_buf, @@ -6512,33 +7095,8 @@ qed_parse_protection_override_dump(struct qed_hwfn *p_hwfn, /* Add 1 for string NULL termination */ *parsed_results_bytes = results_offset + 1; - return DBG_STATUS_OK; -} -enum dbg_status -qed_get_protection_override_results_buf_size(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - u32 *results_buf_size) -{ - return qed_parse_protection_override_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - NULL, results_buf_size); -} - -enum dbg_status qed_print_protection_override_results(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - char *results_buf) -{ - u32 parsed_buf_size; - - return qed_parse_protection_override_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - results_buf, - &parsed_buf_size); + return DBG_STATUS_OK; } /* Parses a FW Asserts dump buffer. @@ -6553,7 +7111,7 @@ static enum dbg_status qed_parse_fw_asserts_dump(struct qed_hwfn *p_hwfn, char *results_buf, u32 *parsed_results_bytes) { - u32 results_offset = 0, num_section_params, param_num_val, i; + u32 num_section_params, param_num_val, i, results_offset = 0; const char *param_name, *param_str_val, *section_name; bool last_section_found = false; @@ -6569,54 +7127,216 @@ static enum dbg_status qed_parse_fw_asserts_dump(struct qed_hwfn *p_hwfn, dump_buf += qed_print_section_params(dump_buf, num_section_params, results_buf, &results_offset); - while (!last_section_found) { - const char *storm_letter = NULL; - u32 storm_dump_size = 0; + while (!last_section_found) { dump_buf += qed_read_section_hdr(dump_buf, §ion_name, &num_section_params); - if (!strcmp(section_name, "last")) { - last_section_found = true; - continue; - } else if (strcmp(section_name, "fw_asserts")) { - return DBG_STATUS_FW_ASSERTS_PARSE_FAILED; - } + if (!strcmp(section_name, "fw_asserts")) { + /* Extract params */ + const char *storm_letter = NULL; + u32 storm_dump_size = 0; + + for (i = 0; i < num_section_params; i++) { + dump_buf += qed_read_param(dump_buf, + ¶m_name, + ¶m_str_val, + ¶m_num_val); + if (!strcmp(param_name, "storm")) + storm_letter = param_str_val; + else if (!strcmp(param_name, "size")) + storm_dump_size = param_num_val; + else + return + DBG_STATUS_FW_ASSERTS_PARSE_FAILED; + } - /* Extract params */ - for (i = 0; i < num_section_params; i++) { - dump_buf += qed_read_param(dump_buf, - ¶m_name, - ¶m_str_val, - ¶m_num_val); - if (!strcmp(param_name, "storm")) - storm_letter = param_str_val; - else if (!strcmp(param_name, "size")) - storm_dump_size = param_num_val; - else + if (!storm_letter || !storm_dump_size) return DBG_STATUS_FW_ASSERTS_PARSE_FAILED; - } - if (!storm_letter || !storm_dump_size) - return DBG_STATUS_FW_ASSERTS_PARSE_FAILED; - - /* Print data */ - results_offset += sprintf(qed_get_buf_ptr(results_buf, - results_offset), - "\n%sSTORM_ASSERT: size=%d\n", - storm_letter, storm_dump_size); - for (i = 0; i < storm_dump_size; i++, dump_buf++) + /* Print data */ results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), - "%08x\n", *dump_buf); + "\n%sSTORM_ASSERT: size=%d\n", + storm_letter, storm_dump_size); + for (i = 0; i < storm_dump_size; i++, dump_buf++) + results_offset += + sprintf(qed_get_buf_ptr(results_buf, + results_offset), + "%08x\n", *dump_buf); + } else if (!strcmp(section_name, "last")) { + last_section_found = true; + } else { + return DBG_STATUS_FW_ASSERTS_PARSE_FAILED; + } } /* Add 1 for string NULL termination */ *parsed_results_bytes = results_offset + 1; + + return DBG_STATUS_OK; +} + +/***************************** Public Functions *******************************/ + +enum dbg_status qed_dbg_user_set_bin_ptr(const u8 * const bin_ptr) +{ + struct bin_buffer_hdr *buf_array = (struct bin_buffer_hdr *)bin_ptr; + u8 buf_id; + + /* Convert binary data to debug arrays */ + for (buf_id = 0; buf_id < MAX_BIN_DBG_BUFFER_TYPE; buf_id++) { + s_user_dbg_arrays[buf_id].ptr = + (u32 *)(bin_ptr + buf_array[buf_id].offset); + s_user_dbg_arrays[buf_id].size_in_dwords = + BYTES_TO_DWORDS(buf_array[buf_id].length); + } + return DBG_STATUS_OK; } +const char *qed_dbg_get_status_str(enum dbg_status status) +{ + return (status < + MAX_DBG_STATUS) ? s_status_str[status] : "Invalid debug status"; +} + +enum dbg_status qed_get_idle_chk_results_buf_size(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + u32 *results_buf_size) +{ + u32 num_errors, num_warnings; + + return qed_parse_idle_chk_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + NULL, + results_buf_size, + &num_errors, &num_warnings); +} + +enum dbg_status qed_print_idle_chk_results(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + char *results_buf, + u32 *num_errors, u32 *num_warnings) +{ + u32 parsed_buf_size; + + return qed_parse_idle_chk_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + results_buf, + &parsed_buf_size, + num_errors, num_warnings); +} + +void qed_dbg_mcp_trace_set_meta_data(u32 *data, u32 size) +{ + s_mcp_trace_meta.ptr = data; + s_mcp_trace_meta.size_in_dwords = size; +} + +enum dbg_status qed_get_mcp_trace_results_buf_size(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + u32 *results_buf_size) +{ + return qed_parse_mcp_trace_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + NULL, results_buf_size); +} + +enum dbg_status qed_print_mcp_trace_results(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + char *results_buf) +{ + u32 parsed_buf_size; + + return qed_parse_mcp_trace_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + results_buf, &parsed_buf_size); +} + +enum dbg_status qed_get_reg_fifo_results_buf_size(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + u32 *results_buf_size) +{ + return qed_parse_reg_fifo_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + NULL, results_buf_size); +} + +enum dbg_status qed_print_reg_fifo_results(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + char *results_buf) +{ + u32 parsed_buf_size; + + return qed_parse_reg_fifo_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + results_buf, &parsed_buf_size); +} + +enum dbg_status qed_get_igu_fifo_results_buf_size(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + u32 *results_buf_size) +{ + return qed_parse_igu_fifo_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + NULL, results_buf_size); +} + +enum dbg_status qed_print_igu_fifo_results(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + char *results_buf) +{ + u32 parsed_buf_size; + + return qed_parse_igu_fifo_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + results_buf, &parsed_buf_size); +} + +enum dbg_status +qed_get_protection_override_results_buf_size(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + u32 *results_buf_size) +{ + return qed_parse_protection_override_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + NULL, results_buf_size); +} + +enum dbg_status qed_print_protection_override_results(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + char *results_buf) +{ + u32 parsed_buf_size; + + return qed_parse_protection_override_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + results_buf, + &parsed_buf_size); +} + enum dbg_status qed_get_fw_asserts_results_buf_size(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, @@ -6641,6 +7361,88 @@ enum dbg_status qed_print_fw_asserts_results(struct qed_hwfn *p_hwfn, results_buf, &parsed_buf_size); } +enum dbg_status qed_dbg_parse_attn(struct qed_hwfn *p_hwfn, + struct dbg_attn_block_result *results) +{ + struct user_dbg_array *block_attn, *pstrings; + const u32 *block_attn_name_offsets; + enum dbg_attn_type attn_type; + const char *block_name; + u8 num_regs, i, j; + + num_regs = GET_FIELD(results->data, DBG_ATTN_BLOCK_RESULT_NUM_REGS); + attn_type = (enum dbg_attn_type) + GET_FIELD(results->data, + DBG_ATTN_BLOCK_RESULT_ATTN_TYPE); + block_name = s_block_info_arr[results->block_id].name; + + if (!s_user_dbg_arrays[BIN_BUF_DBG_ATTN_INDEXES].ptr || + !s_user_dbg_arrays[BIN_BUF_DBG_ATTN_NAME_OFFSETS].ptr || + !s_user_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr) + return DBG_STATUS_DBG_ARRAY_NOT_SET; + + block_attn = &s_user_dbg_arrays[BIN_BUF_DBG_ATTN_NAME_OFFSETS]; + block_attn_name_offsets = &block_attn->ptr[results->names_offset]; + + /* Go over registers with a non-zero attention status */ + for (i = 0; i < num_regs; i++) { + struct dbg_attn_reg_result *reg_result; + struct dbg_attn_bit_mapping *mapping; + u8 num_reg_attn, bit_idx = 0; + + reg_result = &results->reg_results[i]; + num_reg_attn = GET_FIELD(reg_result->data, + DBG_ATTN_REG_RESULT_NUM_REG_ATTN); + block_attn = &s_user_dbg_arrays[BIN_BUF_DBG_ATTN_INDEXES]; + mapping = &((struct dbg_attn_bit_mapping *) + block_attn->ptr)[reg_result->block_attn_offset]; + + pstrings = &s_user_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS]; + + /* Go over attention status bits */ + for (j = 0; j < num_reg_attn; j++) { + u16 attn_idx_val = GET_FIELD(mapping[j].data, + DBG_ATTN_BIT_MAPPING_VAL); + const char *attn_name, *attn_type_str, *masked_str; + u32 name_offset, sts_addr; + + /* Check if bit mask should be advanced (due to unused + * bits). + */ + if (GET_FIELD(mapping[j].data, + DBG_ATTN_BIT_MAPPING_IS_UNUSED_BIT_CNT)) { + bit_idx += (u8)attn_idx_val; + continue; + } + + /* Check current bit index */ + if (!(reg_result->sts_val & BIT(bit_idx))) { + bit_idx++; + continue; + } + + /* Find attention name */ + name_offset = block_attn_name_offsets[attn_idx_val]; + attn_name = &((const char *) + pstrings->ptr)[name_offset]; + attn_type_str = attn_type == ATTN_TYPE_INTERRUPT ? + "Interrupt" : "Parity"; + masked_str = reg_result->mask_val & BIT(bit_idx) ? + " [masked]" : ""; + sts_addr = GET_FIELD(reg_result->data, + DBG_ATTN_REG_RESULT_STS_ADDRESS); + DP_NOTICE(p_hwfn, + "%s (%s) : %s [address 0x%08x, bit %d]%s\n", + block_name, attn_type_str, attn_name, + sts_addr, bit_idx, masked_str); + + bit_idx++; + } + } + + return DBG_STATUS_OK; +} + /* Wrapper for unifying the idle_chk and mcp_trace api */ static enum dbg_status qed_print_idle_chk_results_wrapper(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.h b/drivers/net/ethernet/qlogic/qed/qed_debug.h index f872d7324814..ea1cc8eaa125 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_debug.h +++ b/drivers/net/ethernet/qlogic/qed/qed_debug.h @@ -20,6 +20,9 @@ enum qed_dbg_features { DBG_FEATURE_NUM }; +/* Forward Declaration */ +struct qed_dev; + int qed_dbg_grc(struct qed_dev *cdev, void *buffer, u32 *num_dumped_bytes); int qed_dbg_grc_size(struct qed_dev *cdev); int qed_dbg_idle_chk(struct qed_dev *cdev, void *buffer, diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 463927f17032..65fe4940f20d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -69,12 +69,6 @@ static DEFINE_SPINLOCK(qm_lock); #define QED_MIN_DPIS (4) #define QED_MIN_PWM_REGION (QED_WID_SIZE * QED_MIN_DPIS) -/* API common to all protocols */ -enum BAR_ID { - BAR_ID_0, /* used for GRC */ - BAR_ID_1 /* Used for doorbells */ -}; - static u32 qed_hw_bar_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, enum BAR_ID bar_id) { @@ -83,7 +77,7 @@ static u32 qed_hw_bar_size(struct qed_hwfn *p_hwfn, u32 val; if (IS_VF(p_hwfn->cdev)) - return 1 << 17; + return qed_vf_hw_bar_size(p_hwfn, bar_id); val = qed_rd(p_hwfn, p_ptt, bar_reg); if (val) @@ -154,13 +148,17 @@ void qed_resc_free(struct qed_dev *cdev) { int i; - if (IS_VF(cdev)) + if (IS_VF(cdev)) { + for_each_hwfn(cdev, i) + qed_l2_free(&cdev->hwfns[i]); return; + } kfree(cdev->fw_data); cdev->fw_data = NULL; kfree(cdev->reset_stats); + cdev->reset_stats = NULL; for_each_hwfn(cdev, i) { struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; @@ -168,20 +166,21 @@ void qed_resc_free(struct qed_dev *cdev) qed_cxt_mngr_free(p_hwfn); qed_qm_info_free(p_hwfn); qed_spq_free(p_hwfn); - qed_eq_free(p_hwfn, p_hwfn->p_eq); - qed_consq_free(p_hwfn, p_hwfn->p_consq); + qed_eq_free(p_hwfn); + qed_consq_free(p_hwfn); qed_int_free(p_hwfn); #ifdef CONFIG_QED_LL2 - qed_ll2_free(p_hwfn, p_hwfn->p_ll2_info); + qed_ll2_free(p_hwfn); #endif if (p_hwfn->hw_info.personality == QED_PCI_FCOE) - qed_fcoe_free(p_hwfn, p_hwfn->p_fcoe_info); + qed_fcoe_free(p_hwfn); if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) { - qed_iscsi_free(p_hwfn, p_hwfn->p_iscsi_info); - qed_ooo_free(p_hwfn, p_hwfn->p_ooo_info); + qed_iscsi_free(p_hwfn); + qed_ooo_free(p_hwfn); } qed_iov_free(p_hwfn); + qed_l2_free(p_hwfn); qed_dmae_info_free(p_hwfn); qed_dcbx_info_free(p_hwfn); } @@ -299,7 +298,7 @@ static void qed_init_qm_params(struct qed_hwfn *p_hwfn) qm_info->vport_wfq_en = 1; /* TC config is different for AH 4 port */ - four_port = p_hwfn->cdev->num_ports_in_engines == MAX_NUM_PORTS_K2; + four_port = p_hwfn->cdev->num_ports_in_engine == MAX_NUM_PORTS_K2; /* in AH 4 port we have fewer TCs per port */ qm_info->max_phys_tcs_per_port = four_port ? NUM_PHYS_TCS_4PORT_K2 : @@ -328,7 +327,7 @@ static void qed_init_qm_vport_params(struct qed_hwfn *p_hwfn) static void qed_init_qm_port_params(struct qed_hwfn *p_hwfn) { /* Initialize qm port parameters */ - u8 i, active_phys_tcs, num_ports = p_hwfn->cdev->num_ports_in_engines; + u8 i, active_phys_tcs, num_ports = p_hwfn->cdev->num_ports_in_engine; /* indicate how ooo and high pri traffic is dealt with */ active_phys_tcs = num_ports == MAX_NUM_PORTS_K2 ? @@ -692,7 +691,7 @@ static void qed_dp_init_qm_params(struct qed_hwfn *p_hwfn) qm_info->num_pf_rls, qed_get_pq_flags(p_hwfn)); /* port table */ - for (i = 0; i < p_hwfn->cdev->num_ports_in_engines; i++) { + for (i = 0; i < p_hwfn->cdev->num_ports_in_engine; i++) { port = &(qm_info->qm_port_params[i]); DP_VERBOSE(p_hwfn, NETIF_MSG_HW, @@ -822,7 +821,7 @@ static int qed_alloc_qm_data(struct qed_hwfn *p_hwfn) goto alloc_err; qm_info->qm_port_params = kzalloc(sizeof(*qm_info->qm_port_params) * - p_hwfn->cdev->num_ports_in_engines, + p_hwfn->cdev->num_ports_in_engine, GFP_KERNEL); if (!qm_info->qm_port_params) goto alloc_err; @@ -843,20 +842,18 @@ alloc_err: int qed_resc_alloc(struct qed_dev *cdev) { - struct qed_iscsi_info *p_iscsi_info; - struct qed_fcoe_info *p_fcoe_info; - struct qed_ooo_info *p_ooo_info; -#ifdef CONFIG_QED_LL2 - struct qed_ll2_info *p_ll2_info; -#endif u32 rdma_tasks, excess_tasks; - struct qed_consq *p_consq; - struct qed_eq *p_eq; u32 line_count; int i, rc = 0; - if (IS_VF(cdev)) + if (IS_VF(cdev)) { + for_each_hwfn(cdev, i) { + rc = qed_l2_alloc(&cdev->hwfns[i]); + if (rc) + return rc; + } return rc; + } cdev->fw_data = kzalloc(sizeof(*cdev->fw_data), GFP_KERNEL); if (!cdev->fw_data) @@ -956,45 +953,42 @@ int qed_resc_alloc(struct qed_dev *cdev) DP_ERR(p_hwfn, "Cannot allocate 0x%x EQ elements. The maximum of a u16 chain is 0x%x\n", n_eqes, 0xFFFF); - rc = -EINVAL; - goto alloc_err; + goto alloc_no_mem; } - p_eq = qed_eq_alloc(p_hwfn, (u16) n_eqes); - if (!p_eq) - goto alloc_no_mem; - p_hwfn->p_eq = p_eq; + rc = qed_eq_alloc(p_hwfn, (u16) n_eqes); + if (rc) + goto alloc_err; - p_consq = qed_consq_alloc(p_hwfn); - if (!p_consq) - goto alloc_no_mem; - p_hwfn->p_consq = p_consq; + rc = qed_consq_alloc(p_hwfn); + if (rc) + goto alloc_err; + + rc = qed_l2_alloc(p_hwfn); + if (rc) + goto alloc_err; #ifdef CONFIG_QED_LL2 if (p_hwfn->using_ll2) { - p_ll2_info = qed_ll2_alloc(p_hwfn); - if (!p_ll2_info) - goto alloc_no_mem; - p_hwfn->p_ll2_info = p_ll2_info; + rc = qed_ll2_alloc(p_hwfn); + if (rc) + goto alloc_err; } #endif if (p_hwfn->hw_info.personality == QED_PCI_FCOE) { - p_fcoe_info = qed_fcoe_alloc(p_hwfn); - if (!p_fcoe_info) - goto alloc_no_mem; - p_hwfn->p_fcoe_info = p_fcoe_info; + rc = qed_fcoe_alloc(p_hwfn); + if (rc) + goto alloc_err; } if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) { - p_iscsi_info = qed_iscsi_alloc(p_hwfn); - if (!p_iscsi_info) - goto alloc_no_mem; - p_hwfn->p_iscsi_info = p_iscsi_info; - p_ooo_info = qed_ooo_alloc(p_hwfn); - if (!p_ooo_info) - goto alloc_no_mem; - p_hwfn->p_ooo_info = p_ooo_info; + rc = qed_iscsi_alloc(p_hwfn); + if (rc) + goto alloc_err; + rc = qed_ooo_alloc(p_hwfn); + if (rc) + goto alloc_err; } /* DMA info initialization */ @@ -1025,16 +1019,19 @@ void qed_resc_setup(struct qed_dev *cdev) { int i; - if (IS_VF(cdev)) + if (IS_VF(cdev)) { + for_each_hwfn(cdev, i) + qed_l2_setup(&cdev->hwfns[i]); return; + } for_each_hwfn(cdev, i) { struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; qed_cxt_mngr_setup(p_hwfn); qed_spq_setup(p_hwfn); - qed_eq_setup(p_hwfn, p_hwfn->p_eq); - qed_consq_setup(p_hwfn, p_hwfn->p_consq); + qed_eq_setup(p_hwfn); + qed_consq_setup(p_hwfn); /* Read shadow of current MFW mailbox */ qed_mcp_read_mb(p_hwfn, p_hwfn->p_main_ptt); @@ -1044,17 +1041,18 @@ void qed_resc_setup(struct qed_dev *cdev) qed_int_setup(p_hwfn, p_hwfn->p_main_ptt); - qed_iov_setup(p_hwfn, p_hwfn->p_main_ptt); + qed_l2_setup(p_hwfn); + qed_iov_setup(p_hwfn); #ifdef CONFIG_QED_LL2 if (p_hwfn->using_ll2) - qed_ll2_setup(p_hwfn, p_hwfn->p_ll2_info); + qed_ll2_setup(p_hwfn); #endif if (p_hwfn->hw_info.personality == QED_PCI_FCOE) - qed_fcoe_setup(p_hwfn, p_hwfn->p_fcoe_info); + qed_fcoe_setup(p_hwfn); if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) { - qed_iscsi_setup(p_hwfn, p_hwfn->p_iscsi_info); - qed_ooo_setup(p_hwfn, p_hwfn->p_ooo_info); + qed_iscsi_setup(p_hwfn); + qed_ooo_setup(p_hwfn); } } } @@ -1122,7 +1120,7 @@ static int qed_calc_hw_mode(struct qed_hwfn *p_hwfn) return -EINVAL; } - switch (p_hwfn->cdev->num_ports_in_engines) { + switch (p_hwfn->cdev->num_ports_in_engine) { case 1: hw_mode |= 1 << MODE_PORTS_PER_ENG_1; break; @@ -1134,7 +1132,7 @@ static int qed_calc_hw_mode(struct qed_hwfn *p_hwfn) break; default: DP_NOTICE(p_hwfn, "num_ports_in_engine = %d not supported\n", - p_hwfn->cdev->num_ports_in_engines); + p_hwfn->cdev->num_ports_in_engine); return -EINVAL; } @@ -1169,7 +1167,7 @@ static int qed_calc_hw_mode(struct qed_hwfn *p_hwfn) static void qed_init_cau_rt_data(struct qed_dev *cdev) { u32 offset = CAU_REG_SB_VAR_MEMORY_RT_OFFSET; - int i, sb_id; + int i, igu_sb_id; for_each_hwfn(cdev, i) { struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; @@ -1179,15 +1177,17 @@ static void qed_init_cau_rt_data(struct qed_dev *cdev) p_igu_info = p_hwfn->hw_info.p_igu_info; - for (sb_id = 0; sb_id < QED_MAPPING_MEMORY_SIZE(cdev); - sb_id++) { - p_block = &p_igu_info->igu_map.igu_blocks[sb_id]; + for (igu_sb_id = 0; + igu_sb_id < QED_MAPPING_MEMORY_SIZE(cdev); igu_sb_id++) { + p_block = &p_igu_info->entry[igu_sb_id]; + if (!p_block->is_pf) continue; qed_init_cau_sb_entry(p_hwfn, &sb_entry, p_block->function_id, 0, 0); - STORE_RT_REG_AGG(p_hwfn, offset + sb_id * 2, sb_entry); + STORE_RT_REG_AGG(p_hwfn, offset + igu_sb_id * 2, + sb_entry); } } } @@ -1241,6 +1241,10 @@ static void qed_init_cache_line_size(struct qed_hwfn *p_hwfn, L1_CACHE_BYTES, wr_mbs); STORE_RT_REG(p_hwfn, PGLUE_REG_B_CACHE_LINE_SIZE_RT_OFFSET, val); + if (val > 0) { + STORE_RT_REG(p_hwfn, PSWRQ2_REG_DRAM_ALIGN_WR_RT_OFFSET, val); + STORE_RT_REG(p_hwfn, PSWRQ2_REG_DRAM_ALIGN_RD_RT_OFFSET, val); + } } static int qed_hw_init_common(struct qed_hwfn *p_hwfn, @@ -1267,7 +1271,7 @@ static int qed_hw_init_common(struct qed_hwfn *p_hwfn, } memset(¶ms, 0, sizeof(params)); - params.max_ports_per_engine = p_hwfn->cdev->num_ports_in_engines; + params.max_ports_per_engine = p_hwfn->cdev->num_ports_in_engine; params.max_phys_tcs_per_port = qm_info->max_phys_tcs_per_port; params.pf_rl_en = qm_info->pf_rl_en; params.pf_wfq_en = qm_info->pf_wfq_en; @@ -1447,8 +1451,15 @@ qed_hw_init_pf_doorbell_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) static int qed_hw_init_port(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, int hw_mode) { - return qed_init_run(p_hwfn, p_ptt, PHASE_PORT, - p_hwfn->port_id, hw_mode); + int rc = 0; + + rc = qed_init_run(p_hwfn, p_ptt, PHASE_PORT, p_hwfn->port_id, hw_mode); + if (rc) + return rc; + + qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_MASTER_WRITE_PAD_ENABLE, 0); + + return 0; } static int qed_hw_init_pf(struct qed_hwfn *p_hwfn, @@ -1527,7 +1538,8 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn, qed_int_igu_enable(p_hwfn, p_ptt, int_mode); /* send function start command */ - rc = qed_sp_pf_start(p_hwfn, p_tunn, p_hwfn->cdev->mf_mode, + rc = qed_sp_pf_start(p_hwfn, p_ptt, p_tunn, + p_hwfn->cdev->mf_mode, allow_npar_tx_switch); if (rc) { DP_NOTICE(p_hwfn, "Function start ramrod failed\n"); @@ -1711,6 +1723,11 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) return mfw_rc; } + /* Check if there is a DID mismatch between nvm-cfg/efuse */ + if (param & FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR) + DP_NOTICE(p_hwfn, + "warning: device configuration is not supported on this board type. The device may not function as expected.\n"); + /* send DCBX attention request command */ DP_VERBOSE(p_hwfn, QED_MSG_DCB, @@ -1956,6 +1973,13 @@ int qed_hw_start_fastpath(struct qed_hwfn *p_hwfn) if (!p_ptt) return -EAGAIN; + /* If roce info is allocated it means roce is initialized and should + * be enabled in searcher. + */ + if (p_hwfn->p_rdma_info && + p_hwfn->b_rdma_enabled_in_prs) + qed_wr(p_hwfn, p_ptt, p_hwfn->rdma_prs_search_reg, 0x1); + /* Re-open incoming traffic */ qed_wr(p_hwfn, p_ptt, NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x0); qed_ptt_release(p_hwfn, p_ptt); @@ -1968,6 +1992,7 @@ static void qed_hw_hwfn_free(struct qed_hwfn *p_hwfn) { qed_ptt_pool_free(p_hwfn); kfree(p_hwfn->hw_info.p_igu_info); + p_hwfn->hw_info.p_igu_info = NULL; } /* Setup bar access */ @@ -2025,9 +2050,12 @@ static void get_function_id(struct qed_hwfn *p_hwfn) static void qed_hw_set_feat(struct qed_hwfn *p_hwfn) { u32 *feat_num = p_hwfn->hw_info.feat_num; - struct qed_sb_cnt_info sb_cnt_info; + struct qed_sb_cnt_info sb_cnt; u32 non_l2_sbs = 0; + memset(&sb_cnt, 0, sizeof(sb_cnt)); + qed_int_get_num_sbs(p_hwfn, &sb_cnt); + if (IS_ENABLED(CONFIG_QED_RDMA) && p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) { /* Roce CNQ each requires: 1 status block + 1 CNQ. We divide @@ -2035,7 +2063,7 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn) * consideration as to how many l2 queues / cnqs we have. */ feat_num[QED_RDMA_CNQ] = - min_t(u32, RESC_NUM(p_hwfn, QED_SB) / 2, + min_t(u32, sb_cnt.cnt / 2, RESC_NUM(p_hwfn, QED_RDMA_CNQ_RAM)); non_l2_sbs = feat_num[QED_RDMA_CNQ]; @@ -2044,32 +2072,35 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn) if (p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE || p_hwfn->hw_info.personality == QED_PCI_ETH) { /* Start by allocating VF queues, then PF's */ - memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); - qed_int_get_num_sbs(p_hwfn, &sb_cnt_info); feat_num[QED_VF_L2_QUE] = min_t(u32, RESC_NUM(p_hwfn, QED_L2_QUEUE), - sb_cnt_info.sb_iov_cnt); + sb_cnt.iov_cnt); feat_num[QED_PF_L2_QUE] = min_t(u32, - RESC_NUM(p_hwfn, QED_SB) - - non_l2_sbs, + sb_cnt.cnt - non_l2_sbs, RESC_NUM(p_hwfn, QED_L2_QUEUE) - FEAT_NUM(p_hwfn, QED_VF_L2_QUE)); } + if (p_hwfn->hw_info.personality == QED_PCI_FCOE) + feat_num[QED_FCOE_CQ] = min_t(u32, sb_cnt.cnt, + RESC_NUM(p_hwfn, + QED_CMDQS_CQS)); + if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) - feat_num[QED_ISCSI_CQ] = min_t(u32, RESC_NUM(p_hwfn, QED_SB), + feat_num[QED_ISCSI_CQ] = min_t(u32, sb_cnt.cnt, RESC_NUM(p_hwfn, QED_CMDQS_CQS)); DP_VERBOSE(p_hwfn, NETIF_MSG_PROBE, - "#PF_L2_QUEUES=%d VF_L2_QUEUES=%d #ROCE_CNQ=%d ISCSI_CQ=%d #SBS=%d\n", + "#PF_L2_QUEUES=%d VF_L2_QUEUES=%d #ROCE_CNQ=%d FCOE_CQ=%d ISCSI_CQ=%d #SBS=%d\n", (int)FEAT_NUM(p_hwfn, QED_PF_L2_QUE), (int)FEAT_NUM(p_hwfn, QED_VF_L2_QUE), (int)FEAT_NUM(p_hwfn, QED_RDMA_CNQ), + (int)FEAT_NUM(p_hwfn, QED_FCOE_CQ), (int)FEAT_NUM(p_hwfn, QED_ISCSI_CQ), - RESC_NUM(p_hwfn, QED_SB)); + (int)sb_cnt.cnt); } const char *qed_hw_get_resc_name(enum qed_resources res_id) @@ -2188,7 +2219,6 @@ int qed_hw_get_dflt_resc(struct qed_hwfn *p_hwfn, { u8 num_funcs = p_hwfn->num_funcs_on_engine; bool b_ah = QED_IS_AH(p_hwfn->cdev); - struct qed_sb_cnt_info sb_cnt_info; switch (res_id) { case QED_L2_QUEUE: @@ -2240,9 +2270,10 @@ int qed_hw_get_dflt_resc(struct qed_hwfn *p_hwfn, *p_resc_num = 1; break; case QED_SB: - memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); - qed_int_get_num_sbs(p_hwfn, &sb_cnt_info); - *p_resc_num = sb_cnt_info.sb_cnt; + /* Since we want its value to reflect whether MFW supports + * the new scheme, have a default of 0. + */ + *p_resc_num = 0; break; default: return -EINVAL; @@ -2252,7 +2283,7 @@ int qed_hw_get_dflt_resc(struct qed_hwfn *p_hwfn, case QED_BDQ: if (!*p_resc_num) *p_resc_start = 0; - else if (p_hwfn->cdev->num_ports_in_engines == 4) + else if (p_hwfn->cdev->num_ports_in_engine == 4) *p_resc_start = p_hwfn->port_id; else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) *p_resc_start = p_hwfn->port_id; @@ -2311,11 +2342,6 @@ static int __qed_hw_set_resc_info(struct qed_hwfn *p_hwfn, goto out; } - /* Special handling for status blocks; Would be revised in future */ - if (res_id == QED_SB) { - *p_resc_num -= 1; - *p_resc_start -= p_hwfn->enabled_func_idx; - } out: /* PQs have to divide by 8 [that's the HW granularity]. * Reduce number so it would fit. @@ -2413,6 +2439,10 @@ static int qed_hw_get_resc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) return -EINVAL; } + /* This will also learn the number of SBs from MFW */ + if (qed_int_igu_reset_cam(p_hwfn, p_ptt)) + return -EINVAL; + qed_hw_set_feat(p_hwfn); for (res_id = 0; res_id < QED_MAX_RESC; res_id++) @@ -2669,15 +2699,15 @@ static void qed_hw_info_port_num_bb(struct qed_hwfn *p_hwfn, port_mode = qed_rd(p_hwfn, p_ptt, CNIG_REG_NW_PORT_MODE_BB_B0); if (port_mode < 3) { - p_hwfn->cdev->num_ports_in_engines = 1; + p_hwfn->cdev->num_ports_in_engine = 1; } else if (port_mode <= 5) { - p_hwfn->cdev->num_ports_in_engines = 2; + p_hwfn->cdev->num_ports_in_engine = 2; } else { DP_NOTICE(p_hwfn, "PORT MODE: %d not supported\n", - p_hwfn->cdev->num_ports_in_engines); + p_hwfn->cdev->num_ports_in_engine); - /* Default num_ports_in_engines to something */ - p_hwfn->cdev->num_ports_in_engines = 1; + /* Default num_ports_in_engine to something */ + p_hwfn->cdev->num_ports_in_engine = 1; } } @@ -2687,20 +2717,20 @@ static void qed_hw_info_port_num_ah(struct qed_hwfn *p_hwfn, u32 port; int i; - p_hwfn->cdev->num_ports_in_engines = 0; + p_hwfn->cdev->num_ports_in_engine = 0; for (i = 0; i < MAX_NUM_PORTS_K2; i++) { port = qed_rd(p_hwfn, p_ptt, CNIG_REG_NIG_PORT0_CONF_K2 + (i * 4)); if (port & 1) - p_hwfn->cdev->num_ports_in_engines++; + p_hwfn->cdev->num_ports_in_engine++; } - if (!p_hwfn->cdev->num_ports_in_engines) { + if (!p_hwfn->cdev->num_ports_in_engine) { DP_NOTICE(p_hwfn, "All NIG ports are inactive\n"); /* Default num_ports_in_engine to something */ - p_hwfn->cdev->num_ports_in_engines = 1; + p_hwfn->cdev->num_ports_in_engine = 1; } } @@ -2819,12 +2849,6 @@ static int qed_get_dev_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) cdev->chip_num, cdev->chip_rev, cdev->chip_bond_id, cdev->chip_metal); - if (QED_IS_BB(cdev) && CHIP_REV_IS_A0(cdev)) { - DP_NOTICE(cdev->hwfns, - "The chip type/rev (BB A0) is not supported!\n"); - return -EINVAL; - } - return 0; } @@ -4074,7 +4098,7 @@ static int qed_device_num_ports(struct qed_dev *cdev) if (cdev->num_hwfns > 1) return 1; - return cdev->num_ports_in_engines * qed_device_num_engines(cdev); + return cdev->num_ports_in_engine * qed_device_num_engines(cdev); } int qed_device_get_port_id(struct qed_dev *cdev) diff --git a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c index 21a58fffd02b..df195c02b711 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c +++ b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c @@ -43,7 +43,6 @@ #include <linux/slab.h> #include <linux/stddef.h> #include <linux/string.h> -#include <linux/version.h> #include <linux/workqueue.h> #include <linux/errno.h> #include <linux/list.h> @@ -142,6 +141,15 @@ qed_sp_fcoe_func_start(struct qed_hwfn *p_hwfn, p_data = &p_ramrod->init_ramrod_data; fcoe_pf_params = &p_hwfn->pf_params.fcoe_pf_params; + /* Sanity */ + if (fcoe_pf_params->num_cqs > p_hwfn->hw_info.feat_num[QED_FCOE_CQ]) { + DP_ERR(p_hwfn, + "Cannot satisfy CQ amount. CQs requested %d, CQs available %d. Aborting function start\n", + fcoe_pf_params->num_cqs, + p_hwfn->hw_info.feat_num[QED_FCOE_CQ]); + return -EINVAL; + } + p_data->mtu = cpu_to_le16(fcoe_pf_params->mtu); tmp = cpu_to_le16(fcoe_pf_params->sq_num_pbl_pages); p_data->sq_num_pages_in_pbl = tmp; @@ -184,7 +192,10 @@ qed_sp_fcoe_func_start(struct qed_hwfn *p_hwfn, p_data->q_params.queue_relative_offset = (u8)tmp; for (i = 0; i < fcoe_pf_params->num_cqs; i++) { - tmp = cpu_to_le16(p_hwfn->sbs_info[i]->igu_sb_id); + u16 igu_sb_id; + + igu_sb_id = qed_get_igu_sb_id(p_hwfn, i); + tmp = cpu_to_le16(igu_sb_id); p_data->q_params.cq_cmdq_sb_num_arr[i] = tmp; } @@ -539,7 +550,7 @@ static void __iomem *qed_fcoe_get_secondary_bdq_prod(struct qed_hwfn *p_hwfn, } } -struct qed_fcoe_info *qed_fcoe_alloc(struct qed_hwfn *p_hwfn) +int qed_fcoe_alloc(struct qed_hwfn *p_hwfn) { struct qed_fcoe_info *p_fcoe_info; @@ -547,19 +558,21 @@ struct qed_fcoe_info *qed_fcoe_alloc(struct qed_hwfn *p_hwfn) p_fcoe_info = kzalloc(sizeof(*p_fcoe_info), GFP_KERNEL); if (!p_fcoe_info) { DP_NOTICE(p_hwfn, "Failed to allocate qed_fcoe_info'\n"); - return NULL; + return -ENOMEM; } INIT_LIST_HEAD(&p_fcoe_info->free_list); - return p_fcoe_info; + + p_hwfn->p_fcoe_info = p_fcoe_info; + return 0; } -void qed_fcoe_setup(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info) +void qed_fcoe_setup(struct qed_hwfn *p_hwfn) { struct fcoe_task_context *p_task_ctx = NULL; int rc; u32 i; - spin_lock_init(&p_fcoe_info->lock); + spin_lock_init(&p_hwfn->p_fcoe_info->lock); for (i = 0; i < p_hwfn->pf_params.fcoe_pf_params.num_tasks; i++) { rc = qed_cxt_get_task_ctx(p_hwfn, i, QED_CTX_WORKING_MEM, @@ -577,15 +590,15 @@ void qed_fcoe_setup(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info) } } -void qed_fcoe_free(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info) +void qed_fcoe_free(struct qed_hwfn *p_hwfn) { struct qed_fcoe_conn *p_conn = NULL; - if (!p_fcoe_info) + if (!p_hwfn->p_fcoe_info) return; - while (!list_empty(&p_fcoe_info->free_list)) { - p_conn = list_first_entry(&p_fcoe_info->free_list, + while (!list_empty(&p_hwfn->p_fcoe_info->free_list)) { + p_conn = list_first_entry(&p_hwfn->p_fcoe_info->free_list, struct qed_fcoe_conn, list_entry); if (!p_conn) break; @@ -593,7 +606,8 @@ void qed_fcoe_free(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info) qed_fcoe_free_connection(p_hwfn, p_conn); } - kfree(p_fcoe_info); + kfree(p_hwfn->p_fcoe_info); + p_hwfn->p_fcoe_info = NULL; } static int @@ -734,6 +748,11 @@ static int qed_fill_fcoe_dev_info(struct qed_dev *cdev, info->secondary_bdq_rq_addr = qed_fcoe_get_secondary_bdq_prod(hwfn, BDQ_ID_RQ); + info->wwpn = hwfn->mcp_info->func_info.wwn_port; + info->wwnn = hwfn->mcp_info->func_info.wwn_node; + + info->num_cqs = FEAT_NUM(hwfn, QED_FCOE_CQ); + return rc; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_fcoe.h b/drivers/net/ethernet/qlogic/qed/qed_fcoe.h index 472af34a171d..027a76ac839a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_fcoe.h +++ b/drivers/net/ethernet/qlogic/qed/qed_fcoe.h @@ -49,29 +49,21 @@ struct qed_fcoe_info { }; #if IS_ENABLED(CONFIG_QED_FCOE) -struct qed_fcoe_info *qed_fcoe_alloc(struct qed_hwfn *p_hwfn); +int qed_fcoe_alloc(struct qed_hwfn *p_hwfn); -void qed_fcoe_setup(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info); +void qed_fcoe_setup(struct qed_hwfn *p_hwfn); -void qed_fcoe_free(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info); +void qed_fcoe_free(struct qed_hwfn *p_hwfn); void qed_get_protocol_stats_fcoe(struct qed_dev *cdev, struct qed_mcp_fcoe_stats *stats); #else /* CONFIG_QED_FCOE */ -static inline struct qed_fcoe_info * -qed_fcoe_alloc(struct qed_hwfn *p_hwfn) +static inline int qed_fcoe_alloc(struct qed_hwfn *p_hwfn) { - return NULL; + return -EINVAL; } -static inline void qed_fcoe_setup(struct qed_hwfn *p_hwfn, - struct qed_fcoe_info *p_fcoe_info) -{ -} - -static inline void qed_fcoe_free(struct qed_hwfn *p_hwfn, - struct qed_fcoe_info *p_fcoe_info) -{ -} +static inline void qed_fcoe_setup(struct qed_hwfn *p_hwfn) {} +static inline void qed_fcoe_free(struct qed_hwfn *p_hwfn) {} static inline void qed_get_protocol_stats_fcoe(struct qed_dev *cdev, struct qed_mcp_fcoe_stats *stats) diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index 858a57a73589..3bf3614b3084 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -346,7 +346,7 @@ struct xstorm_core_conn_ag_ctx { u8 byte13; u8 byte14; u8 byte15; - u8 byte16; + u8 e5_reserved; __le16 word11; __le32 reg10; __le32 reg11; @@ -368,85 +368,85 @@ struct tstorm_core_conn_ag_ctx { u8 byte0; u8 byte1; u8 flags0; -#define TSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 -#define TSTORM_CORE_CONN_AG_CTX_BIT2_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_BIT2_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_BIT3_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_BIT3_SHIFT 3 -#define TSTORM_CORE_CONN_AG_CTX_BIT4_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_BIT4_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_BIT5_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_BIT5_SHIFT 5 -#define TSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 /* exist_in_qm0 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 /* exist_in_qm1 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 +#define TSTORM_CORE_CONN_AG_CTX_BIT2_MASK 0x1 /* bit2 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT2_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_BIT3_MASK 0x1 /* bit3 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT3_SHIFT 3 +#define TSTORM_CORE_CONN_AG_CTX_BIT4_MASK 0x1 /* bit4 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT4_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_BIT5_MASK 0x1 /* bit5 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT5_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 /* timer0cf */ +#define TSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 6 u8 flags1; -#define TSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_CF3_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF3_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_CF4_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF4_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 /* timer1cf */ +#define TSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 /* timer2cf */ +#define TSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF3_MASK 0x3 /* timer_stop_all */ +#define TSTORM_CORE_CONN_AG_CTX_CF3_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF4_MASK 0x3 /* cf4 */ +#define TSTORM_CORE_CONN_AG_CTX_CF4_SHIFT 6 u8 flags2; -#define TSTORM_CORE_CONN_AG_CTX_CF5_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF5_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_CF6_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF6_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_CF7_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF7_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_CF8_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF8_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_CF5_MASK 0x3 /* cf5 */ +#define TSTORM_CORE_CONN_AG_CTX_CF5_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF6_MASK 0x3 /* cf6 */ +#define TSTORM_CORE_CONN_AG_CTX_CF6_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF7_MASK 0x3 /* cf7 */ +#define TSTORM_CORE_CONN_AG_CTX_CF7_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF8_MASK 0x3 /* cf8 */ +#define TSTORM_CORE_CONN_AG_CTX_CF8_SHIFT 6 u8 flags3; -#define TSTORM_CORE_CONN_AG_CTX_CF9_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF9_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_CF10_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF10_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 5 -#define TSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 6 -#define TSTORM_CORE_CONN_AG_CTX_CF3EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT 7 +#define TSTORM_CORE_CONN_AG_CTX_CF9_MASK 0x3 /* cf9 */ +#define TSTORM_CORE_CONN_AG_CTX_CF9_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF10_MASK 0x3 /* cf10 */ +#define TSTORM_CORE_CONN_AG_CTX_CF10_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ +#define TSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ +#define TSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ +#define TSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_CF3EN_MASK 0x1 /* cf3en */ +#define TSTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT 7 u8 flags4; -#define TSTORM_CORE_CONN_AG_CTX_CF4EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_CF5EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT 1 -#define TSTORM_CORE_CONN_AG_CTX_CF6EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_CF7EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF7EN_SHIFT 3 -#define TSTORM_CORE_CONN_AG_CTX_CF8EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF8EN_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_CF9EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF9EN_SHIFT 5 -#define TSTORM_CORE_CONN_AG_CTX_CF10EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF10EN_SHIFT 6 -#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 7 +#define TSTORM_CORE_CONN_AG_CTX_CF4EN_MASK 0x1 /* cf4en */ +#define TSTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF5EN_MASK 0x1 /* cf5en */ +#define TSTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT 1 +#define TSTORM_CORE_CONN_AG_CTX_CF6EN_MASK 0x1 /* cf6en */ +#define TSTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF7EN_MASK 0x1 /* cf7en */ +#define TSTORM_CORE_CONN_AG_CTX_CF7EN_SHIFT 3 +#define TSTORM_CORE_CONN_AG_CTX_CF8EN_MASK 0x1 /* cf8en */ +#define TSTORM_CORE_CONN_AG_CTX_CF8EN_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF9EN_MASK 0x1 /* cf9en */ +#define TSTORM_CORE_CONN_AG_CTX_CF9EN_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_CF10EN_MASK 0x1 /* cf10en */ +#define TSTORM_CORE_CONN_AG_CTX_CF10EN_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 /* rule0en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 7 u8 flags5; -#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 1 -#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 3 -#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 5 -#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 6 -#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_SHIFT 7 +#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 /* rule1en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 /* rule2en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 /* rule3en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 /* rule4en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_MASK 0x1 /* rule5en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_MASK 0x1 /* rule6en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_MASK 0x1 /* rule7en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_MASK 0x1 /* rule8en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_SHIFT 7 __le32 reg0; __le32 reg1; __le32 reg2; @@ -681,7 +681,9 @@ struct core_rx_fast_path_cqe { __le16 packet_length; __le16 vlan; struct core_rx_cqe_opaque_data opaque_data; - __le32 reserved[4]; + struct parsing_err_flags err_flags; + __le16 reserved0; + __le32 reserved1[3]; }; struct core_rx_gsi_offload_cqe { @@ -692,7 +694,7 @@ struct core_rx_gsi_offload_cqe { __le16 vlan; __le32 src_mac_addrhi; __le16 src_mac_addrlo; - u8 reserved1[2]; + __le16 qp_id; __le32 gid_dst[4]; }; @@ -774,15 +776,15 @@ struct core_tx_bd { __le16 bitfield1; #define CORE_TX_BD_L4_HDR_OFFSET_W_MASK 0x3FFF #define CORE_TX_BD_L4_HDR_OFFSET_W_SHIFT 0 -#define CORE_TX_BD_TX_DST_MASK 0x1 -#define CORE_TX_BD_TX_DST_SHIFT 14 -#define CORE_TX_BD_RESERVED_MASK 0x1 -#define CORE_TX_BD_RESERVED_SHIFT 15 +#define CORE_TX_BD_TX_DST_MASK 0x3 +#define CORE_TX_BD_TX_DST_SHIFT 14 }; enum core_tx_dest { CORE_TX_DEST_NW, CORE_TX_DEST_LB, + CORE_TX_DEST_RESERVED, + CORE_TX_DEST_DROP, MAX_CORE_TX_DEST }; @@ -804,12 +806,12 @@ struct core_tx_stop_ramrod_data { __le32 reserved0[2]; }; -enum dcb_dhcp_update_flag { - DONT_UPDATE_DCB_DHCP, +enum dcb_dscp_update_mode { + DONT_UPDATE_DCB_DSCP, UPDATE_DCB, UPDATE_DSCP, UPDATE_DCB_DSCP, - MAX_DCB_DHCP_UPDATE_FLAG + MAX_DCB_DSCP_UPDATE_MODE }; struct eth_mstorm_per_pf_stat { @@ -917,6 +919,14 @@ struct hsi_fp_ver_struct { u8 major_ver_arr[2]; }; +enum iwarp_ll2_tx_queues { + IWARP_LL2_IN_ORDER_TX_QUEUE = 1, + IWARP_LL2_ALIGNED_TX_QUEUE, + IWARP_LL2_ALIGNED_RIGHT_TRIMMED_TX_QUEUE, + IWARP_LL2_ERROR, + MAX_IWARP_LL2_TX_QUEUES +}; + /* Mstorm non-triggering VF zone */ enum malicious_vf_error_id { MALICIOUS_VF_NO_ERROR, @@ -960,7 +970,7 @@ enum personality_type { PERSONALITY_ISCSI, PERSONALITY_FCOE, PERSONALITY_RDMA_AND_ETH, - PERSONALITY_RESERVED3, + PERSONALITY_RDMA, PERSONALITY_CORE, PERSONALITY_ETH, PERSONALITY_RESERVED4, @@ -971,16 +981,12 @@ enum personality_type { struct pf_start_tunnel_config { u8 set_vxlan_udp_port_flg; u8 set_geneve_udp_port_flg; - u8 tx_enable_vxlan; - u8 tx_enable_l2geneve; - u8 tx_enable_ipgeneve; - u8 tx_enable_l2gre; - u8 tx_enable_ipgre; u8 tunnel_clss_vxlan; u8 tunnel_clss_l2geneve; u8 tunnel_clss_ipgeneve; u8 tunnel_clss_l2gre; u8 tunnel_clss_ipgre; + u8 reserved; __le16 vxlan_udp_port; __le16 geneve_udp_port; }; @@ -990,6 +996,7 @@ struct pf_start_ramrod_data { struct regpair event_ring_pbl_addr; struct regpair consolid_q_pbl_addr; struct pf_start_tunnel_config tunnel_config; + __le32 reserved; __le16 event_ring_sb_id; u8 base_vf_id; u8 num_vfs; @@ -1007,7 +1014,6 @@ struct pf_start_ramrod_data { u8 pri_map_valid; __le32 outer_tag; struct hsi_fp_ver_struct hsi_fp_ver; - }; struct protocol_dcb_data { @@ -1023,14 +1029,8 @@ struct pf_update_tunnel_config { u8 update_rx_pf_clss; u8 update_rx_def_ucast_clss; u8 update_rx_def_non_ucast_clss; - u8 update_tx_pf_clss; u8 set_vxlan_udp_port_flg; u8 set_geneve_udp_port_flg; - u8 tx_enable_vxlan; - u8 tx_enable_l2geneve; - u8 tx_enable_ipgeneve; - u8 tx_enable_l2gre; - u8 tx_enable_ipgre; u8 tunnel_clss_vxlan; u8 tunnel_clss_l2geneve; u8 tunnel_clss_ipgeneve; @@ -1038,17 +1038,17 @@ struct pf_update_tunnel_config { u8 tunnel_clss_ipgre; __le16 vxlan_udp_port; __le16 geneve_udp_port; - __le16 reserved[2]; + __le16 reserved; }; struct pf_update_ramrod_data { u8 pf_id; - u8 update_eth_dcb_data_flag; - u8 update_fcoe_dcb_data_flag; - u8 update_iscsi_dcb_data_flag; - u8 update_roce_dcb_data_flag; - u8 update_rroce_dcb_data_flag; - u8 update_iwarp_dcb_data_flag; + u8 update_eth_dcb_data_mode; + u8 update_fcoe_dcb_data_mode; + u8 update_iscsi_dcb_data_mode; + u8 update_roce_dcb_data_mode; + u8 update_rroce_dcb_data_mode; + u8 update_iwarp_dcb_data_mode; u8 update_mf_vlan_flag; struct protocol_dcb_data eth_dcb_data; struct protocol_dcb_data fcoe_dcb_data; @@ -1127,7 +1127,7 @@ struct tstorm_per_port_stat { struct regpair iscsi_irregular_pkt; struct regpair fcoe_irregular_pkt; struct regpair roce_irregular_pkt; - struct regpair reserved; + struct regpair iwarp_irregular_pkt; struct regpair eth_irregular_pkt; struct regpair reserved1; struct regpair preroce_irregular_pkt; @@ -1326,6 +1326,87 @@ enum dmae_cmd_src_enum { MAX_DMAE_CMD_SRC_ENUM }; +struct mstorm_core_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define MSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 +#define MSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 +#define MSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 +#define MSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 +#define MSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 +#define MSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 +#define MSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 +#define MSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define MSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 +#define MSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 +#define MSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 +#define MSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define MSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define MSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define MSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define MSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 7 + __le16 word0; + __le16 word1; + __le32 reg0; + __le32 reg1; +}; + +struct ystorm_core_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define YSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 +#define YSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 +#define YSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 +#define YSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 +#define YSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 +#define YSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 +#define YSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 +#define YSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define YSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 +#define YSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 +#define YSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 +#define YSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define YSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define YSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define YSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define YSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le32 reg0; + __le32 reg1; + __le16 word1; + __le16 word2; + __le16 word3; + __le16 word4; + __le32 reg2; + __le32 reg3; +}; + /* IGU cleanup command */ struct igu_cleanup { __le32 sb_id_and_flags; @@ -1389,44 +1470,6 @@ struct igu_msix_vector { #define IGU_MSIX_VECTOR_RESERVED1_MASK 0xFF #define IGU_MSIX_VECTOR_RESERVED1_SHIFT 24 }; - -struct mstorm_core_conn_ag_ctx { - u8 byte0; - u8 byte1; - u8 flags0; -#define MSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 -#define MSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 -#define MSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 -#define MSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 -#define MSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 -#define MSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 -#define MSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 -#define MSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 - u8 flags1; -#define MSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 -#define MSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 -#define MSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 -#define MSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 3 -#define MSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 4 -#define MSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 5 -#define MSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 6 -#define MSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 7 - __le16 word0; - __le16 word1; - __le32 reg0; - __le32 reg1; -}; - /* per encapsulation type enabling flags */ struct prs_reg_encapsulation_type_en { u8 flags; @@ -1541,50 +1584,6 @@ struct sdm_op_gen { #define SDM_OP_GEN_RESERVED_SHIFT 20 }; -struct ystorm_core_conn_ag_ctx { - u8 byte0; - u8 byte1; - u8 flags0; -#define YSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 -#define YSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 -#define YSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 -#define YSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 -#define YSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 -#define YSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 -#define YSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 -#define YSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 - u8 flags1; -#define YSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 -#define YSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 -#define YSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 -#define YSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 3 -#define YSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 4 -#define YSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 5 -#define YSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 6 -#define YSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 7 - u8 byte2; - u8 byte3; - __le16 word0; - __le32 reg0; - __le32 reg1; - __le16 word1; - __le16 word2; - __le16 word3; - __le16 word4; - __le32 reg2; - __le32 reg3; -}; - /****************************************/ /* Debug Tools HSI constants and macros */ /****************************************/ @@ -1643,6 +1642,8 @@ enum block_addr { GRCBASE_MULD = 0x4e0000, GRCBASE_YULD = 0x4c8000, GRCBASE_XYLD = 0x4c0000, + GRCBASE_PTLD = 0x590000, + GRCBASE_YPLD = 0x5b0000, GRCBASE_PRM = 0x230000, GRCBASE_PBF_PB1 = 0xda0000, GRCBASE_PBF_PB2 = 0xda4000, @@ -1656,6 +1657,10 @@ enum block_addr { GRCBASE_TCFC = 0x2d0000, GRCBASE_IGU = 0x180000, GRCBASE_CAU = 0x1c0000, + GRCBASE_RGFS = 0xf00000, + GRCBASE_RGSRC = 0x320000, + GRCBASE_TGFS = 0xd00000, + GRCBASE_TGSRC = 0x322000, GRCBASE_UMAC = 0x51000, GRCBASE_XMAC = 0x210000, GRCBASE_DBG = 0x10000, @@ -1669,10 +1674,6 @@ enum block_addr { GRCBASE_PHY_PCIE = 0x620000, GRCBASE_LED = 0x6b8000, GRCBASE_AVS_WRAP = 0x6b0000, - GRCBASE_RGFS = 0x19d0000, - GRCBASE_TGFS = 0x19e0000, - GRCBASE_PTLD = 0x19f0000, - GRCBASE_YPLD = 0x1a10000, GRCBASE_MISC_AEU = 0x8000, GRCBASE_BAR0_MAP = 0x1c00000, MAX_BLOCK_ADDR @@ -1732,6 +1733,8 @@ enum block_id { BLOCK_MULD, BLOCK_YULD, BLOCK_XYLD, + BLOCK_PTLD, + BLOCK_YPLD, BLOCK_PRM, BLOCK_PBF_PB1, BLOCK_PBF_PB2, @@ -1745,6 +1748,10 @@ enum block_id { BLOCK_TCFC, BLOCK_IGU, BLOCK_CAU, + BLOCK_RGFS, + BLOCK_RGSRC, + BLOCK_TGFS, + BLOCK_TGSRC, BLOCK_UMAC, BLOCK_XMAC, BLOCK_DBG, @@ -1758,10 +1765,6 @@ enum block_id { BLOCK_PHY_PCIE, BLOCK_LED, BLOCK_AVS_WRAP, - BLOCK_RGFS, - BLOCK_TGFS, - BLOCK_PTLD, - BLOCK_YPLD, BLOCK_MISC_AEU, BLOCK_BAR0_MAP, MAX_BLOCK_ID @@ -1780,6 +1783,10 @@ enum bin_dbg_buffer_type { BIN_BUF_DBG_ATTN_REGS, BIN_BUF_DBG_ATTN_INDEXES, BIN_BUF_DBG_ATTN_NAME_OFFSETS, + BIN_BUF_DBG_BUS_BLOCKS, + BIN_BUF_DBG_BUS_LINES, + BIN_BUF_DBG_BUS_BLOCKS_USER_DATA, + BIN_BUF_DBG_BUS_LINE_NAME_OFFSETS, BIN_BUF_DBG_PARSING_STRINGS, MAX_BIN_DBG_BUFFER_TYPE }; @@ -1862,6 +1869,29 @@ enum dbg_attn_type { MAX_DBG_ATTN_TYPE }; +struct dbg_bus_block { + u8 num_of_lines; + u8 has_latency_events; + __le16 lines_offset; +}; + +struct dbg_bus_block_user_data { + u8 num_of_lines; + u8 has_latency_events; + __le16 names_offset; +}; + +struct dbg_bus_line { + u8 data; +#define DBG_BUS_LINE_NUM_OF_GROUPS_MASK 0xF +#define DBG_BUS_LINE_NUM_OF_GROUPS_SHIFT 0 +#define DBG_BUS_LINE_IS_256B_MASK 0x1 +#define DBG_BUS_LINE_IS_256B_SHIFT 4 +#define DBG_BUS_LINE_RESERVED_MASK 0x7 +#define DBG_BUS_LINE_RESERVED_SHIFT 5 + u8 group_sizes; +}; + /* condition header for registers dump */ struct dbg_dump_cond_hdr { struct dbg_mode_hdr mode; /* Mode header */ @@ -1879,17 +1909,21 @@ struct dbg_dump_mem { __le32 dword1; #define DBG_DUMP_MEM_LENGTH_MASK 0xFFFFFF #define DBG_DUMP_MEM_LENGTH_SHIFT 0 -#define DBG_DUMP_MEM_RESERVED_MASK 0xFF -#define DBG_DUMP_MEM_RESERVED_SHIFT 24 +#define DBG_DUMP_MEM_WIDE_BUS_MASK 0x1 +#define DBG_DUMP_MEM_WIDE_BUS_SHIFT 24 +#define DBG_DUMP_MEM_RESERVED_MASK 0x7F +#define DBG_DUMP_MEM_RESERVED_SHIFT 25 }; /* register data for registers dump */ struct dbg_dump_reg { __le32 data; -#define DBG_DUMP_REG_ADDRESS_MASK 0xFFFFFF /* register address (in dwords) */ +#define DBG_DUMP_REG_ADDRESS_MASK 0x7FFFFF /* register address (in dwords) */ #define DBG_DUMP_REG_ADDRESS_SHIFT 0 -#define DBG_DUMP_REG_LENGTH_MASK 0xFF /* register size (in dwords) */ -#define DBG_DUMP_REG_LENGTH_SHIFT 24 +#define DBG_DUMP_REG_WIDE_BUS_MASK 0x1 /* indicates register is wide-bus */ +#define DBG_DUMP_REG_WIDE_BUS_SHIFT 23 +#define DBG_DUMP_REG_LENGTH_MASK 0xFF /* register size (in dwords) */ +#define DBG_DUMP_REG_LENGTH_SHIFT 24 }; /* split header for registers dump */ @@ -1910,20 +1944,24 @@ struct dbg_idle_chk_cond_hdr { /* Idle Check condition register */ struct dbg_idle_chk_cond_reg { __le32 data; -#define DBG_IDLE_CHK_COND_REG_ADDRESS_MASK 0xFFFFFF +#define DBG_IDLE_CHK_COND_REG_ADDRESS_MASK 0x7FFFFF #define DBG_IDLE_CHK_COND_REG_ADDRESS_SHIFT 0 +#define DBG_IDLE_CHK_COND_REG_WIDE_BUS_MASK 0x1 +#define DBG_IDLE_CHK_COND_REG_WIDE_BUS_SHIFT 23 #define DBG_IDLE_CHK_COND_REG_BLOCK_ID_MASK 0xFF #define DBG_IDLE_CHK_COND_REG_BLOCK_ID_SHIFT 24 - __le16 num_entries; /* number of registers entries to check */ - u8 entry_size; /* size of registers entry (in dwords) */ - u8 start_entry; /* index of the first entry to check */ + __le16 num_entries; + u8 entry_size; + u8 start_entry; }; /* Idle Check info register */ struct dbg_idle_chk_info_reg { __le32 data; -#define DBG_IDLE_CHK_INFO_REG_ADDRESS_MASK 0xFFFFFF +#define DBG_IDLE_CHK_INFO_REG_ADDRESS_MASK 0x7FFFFF #define DBG_IDLE_CHK_INFO_REG_ADDRESS_SHIFT 0 +#define DBG_IDLE_CHK_INFO_REG_WIDE_BUS_MASK 0x1 +#define DBG_IDLE_CHK_INFO_REG_WIDE_BUS_SHIFT 23 #define DBG_IDLE_CHK_INFO_REG_BLOCK_ID_MASK 0xFF #define DBG_IDLE_CHK_INFO_REG_BLOCK_ID_SHIFT 24 __le16 size; /* register size in dwords */ @@ -1996,15 +2034,17 @@ enum dbg_idle_chk_severity_types { /* Debug Bus block data */ struct dbg_bus_block_data { - u8 enabled; /* Indicates if the block is enabled for recording (0/1) */ - u8 hw_id; /* HW ID associated with the block */ - u8 line_num; /* Debug line number to select */ - u8 right_shift; /* Number of units to right the debug data (0-3) */ - u8 cycle_en; /* 4-bit value: bit i set -> unit i is enabled. */ - u8 force_valid; /* 4-bit value: bit i set -> unit i is forced valid. */ - u8 force_frame; /* 4-bit value: bit i set -> unit i frame bit is forced. - */ - u8 reserved; + __le16 data; +#define DBG_BUS_BLOCK_DATA_ENABLE_MASK_MASK 0xF +#define DBG_BUS_BLOCK_DATA_ENABLE_MASK_SHIFT 0 +#define DBG_BUS_BLOCK_DATA_RIGHT_SHIFT_MASK 0xF +#define DBG_BUS_BLOCK_DATA_RIGHT_SHIFT_SHIFT 4 +#define DBG_BUS_BLOCK_DATA_FORCE_VALID_MASK_MASK 0xF +#define DBG_BUS_BLOCK_DATA_FORCE_VALID_MASK_SHIFT 8 +#define DBG_BUS_BLOCK_DATA_FORCE_FRAME_MASK_MASK 0xF +#define DBG_BUS_BLOCK_DATA_FORCE_FRAME_MASK_SHIFT 12 + u8 line_num; + u8 hw_id; }; /* Debug Bus Clients */ @@ -2045,6 +2085,14 @@ enum dbg_bus_constraint_ops { MAX_DBG_BUS_CONSTRAINT_OPS }; +struct dbg_bus_trigger_state_data { + u8 data; +#define DBG_BUS_TRIGGER_STATE_DATA_BLOCK_SHIFTED_ENABLE_MASK_MASK 0xF +#define DBG_BUS_TRIGGER_STATE_DATA_BLOCK_SHIFTED_ENABLE_MASK_SHIFT 0 +#define DBG_BUS_TRIGGER_STATE_DATA_CONSTRAINT_DWORD_MASK_MASK 0xF +#define DBG_BUS_TRIGGER_STATE_DATA_CONSTRAINT_DWORD_MASK_SHIFT 4 +}; + /* Debug Bus memory address */ struct dbg_bus_mem_addr { __le32 lo; @@ -2078,66 +2126,42 @@ union dbg_bus_storm_eid_params { /* Debug Bus Storm data */ struct dbg_bus_storm_data { - u8 fast_enabled; - u8 fast_mode; - u8 slow_enabled; - u8 slow_mode; + u8 enabled; + u8 mode; u8 hw_id; u8 eid_filter_en; u8 eid_range_not_mask; u8 cid_filter_en; union dbg_bus_storm_eid_params eid_filter_params; - __le16 reserved; __le32 cid; }; /* Debug Bus data */ struct dbg_bus_data { - __le32 app_version; /* The tools version number of the application */ - u8 state; /* The current debug bus state */ - u8 hw_dwords; /* HW dwords per cycle */ - u8 next_hw_id; /* Next HW ID to be associated with an input */ - u8 num_enabled_blocks; /* Number of blocks enabled for recording */ - u8 num_enabled_storms; /* Number of Storms enabled for recording */ - u8 target; /* Output target */ - u8 next_trigger_state; /* ID of next trigger state to be added */ - u8 next_constraint_id; /* ID of next filter/trigger constraint to be - * added. - */ - u8 one_shot_en; /* Indicates if one-shot mode is enabled (0/1) */ - u8 grc_input_en; /* Indicates if GRC recording is enabled (0/1) */ - u8 timestamp_input_en; /* Indicates if timestamp recording is enabled - * (0/1). - */ - u8 filter_en; /* Indicates if the recording filter is enabled (0/1) */ - u8 trigger_en; /* Indicates if the recording trigger is enabled (0/1) */ - u8 adding_filter; /* If true, the next added constraint belong to the - * filter. Otherwise, it belongs to the last added - * trigger state. Valid only if either filter or - * triggers are enabled. - */ - u8 filter_pre_trigger; /* Indicates if the recording filter should be - * applied before the trigger. Valid only if both - * filter and trigger are enabled (0/1). - */ - u8 filter_post_trigger; /* Indicates if the recording filter should be - * applied after the trigger. Valid only if both - * filter and trigger are enabled (0/1). - */ - u8 unify_inputs; /* If true, all inputs are associated with HW ID 0. - * Otherwise, each input is assigned a different HW ID - * (0/1). - */ - u8 rcv_from_other_engine; /* Indicates if the other engine sends it NW - * recording to this engine (0/1). - */ - struct dbg_bus_pci_buf_data pci_buf; /* Debug Bus PCI buffer data. Valid - * only when the target is - * DBG_BUS_TARGET_ID_PCI. - */ + __le32 app_version; + u8 state; + u8 hw_dwords; + __le16 hw_id_mask; + u8 num_enabled_blocks; + u8 num_enabled_storms; + u8 target; + u8 one_shot_en; + u8 grc_input_en; + u8 timestamp_input_en; + u8 filter_en; + u8 adding_filter; + u8 filter_pre_trigger; + u8 filter_post_trigger; __le16 reserved; - struct dbg_bus_block_data blocks[88];/* Debug Bus data for each block */ - struct dbg_bus_storm_data storms[6]; /* Debug Bus data for each block */ + u8 trigger_en; + struct dbg_bus_trigger_state_data trigger_states[3]; + u8 next_trigger_state; + u8 next_constraint_id; + u8 unify_inputs; + u8 rcv_from_other_engine; + struct dbg_bus_pci_buf_data pci_buf; + struct dbg_bus_block_data blocks[88]; + struct dbg_bus_storm_data storms[6]; }; enum dbg_bus_filter_types { @@ -2156,12 +2180,6 @@ enum dbg_bus_frame_modes { MAX_DBG_BUS_FRAME_MODES }; -enum dbg_bus_input_types { - DBG_BUS_INPUT_TYPE_STORM, - DBG_BUS_INPUT_TYPE_BLOCK, - MAX_DBG_BUS_INPUT_TYPES -}; - enum dbg_bus_other_engine_modes { DBG_BUS_OTHER_ENGINE_MODE_NONE, DBG_BUS_OTHER_ENGINE_MODE_DOUBLE_BW_TX, @@ -2185,19 +2203,19 @@ enum dbg_bus_pre_trigger_types { }; enum dbg_bus_semi_frame_modes { - DBG_BUS_SEMI_FRAME_MODE_0SLOW_4FAST = 0, - DBG_BUS_SEMI_FRAME_MODE_4SLOW_0FAST = 3, + DBG_BUS_SEMI_FRAME_MODE_0SLOW_4FAST = + 0, + DBG_BUS_SEMI_FRAME_MODE_4SLOW_0FAST = + 3, MAX_DBG_BUS_SEMI_FRAME_MODES }; /* Debug bus states */ enum dbg_bus_states { - DBG_BUS_STATE_IDLE, /* debug bus idle state (not recording) */ - DBG_BUS_STATE_READY, /* debug bus is ready for configuration and - * recording. - */ - DBG_BUS_STATE_RECORDING, /* debug bus is currently recording */ - DBG_BUS_STATE_STOPPED, /* debug bus recording has stopped */ + DBG_BUS_STATE_IDLE, + DBG_BUS_STATE_READY, + DBG_BUS_STATE_RECORDING, + DBG_BUS_STATE_STOPPED, MAX_DBG_BUS_STATES }; @@ -2216,11 +2234,8 @@ enum dbg_bus_storm_modes { /* Debug bus target IDs */ enum dbg_bus_targets { - /* records debug bus to DBG block internal buffer */ DBG_BUS_TARGET_ID_INT_BUF, - /* records debug bus to the NW */ DBG_BUS_TARGET_ID_NIG, - /* records debug bus to a PCI buffer */ DBG_BUS_TARGET_ID_PCI, MAX_DBG_BUS_TARGETS }; @@ -2235,48 +2250,45 @@ struct dbg_grc_data { /* Debug GRC params */ enum dbg_grc_params { - DBG_GRC_PARAM_DUMP_TSTORM, /* dump Tstorm memories (0/1) */ - DBG_GRC_PARAM_DUMP_MSTORM, /* dump Mstorm memories (0/1) */ - DBG_GRC_PARAM_DUMP_USTORM, /* dump Ustorm memories (0/1) */ - DBG_GRC_PARAM_DUMP_XSTORM, /* dump Xstorm memories (0/1) */ - DBG_GRC_PARAM_DUMP_YSTORM, /* dump Ystorm memories (0/1) */ - DBG_GRC_PARAM_DUMP_PSTORM, /* dump Pstorm memories (0/1) */ - DBG_GRC_PARAM_DUMP_REGS, /* dump non-memory registers (0/1) */ - DBG_GRC_PARAM_DUMP_RAM, /* dump Storm internal RAMs (0/1) */ - DBG_GRC_PARAM_DUMP_PBUF, /* dump Storm passive buffer (0/1) */ - DBG_GRC_PARAM_DUMP_IOR, /* dump Storm IORs (0/1) */ - DBG_GRC_PARAM_DUMP_VFC, /* dump VFC memories (0/1) */ - DBG_GRC_PARAM_DUMP_CM_CTX, /* dump CM contexts (0/1) */ - DBG_GRC_PARAM_DUMP_PXP, /* dump PXP memories (0/1) */ - DBG_GRC_PARAM_DUMP_RSS, /* dump RSS memories (0/1) */ - DBG_GRC_PARAM_DUMP_CAU, /* dump CAU memories (0/1) */ - DBG_GRC_PARAM_DUMP_QM, /* dump QM memories (0/1) */ - DBG_GRC_PARAM_DUMP_MCP, /* dump MCP memories (0/1) */ - DBG_GRC_PARAM_RESERVED, /* reserved */ - DBG_GRC_PARAM_DUMP_CFC, /* dump CFC memories (0/1) */ - DBG_GRC_PARAM_DUMP_IGU, /* dump IGU memories (0/1) */ - DBG_GRC_PARAM_DUMP_BRB, /* dump BRB memories (0/1) */ - DBG_GRC_PARAM_DUMP_BTB, /* dump BTB memories (0/1) */ - DBG_GRC_PARAM_DUMP_BMB, /* dump BMB memories (0/1) */ - DBG_GRC_PARAM_DUMP_NIG, /* dump NIG memories (0/1) */ - DBG_GRC_PARAM_DUMP_MULD, /* dump MULD memories (0/1) */ - DBG_GRC_PARAM_DUMP_PRS, /* dump PRS memories (0/1) */ - DBG_GRC_PARAM_DUMP_DMAE, /* dump PRS memories (0/1) */ - DBG_GRC_PARAM_DUMP_TM, /* dump TM (timers) memories (0/1) */ - DBG_GRC_PARAM_DUMP_SDM, /* dump SDM memories (0/1) */ - DBG_GRC_PARAM_DUMP_DIF, /* dump DIF memories (0/1) */ - DBG_GRC_PARAM_DUMP_STATIC, /* dump static debug data (0/1) */ - DBG_GRC_PARAM_UNSTALL, /* un-stall Storms after dump (0/1) */ - DBG_GRC_PARAM_NUM_LCIDS, /* number of LCIDs (0..320) */ - DBG_GRC_PARAM_NUM_LTIDS, /* number of LTIDs (0..320) */ - /* preset: exclude all memories from dump (1 only) */ + DBG_GRC_PARAM_DUMP_TSTORM, + DBG_GRC_PARAM_DUMP_MSTORM, + DBG_GRC_PARAM_DUMP_USTORM, + DBG_GRC_PARAM_DUMP_XSTORM, + DBG_GRC_PARAM_DUMP_YSTORM, + DBG_GRC_PARAM_DUMP_PSTORM, + DBG_GRC_PARAM_DUMP_REGS, + DBG_GRC_PARAM_DUMP_RAM, + DBG_GRC_PARAM_DUMP_PBUF, + DBG_GRC_PARAM_DUMP_IOR, + DBG_GRC_PARAM_DUMP_VFC, + DBG_GRC_PARAM_DUMP_CM_CTX, + DBG_GRC_PARAM_DUMP_PXP, + DBG_GRC_PARAM_DUMP_RSS, + DBG_GRC_PARAM_DUMP_CAU, + DBG_GRC_PARAM_DUMP_QM, + DBG_GRC_PARAM_DUMP_MCP, + DBG_GRC_PARAM_RESERVED, + DBG_GRC_PARAM_DUMP_CFC, + DBG_GRC_PARAM_DUMP_IGU, + DBG_GRC_PARAM_DUMP_BRB, + DBG_GRC_PARAM_DUMP_BTB, + DBG_GRC_PARAM_DUMP_BMB, + DBG_GRC_PARAM_DUMP_NIG, + DBG_GRC_PARAM_DUMP_MULD, + DBG_GRC_PARAM_DUMP_PRS, + DBG_GRC_PARAM_DUMP_DMAE, + DBG_GRC_PARAM_DUMP_TM, + DBG_GRC_PARAM_DUMP_SDM, + DBG_GRC_PARAM_DUMP_DIF, + DBG_GRC_PARAM_DUMP_STATIC, + DBG_GRC_PARAM_UNSTALL, + DBG_GRC_PARAM_NUM_LCIDS, + DBG_GRC_PARAM_NUM_LTIDS, DBG_GRC_PARAM_EXCLUDE_ALL, - /* preset: include memories for crash dump (1 only) */ DBG_GRC_PARAM_CRASH, - /* perform dump only if MFW is responding (0/1) */ DBG_GRC_PARAM_PARITY_SAFE, - DBG_GRC_PARAM_DUMP_CM, /* dump CM memories (0/1) */ - DBG_GRC_PARAM_DUMP_PHY, /* dump PHY memories (0/1) */ + DBG_GRC_PARAM_DUMP_CM, + DBG_GRC_PARAM_DUMP_PHY, DBG_GRC_PARAM_NO_MCP, DBG_GRC_PARAM_NO_FW_VER, MAX_DBG_GRC_PARAMS @@ -2347,7 +2359,10 @@ enum dbg_status { DBG_STATUS_REG_FIFO_BAD_DATA, DBG_STATUS_PROTECTION_OVERRIDE_BAD_DATA, DBG_STATUS_DBG_ARRAY_NOT_SET, - DBG_STATUS_MULTI_BLOCKS_WITH_FILTER, + DBG_STATUS_FILTER_BUG, + DBG_STATUS_NON_MATCHING_LINES, + DBG_STATUS_INVALID_TRIGGER_DWORD_OFFSET, + DBG_STATUS_DBG_BUS_IN_USE, MAX_DBG_STATUS }; @@ -2364,25 +2379,22 @@ enum dbg_storms { /* Idle Check data */ struct idle_chk_data { - __le32 buf_size; /* Idle check buffer size in dwords */ - u8 buf_size_set; /* Indicates if the idle check buffer size was set - * (0/1). - */ + __le32 buf_size; + u8 buf_size_set; u8 reserved1; __le16 reserved2; }; /* Debug Tools data (per HW function) */ struct dbg_tools_data { - struct dbg_grc_data grc; /* GRC Dump data */ - struct dbg_bus_data bus; /* Debug Bus data */ - struct idle_chk_data idle_chk; /* Idle Check data */ - u8 mode_enable[40]; /* Indicates if a mode is enabled (0/1) */ - u8 block_in_reset[88]; /* Indicates if a block is in reset state (0/1). - */ - u8 chip_id; /* Chip ID (from enum chip_ids) */ - u8 platform_id; /* Platform ID (from enum platform_ids) */ - u8 initialized; /* Indicates if the data was initialized */ + struct dbg_grc_data grc; + struct dbg_bus_data bus; + struct idle_chk_data idle_chk; + u8 mode_enable[40]; + u8 block_in_reset[88]; + u8 chip_id; + u8 platform_id; + u8 initialized; u8 reserved; }; @@ -2464,6 +2476,12 @@ struct init_qm_vport_params { /* Max size in dwords of a zipped array */ #define MAX_ZIPPED_SIZE 8192 +enum chip_ids { + CHIP_BB, + CHIP_K2, + CHIP_RESERVED, + MAX_CHIP_IDS +}; struct fw_asserts_ram_section { __le16 section_ram_line_offset; @@ -2475,18 +2493,18 @@ struct fw_asserts_ram_section { }; struct fw_ver_num { - u8 major; /* Firmware major version number */ - u8 minor; /* Firmware minor version number */ - u8 rev; /* Firmware revision version number */ - u8 eng; /* Firmware engineering version number (for bootleg versions) */ + u8 major; + u8 minor; + u8 rev; + u8 eng; }; struct fw_ver_info { - __le16 tools_ver; /* Tools version number */ - u8 image_id; /* FW image ID (e.g. main) */ + __le16 tools_ver; + u8 image_id; u8 reserved1; - struct fw_ver_num num; /* FW version number */ - __le32 timestamp; /* FW Timestamp in unix time (sec. since 1970) */ + struct fw_ver_num num; + __le32 timestamp; __le32 reserved2; }; @@ -2722,7 +2740,6 @@ struct init_read_op { #define INIT_READ_OP_ADDRESS_MASK 0x7FFFFF #define INIT_READ_OP_ADDRESS_SHIFT 9 __le32 expected_val; - }; /* Init operations union */ @@ -2782,6 +2799,7 @@ struct iro { * @param bin_ptr - a pointer to the binary data with debug arrays. */ enum dbg_status qed_dbg_set_bin_ptr(const u8 * const bin_ptr); + /** * @brief qed_dbg_grc_set_params_default - Reverts all GRC parameters to their * default value. @@ -2805,6 +2823,7 @@ void qed_dbg_grc_set_params_default(struct qed_hwfn *p_hwfn); enum dbg_status qed_dbg_grc_get_dump_buf_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *buf_size); + /** * @brief qed_dbg_grc_dump - Dumps GRC data into the specified buffer. * @@ -2824,6 +2843,7 @@ enum dbg_status qed_dbg_grc_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 buf_size_in_dwords, u32 *num_dumped_dwords); + /** * @brief qed_dbg_idle_chk_get_dump_buf_size - Returns the required buffer size * for idle check results. @@ -2840,6 +2860,7 @@ enum dbg_status qed_dbg_grc_dump(struct qed_hwfn *p_hwfn, enum dbg_status qed_dbg_idle_chk_get_dump_buf_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *buf_size); + /** * @brief qed_dbg_idle_chk_dump - Performs idle check and writes the results * into the specified buffer. @@ -2860,6 +2881,7 @@ enum dbg_status qed_dbg_idle_chk_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 buf_size_in_dwords, u32 *num_dumped_dwords); + /** * @brief qed_dbg_mcp_trace_get_dump_buf_size - Returns the required buffer size * for mcp trace results. @@ -2878,6 +2900,7 @@ enum dbg_status qed_dbg_idle_chk_dump(struct qed_hwfn *p_hwfn, enum dbg_status qed_dbg_mcp_trace_get_dump_buf_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *buf_size); + /** * @brief qed_dbg_mcp_trace_dump - Performs mcp trace and writes the results * into the specified buffer. @@ -2902,6 +2925,7 @@ enum dbg_status qed_dbg_mcp_trace_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 buf_size_in_dwords, u32 *num_dumped_dwords); + /** * @brief qed_dbg_reg_fifo_get_dump_buf_size - Returns the required buffer size * for grc trace fifo results. @@ -2917,6 +2941,7 @@ enum dbg_status qed_dbg_mcp_trace_dump(struct qed_hwfn *p_hwfn, enum dbg_status qed_dbg_reg_fifo_get_dump_buf_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *buf_size); + /** * @brief qed_dbg_reg_fifo_dump - Reads the reg fifo and writes the results into * the specified buffer. @@ -2938,6 +2963,7 @@ enum dbg_status qed_dbg_reg_fifo_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 buf_size_in_dwords, u32 *num_dumped_dwords); + /** * @brief qed_dbg_igu_fifo_get_dump_buf_size - Returns the required buffer size * for the IGU fifo results. @@ -2954,6 +2980,7 @@ enum dbg_status qed_dbg_reg_fifo_dump(struct qed_hwfn *p_hwfn, enum dbg_status qed_dbg_igu_fifo_get_dump_buf_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *buf_size); + /** * @brief qed_dbg_igu_fifo_dump - Reads the IGU fifo and writes the results into * the specified buffer. @@ -2975,6 +3002,7 @@ enum dbg_status qed_dbg_igu_fifo_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 buf_size_in_dwords, u32 *num_dumped_dwords); + /** * @brief qed_dbg_protection_override_get_dump_buf_size - Returns the required * buffer size for protection override window results. @@ -3048,6 +3076,29 @@ enum dbg_status qed_dbg_fw_asserts_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 buf_size_in_dwords, u32 *num_dumped_dwords); + +/** + * @brief qed_dbg_read_attn - Reads the attention registers of the specified + * block and type, and writes the results into the specified buffer. + * + * @param p_hwfn - HW device data + * @param p_ptt - Ptt window used for writing the registers. + * @param block - Block ID. + * @param attn_type - Attention type. + * @param clear_status - Indicates if the attention status should be cleared. + * @param results - OUT: Pointer to write the read results into + * + * @return error if one of the following holds: + * - the version wasn't set + * Otherwise, returns ok. + */ +enum dbg_status qed_dbg_read_attn(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum block_id block, + enum dbg_attn_type attn_type, + bool clear_status, + struct dbg_attn_block_result *results); + /** * @brief qed_dbg_print_attn - Prints attention registers values in the * specified results struct. @@ -3074,6 +3125,7 @@ enum dbg_status qed_dbg_print_attn(struct qed_hwfn *p_hwfn, * @param bin_ptr - a pointer to the binary data with debug arrays. */ enum dbg_status qed_dbg_user_set_bin_ptr(const u8 * const bin_ptr); + /** * @brief qed_dbg_get_status_str - Returns a string for the specified status. * @@ -3082,6 +3134,7 @@ enum dbg_status qed_dbg_user_set_bin_ptr(const u8 * const bin_ptr); * @return a string for the specified status */ const char *qed_dbg_get_status_str(enum dbg_status status); + /** * @brief qed_get_idle_chk_results_buf_size - Returns the required buffer size * for idle check results (in bytes). @@ -3116,6 +3169,7 @@ enum dbg_status qed_print_idle_chk_results(struct qed_hwfn *p_hwfn, char *results_buf, u32 *num_errors, u32 *num_warnings); + /** * @brief qed_get_mcp_trace_results_buf_size - Returns the required buffer size * for MCP Trace results (in bytes). @@ -3132,6 +3186,7 @@ enum dbg_status qed_get_mcp_trace_results_buf_size(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, u32 *results_buf_size); + /** * @brief qed_print_mcp_trace_results - Prints MCP Trace results * @@ -3146,6 +3201,7 @@ enum dbg_status qed_print_mcp_trace_results(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, char *results_buf); + /** * @brief qed_get_reg_fifo_results_buf_size - Returns the required buffer size * for reg_fifo results (in bytes). @@ -3162,6 +3218,7 @@ enum dbg_status qed_get_reg_fifo_results_buf_size(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, u32 *results_buf_size); + /** * @brief qed_print_reg_fifo_results - Prints reg fifo results * @@ -3176,6 +3233,7 @@ enum dbg_status qed_print_reg_fifo_results(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, char *results_buf); + /** * @brief qed_get_igu_fifo_results_buf_size - Returns the required buffer size * for igu_fifo results (in bytes). @@ -3192,6 +3250,7 @@ enum dbg_status qed_get_igu_fifo_results_buf_size(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, u32 *results_buf_size); + /** * @brief qed_print_igu_fifo_results - Prints IGU fifo results * @@ -3206,6 +3265,7 @@ enum dbg_status qed_print_igu_fifo_results(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, char *results_buf); + /** * @brief qed_get_protection_override_results_buf_size - Returns the required * buffer size for protection override results (in bytes). @@ -3223,6 +3283,7 @@ qed_get_protection_override_results_buf_size(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, u32 *results_buf_size); + /** * @brief qed_print_protection_override_results - Prints protection override * results. @@ -3238,6 +3299,7 @@ enum dbg_status qed_print_protection_override_results(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, char *results_buf); + /** * @brief qed_get_fw_asserts_results_buf_size - Returns the required buffer size * for FW Asserts results (in bytes). @@ -3254,6 +3316,7 @@ enum dbg_status qed_get_fw_asserts_results_buf_size(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, u32 *results_buf_size); + /** * @brief qed_print_fw_asserts_results - Prints FW Asserts results * @@ -3268,6 +3331,283 @@ enum dbg_status qed_print_fw_asserts_results(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, char *results_buf); + +/** + * @brief qed_dbg_parse_attn - Parses and prints attention registers values in + * the specified results struct. + * + * @param p_hwfn - HW device data + * @param results - Pointer to the attention read results + * + * @return error if one of the following holds: + * - the version wasn't set + * Otherwise, returns ok. + */ +enum dbg_status qed_dbg_parse_attn(struct qed_hwfn *p_hwfn, + struct dbg_attn_block_result *results); + +/* Debug Bus blocks */ +static const u32 dbg_bus_blocks[] = { + 0x0000000f, /* grc, bb, 15 lines */ + 0x0000000f, /* grc, k2, 15 lines */ + 0x00000000, + 0x00000000, /* miscs, bb, 0 lines */ + 0x00000000, /* miscs, k2, 0 lines */ + 0x00000000, + 0x00000000, /* misc, bb, 0 lines */ + 0x00000000, /* misc, k2, 0 lines */ + 0x00000000, + 0x00000000, /* dbu, bb, 0 lines */ + 0x00000000, /* dbu, k2, 0 lines */ + 0x00000000, + 0x000f0127, /* pglue_b, bb, 39 lines */ + 0x0036012a, /* pglue_b, k2, 42 lines */ + 0x00000000, + 0x00000000, /* cnig, bb, 0 lines */ + 0x00120102, /* cnig, k2, 2 lines */ + 0x00000000, + 0x00000000, /* cpmu, bb, 0 lines */ + 0x00000000, /* cpmu, k2, 0 lines */ + 0x00000000, + 0x00000001, /* ncsi, bb, 1 lines */ + 0x00000001, /* ncsi, k2, 1 lines */ + 0x00000000, + 0x00000000, /* opte, bb, 0 lines */ + 0x00000000, /* opte, k2, 0 lines */ + 0x00000000, + 0x00600085, /* bmb, bb, 133 lines */ + 0x00600085, /* bmb, k2, 133 lines */ + 0x00000000, + 0x00000000, /* pcie, bb, 0 lines */ + 0x00e50033, /* pcie, k2, 51 lines */ + 0x00000000, + 0x00000000, /* mcp, bb, 0 lines */ + 0x00000000, /* mcp, k2, 0 lines */ + 0x00000000, + 0x01180009, /* mcp2, bb, 9 lines */ + 0x01180009, /* mcp2, k2, 9 lines */ + 0x00000000, + 0x01210104, /* pswhst, bb, 4 lines */ + 0x01210104, /* pswhst, k2, 4 lines */ + 0x00000000, + 0x01250103, /* pswhst2, bb, 3 lines */ + 0x01250103, /* pswhst2, k2, 3 lines */ + 0x00000000, + 0x00340101, /* pswrd, bb, 1 lines */ + 0x00340101, /* pswrd, k2, 1 lines */ + 0x00000000, + 0x01280119, /* pswrd2, bb, 25 lines */ + 0x01280119, /* pswrd2, k2, 25 lines */ + 0x00000000, + 0x01410109, /* pswwr, bb, 9 lines */ + 0x01410109, /* pswwr, k2, 9 lines */ + 0x00000000, + 0x00000000, /* pswwr2, bb, 0 lines */ + 0x00000000, /* pswwr2, k2, 0 lines */ + 0x00000000, + 0x001c0001, /* pswrq, bb, 1 lines */ + 0x001c0001, /* pswrq, k2, 1 lines */ + 0x00000000, + 0x014a0015, /* pswrq2, bb, 21 lines */ + 0x014a0015, /* pswrq2, k2, 21 lines */ + 0x00000000, + 0x00000000, /* pglcs, bb, 0 lines */ + 0x00120006, /* pglcs, k2, 6 lines */ + 0x00000000, + 0x00100001, /* dmae, bb, 1 lines */ + 0x00100001, /* dmae, k2, 1 lines */ + 0x00000000, + 0x015f0105, /* ptu, bb, 5 lines */ + 0x015f0105, /* ptu, k2, 5 lines */ + 0x00000000, + 0x01640120, /* tcm, bb, 32 lines */ + 0x01640120, /* tcm, k2, 32 lines */ + 0x00000000, + 0x01640120, /* mcm, bb, 32 lines */ + 0x01640120, /* mcm, k2, 32 lines */ + 0x00000000, + 0x01640120, /* ucm, bb, 32 lines */ + 0x01640120, /* ucm, k2, 32 lines */ + 0x00000000, + 0x01640120, /* xcm, bb, 32 lines */ + 0x01640120, /* xcm, k2, 32 lines */ + 0x00000000, + 0x01640120, /* ycm, bb, 32 lines */ + 0x01640120, /* ycm, k2, 32 lines */ + 0x00000000, + 0x01640120, /* pcm, bb, 32 lines */ + 0x01640120, /* pcm, k2, 32 lines */ + 0x00000000, + 0x01840062, /* qm, bb, 98 lines */ + 0x01840062, /* qm, k2, 98 lines */ + 0x00000000, + 0x01e60021, /* tm, bb, 33 lines */ + 0x01e60021, /* tm, k2, 33 lines */ + 0x00000000, + 0x02070107, /* dorq, bb, 7 lines */ + 0x02070107, /* dorq, k2, 7 lines */ + 0x00000000, + 0x00600185, /* brb, bb, 133 lines */ + 0x00600185, /* brb, k2, 133 lines */ + 0x00000000, + 0x020e0019, /* src, bb, 25 lines */ + 0x020c001a, /* src, k2, 26 lines */ + 0x00000000, + 0x02270104, /* prs, bb, 4 lines */ + 0x02270104, /* prs, k2, 4 lines */ + 0x00000000, + 0x022b0133, /* tsdm, bb, 51 lines */ + 0x022b0133, /* tsdm, k2, 51 lines */ + 0x00000000, + 0x022b0133, /* msdm, bb, 51 lines */ + 0x022b0133, /* msdm, k2, 51 lines */ + 0x00000000, + 0x022b0133, /* usdm, bb, 51 lines */ + 0x022b0133, /* usdm, k2, 51 lines */ + 0x00000000, + 0x022b0133, /* xsdm, bb, 51 lines */ + 0x022b0133, /* xsdm, k2, 51 lines */ + 0x00000000, + 0x022b0133, /* ysdm, bb, 51 lines */ + 0x022b0133, /* ysdm, k2, 51 lines */ + 0x00000000, + 0x022b0133, /* psdm, bb, 51 lines */ + 0x022b0133, /* psdm, k2, 51 lines */ + 0x00000000, + 0x025e010c, /* tsem, bb, 12 lines */ + 0x025e010c, /* tsem, k2, 12 lines */ + 0x00000000, + 0x025e010c, /* msem, bb, 12 lines */ + 0x025e010c, /* msem, k2, 12 lines */ + 0x00000000, + 0x025e010c, /* usem, bb, 12 lines */ + 0x025e010c, /* usem, k2, 12 lines */ + 0x00000000, + 0x025e010c, /* xsem, bb, 12 lines */ + 0x025e010c, /* xsem, k2, 12 lines */ + 0x00000000, + 0x025e010c, /* ysem, bb, 12 lines */ + 0x025e010c, /* ysem, k2, 12 lines */ + 0x00000000, + 0x025e010c, /* psem, bb, 12 lines */ + 0x025e010c, /* psem, k2, 12 lines */ + 0x00000000, + 0x026a000d, /* rss, bb, 13 lines */ + 0x026a000d, /* rss, k2, 13 lines */ + 0x00000000, + 0x02770106, /* tmld, bb, 6 lines */ + 0x02770106, /* tmld, k2, 6 lines */ + 0x00000000, + 0x027d0106, /* muld, bb, 6 lines */ + 0x027d0106, /* muld, k2, 6 lines */ + 0x00000000, + 0x02770005, /* yuld, bb, 5 lines */ + 0x02770005, /* yuld, k2, 5 lines */ + 0x00000000, + 0x02830107, /* xyld, bb, 7 lines */ + 0x027d0107, /* xyld, k2, 7 lines */ + 0x00000000, + 0x00000000, /* ptld, bb, 0 lines */ + 0x00000000, /* ptld, k2, 0 lines */ + 0x00000000, + 0x00000000, /* ypld, bb, 0 lines */ + 0x00000000, /* ypld, k2, 0 lines */ + 0x00000000, + 0x028a010e, /* prm, bb, 14 lines */ + 0x02980110, /* prm, k2, 16 lines */ + 0x00000000, + 0x02a8000d, /* pbf_pb1, bb, 13 lines */ + 0x02a8000d, /* pbf_pb1, k2, 13 lines */ + 0x00000000, + 0x02a8000d, /* pbf_pb2, bb, 13 lines */ + 0x02a8000d, /* pbf_pb2, k2, 13 lines */ + 0x00000000, + 0x02a8000d, /* rpb, bb, 13 lines */ + 0x02a8000d, /* rpb, k2, 13 lines */ + 0x00000000, + 0x00600185, /* btb, bb, 133 lines */ + 0x00600185, /* btb, k2, 133 lines */ + 0x00000000, + 0x02b50117, /* pbf, bb, 23 lines */ + 0x02b50117, /* pbf, k2, 23 lines */ + 0x00000000, + 0x02cc0006, /* rdif, bb, 6 lines */ + 0x02cc0006, /* rdif, k2, 6 lines */ + 0x00000000, + 0x02d20006, /* tdif, bb, 6 lines */ + 0x02d20006, /* tdif, k2, 6 lines */ + 0x00000000, + 0x02d80003, /* cdu, bb, 3 lines */ + 0x02db000e, /* cdu, k2, 14 lines */ + 0x00000000, + 0x02e9010d, /* ccfc, bb, 13 lines */ + 0x02f60117, /* ccfc, k2, 23 lines */ + 0x00000000, + 0x02e9010d, /* tcfc, bb, 13 lines */ + 0x02f60117, /* tcfc, k2, 23 lines */ + 0x00000000, + 0x030d0133, /* igu, bb, 51 lines */ + 0x030d0133, /* igu, k2, 51 lines */ + 0x00000000, + 0x03400106, /* cau, bb, 6 lines */ + 0x03400106, /* cau, k2, 6 lines */ + 0x00000000, + 0x00000000, /* rgfs, bb, 0 lines */ + 0x00000000, /* rgfs, k2, 0 lines */ + 0x00000000, + 0x00000000, /* rgsrc, bb, 0 lines */ + 0x00000000, /* rgsrc, k2, 0 lines */ + 0x00000000, + 0x00000000, /* tgfs, bb, 0 lines */ + 0x00000000, /* tgfs, k2, 0 lines */ + 0x00000000, + 0x00000000, /* tgsrc, bb, 0 lines */ + 0x00000000, /* tgsrc, k2, 0 lines */ + 0x00000000, + 0x00000000, /* umac, bb, 0 lines */ + 0x00120006, /* umac, k2, 6 lines */ + 0x00000000, + 0x00000000, /* xmac, bb, 0 lines */ + 0x00000000, /* xmac, k2, 0 lines */ + 0x00000000, + 0x00000000, /* dbg, bb, 0 lines */ + 0x00000000, /* dbg, k2, 0 lines */ + 0x00000000, + 0x0346012b, /* nig, bb, 43 lines */ + 0x0346011d, /* nig, k2, 29 lines */ + 0x00000000, + 0x00000000, /* wol, bb, 0 lines */ + 0x001c0002, /* wol, k2, 2 lines */ + 0x00000000, + 0x00000000, /* bmbn, bb, 0 lines */ + 0x00210008, /* bmbn, k2, 8 lines */ + 0x00000000, + 0x00000000, /* ipc, bb, 0 lines */ + 0x00000000, /* ipc, k2, 0 lines */ + 0x00000000, + 0x00000000, /* nwm, bb, 0 lines */ + 0x0371000b, /* nwm, k2, 11 lines */ + 0x00000000, + 0x00000000, /* nws, bb, 0 lines */ + 0x037c0009, /* nws, k2, 9 lines */ + 0x00000000, + 0x00000000, /* ms, bb, 0 lines */ + 0x00120004, /* ms, k2, 4 lines */ + 0x00000000, + 0x00000000, /* phy_pcie, bb, 0 lines */ + 0x00e5001a, /* phy_pcie, k2, 26 lines */ + 0x00000000, + 0x00000000, /* led, bb, 0 lines */ + 0x00000000, /* led, k2, 0 lines */ + 0x00000000, + 0x00000000, /* avs_wrap, bb, 0 lines */ + 0x00000000, /* avs_wrap, k2, 0 lines */ + 0x00000000, + 0x00000000, /* bar0_map, bb, 0 lines */ + 0x00000000, /* bar0_map, k2, 0 lines */ + 0x00000000, +}; + /* Win 2 */ #define GTT_BAR0_MAP_REG_IGU_CMD 0x00f000UL @@ -3589,37 +3929,37 @@ void qed_set_rfs_mode_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, #define PSTORM_FCOE_TX_STATS_OFFSET(pf_id) \ (IRO[44].base + ((pf_id) * IRO[44].m1)) -static const struct iro iro_arr[47] = { +static const struct iro iro_arr[49] = { {0x0, 0x0, 0x0, 0x0, 0x8}, {0x4cb0, 0x80, 0x0, 0x0, 0x80}, - {0x6318, 0x20, 0x0, 0x0, 0x20}, + {0x6518, 0x20, 0x0, 0x0, 0x20}, {0xb00, 0x8, 0x0, 0x0, 0x4}, {0xa80, 0x8, 0x0, 0x0, 0x4}, {0x0, 0x8, 0x0, 0x0, 0x2}, {0x80, 0x8, 0x0, 0x0, 0x4}, {0x84, 0x8, 0x0, 0x0, 0x2}, - {0x4bc0, 0x0, 0x0, 0x0, 0x78}, + {0x4c40, 0x0, 0x0, 0x0, 0x78}, {0x3df0, 0x0, 0x0, 0x0, 0x78}, {0x29b0, 0x0, 0x0, 0x0, 0x78}, {0x4c38, 0x0, 0x0, 0x0, 0x78}, {0x4990, 0x0, 0x0, 0x0, 0x78}, - {0x7e48, 0x0, 0x0, 0x0, 0x78}, + {0x7f48, 0x0, 0x0, 0x0, 0x78}, {0xa28, 0x8, 0x0, 0x0, 0x8}, - {0x60f8, 0x10, 0x0, 0x0, 0x10}, - {0xb820, 0x30, 0x0, 0x0, 0x30}, + {0x61f8, 0x10, 0x0, 0x0, 0x10}, + {0xbd20, 0x30, 0x0, 0x0, 0x30}, {0x95b8, 0x30, 0x0, 0x0, 0x30}, {0x4b60, 0x80, 0x0, 0x0, 0x40}, {0x1f8, 0x4, 0x0, 0x0, 0x4}, {0x53a0, 0x80, 0x4, 0x0, 0x4}, - {0xc8f0, 0x0, 0x0, 0x0, 0x4}, + {0xc7c8, 0x0, 0x0, 0x0, 0x4}, {0x4ba0, 0x80, 0x0, 0x0, 0x20}, - {0x8050, 0x40, 0x0, 0x0, 0x30}, - {0xe770, 0x60, 0x0, 0x0, 0x60}, + {0x8150, 0x40, 0x0, 0x0, 0x30}, + {0xec70, 0x60, 0x0, 0x0, 0x60}, {0x2b48, 0x80, 0x0, 0x0, 0x38}, - {0xf188, 0x78, 0x0, 0x0, 0x78}, + {0xf1b0, 0x78, 0x0, 0x0, 0x78}, {0x1f8, 0x4, 0x0, 0x0, 0x4}, - {0xacf0, 0x0, 0x0, 0x0, 0xf0}, - {0xade0, 0x8, 0x0, 0x0, 0x8}, + {0xaef8, 0x0, 0x0, 0x0, 0xf0}, + {0xafe8, 0x8, 0x0, 0x0, 0x8}, {0x1f8, 0x8, 0x0, 0x0, 0x8}, {0xac0, 0x8, 0x0, 0x0, 0x8}, {0x2578, 0x8, 0x0, 0x0, 0x8}, @@ -3627,16 +3967,18 @@ static const struct iro iro_arr[47] = { {0x0, 0x8, 0x0, 0x0, 0x8}, {0x200, 0x10, 0x8, 0x0, 0x8}, {0xb78, 0x10, 0x8, 0x0, 0x2}, - {0xd888, 0x38, 0x0, 0x0, 0x24}, - {0x12c38, 0x10, 0x0, 0x0, 0x8}, - {0x11aa0, 0x38, 0x0, 0x0, 0x18}, - {0xa8c0, 0x38, 0x0, 0x0, 0x10}, + {0xd9a8, 0x38, 0x0, 0x0, 0x24}, + {0x12988, 0x10, 0x0, 0x0, 0x8}, + {0x11fa0, 0x38, 0x0, 0x0, 0x18}, + {0xa580, 0x38, 0x0, 0x0, 0x10}, {0x86f8, 0x30, 0x0, 0x0, 0x18}, {0x101f8, 0x10, 0x0, 0x0, 0x10}, - {0xdd08, 0x48, 0x0, 0x0, 0x38}, + {0xde28, 0x48, 0x0, 0x0, 0x38}, {0x10660, 0x20, 0x0, 0x0, 0x20}, {0x2b80, 0x80, 0x0, 0x0, 0x10}, {0x5020, 0x10, 0x0, 0x0, 0x10}, + {0xc9b0, 0x30, 0x0, 0x0, 0x10}, + {0xeec0, 0x10, 0x0, 0x0, 0x10}, }; /* Runtime array offsets */ @@ -3724,361 +4066,359 @@ static const struct iro iro_arr[47] = { #define PSWRQ2_REG_CDUC_BLOCKS_FACTOR_RT_OFFSET 6697 #define PSWRQ2_REG_VF_BASE_RT_OFFSET 6698 #define PSWRQ2_REG_VF_LAST_ILT_RT_OFFSET 6699 -#define PSWRQ2_REG_WR_MBS0_RT_OFFSET 6700 -#define PSWRQ2_REG_RD_MBS0_RT_OFFSET 6701 -#define PSWRQ2_REG_DRAM_ALIGN_WR_RT_OFFSET 6702 -#define PSWRQ2_REG_DRAM_ALIGN_RD_RT_OFFSET 6703 -#define PSWRQ2_REG_ILT_MEMORY_RT_OFFSET 6704 +#define PSWRQ2_REG_DRAM_ALIGN_WR_RT_OFFSET 6700 +#define PSWRQ2_REG_DRAM_ALIGN_RD_RT_OFFSET 6701 +#define PSWRQ2_REG_ILT_MEMORY_RT_OFFSET 6702 #define PSWRQ2_REG_ILT_MEMORY_RT_SIZE 22000 -#define PGLUE_REG_B_VF_BASE_RT_OFFSET 28704 -#define PGLUE_REG_B_MSDM_OFFSET_MASK_B_RT_OFFSET 28705 -#define PGLUE_REG_B_MSDM_VF_SHIFT_B_RT_OFFSET 28706 -#define PGLUE_REG_B_CACHE_LINE_SIZE_RT_OFFSET 28707 -#define PGLUE_REG_B_PF_BAR0_SIZE_RT_OFFSET 28708 -#define PGLUE_REG_B_PF_BAR1_SIZE_RT_OFFSET 28709 -#define PGLUE_REG_B_VF_BAR1_SIZE_RT_OFFSET 28710 -#define TM_REG_VF_ENABLE_CONN_RT_OFFSET 28711 -#define TM_REG_PF_ENABLE_CONN_RT_OFFSET 28712 -#define TM_REG_PF_ENABLE_TASK_RT_OFFSET 28713 -#define TM_REG_GROUP_SIZE_RESOLUTION_CONN_RT_OFFSET 28714 -#define TM_REG_GROUP_SIZE_RESOLUTION_TASK_RT_OFFSET 28715 -#define TM_REG_CONFIG_CONN_MEM_RT_OFFSET 28716 +#define PGLUE_REG_B_VF_BASE_RT_OFFSET 28702 +#define PGLUE_REG_B_MSDM_OFFSET_MASK_B_RT_OFFSET 28703 +#define PGLUE_REG_B_MSDM_VF_SHIFT_B_RT_OFFSET 28704 +#define PGLUE_REG_B_CACHE_LINE_SIZE_RT_OFFSET 28705 +#define PGLUE_REG_B_PF_BAR0_SIZE_RT_OFFSET 28706 +#define PGLUE_REG_B_PF_BAR1_SIZE_RT_OFFSET 28707 +#define PGLUE_REG_B_VF_BAR1_SIZE_RT_OFFSET 28708 +#define TM_REG_VF_ENABLE_CONN_RT_OFFSET 28709 +#define TM_REG_PF_ENABLE_CONN_RT_OFFSET 28710 +#define TM_REG_PF_ENABLE_TASK_RT_OFFSET 28711 +#define TM_REG_GROUP_SIZE_RESOLUTION_CONN_RT_OFFSET 28712 +#define TM_REG_GROUP_SIZE_RESOLUTION_TASK_RT_OFFSET 28713 +#define TM_REG_CONFIG_CONN_MEM_RT_OFFSET 28714 #define TM_REG_CONFIG_CONN_MEM_RT_SIZE 416 -#define TM_REG_CONFIG_TASK_MEM_RT_OFFSET 29132 -#define TM_REG_CONFIG_TASK_MEM_RT_SIZE 512 -#define QM_REG_MAXPQSIZE_0_RT_OFFSET 29644 -#define QM_REG_MAXPQSIZE_1_RT_OFFSET 29645 -#define QM_REG_MAXPQSIZE_2_RT_OFFSET 29646 -#define QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET 29647 -#define QM_REG_MAXPQSIZETXSEL_1_RT_OFFSET 29648 -#define QM_REG_MAXPQSIZETXSEL_2_RT_OFFSET 29649 -#define QM_REG_MAXPQSIZETXSEL_3_RT_OFFSET 29650 -#define QM_REG_MAXPQSIZETXSEL_4_RT_OFFSET 29651 -#define QM_REG_MAXPQSIZETXSEL_5_RT_OFFSET 29652 -#define QM_REG_MAXPQSIZETXSEL_6_RT_OFFSET 29653 -#define QM_REG_MAXPQSIZETXSEL_7_RT_OFFSET 29654 -#define QM_REG_MAXPQSIZETXSEL_8_RT_OFFSET 29655 -#define QM_REG_MAXPQSIZETXSEL_9_RT_OFFSET 29656 -#define QM_REG_MAXPQSIZETXSEL_10_RT_OFFSET 29657 -#define QM_REG_MAXPQSIZETXSEL_11_RT_OFFSET 29658 -#define QM_REG_MAXPQSIZETXSEL_12_RT_OFFSET 29659 -#define QM_REG_MAXPQSIZETXSEL_13_RT_OFFSET 29660 -#define QM_REG_MAXPQSIZETXSEL_14_RT_OFFSET 29661 -#define QM_REG_MAXPQSIZETXSEL_15_RT_OFFSET 29662 -#define QM_REG_MAXPQSIZETXSEL_16_RT_OFFSET 29663 -#define QM_REG_MAXPQSIZETXSEL_17_RT_OFFSET 29664 -#define QM_REG_MAXPQSIZETXSEL_18_RT_OFFSET 29665 -#define QM_REG_MAXPQSIZETXSEL_19_RT_OFFSET 29666 -#define QM_REG_MAXPQSIZETXSEL_20_RT_OFFSET 29667 -#define QM_REG_MAXPQSIZETXSEL_21_RT_OFFSET 29668 -#define QM_REG_MAXPQSIZETXSEL_22_RT_OFFSET 29669 -#define QM_REG_MAXPQSIZETXSEL_23_RT_OFFSET 29670 -#define QM_REG_MAXPQSIZETXSEL_24_RT_OFFSET 29671 -#define QM_REG_MAXPQSIZETXSEL_25_RT_OFFSET 29672 -#define QM_REG_MAXPQSIZETXSEL_26_RT_OFFSET 29673 -#define QM_REG_MAXPQSIZETXSEL_27_RT_OFFSET 29674 -#define QM_REG_MAXPQSIZETXSEL_28_RT_OFFSET 29675 -#define QM_REG_MAXPQSIZETXSEL_29_RT_OFFSET 29676 -#define QM_REG_MAXPQSIZETXSEL_30_RT_OFFSET 29677 -#define QM_REG_MAXPQSIZETXSEL_31_RT_OFFSET 29678 -#define QM_REG_MAXPQSIZETXSEL_32_RT_OFFSET 29679 -#define QM_REG_MAXPQSIZETXSEL_33_RT_OFFSET 29680 -#define QM_REG_MAXPQSIZETXSEL_34_RT_OFFSET 29681 -#define QM_REG_MAXPQSIZETXSEL_35_RT_OFFSET 29682 -#define QM_REG_MAXPQSIZETXSEL_36_RT_OFFSET 29683 -#define QM_REG_MAXPQSIZETXSEL_37_RT_OFFSET 29684 -#define QM_REG_MAXPQSIZETXSEL_38_RT_OFFSET 29685 -#define QM_REG_MAXPQSIZETXSEL_39_RT_OFFSET 29686 -#define QM_REG_MAXPQSIZETXSEL_40_RT_OFFSET 29687 -#define QM_REG_MAXPQSIZETXSEL_41_RT_OFFSET 29688 -#define QM_REG_MAXPQSIZETXSEL_42_RT_OFFSET 29689 -#define QM_REG_MAXPQSIZETXSEL_43_RT_OFFSET 29690 -#define QM_REG_MAXPQSIZETXSEL_44_RT_OFFSET 29691 -#define QM_REG_MAXPQSIZETXSEL_45_RT_OFFSET 29692 -#define QM_REG_MAXPQSIZETXSEL_46_RT_OFFSET 29693 -#define QM_REG_MAXPQSIZETXSEL_47_RT_OFFSET 29694 -#define QM_REG_MAXPQSIZETXSEL_48_RT_OFFSET 29695 -#define QM_REG_MAXPQSIZETXSEL_49_RT_OFFSET 29696 -#define QM_REG_MAXPQSIZETXSEL_50_RT_OFFSET 29697 -#define QM_REG_MAXPQSIZETXSEL_51_RT_OFFSET 29698 -#define QM_REG_MAXPQSIZETXSEL_52_RT_OFFSET 29699 -#define QM_REG_MAXPQSIZETXSEL_53_RT_OFFSET 29700 -#define QM_REG_MAXPQSIZETXSEL_54_RT_OFFSET 29701 -#define QM_REG_MAXPQSIZETXSEL_55_RT_OFFSET 29702 -#define QM_REG_MAXPQSIZETXSEL_56_RT_OFFSET 29703 -#define QM_REG_MAXPQSIZETXSEL_57_RT_OFFSET 29704 -#define QM_REG_MAXPQSIZETXSEL_58_RT_OFFSET 29705 -#define QM_REG_MAXPQSIZETXSEL_59_RT_OFFSET 29706 -#define QM_REG_MAXPQSIZETXSEL_60_RT_OFFSET 29707 -#define QM_REG_MAXPQSIZETXSEL_61_RT_OFFSET 29708 -#define QM_REG_MAXPQSIZETXSEL_62_RT_OFFSET 29709 -#define QM_REG_MAXPQSIZETXSEL_63_RT_OFFSET 29710 -#define QM_REG_BASEADDROTHERPQ_RT_OFFSET 29711 +#define TM_REG_CONFIG_TASK_MEM_RT_OFFSET 29130 +#define TM_REG_CONFIG_TASK_MEM_RT_SIZE 608 +#define QM_REG_MAXPQSIZE_0_RT_OFFSET 29738 +#define QM_REG_MAXPQSIZE_1_RT_OFFSET 29739 +#define QM_REG_MAXPQSIZE_2_RT_OFFSET 29740 +#define QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET 29741 +#define QM_REG_MAXPQSIZETXSEL_1_RT_OFFSET 29742 +#define QM_REG_MAXPQSIZETXSEL_2_RT_OFFSET 29743 +#define QM_REG_MAXPQSIZETXSEL_3_RT_OFFSET 29744 +#define QM_REG_MAXPQSIZETXSEL_4_RT_OFFSET 29745 +#define QM_REG_MAXPQSIZETXSEL_5_RT_OFFSET 29746 +#define QM_REG_MAXPQSIZETXSEL_6_RT_OFFSET 29747 +#define QM_REG_MAXPQSIZETXSEL_7_RT_OFFSET 29748 +#define QM_REG_MAXPQSIZETXSEL_8_RT_OFFSET 29749 +#define QM_REG_MAXPQSIZETXSEL_9_RT_OFFSET 29750 +#define QM_REG_MAXPQSIZETXSEL_10_RT_OFFSET 29751 +#define QM_REG_MAXPQSIZETXSEL_11_RT_OFFSET 29752 +#define QM_REG_MAXPQSIZETXSEL_12_RT_OFFSET 29753 +#define QM_REG_MAXPQSIZETXSEL_13_RT_OFFSET 29754 +#define QM_REG_MAXPQSIZETXSEL_14_RT_OFFSET 29755 +#define QM_REG_MAXPQSIZETXSEL_15_RT_OFFSET 29756 +#define QM_REG_MAXPQSIZETXSEL_16_RT_OFFSET 29757 +#define QM_REG_MAXPQSIZETXSEL_17_RT_OFFSET 29758 +#define QM_REG_MAXPQSIZETXSEL_18_RT_OFFSET 29759 +#define QM_REG_MAXPQSIZETXSEL_19_RT_OFFSET 29760 +#define QM_REG_MAXPQSIZETXSEL_20_RT_OFFSET 29761 +#define QM_REG_MAXPQSIZETXSEL_21_RT_OFFSET 29762 +#define QM_REG_MAXPQSIZETXSEL_22_RT_OFFSET 29763 +#define QM_REG_MAXPQSIZETXSEL_23_RT_OFFSET 29764 +#define QM_REG_MAXPQSIZETXSEL_24_RT_OFFSET 29765 +#define QM_REG_MAXPQSIZETXSEL_25_RT_OFFSET 29766 +#define QM_REG_MAXPQSIZETXSEL_26_RT_OFFSET 29767 +#define QM_REG_MAXPQSIZETXSEL_27_RT_OFFSET 29768 +#define QM_REG_MAXPQSIZETXSEL_28_RT_OFFSET 29769 +#define QM_REG_MAXPQSIZETXSEL_29_RT_OFFSET 29770 +#define QM_REG_MAXPQSIZETXSEL_30_RT_OFFSET 29771 +#define QM_REG_MAXPQSIZETXSEL_31_RT_OFFSET 29772 +#define QM_REG_MAXPQSIZETXSEL_32_RT_OFFSET 29773 +#define QM_REG_MAXPQSIZETXSEL_33_RT_OFFSET 29774 +#define QM_REG_MAXPQSIZETXSEL_34_RT_OFFSET 29775 +#define QM_REG_MAXPQSIZETXSEL_35_RT_OFFSET 29776 +#define QM_REG_MAXPQSIZETXSEL_36_RT_OFFSET 29777 +#define QM_REG_MAXPQSIZETXSEL_37_RT_OFFSET 29778 +#define QM_REG_MAXPQSIZETXSEL_38_RT_OFFSET 29779 +#define QM_REG_MAXPQSIZETXSEL_39_RT_OFFSET 29780 +#define QM_REG_MAXPQSIZETXSEL_40_RT_OFFSET 29781 +#define QM_REG_MAXPQSIZETXSEL_41_RT_OFFSET 29782 +#define QM_REG_MAXPQSIZETXSEL_42_RT_OFFSET 29783 +#define QM_REG_MAXPQSIZETXSEL_43_RT_OFFSET 29784 +#define QM_REG_MAXPQSIZETXSEL_44_RT_OFFSET 29785 +#define QM_REG_MAXPQSIZETXSEL_45_RT_OFFSET 29786 +#define QM_REG_MAXPQSIZETXSEL_46_RT_OFFSET 29787 +#define QM_REG_MAXPQSIZETXSEL_47_RT_OFFSET 29788 +#define QM_REG_MAXPQSIZETXSEL_48_RT_OFFSET 29789 +#define QM_REG_MAXPQSIZETXSEL_49_RT_OFFSET 29790 +#define QM_REG_MAXPQSIZETXSEL_50_RT_OFFSET 29791 +#define QM_REG_MAXPQSIZETXSEL_51_RT_OFFSET 29792 +#define QM_REG_MAXPQSIZETXSEL_52_RT_OFFSET 29793 +#define QM_REG_MAXPQSIZETXSEL_53_RT_OFFSET 29794 +#define QM_REG_MAXPQSIZETXSEL_54_RT_OFFSET 29795 +#define QM_REG_MAXPQSIZETXSEL_55_RT_OFFSET 29796 +#define QM_REG_MAXPQSIZETXSEL_56_RT_OFFSET 29797 +#define QM_REG_MAXPQSIZETXSEL_57_RT_OFFSET 29798 +#define QM_REG_MAXPQSIZETXSEL_58_RT_OFFSET 29799 +#define QM_REG_MAXPQSIZETXSEL_59_RT_OFFSET 29800 +#define QM_REG_MAXPQSIZETXSEL_60_RT_OFFSET 29801 +#define QM_REG_MAXPQSIZETXSEL_61_RT_OFFSET 29802 +#define QM_REG_MAXPQSIZETXSEL_62_RT_OFFSET 29803 +#define QM_REG_MAXPQSIZETXSEL_63_RT_OFFSET 29804 +#define QM_REG_BASEADDROTHERPQ_RT_OFFSET 29805 #define QM_REG_BASEADDROTHERPQ_RT_SIZE 128 -#define QM_REG_VOQCRDLINE_RT_OFFSET 29839 -#define QM_REG_VOQCRDLINE_RT_SIZE 20 -#define QM_REG_VOQINITCRDLINE_RT_OFFSET 29859 -#define QM_REG_VOQINITCRDLINE_RT_SIZE 20 -#define QM_REG_AFULLQMBYPTHRPFWFQ_RT_OFFSET 29879 -#define QM_REG_AFULLQMBYPTHRVPWFQ_RT_OFFSET 29880 -#define QM_REG_AFULLQMBYPTHRPFRL_RT_OFFSET 29881 -#define QM_REG_AFULLQMBYPTHRGLBLRL_RT_OFFSET 29882 -#define QM_REG_AFULLOPRTNSTCCRDMASK_RT_OFFSET 29883 -#define QM_REG_WRROTHERPQGRP_0_RT_OFFSET 29884 -#define QM_REG_WRROTHERPQGRP_1_RT_OFFSET 29885 -#define QM_REG_WRROTHERPQGRP_2_RT_OFFSET 29886 -#define QM_REG_WRROTHERPQGRP_3_RT_OFFSET 29887 -#define QM_REG_WRROTHERPQGRP_4_RT_OFFSET 29888 -#define QM_REG_WRROTHERPQGRP_5_RT_OFFSET 29889 -#define QM_REG_WRROTHERPQGRP_6_RT_OFFSET 29890 -#define QM_REG_WRROTHERPQGRP_7_RT_OFFSET 29891 -#define QM_REG_WRROTHERPQGRP_8_RT_OFFSET 29892 -#define QM_REG_WRROTHERPQGRP_9_RT_OFFSET 29893 -#define QM_REG_WRROTHERPQGRP_10_RT_OFFSET 29894 -#define QM_REG_WRROTHERPQGRP_11_RT_OFFSET 29895 -#define QM_REG_WRROTHERPQGRP_12_RT_OFFSET 29896 -#define QM_REG_WRROTHERPQGRP_13_RT_OFFSET 29897 -#define QM_REG_WRROTHERPQGRP_14_RT_OFFSET 29898 -#define QM_REG_WRROTHERPQGRP_15_RT_OFFSET 29899 -#define QM_REG_WRROTHERGRPWEIGHT_0_RT_OFFSET 29900 -#define QM_REG_WRROTHERGRPWEIGHT_1_RT_OFFSET 29901 -#define QM_REG_WRROTHERGRPWEIGHT_2_RT_OFFSET 29902 -#define QM_REG_WRROTHERGRPWEIGHT_3_RT_OFFSET 29903 -#define QM_REG_WRRTXGRPWEIGHT_0_RT_OFFSET 29904 -#define QM_REG_WRRTXGRPWEIGHT_1_RT_OFFSET 29905 -#define QM_REG_PQTX2PF_0_RT_OFFSET 29906 -#define QM_REG_PQTX2PF_1_RT_OFFSET 29907 -#define QM_REG_PQTX2PF_2_RT_OFFSET 29908 -#define QM_REG_PQTX2PF_3_RT_OFFSET 29909 -#define QM_REG_PQTX2PF_4_RT_OFFSET 29910 -#define QM_REG_PQTX2PF_5_RT_OFFSET 29911 -#define QM_REG_PQTX2PF_6_RT_OFFSET 29912 -#define QM_REG_PQTX2PF_7_RT_OFFSET 29913 -#define QM_REG_PQTX2PF_8_RT_OFFSET 29914 -#define QM_REG_PQTX2PF_9_RT_OFFSET 29915 -#define QM_REG_PQTX2PF_10_RT_OFFSET 29916 -#define QM_REG_PQTX2PF_11_RT_OFFSET 29917 -#define QM_REG_PQTX2PF_12_RT_OFFSET 29918 -#define QM_REG_PQTX2PF_13_RT_OFFSET 29919 -#define QM_REG_PQTX2PF_14_RT_OFFSET 29920 -#define QM_REG_PQTX2PF_15_RT_OFFSET 29921 -#define QM_REG_PQTX2PF_16_RT_OFFSET 29922 -#define QM_REG_PQTX2PF_17_RT_OFFSET 29923 -#define QM_REG_PQTX2PF_18_RT_OFFSET 29924 -#define QM_REG_PQTX2PF_19_RT_OFFSET 29925 -#define QM_REG_PQTX2PF_20_RT_OFFSET 29926 -#define QM_REG_PQTX2PF_21_RT_OFFSET 29927 -#define QM_REG_PQTX2PF_22_RT_OFFSET 29928 -#define QM_REG_PQTX2PF_23_RT_OFFSET 29929 -#define QM_REG_PQTX2PF_24_RT_OFFSET 29930 -#define QM_REG_PQTX2PF_25_RT_OFFSET 29931 -#define QM_REG_PQTX2PF_26_RT_OFFSET 29932 -#define QM_REG_PQTX2PF_27_RT_OFFSET 29933 -#define QM_REG_PQTX2PF_28_RT_OFFSET 29934 -#define QM_REG_PQTX2PF_29_RT_OFFSET 29935 -#define QM_REG_PQTX2PF_30_RT_OFFSET 29936 -#define QM_REG_PQTX2PF_31_RT_OFFSET 29937 -#define QM_REG_PQTX2PF_32_RT_OFFSET 29938 -#define QM_REG_PQTX2PF_33_RT_OFFSET 29939 -#define QM_REG_PQTX2PF_34_RT_OFFSET 29940 -#define QM_REG_PQTX2PF_35_RT_OFFSET 29941 -#define QM_REG_PQTX2PF_36_RT_OFFSET 29942 -#define QM_REG_PQTX2PF_37_RT_OFFSET 29943 -#define QM_REG_PQTX2PF_38_RT_OFFSET 29944 -#define QM_REG_PQTX2PF_39_RT_OFFSET 29945 -#define QM_REG_PQTX2PF_40_RT_OFFSET 29946 -#define QM_REG_PQTX2PF_41_RT_OFFSET 29947 -#define QM_REG_PQTX2PF_42_RT_OFFSET 29948 -#define QM_REG_PQTX2PF_43_RT_OFFSET 29949 -#define QM_REG_PQTX2PF_44_RT_OFFSET 29950 -#define QM_REG_PQTX2PF_45_RT_OFFSET 29951 -#define QM_REG_PQTX2PF_46_RT_OFFSET 29952 -#define QM_REG_PQTX2PF_47_RT_OFFSET 29953 -#define QM_REG_PQTX2PF_48_RT_OFFSET 29954 -#define QM_REG_PQTX2PF_49_RT_OFFSET 29955 -#define QM_REG_PQTX2PF_50_RT_OFFSET 29956 -#define QM_REG_PQTX2PF_51_RT_OFFSET 29957 -#define QM_REG_PQTX2PF_52_RT_OFFSET 29958 -#define QM_REG_PQTX2PF_53_RT_OFFSET 29959 -#define QM_REG_PQTX2PF_54_RT_OFFSET 29960 -#define QM_REG_PQTX2PF_55_RT_OFFSET 29961 -#define QM_REG_PQTX2PF_56_RT_OFFSET 29962 -#define QM_REG_PQTX2PF_57_RT_OFFSET 29963 -#define QM_REG_PQTX2PF_58_RT_OFFSET 29964 -#define QM_REG_PQTX2PF_59_RT_OFFSET 29965 -#define QM_REG_PQTX2PF_60_RT_OFFSET 29966 -#define QM_REG_PQTX2PF_61_RT_OFFSET 29967 -#define QM_REG_PQTX2PF_62_RT_OFFSET 29968 -#define QM_REG_PQTX2PF_63_RT_OFFSET 29969 -#define QM_REG_PQOTHER2PF_0_RT_OFFSET 29970 -#define QM_REG_PQOTHER2PF_1_RT_OFFSET 29971 -#define QM_REG_PQOTHER2PF_2_RT_OFFSET 29972 -#define QM_REG_PQOTHER2PF_3_RT_OFFSET 29973 -#define QM_REG_PQOTHER2PF_4_RT_OFFSET 29974 -#define QM_REG_PQOTHER2PF_5_RT_OFFSET 29975 -#define QM_REG_PQOTHER2PF_6_RT_OFFSET 29976 -#define QM_REG_PQOTHER2PF_7_RT_OFFSET 29977 -#define QM_REG_PQOTHER2PF_8_RT_OFFSET 29978 -#define QM_REG_PQOTHER2PF_9_RT_OFFSET 29979 -#define QM_REG_PQOTHER2PF_10_RT_OFFSET 29980 -#define QM_REG_PQOTHER2PF_11_RT_OFFSET 29981 -#define QM_REG_PQOTHER2PF_12_RT_OFFSET 29982 -#define QM_REG_PQOTHER2PF_13_RT_OFFSET 29983 -#define QM_REG_PQOTHER2PF_14_RT_OFFSET 29984 -#define QM_REG_PQOTHER2PF_15_RT_OFFSET 29985 -#define QM_REG_RLGLBLPERIOD_0_RT_OFFSET 29986 -#define QM_REG_RLGLBLPERIOD_1_RT_OFFSET 29987 -#define QM_REG_RLGLBLPERIODTIMER_0_RT_OFFSET 29988 -#define QM_REG_RLGLBLPERIODTIMER_1_RT_OFFSET 29989 -#define QM_REG_RLGLBLPERIODSEL_0_RT_OFFSET 29990 -#define QM_REG_RLGLBLPERIODSEL_1_RT_OFFSET 29991 -#define QM_REG_RLGLBLPERIODSEL_2_RT_OFFSET 29992 -#define QM_REG_RLGLBLPERIODSEL_3_RT_OFFSET 29993 -#define QM_REG_RLGLBLPERIODSEL_4_RT_OFFSET 29994 -#define QM_REG_RLGLBLPERIODSEL_5_RT_OFFSET 29995 -#define QM_REG_RLGLBLPERIODSEL_6_RT_OFFSET 29996 -#define QM_REG_RLGLBLPERIODSEL_7_RT_OFFSET 29997 -#define QM_REG_RLGLBLINCVAL_RT_OFFSET 29998 +#define QM_REG_AFULLQMBYPTHRPFWFQ_RT_OFFSET 29933 +#define QM_REG_AFULLQMBYPTHRVPWFQ_RT_OFFSET 29934 +#define QM_REG_AFULLQMBYPTHRPFRL_RT_OFFSET 29935 +#define QM_REG_AFULLQMBYPTHRGLBLRL_RT_OFFSET 29936 +#define QM_REG_AFULLOPRTNSTCCRDMASK_RT_OFFSET 29937 +#define QM_REG_WRROTHERPQGRP_0_RT_OFFSET 29938 +#define QM_REG_WRROTHERPQGRP_1_RT_OFFSET 29939 +#define QM_REG_WRROTHERPQGRP_2_RT_OFFSET 29940 +#define QM_REG_WRROTHERPQGRP_3_RT_OFFSET 29941 +#define QM_REG_WRROTHERPQGRP_4_RT_OFFSET 29942 +#define QM_REG_WRROTHERPQGRP_5_RT_OFFSET 29943 +#define QM_REG_WRROTHERPQGRP_6_RT_OFFSET 29944 +#define QM_REG_WRROTHERPQGRP_7_RT_OFFSET 29945 +#define QM_REG_WRROTHERPQGRP_8_RT_OFFSET 29946 +#define QM_REG_WRROTHERPQGRP_9_RT_OFFSET 29947 +#define QM_REG_WRROTHERPQGRP_10_RT_OFFSET 29948 +#define QM_REG_WRROTHERPQGRP_11_RT_OFFSET 29949 +#define QM_REG_WRROTHERPQGRP_12_RT_OFFSET 29950 +#define QM_REG_WRROTHERPQGRP_13_RT_OFFSET 29951 +#define QM_REG_WRROTHERPQGRP_14_RT_OFFSET 29952 +#define QM_REG_WRROTHERPQGRP_15_RT_OFFSET 29953 +#define QM_REG_WRROTHERGRPWEIGHT_0_RT_OFFSET 29954 +#define QM_REG_WRROTHERGRPWEIGHT_1_RT_OFFSET 29955 +#define QM_REG_WRROTHERGRPWEIGHT_2_RT_OFFSET 29956 +#define QM_REG_WRROTHERGRPWEIGHT_3_RT_OFFSET 29957 +#define QM_REG_WRRTXGRPWEIGHT_0_RT_OFFSET 29958 +#define QM_REG_WRRTXGRPWEIGHT_1_RT_OFFSET 29959 +#define QM_REG_PQTX2PF_0_RT_OFFSET 29960 +#define QM_REG_PQTX2PF_1_RT_OFFSET 29961 +#define QM_REG_PQTX2PF_2_RT_OFFSET 29962 +#define QM_REG_PQTX2PF_3_RT_OFFSET 29963 +#define QM_REG_PQTX2PF_4_RT_OFFSET 29964 +#define QM_REG_PQTX2PF_5_RT_OFFSET 29965 +#define QM_REG_PQTX2PF_6_RT_OFFSET 29966 +#define QM_REG_PQTX2PF_7_RT_OFFSET 29967 +#define QM_REG_PQTX2PF_8_RT_OFFSET 29968 +#define QM_REG_PQTX2PF_9_RT_OFFSET 29969 +#define QM_REG_PQTX2PF_10_RT_OFFSET 29970 +#define QM_REG_PQTX2PF_11_RT_OFFSET 29971 +#define QM_REG_PQTX2PF_12_RT_OFFSET 29972 +#define QM_REG_PQTX2PF_13_RT_OFFSET 29973 +#define QM_REG_PQTX2PF_14_RT_OFFSET 29974 +#define QM_REG_PQTX2PF_15_RT_OFFSET 29975 +#define QM_REG_PQTX2PF_16_RT_OFFSET 29976 +#define QM_REG_PQTX2PF_17_RT_OFFSET 29977 +#define QM_REG_PQTX2PF_18_RT_OFFSET 29978 +#define QM_REG_PQTX2PF_19_RT_OFFSET 29979 +#define QM_REG_PQTX2PF_20_RT_OFFSET 29980 +#define QM_REG_PQTX2PF_21_RT_OFFSET 29981 +#define QM_REG_PQTX2PF_22_RT_OFFSET 29982 +#define QM_REG_PQTX2PF_23_RT_OFFSET 29983 +#define QM_REG_PQTX2PF_24_RT_OFFSET 29984 +#define QM_REG_PQTX2PF_25_RT_OFFSET 29985 +#define QM_REG_PQTX2PF_26_RT_OFFSET 29986 +#define QM_REG_PQTX2PF_27_RT_OFFSET 29987 +#define QM_REG_PQTX2PF_28_RT_OFFSET 29988 +#define QM_REG_PQTX2PF_29_RT_OFFSET 29989 +#define QM_REG_PQTX2PF_30_RT_OFFSET 29990 +#define QM_REG_PQTX2PF_31_RT_OFFSET 29991 +#define QM_REG_PQTX2PF_32_RT_OFFSET 29992 +#define QM_REG_PQTX2PF_33_RT_OFFSET 29993 +#define QM_REG_PQTX2PF_34_RT_OFFSET 29994 +#define QM_REG_PQTX2PF_35_RT_OFFSET 29995 +#define QM_REG_PQTX2PF_36_RT_OFFSET 29996 +#define QM_REG_PQTX2PF_37_RT_OFFSET 29997 +#define QM_REG_PQTX2PF_38_RT_OFFSET 29998 +#define QM_REG_PQTX2PF_39_RT_OFFSET 29999 +#define QM_REG_PQTX2PF_40_RT_OFFSET 30000 +#define QM_REG_PQTX2PF_41_RT_OFFSET 30001 +#define QM_REG_PQTX2PF_42_RT_OFFSET 30002 +#define QM_REG_PQTX2PF_43_RT_OFFSET 30003 +#define QM_REG_PQTX2PF_44_RT_OFFSET 30004 +#define QM_REG_PQTX2PF_45_RT_OFFSET 30005 +#define QM_REG_PQTX2PF_46_RT_OFFSET 30006 +#define QM_REG_PQTX2PF_47_RT_OFFSET 30007 +#define QM_REG_PQTX2PF_48_RT_OFFSET 30008 +#define QM_REG_PQTX2PF_49_RT_OFFSET 30009 +#define QM_REG_PQTX2PF_50_RT_OFFSET 30010 +#define QM_REG_PQTX2PF_51_RT_OFFSET 30011 +#define QM_REG_PQTX2PF_52_RT_OFFSET 30012 +#define QM_REG_PQTX2PF_53_RT_OFFSET 30013 +#define QM_REG_PQTX2PF_54_RT_OFFSET 30014 +#define QM_REG_PQTX2PF_55_RT_OFFSET 30015 +#define QM_REG_PQTX2PF_56_RT_OFFSET 30016 +#define QM_REG_PQTX2PF_57_RT_OFFSET 30017 +#define QM_REG_PQTX2PF_58_RT_OFFSET 30018 +#define QM_REG_PQTX2PF_59_RT_OFFSET 30019 +#define QM_REG_PQTX2PF_60_RT_OFFSET 30020 +#define QM_REG_PQTX2PF_61_RT_OFFSET 30021 +#define QM_REG_PQTX2PF_62_RT_OFFSET 30022 +#define QM_REG_PQTX2PF_63_RT_OFFSET 30023 +#define QM_REG_PQOTHER2PF_0_RT_OFFSET 30024 +#define QM_REG_PQOTHER2PF_1_RT_OFFSET 30025 +#define QM_REG_PQOTHER2PF_2_RT_OFFSET 30026 +#define QM_REG_PQOTHER2PF_3_RT_OFFSET 30027 +#define QM_REG_PQOTHER2PF_4_RT_OFFSET 30028 +#define QM_REG_PQOTHER2PF_5_RT_OFFSET 30029 +#define QM_REG_PQOTHER2PF_6_RT_OFFSET 30030 +#define QM_REG_PQOTHER2PF_7_RT_OFFSET 30031 +#define QM_REG_PQOTHER2PF_8_RT_OFFSET 30032 +#define QM_REG_PQOTHER2PF_9_RT_OFFSET 30033 +#define QM_REG_PQOTHER2PF_10_RT_OFFSET 30034 +#define QM_REG_PQOTHER2PF_11_RT_OFFSET 30035 +#define QM_REG_PQOTHER2PF_12_RT_OFFSET 30036 +#define QM_REG_PQOTHER2PF_13_RT_OFFSET 30037 +#define QM_REG_PQOTHER2PF_14_RT_OFFSET 30038 +#define QM_REG_PQOTHER2PF_15_RT_OFFSET 30039 +#define QM_REG_RLGLBLPERIOD_0_RT_OFFSET 30040 +#define QM_REG_RLGLBLPERIOD_1_RT_OFFSET 30041 +#define QM_REG_RLGLBLPERIODTIMER_0_RT_OFFSET 30042 +#define QM_REG_RLGLBLPERIODTIMER_1_RT_OFFSET 30043 +#define QM_REG_RLGLBLPERIODSEL_0_RT_OFFSET 30044 +#define QM_REG_RLGLBLPERIODSEL_1_RT_OFFSET 30045 +#define QM_REG_RLGLBLPERIODSEL_2_RT_OFFSET 30046 +#define QM_REG_RLGLBLPERIODSEL_3_RT_OFFSET 30047 +#define QM_REG_RLGLBLPERIODSEL_4_RT_OFFSET 30048 +#define QM_REG_RLGLBLPERIODSEL_5_RT_OFFSET 30049 +#define QM_REG_RLGLBLPERIODSEL_6_RT_OFFSET 30050 +#define QM_REG_RLGLBLPERIODSEL_7_RT_OFFSET 30051 +#define QM_REG_RLGLBLINCVAL_RT_OFFSET 30052 #define QM_REG_RLGLBLINCVAL_RT_SIZE 256 -#define QM_REG_RLGLBLUPPERBOUND_RT_OFFSET 30254 +#define QM_REG_RLGLBLUPPERBOUND_RT_OFFSET 30308 #define QM_REG_RLGLBLUPPERBOUND_RT_SIZE 256 -#define QM_REG_RLGLBLCRD_RT_OFFSET 30510 +#define QM_REG_RLGLBLCRD_RT_OFFSET 30564 #define QM_REG_RLGLBLCRD_RT_SIZE 256 -#define QM_REG_RLGLBLENABLE_RT_OFFSET 30766 -#define QM_REG_RLPFPERIOD_RT_OFFSET 30767 -#define QM_REG_RLPFPERIODTIMER_RT_OFFSET 30768 -#define QM_REG_RLPFINCVAL_RT_OFFSET 30769 +#define QM_REG_RLGLBLENABLE_RT_OFFSET 30820 +#define QM_REG_RLPFPERIOD_RT_OFFSET 30821 +#define QM_REG_RLPFPERIODTIMER_RT_OFFSET 30822 +#define QM_REG_RLPFINCVAL_RT_OFFSET 30823 #define QM_REG_RLPFINCVAL_RT_SIZE 16 -#define QM_REG_RLPFUPPERBOUND_RT_OFFSET 30785 +#define QM_REG_RLPFUPPERBOUND_RT_OFFSET 30839 #define QM_REG_RLPFUPPERBOUND_RT_SIZE 16 -#define QM_REG_RLPFCRD_RT_OFFSET 30801 +#define QM_REG_RLPFCRD_RT_OFFSET 30855 #define QM_REG_RLPFCRD_RT_SIZE 16 -#define QM_REG_RLPFENABLE_RT_OFFSET 30817 -#define QM_REG_RLPFVOQENABLE_RT_OFFSET 30818 -#define QM_REG_WFQPFWEIGHT_RT_OFFSET 30819 +#define QM_REG_RLPFENABLE_RT_OFFSET 30871 +#define QM_REG_RLPFVOQENABLE_RT_OFFSET 30872 +#define QM_REG_WFQPFWEIGHT_RT_OFFSET 30873 #define QM_REG_WFQPFWEIGHT_RT_SIZE 16 -#define QM_REG_WFQPFUPPERBOUND_RT_OFFSET 30835 +#define QM_REG_WFQPFUPPERBOUND_RT_OFFSET 30889 #define QM_REG_WFQPFUPPERBOUND_RT_SIZE 16 -#define QM_REG_WFQPFCRD_RT_OFFSET 30851 -#define QM_REG_WFQPFCRD_RT_SIZE 160 -#define QM_REG_WFQPFENABLE_RT_OFFSET 31011 -#define QM_REG_WFQVPENABLE_RT_OFFSET 31012 -#define QM_REG_BASEADDRTXPQ_RT_OFFSET 31013 +#define QM_REG_WFQPFCRD_RT_OFFSET 30905 +#define QM_REG_WFQPFCRD_RT_SIZE 256 +#define QM_REG_WFQPFENABLE_RT_OFFSET 31161 +#define QM_REG_WFQVPENABLE_RT_OFFSET 31162 +#define QM_REG_BASEADDRTXPQ_RT_OFFSET 31163 #define QM_REG_BASEADDRTXPQ_RT_SIZE 512 -#define QM_REG_TXPQMAP_RT_OFFSET 31525 +#define QM_REG_TXPQMAP_RT_OFFSET 31675 #define QM_REG_TXPQMAP_RT_SIZE 512 -#define QM_REG_WFQVPWEIGHT_RT_OFFSET 32037 +#define QM_REG_WFQVPWEIGHT_RT_OFFSET 32187 #define QM_REG_WFQVPWEIGHT_RT_SIZE 512 -#define QM_REG_WFQVPCRD_RT_OFFSET 32549 +#define QM_REG_WFQVPCRD_RT_OFFSET 32699 #define QM_REG_WFQVPCRD_RT_SIZE 512 -#define QM_REG_WFQVPMAP_RT_OFFSET 33061 +#define QM_REG_WFQVPMAP_RT_OFFSET 33211 #define QM_REG_WFQVPMAP_RT_SIZE 512 -#define QM_REG_WFQPFCRD_MSB_RT_OFFSET 33573 -#define QM_REG_WFQPFCRD_MSB_RT_SIZE 160 -#define NIG_REG_TAG_ETHERTYPE_0_RT_OFFSET 33733 -#define NIG_REG_OUTER_TAG_VALUE_LIST0_RT_OFFSET 33734 -#define NIG_REG_OUTER_TAG_VALUE_LIST1_RT_OFFSET 33735 -#define NIG_REG_OUTER_TAG_VALUE_LIST2_RT_OFFSET 33736 -#define NIG_REG_OUTER_TAG_VALUE_LIST3_RT_OFFSET 33737 -#define NIG_REG_OUTER_TAG_VALUE_MASK_RT_OFFSET 33738 -#define NIG_REG_LLH_FUNC_TAGMAC_CLS_TYPE_RT_OFFSET 33739 -#define NIG_REG_LLH_FUNC_TAG_EN_RT_OFFSET 33740 +#define QM_REG_WFQPFCRD_MSB_RT_OFFSET 33723 +#define QM_REG_WFQPFCRD_MSB_RT_SIZE 320 +#define QM_REG_VOQCRDLINE_RT_OFFSET 34043 +#define QM_REG_VOQCRDLINE_RT_SIZE 36 +#define QM_REG_VOQINITCRDLINE_RT_OFFSET 34079 +#define QM_REG_VOQINITCRDLINE_RT_SIZE 36 +#define NIG_REG_TAG_ETHERTYPE_0_RT_OFFSET 34115 +#define NIG_REG_OUTER_TAG_VALUE_LIST0_RT_OFFSET 34116 +#define NIG_REG_OUTER_TAG_VALUE_LIST1_RT_OFFSET 34117 +#define NIG_REG_OUTER_TAG_VALUE_LIST2_RT_OFFSET 34118 +#define NIG_REG_OUTER_TAG_VALUE_LIST3_RT_OFFSET 34119 +#define NIG_REG_OUTER_TAG_VALUE_MASK_RT_OFFSET 34120 +#define NIG_REG_LLH_FUNC_TAGMAC_CLS_TYPE_RT_OFFSET 34121 +#define NIG_REG_LLH_FUNC_TAG_EN_RT_OFFSET 34122 #define NIG_REG_LLH_FUNC_TAG_EN_RT_SIZE 4 -#define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_OFFSET 33744 +#define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_OFFSET 34126 #define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_SIZE 4 -#define NIG_REG_LLH_FUNC_TAG_VALUE_RT_OFFSET 33748 +#define NIG_REG_LLH_FUNC_TAG_VALUE_RT_OFFSET 34130 #define NIG_REG_LLH_FUNC_TAG_VALUE_RT_SIZE 4 -#define NIG_REG_LLH_FUNC_NO_TAG_RT_OFFSET 33752 -#define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_OFFSET 33753 +#define NIG_REG_LLH_FUNC_NO_TAG_RT_OFFSET 34134 +#define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_OFFSET 34135 #define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_SIZE 32 -#define NIG_REG_LLH_FUNC_FILTER_EN_RT_OFFSET 33785 +#define NIG_REG_LLH_FUNC_FILTER_EN_RT_OFFSET 34167 #define NIG_REG_LLH_FUNC_FILTER_EN_RT_SIZE 16 -#define NIG_REG_LLH_FUNC_FILTER_MODE_RT_OFFSET 33801 +#define NIG_REG_LLH_FUNC_FILTER_MODE_RT_OFFSET 34183 #define NIG_REG_LLH_FUNC_FILTER_MODE_RT_SIZE 16 -#define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_OFFSET 33817 +#define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_OFFSET 34199 #define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_SIZE 16 -#define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_OFFSET 33833 +#define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_OFFSET 34215 #define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_SIZE 16 -#define NIG_REG_TX_EDPM_CTRL_RT_OFFSET 33849 -#define NIG_REG_ROCE_DUPLICATE_TO_HOST_RT_OFFSET 33850 -#define CDU_REG_CID_ADDR_PARAMS_RT_OFFSET 33851 -#define CDU_REG_SEGMENT0_PARAMS_RT_OFFSET 33852 -#define CDU_REG_SEGMENT1_PARAMS_RT_OFFSET 33853 -#define CDU_REG_PF_SEG0_TYPE_OFFSET_RT_OFFSET 33854 -#define CDU_REG_PF_SEG1_TYPE_OFFSET_RT_OFFSET 33855 -#define CDU_REG_PF_SEG2_TYPE_OFFSET_RT_OFFSET 33856 -#define CDU_REG_PF_SEG3_TYPE_OFFSET_RT_OFFSET 33857 -#define CDU_REG_PF_FL_SEG0_TYPE_OFFSET_RT_OFFSET 33858 -#define CDU_REG_PF_FL_SEG1_TYPE_OFFSET_RT_OFFSET 33859 -#define CDU_REG_PF_FL_SEG2_TYPE_OFFSET_RT_OFFSET 33860 -#define CDU_REG_PF_FL_SEG3_TYPE_OFFSET_RT_OFFSET 33861 -#define CDU_REG_VF_SEG_TYPE_OFFSET_RT_OFFSET 33862 -#define CDU_REG_VF_FL_SEG_TYPE_OFFSET_RT_OFFSET 33863 -#define PBF_REG_TAG_ETHERTYPE_0_RT_OFFSET 33864 -#define PBF_REG_BTB_SHARED_AREA_SIZE_RT_OFFSET 33865 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ0_RT_OFFSET 33866 -#define PBF_REG_BTB_GUARANTEED_VOQ0_RT_OFFSET 33867 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ0_RT_OFFSET 33868 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ1_RT_OFFSET 33869 -#define PBF_REG_BTB_GUARANTEED_VOQ1_RT_OFFSET 33870 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ1_RT_OFFSET 33871 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ2_RT_OFFSET 33872 -#define PBF_REG_BTB_GUARANTEED_VOQ2_RT_OFFSET 33873 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ2_RT_OFFSET 33874 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ3_RT_OFFSET 33875 -#define PBF_REG_BTB_GUARANTEED_VOQ3_RT_OFFSET 33876 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ3_RT_OFFSET 33877 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ4_RT_OFFSET 33878 -#define PBF_REG_BTB_GUARANTEED_VOQ4_RT_OFFSET 33879 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ4_RT_OFFSET 33880 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ5_RT_OFFSET 33881 -#define PBF_REG_BTB_GUARANTEED_VOQ5_RT_OFFSET 33882 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ5_RT_OFFSET 33883 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ6_RT_OFFSET 33884 -#define PBF_REG_BTB_GUARANTEED_VOQ6_RT_OFFSET 33885 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ6_RT_OFFSET 33886 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ7_RT_OFFSET 33887 -#define PBF_REG_BTB_GUARANTEED_VOQ7_RT_OFFSET 33888 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ7_RT_OFFSET 33889 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ8_RT_OFFSET 33890 -#define PBF_REG_BTB_GUARANTEED_VOQ8_RT_OFFSET 33891 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ8_RT_OFFSET 33892 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ9_RT_OFFSET 33893 -#define PBF_REG_BTB_GUARANTEED_VOQ9_RT_OFFSET 33894 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ9_RT_OFFSET 33895 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ10_RT_OFFSET 33896 -#define PBF_REG_BTB_GUARANTEED_VOQ10_RT_OFFSET 33897 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ10_RT_OFFSET 33898 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ11_RT_OFFSET 33899 -#define PBF_REG_BTB_GUARANTEED_VOQ11_RT_OFFSET 33900 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ11_RT_OFFSET 33901 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ12_RT_OFFSET 33902 -#define PBF_REG_BTB_GUARANTEED_VOQ12_RT_OFFSET 33903 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ12_RT_OFFSET 33904 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ13_RT_OFFSET 33905 -#define PBF_REG_BTB_GUARANTEED_VOQ13_RT_OFFSET 33906 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ13_RT_OFFSET 33907 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ14_RT_OFFSET 33908 -#define PBF_REG_BTB_GUARANTEED_VOQ14_RT_OFFSET 33909 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ14_RT_OFFSET 33910 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ15_RT_OFFSET 33911 -#define PBF_REG_BTB_GUARANTEED_VOQ15_RT_OFFSET 33912 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ15_RT_OFFSET 33913 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ16_RT_OFFSET 33914 -#define PBF_REG_BTB_GUARANTEED_VOQ16_RT_OFFSET 33915 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ16_RT_OFFSET 33916 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ17_RT_OFFSET 33917 -#define PBF_REG_BTB_GUARANTEED_VOQ17_RT_OFFSET 33918 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ17_RT_OFFSET 33919 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ18_RT_OFFSET 33920 -#define PBF_REG_BTB_GUARANTEED_VOQ18_RT_OFFSET 33921 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ18_RT_OFFSET 33922 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ19_RT_OFFSET 33923 -#define PBF_REG_BTB_GUARANTEED_VOQ19_RT_OFFSET 33924 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ19_RT_OFFSET 33925 -#define XCM_REG_CON_PHY_Q3_RT_OFFSET 33926 - -#define RUNTIME_ARRAY_SIZE 33927 +#define NIG_REG_TX_EDPM_CTRL_RT_OFFSET 34231 +#define NIG_REG_ROCE_DUPLICATE_TO_HOST_RT_OFFSET 34232 +#define CDU_REG_CID_ADDR_PARAMS_RT_OFFSET 34233 +#define CDU_REG_SEGMENT0_PARAMS_RT_OFFSET 34234 +#define CDU_REG_SEGMENT1_PARAMS_RT_OFFSET 34235 +#define CDU_REG_PF_SEG0_TYPE_OFFSET_RT_OFFSET 34236 +#define CDU_REG_PF_SEG1_TYPE_OFFSET_RT_OFFSET 34237 +#define CDU_REG_PF_SEG2_TYPE_OFFSET_RT_OFFSET 34238 +#define CDU_REG_PF_SEG3_TYPE_OFFSET_RT_OFFSET 34239 +#define CDU_REG_PF_FL_SEG0_TYPE_OFFSET_RT_OFFSET 34240 +#define CDU_REG_PF_FL_SEG1_TYPE_OFFSET_RT_OFFSET 34241 +#define CDU_REG_PF_FL_SEG2_TYPE_OFFSET_RT_OFFSET 34242 +#define CDU_REG_PF_FL_SEG3_TYPE_OFFSET_RT_OFFSET 34243 +#define CDU_REG_VF_SEG_TYPE_OFFSET_RT_OFFSET 34244 +#define CDU_REG_VF_FL_SEG_TYPE_OFFSET_RT_OFFSET 34245 +#define PBF_REG_TAG_ETHERTYPE_0_RT_OFFSET 34246 +#define PBF_REG_BTB_SHARED_AREA_SIZE_RT_OFFSET 34247 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ0_RT_OFFSET 34248 +#define PBF_REG_BTB_GUARANTEED_VOQ0_RT_OFFSET 34249 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ0_RT_OFFSET 34250 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ1_RT_OFFSET 34251 +#define PBF_REG_BTB_GUARANTEED_VOQ1_RT_OFFSET 34252 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ1_RT_OFFSET 34253 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ2_RT_OFFSET 34254 +#define PBF_REG_BTB_GUARANTEED_VOQ2_RT_OFFSET 34255 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ2_RT_OFFSET 34256 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ3_RT_OFFSET 34257 +#define PBF_REG_BTB_GUARANTEED_VOQ3_RT_OFFSET 34258 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ3_RT_OFFSET 34259 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ4_RT_OFFSET 34260 +#define PBF_REG_BTB_GUARANTEED_VOQ4_RT_OFFSET 34261 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ4_RT_OFFSET 34262 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ5_RT_OFFSET 34263 +#define PBF_REG_BTB_GUARANTEED_VOQ5_RT_OFFSET 34264 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ5_RT_OFFSET 34265 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ6_RT_OFFSET 34266 +#define PBF_REG_BTB_GUARANTEED_VOQ6_RT_OFFSET 34267 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ6_RT_OFFSET 34268 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ7_RT_OFFSET 34269 +#define PBF_REG_BTB_GUARANTEED_VOQ7_RT_OFFSET 34270 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ7_RT_OFFSET 34271 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ8_RT_OFFSET 34272 +#define PBF_REG_BTB_GUARANTEED_VOQ8_RT_OFFSET 34273 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ8_RT_OFFSET 34274 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ9_RT_OFFSET 34275 +#define PBF_REG_BTB_GUARANTEED_VOQ9_RT_OFFSET 34276 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ9_RT_OFFSET 34277 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ10_RT_OFFSET 34278 +#define PBF_REG_BTB_GUARANTEED_VOQ10_RT_OFFSET 34279 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ10_RT_OFFSET 34280 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ11_RT_OFFSET 34281 +#define PBF_REG_BTB_GUARANTEED_VOQ11_RT_OFFSET 34282 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ11_RT_OFFSET 34283 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ12_RT_OFFSET 34284 +#define PBF_REG_BTB_GUARANTEED_VOQ12_RT_OFFSET 34285 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ12_RT_OFFSET 34286 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ13_RT_OFFSET 34287 +#define PBF_REG_BTB_GUARANTEED_VOQ13_RT_OFFSET 34288 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ13_RT_OFFSET 34289 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ14_RT_OFFSET 34290 +#define PBF_REG_BTB_GUARANTEED_VOQ14_RT_OFFSET 34291 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ14_RT_OFFSET 34292 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ15_RT_OFFSET 34293 +#define PBF_REG_BTB_GUARANTEED_VOQ15_RT_OFFSET 34294 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ15_RT_OFFSET 34295 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ16_RT_OFFSET 34296 +#define PBF_REG_BTB_GUARANTEED_VOQ16_RT_OFFSET 34297 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ16_RT_OFFSET 34298 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ17_RT_OFFSET 34299 +#define PBF_REG_BTB_GUARANTEED_VOQ17_RT_OFFSET 34300 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ17_RT_OFFSET 34301 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ18_RT_OFFSET 34302 +#define PBF_REG_BTB_GUARANTEED_VOQ18_RT_OFFSET 34303 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ18_RT_OFFSET 34304 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ19_RT_OFFSET 34305 +#define PBF_REG_BTB_GUARANTEED_VOQ19_RT_OFFSET 34306 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ19_RT_OFFSET 34307 +#define XCM_REG_CON_PHY_Q3_RT_OFFSET 34308 + +#define RUNTIME_ARRAY_SIZE 34309 /* The eth storm context for the Tstorm */ struct tstorm_eth_conn_st_ctx { @@ -4307,7 +4647,7 @@ struct xstorm_eth_conn_ag_ctx { #define XSTORM_ETH_CONN_AG_CTX_TPH_ENABLE_SHIFT 6 u8 edpm_event_id; __le16 physical_q0; - __le16 quota; + __le16 ereserved1; __le16 edpm_num_bds; __le16 tx_bd_cons; __le16 tx_bd_prod; @@ -4340,7 +4680,7 @@ struct xstorm_eth_conn_ag_ctx { u8 byte13; u8 byte14; u8 byte15; - u8 byte16; + u8 ereserved; __le16 word11; __le32 reg10; __le32 reg11; @@ -4627,6 +4967,7 @@ enum eth_error_code { ETH_FILTERS_PAIR_ADD_FAIL_ZERO_MAC, ETH_FILTERS_VNI_ADD_FAIL_FULL, ETH_FILTERS_VNI_ADD_FAIL_DUP, + ETH_FILTERS_GFT_UPDATE_FAIL, MAX_ETH_ERROR_CODE }; @@ -4879,6 +5220,39 @@ enum gft_logic_filter_type { MAX_GFT_LOGIC_FILTER_TYPE }; +struct rx_add_openflow_filter_data { + __le16 action_icid; + u8 priority; + u8 reserved0; + __le32 tenant_id; + __le16 dst_mac_hi; + __le16 dst_mac_mid; + __le16 dst_mac_lo; + __le16 src_mac_hi; + __le16 src_mac_mid; + __le16 src_mac_lo; + __le16 vlan_id; + __le16 l2_eth_type; + u8 ipv4_dscp; + u8 ipv4_frag_type; + u8 ipv4_over_ip; + u8 tenant_id_exists; + __le32 ipv4_dst_addr; + __le32 ipv4_src_addr; + __le16 l4_dst_port; + __le16 l4_src_port; +}; + +struct rx_create_gft_action_data { + u8 vport_id; + u8 reserved[7]; +}; + +struct rx_create_openflow_action_data { + u8 vport_id; + u8 reserved[7]; +}; + /* Ramrod data for rx queue start ramrod */ struct rx_queue_start_ramrod_data { __le16 rx_queue_id; @@ -4956,7 +5330,7 @@ struct rx_update_gft_filter_data { u8 vport_id; u8 filter_type; u8 filter_action; - u8 reserved; + u8 assert_on_error; }; /* Ramrod data for rx queue start ramrod */ @@ -5102,203 +5476,6 @@ struct vport_update_ramrod_data { struct eth_vport_rss_config rss_config; }; -struct gft_cam_line { - __le32 camline; -#define GFT_CAM_LINE_VALID_MASK 0x1 -#define GFT_CAM_LINE_VALID_SHIFT 0 -#define GFT_CAM_LINE_DATA_MASK 0x3FFF -#define GFT_CAM_LINE_DATA_SHIFT 1 -#define GFT_CAM_LINE_MASK_BITS_MASK 0x3FFF -#define GFT_CAM_LINE_MASK_BITS_SHIFT 15 -#define GFT_CAM_LINE_RESERVED1_MASK 0x7 -#define GFT_CAM_LINE_RESERVED1_SHIFT 29 -}; - -struct gft_cam_line_mapped { - __le32 camline; -#define GFT_CAM_LINE_MAPPED_VALID_MASK 0x1 -#define GFT_CAM_LINE_MAPPED_VALID_SHIFT 0 -#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK 0x1 -#define GFT_CAM_LINE_MAPPED_IP_VERSION_SHIFT 1 -#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK 0x1 -#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_SHIFT 2 -#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK 0xF -#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_SHIFT 3 -#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK 0xF -#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_SHIFT 7 -#define GFT_CAM_LINE_MAPPED_PF_ID_MASK 0xF -#define GFT_CAM_LINE_MAPPED_PF_ID_SHIFT 11 -#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK_MASK 0x1 -#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK_SHIFT 15 -#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK_MASK 0x1 -#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK_SHIFT 16 -#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK_MASK 0xF -#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK_SHIFT 17 -#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK_MASK 0xF -#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK_SHIFT 21 -#define GFT_CAM_LINE_MAPPED_PF_ID_MASK_MASK 0xF -#define GFT_CAM_LINE_MAPPED_PF_ID_MASK_SHIFT 25 -#define GFT_CAM_LINE_MAPPED_RESERVED1_MASK 0x7 -#define GFT_CAM_LINE_MAPPED_RESERVED1_SHIFT 29 -}; - -union gft_cam_line_union { - struct gft_cam_line cam_line; - struct gft_cam_line_mapped cam_line_mapped; -}; - -enum gft_profile_ip_version { - GFT_PROFILE_IPV4 = 0, - GFT_PROFILE_IPV6 = 1, - MAX_GFT_PROFILE_IP_VERSION -}; - -enum gft_profile_upper_protocol_type { - GFT_PROFILE_ROCE_PROTOCOL = 0, - GFT_PROFILE_RROCE_PROTOCOL = 1, - GFT_PROFILE_FCOE_PROTOCOL = 2, - GFT_PROFILE_ICMP_PROTOCOL = 3, - GFT_PROFILE_ARP_PROTOCOL = 4, - GFT_PROFILE_USER_TCP_SRC_PORT_1_INNER = 5, - GFT_PROFILE_USER_TCP_DST_PORT_1_INNER = 6, - GFT_PROFILE_TCP_PROTOCOL = 7, - GFT_PROFILE_USER_UDP_DST_PORT_1_INNER = 8, - GFT_PROFILE_USER_UDP_DST_PORT_2_OUTER = 9, - GFT_PROFILE_UDP_PROTOCOL = 10, - GFT_PROFILE_USER_IP_1_INNER = 11, - GFT_PROFILE_USER_IP_2_OUTER = 12, - GFT_PROFILE_USER_ETH_1_INNER = 13, - GFT_PROFILE_USER_ETH_2_OUTER = 14, - GFT_PROFILE_RAW = 15, - MAX_GFT_PROFILE_UPPER_PROTOCOL_TYPE -}; - -struct gft_ram_line { - __le32 low32bits; -#define GFT_RAM_LINE_VLAN_SELECT_MASK 0x3 -#define GFT_RAM_LINE_VLAN_SELECT_SHIFT 0 -#define GFT_RAM_LINE_TUNNEL_ENTROPHY_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_ENTROPHY_SHIFT 2 -#define GFT_RAM_LINE_TUNNEL_TTL_EQUAL_ONE_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_TTL_EQUAL_ONE_SHIFT 3 -#define GFT_RAM_LINE_TUNNEL_TTL_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_TTL_SHIFT 4 -#define GFT_RAM_LINE_TUNNEL_ETHERTYPE_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_ETHERTYPE_SHIFT 5 -#define GFT_RAM_LINE_TUNNEL_DST_PORT_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_DST_PORT_SHIFT 6 -#define GFT_RAM_LINE_TUNNEL_SRC_PORT_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_SRC_PORT_SHIFT 7 -#define GFT_RAM_LINE_TUNNEL_DSCP_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_DSCP_SHIFT 8 -#define GFT_RAM_LINE_TUNNEL_OVER_IP_PROTOCOL_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_OVER_IP_PROTOCOL_SHIFT 9 -#define GFT_RAM_LINE_TUNNEL_DST_IP_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_DST_IP_SHIFT 10 -#define GFT_RAM_LINE_TUNNEL_SRC_IP_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_SRC_IP_SHIFT 11 -#define GFT_RAM_LINE_TUNNEL_PRIORITY_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_PRIORITY_SHIFT 12 -#define GFT_RAM_LINE_TUNNEL_PROVIDER_VLAN_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_PROVIDER_VLAN_SHIFT 13 -#define GFT_RAM_LINE_TUNNEL_VLAN_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_VLAN_SHIFT 14 -#define GFT_RAM_LINE_TUNNEL_DST_MAC_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_DST_MAC_SHIFT 15 -#define GFT_RAM_LINE_TUNNEL_SRC_MAC_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_SRC_MAC_SHIFT 16 -#define GFT_RAM_LINE_TTL_EQUAL_ONE_MASK 0x1 -#define GFT_RAM_LINE_TTL_EQUAL_ONE_SHIFT 17 -#define GFT_RAM_LINE_TTL_MASK 0x1 -#define GFT_RAM_LINE_TTL_SHIFT 18 -#define GFT_RAM_LINE_ETHERTYPE_MASK 0x1 -#define GFT_RAM_LINE_ETHERTYPE_SHIFT 19 -#define GFT_RAM_LINE_RESERVED0_MASK 0x1 -#define GFT_RAM_LINE_RESERVED0_SHIFT 20 -#define GFT_RAM_LINE_TCP_FLAG_FIN_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_FIN_SHIFT 21 -#define GFT_RAM_LINE_TCP_FLAG_SYN_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_SYN_SHIFT 22 -#define GFT_RAM_LINE_TCP_FLAG_RST_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_RST_SHIFT 23 -#define GFT_RAM_LINE_TCP_FLAG_PSH_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_PSH_SHIFT 24 -#define GFT_RAM_LINE_TCP_FLAG_ACK_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_ACK_SHIFT 25 -#define GFT_RAM_LINE_TCP_FLAG_URG_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_URG_SHIFT 26 -#define GFT_RAM_LINE_TCP_FLAG_ECE_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_ECE_SHIFT 27 -#define GFT_RAM_LINE_TCP_FLAG_CWR_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_CWR_SHIFT 28 -#define GFT_RAM_LINE_TCP_FLAG_NS_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_NS_SHIFT 29 -#define GFT_RAM_LINE_DST_PORT_MASK 0x1 -#define GFT_RAM_LINE_DST_PORT_SHIFT 30 -#define GFT_RAM_LINE_SRC_PORT_MASK 0x1 -#define GFT_RAM_LINE_SRC_PORT_SHIFT 31 - __le32 high32bits; -#define GFT_RAM_LINE_DSCP_MASK 0x1 -#define GFT_RAM_LINE_DSCP_SHIFT 0 -#define GFT_RAM_LINE_OVER_IP_PROTOCOL_MASK 0x1 -#define GFT_RAM_LINE_OVER_IP_PROTOCOL_SHIFT 1 -#define GFT_RAM_LINE_DST_IP_MASK 0x1 -#define GFT_RAM_LINE_DST_IP_SHIFT 2 -#define GFT_RAM_LINE_SRC_IP_MASK 0x1 -#define GFT_RAM_LINE_SRC_IP_SHIFT 3 -#define GFT_RAM_LINE_PRIORITY_MASK 0x1 -#define GFT_RAM_LINE_PRIORITY_SHIFT 4 -#define GFT_RAM_LINE_PROVIDER_VLAN_MASK 0x1 -#define GFT_RAM_LINE_PROVIDER_VLAN_SHIFT 5 -#define GFT_RAM_LINE_VLAN_MASK 0x1 -#define GFT_RAM_LINE_VLAN_SHIFT 6 -#define GFT_RAM_LINE_DST_MAC_MASK 0x1 -#define GFT_RAM_LINE_DST_MAC_SHIFT 7 -#define GFT_RAM_LINE_SRC_MAC_MASK 0x1 -#define GFT_RAM_LINE_SRC_MAC_SHIFT 8 -#define GFT_RAM_LINE_TENANT_ID_MASK 0x1 -#define GFT_RAM_LINE_TENANT_ID_SHIFT 9 -#define GFT_RAM_LINE_RESERVED1_MASK 0x3FFFFF -#define GFT_RAM_LINE_RESERVED1_SHIFT 10 -}; - -struct mstorm_eth_conn_ag_ctx { - u8 byte0; - u8 byte1; - u8 flags0; -#define MSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 -#define MSTORM_ETH_CONN_AG_CTX_BIT1_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_BIT1_SHIFT 1 -#define MSTORM_ETH_CONN_AG_CTX_CF0_MASK 0x3 -#define MSTORM_ETH_CONN_AG_CTX_CF0_SHIFT 2 -#define MSTORM_ETH_CONN_AG_CTX_CF1_MASK 0x3 -#define MSTORM_ETH_CONN_AG_CTX_CF1_SHIFT 4 -#define MSTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 -#define MSTORM_ETH_CONN_AG_CTX_CF2_SHIFT 6 - u8 flags1; -#define MSTORM_ETH_CONN_AG_CTX_CF0EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT 0 -#define MSTORM_ETH_CONN_AG_CTX_CF1EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT 1 -#define MSTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 2 -#define MSTORM_ETH_CONN_AG_CTX_RULE0EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT 3 -#define MSTORM_ETH_CONN_AG_CTX_RULE1EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT 4 -#define MSTORM_ETH_CONN_AG_CTX_RULE2EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT 5 -#define MSTORM_ETH_CONN_AG_CTX_RULE3EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT 6 -#define MSTORM_ETH_CONN_AG_CTX_RULE4EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT 7 - __le16 word0; - __le16 word1; - __le32 reg0; - __le32 reg1; -}; - struct xstorm_eth_conn_agctxdq_ext_ldpart { u8 reserved0; u8 eth_state; @@ -5511,7 +5688,7 @@ struct xstorm_eth_conn_agctxdq_ext_ldpart { #define XSTORMETHCONNAGCTXDQEXTLDPART_TPH_ENABLE_SHIFT 6 u8 edpm_event_id; __le16 physical_q0; - __le16 quota; + __le16 ereserved1; __le16 edpm_num_bds; __le16 tx_bd_cons; __le16 tx_bd_prod; @@ -5528,6 +5705,43 @@ struct xstorm_eth_conn_agctxdq_ext_ldpart { __le32 reg4; }; +struct mstorm_eth_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define MSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define MSTORM_ETH_CONN_AG_CTX_BIT1_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_BIT1_SHIFT 1 +#define MSTORM_ETH_CONN_AG_CTX_CF0_MASK 0x3 +#define MSTORM_ETH_CONN_AG_CTX_CF0_SHIFT 2 +#define MSTORM_ETH_CONN_AG_CTX_CF1_MASK 0x3 +#define MSTORM_ETH_CONN_AG_CTX_CF1_SHIFT 4 +#define MSTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 +#define MSTORM_ETH_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define MSTORM_ETH_CONN_AG_CTX_CF0EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT 0 +#define MSTORM_ETH_CONN_AG_CTX_CF1EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT 1 +#define MSTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 2 +#define MSTORM_ETH_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define MSTORM_ETH_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define MSTORM_ETH_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define MSTORM_ETH_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define MSTORM_ETH_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT 7 + __le16 word0; + __le16 word1; + __le32 reg0; + __le32 reg1; +}; + struct xstorm_eth_hw_conn_ag_ctx { u8 reserved0; u8 eth_state; @@ -5740,7 +5954,7 @@ struct xstorm_eth_hw_conn_ag_ctx { #define XSTORM_ETH_HW_CONN_AG_CTX_TPH_ENABLE_SHIFT 6 u8 edpm_event_id; __le16 physical_q0; - __le16 quota; + __le16 ereserved1; __le16 edpm_num_bds; __le16 tx_bd_cons; __le16 tx_bd_prod; @@ -5748,6 +5962,200 @@ struct xstorm_eth_hw_conn_ag_ctx { __le16 conn_dpi; }; +struct gft_cam_line { + __le32 camline; +#define GFT_CAM_LINE_VALID_MASK 0x1 +#define GFT_CAM_LINE_VALID_SHIFT 0 +#define GFT_CAM_LINE_DATA_MASK 0x3FFF +#define GFT_CAM_LINE_DATA_SHIFT 1 +#define GFT_CAM_LINE_MASK_BITS_MASK 0x3FFF +#define GFT_CAM_LINE_MASK_BITS_SHIFT 15 +#define GFT_CAM_LINE_RESERVED1_MASK 0x7 +#define GFT_CAM_LINE_RESERVED1_SHIFT 29 +}; + +struct gft_cam_line_mapped { + __le32 camline; +#define GFT_CAM_LINE_MAPPED_VALID_MASK 0x1 +#define GFT_CAM_LINE_MAPPED_VALID_SHIFT 0 +#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK 0x1 +#define GFT_CAM_LINE_MAPPED_IP_VERSION_SHIFT 1 +#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK 0x1 +#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_SHIFT 2 +#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK 0xF +#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_SHIFT 3 +#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK 0xF +#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_SHIFT 7 +#define GFT_CAM_LINE_MAPPED_PF_ID_MASK 0xF +#define GFT_CAM_LINE_MAPPED_PF_ID_SHIFT 11 +#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK_MASK 0x1 +#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK_SHIFT 15 +#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK_MASK 0x1 +#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK_SHIFT 16 +#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK_MASK 0xF +#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK_SHIFT 17 +#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK_MASK 0xF +#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK_SHIFT 21 +#define GFT_CAM_LINE_MAPPED_PF_ID_MASK_MASK 0xF +#define GFT_CAM_LINE_MAPPED_PF_ID_MASK_SHIFT 25 +#define GFT_CAM_LINE_MAPPED_RESERVED1_MASK 0x7 +#define GFT_CAM_LINE_MAPPED_RESERVED1_SHIFT 29 +}; + +union gft_cam_line_union { + struct gft_cam_line cam_line; + struct gft_cam_line_mapped cam_line_mapped; +}; + +enum gft_profile_ip_version { + GFT_PROFILE_IPV4 = 0, + GFT_PROFILE_IPV6 = 1, + MAX_GFT_PROFILE_IP_VERSION +}; + +struct gft_profile_key { + __le16 profile_key; +#define GFT_PROFILE_KEY_IP_VERSION_MASK 0x1 +#define GFT_PROFILE_KEY_IP_VERSION_SHIFT 0 +#define GFT_PROFILE_KEY_TUNNEL_IP_VERSION_MASK 0x1 +#define GFT_PROFILE_KEY_TUNNEL_IP_VERSION_SHIFT 1 +#define GFT_PROFILE_KEY_UPPER_PROTOCOL_TYPE_MASK 0xF +#define GFT_PROFILE_KEY_UPPER_PROTOCOL_TYPE_SHIFT 2 +#define GFT_PROFILE_KEY_TUNNEL_TYPE_MASK 0xF +#define GFT_PROFILE_KEY_TUNNEL_TYPE_SHIFT 6 +#define GFT_PROFILE_KEY_PF_ID_MASK 0xF +#define GFT_PROFILE_KEY_PF_ID_SHIFT 10 +#define GFT_PROFILE_KEY_RESERVED0_MASK 0x3 +#define GFT_PROFILE_KEY_RESERVED0_SHIFT 14 +}; + +enum gft_profile_tunnel_type { + GFT_PROFILE_NO_TUNNEL = 0, + GFT_PROFILE_VXLAN_TUNNEL = 1, + GFT_PROFILE_GRE_MAC_OR_NVGRE_TUNNEL = 2, + GFT_PROFILE_GRE_IP_TUNNEL = 3, + GFT_PROFILE_GENEVE_MAC_TUNNEL = 4, + GFT_PROFILE_GENEVE_IP_TUNNEL = 5, + MAX_GFT_PROFILE_TUNNEL_TYPE +}; + +enum gft_profile_upper_protocol_type { + GFT_PROFILE_ROCE_PROTOCOL = 0, + GFT_PROFILE_RROCE_PROTOCOL = 1, + GFT_PROFILE_FCOE_PROTOCOL = 2, + GFT_PROFILE_ICMP_PROTOCOL = 3, + GFT_PROFILE_ARP_PROTOCOL = 4, + GFT_PROFILE_USER_TCP_SRC_PORT_1_INNER = 5, + GFT_PROFILE_USER_TCP_DST_PORT_1_INNER = 6, + GFT_PROFILE_TCP_PROTOCOL = 7, + GFT_PROFILE_USER_UDP_DST_PORT_1_INNER = 8, + GFT_PROFILE_USER_UDP_DST_PORT_2_OUTER = 9, + GFT_PROFILE_UDP_PROTOCOL = 10, + GFT_PROFILE_USER_IP_1_INNER = 11, + GFT_PROFILE_USER_IP_2_OUTER = 12, + GFT_PROFILE_USER_ETH_1_INNER = 13, + GFT_PROFILE_USER_ETH_2_OUTER = 14, + GFT_PROFILE_RAW = 15, + MAX_GFT_PROFILE_UPPER_PROTOCOL_TYPE +}; + +struct gft_ram_line { + __le32 lo; +#define GFT_RAM_LINE_VLAN_SELECT_MASK 0x3 +#define GFT_RAM_LINE_VLAN_SELECT_SHIFT 0 +#define GFT_RAM_LINE_TUNNEL_ENTROPHY_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_ENTROPHY_SHIFT 2 +#define GFT_RAM_LINE_TUNNEL_TTL_EQUAL_ONE_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_TTL_EQUAL_ONE_SHIFT 3 +#define GFT_RAM_LINE_TUNNEL_TTL_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_TTL_SHIFT 4 +#define GFT_RAM_LINE_TUNNEL_ETHERTYPE_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_ETHERTYPE_SHIFT 5 +#define GFT_RAM_LINE_TUNNEL_DST_PORT_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_DST_PORT_SHIFT 6 +#define GFT_RAM_LINE_TUNNEL_SRC_PORT_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_SRC_PORT_SHIFT 7 +#define GFT_RAM_LINE_TUNNEL_DSCP_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_DSCP_SHIFT 8 +#define GFT_RAM_LINE_TUNNEL_OVER_IP_PROTOCOL_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_OVER_IP_PROTOCOL_SHIFT 9 +#define GFT_RAM_LINE_TUNNEL_DST_IP_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_DST_IP_SHIFT 10 +#define GFT_RAM_LINE_TUNNEL_SRC_IP_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_SRC_IP_SHIFT 11 +#define GFT_RAM_LINE_TUNNEL_PRIORITY_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_PRIORITY_SHIFT 12 +#define GFT_RAM_LINE_TUNNEL_PROVIDER_VLAN_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_PROVIDER_VLAN_SHIFT 13 +#define GFT_RAM_LINE_TUNNEL_VLAN_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_VLAN_SHIFT 14 +#define GFT_RAM_LINE_TUNNEL_DST_MAC_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_DST_MAC_SHIFT 15 +#define GFT_RAM_LINE_TUNNEL_SRC_MAC_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_SRC_MAC_SHIFT 16 +#define GFT_RAM_LINE_TTL_EQUAL_ONE_MASK 0x1 +#define GFT_RAM_LINE_TTL_EQUAL_ONE_SHIFT 17 +#define GFT_RAM_LINE_TTL_MASK 0x1 +#define GFT_RAM_LINE_TTL_SHIFT 18 +#define GFT_RAM_LINE_ETHERTYPE_MASK 0x1 +#define GFT_RAM_LINE_ETHERTYPE_SHIFT 19 +#define GFT_RAM_LINE_RESERVED0_MASK 0x1 +#define GFT_RAM_LINE_RESERVED0_SHIFT 20 +#define GFT_RAM_LINE_TCP_FLAG_FIN_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_FIN_SHIFT 21 +#define GFT_RAM_LINE_TCP_FLAG_SYN_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_SYN_SHIFT 22 +#define GFT_RAM_LINE_TCP_FLAG_RST_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_RST_SHIFT 23 +#define GFT_RAM_LINE_TCP_FLAG_PSH_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_PSH_SHIFT 24 +#define GFT_RAM_LINE_TCP_FLAG_ACK_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_ACK_SHIFT 25 +#define GFT_RAM_LINE_TCP_FLAG_URG_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_URG_SHIFT 26 +#define GFT_RAM_LINE_TCP_FLAG_ECE_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_ECE_SHIFT 27 +#define GFT_RAM_LINE_TCP_FLAG_CWR_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_CWR_SHIFT 28 +#define GFT_RAM_LINE_TCP_FLAG_NS_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_NS_SHIFT 29 +#define GFT_RAM_LINE_DST_PORT_MASK 0x1 +#define GFT_RAM_LINE_DST_PORT_SHIFT 30 +#define GFT_RAM_LINE_SRC_PORT_MASK 0x1 +#define GFT_RAM_LINE_SRC_PORT_SHIFT 31 + __le32 hi; +#define GFT_RAM_LINE_DSCP_MASK 0x1 +#define GFT_RAM_LINE_DSCP_SHIFT 0 +#define GFT_RAM_LINE_OVER_IP_PROTOCOL_MASK 0x1 +#define GFT_RAM_LINE_OVER_IP_PROTOCOL_SHIFT 1 +#define GFT_RAM_LINE_DST_IP_MASK 0x1 +#define GFT_RAM_LINE_DST_IP_SHIFT 2 +#define GFT_RAM_LINE_SRC_IP_MASK 0x1 +#define GFT_RAM_LINE_SRC_IP_SHIFT 3 +#define GFT_RAM_LINE_PRIORITY_MASK 0x1 +#define GFT_RAM_LINE_PRIORITY_SHIFT 4 +#define GFT_RAM_LINE_PROVIDER_VLAN_MASK 0x1 +#define GFT_RAM_LINE_PROVIDER_VLAN_SHIFT 5 +#define GFT_RAM_LINE_VLAN_MASK 0x1 +#define GFT_RAM_LINE_VLAN_SHIFT 6 +#define GFT_RAM_LINE_DST_MAC_MASK 0x1 +#define GFT_RAM_LINE_DST_MAC_SHIFT 7 +#define GFT_RAM_LINE_SRC_MAC_MASK 0x1 +#define GFT_RAM_LINE_SRC_MAC_SHIFT 8 +#define GFT_RAM_LINE_TENANT_ID_MASK 0x1 +#define GFT_RAM_LINE_TENANT_ID_SHIFT 9 +#define GFT_RAM_LINE_RESERVED1_MASK 0x3FFFFF +#define GFT_RAM_LINE_RESERVED1_SHIFT 10 +}; + +enum gft_vlan_select { + INNER_PROVIDER_VLAN = 0, + INNER_VLAN = 1, + OUTER_PROVIDER_VLAN = 2, + OUTER_VLAN = 3, + MAX_GFT_VLAN_SELECT +}; + struct mstorm_rdma_task_st_ctx { struct regpair temp[4]; }; @@ -5827,12 +6235,9 @@ struct rdma_init_func_hdr { u8 cnq_start_offset; u8 num_cnqs; u8 cq_ring_mode; - u8 cnp_vlan_priority; - __le32 cnp_send_timeout; - u8 cnp_dscp; u8 vf_id; u8 vf_valid; - u8 reserved[5]; + u8 reserved[3]; }; struct rdma_init_func_ramrod_data { @@ -5856,54 +6261,55 @@ enum rdma_ramrod_cmd_id { }; struct rdma_register_tid_ramrod_data { - __le32 flags; -#define RDMA_REGISTER_TID_RAMROD_DATA_MAX_ID_MASK 0x3FFFF -#define RDMA_REGISTER_TID_RAMROD_DATA_MAX_ID_SHIFT 0 -#define RDMA_REGISTER_TID_RAMROD_DATA_PAGE_SIZE_LOG_MASK 0x1F -#define RDMA_REGISTER_TID_RAMROD_DATA_PAGE_SIZE_LOG_SHIFT 18 -#define RDMA_REGISTER_TID_RAMROD_DATA_TWO_LEVEL_PBL_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_TWO_LEVEL_PBL_SHIFT 23 -#define RDMA_REGISTER_TID_RAMROD_DATA_ZERO_BASED_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_ZERO_BASED_SHIFT 24 -#define RDMA_REGISTER_TID_RAMROD_DATA_PHY_MR_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_PHY_MR_SHIFT 25 -#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_READ_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_READ_SHIFT 26 -#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_WRITE_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_WRITE_SHIFT 27 -#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_ATOMIC_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_ATOMIC_SHIFT 28 -#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_WRITE_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_WRITE_SHIFT 29 -#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_READ_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_READ_SHIFT 30 -#define RDMA_REGISTER_TID_RAMROD_DATA_ENABLE_MW_BIND_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_ENABLE_MW_BIND_SHIFT 31 + __le16 flags; +#define RDMA_REGISTER_TID_RAMROD_DATA_PAGE_SIZE_LOG_MASK 0x1F +#define RDMA_REGISTER_TID_RAMROD_DATA_PAGE_SIZE_LOG_SHIFT 0 +#define RDMA_REGISTER_TID_RAMROD_DATA_TWO_LEVEL_PBL_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_TWO_LEVEL_PBL_SHIFT 5 +#define RDMA_REGISTER_TID_RAMROD_DATA_ZERO_BASED_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_ZERO_BASED_SHIFT 6 +#define RDMA_REGISTER_TID_RAMROD_DATA_PHY_MR_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_PHY_MR_SHIFT 7 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_READ_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_READ_SHIFT 8 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_WRITE_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_WRITE_SHIFT 9 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_ATOMIC_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_ATOMIC_SHIFT 10 +#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_WRITE_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_WRITE_SHIFT 11 +#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_READ_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_READ_SHIFT 12 +#define RDMA_REGISTER_TID_RAMROD_DATA_ENABLE_MW_BIND_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_ENABLE_MW_BIND_SHIFT 13 +#define RDMA_REGISTER_TID_RAMROD_DATA_RESERVED_MASK 0x3 +#define RDMA_REGISTER_TID_RAMROD_DATA_RESERVED_SHIFT 14 u8 flags1; -#define RDMA_REGISTER_TID_RAMROD_DATA_PBL_PAGE_SIZE_LOG_MASK 0x1F +#define RDMA_REGISTER_TID_RAMROD_DATA_PBL_PAGE_SIZE_LOG_MASK 0x1F #define RDMA_REGISTER_TID_RAMROD_DATA_PBL_PAGE_SIZE_LOG_SHIFT 0 -#define RDMA_REGISTER_TID_RAMROD_DATA_TID_TYPE_MASK 0x7 -#define RDMA_REGISTER_TID_RAMROD_DATA_TID_TYPE_SHIFT 5 +#define RDMA_REGISTER_TID_RAMROD_DATA_TID_TYPE_MASK 0x7 +#define RDMA_REGISTER_TID_RAMROD_DATA_TID_TYPE_SHIFT 5 u8 flags2; -#define RDMA_REGISTER_TID_RAMROD_DATA_DMA_MR_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_DMA_MR_SHIFT 0 -#define RDMA_REGISTER_TID_RAMROD_DATA_DIF_ON_HOST_FLG_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_DIF_ON_HOST_FLG_SHIFT 1 -#define RDMA_REGISTER_TID_RAMROD_DATA_RESERVED1_MASK 0x3F -#define RDMA_REGISTER_TID_RAMROD_DATA_RESERVED1_SHIFT 2 +#define RDMA_REGISTER_TID_RAMROD_DATA_DMA_MR_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_DMA_MR_SHIFT 0 +#define RDMA_REGISTER_TID_RAMROD_DATA_DIF_ON_HOST_FLG_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_DIF_ON_HOST_FLG_SHIFT 1 +#define RDMA_REGISTER_TID_RAMROD_DATA_RESERVED1_MASK 0x3F +#define RDMA_REGISTER_TID_RAMROD_DATA_RESERVED1_SHIFT 2 u8 key; u8 length_hi; u8 vf_id; u8 vf_valid; __le16 pd; + __le16 reserved2; __le32 length_lo; __le32 itid; - __le32 reserved2; + __le32 reserved3; struct regpair va; struct regpair pbl_base; struct regpair dif_error_addr; struct regpair dif_runt_addr; - __le32 reserved3[2]; + __le32 reserved4[2]; }; struct rdma_resize_cq_output_params { @@ -6149,6 +6555,233 @@ enum rdma_tid_type { MAX_RDMA_TID_TYPE }; +struct xstorm_roce_conn_ag_ctx_dq_ext_ld_part { + u8 reserved0; + u8 state; + u8 flags0; +#define XSTORMROCECONNAGCTXDQEXTLDPART_EXIST_IN_QM0_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_EXIST_IN_QM0_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT1_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT1_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT2_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT2_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_EXIST_IN_QM3_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_EXIST_IN_QM3_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT4_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT4_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT5_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT5_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT6_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT6_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT7_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT7_SHIFT 7 + u8 flags1; +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT8_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT8_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT9_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT9_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT10_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT10_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT11_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT11_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT12_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT12_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_MSTORM_FLUSH_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_MSTORM_FLUSH_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT14_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT14_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_YSTORM_FLUSH_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_YSTORM_FLUSH_SHIFT 7 + u8 flags2; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF0_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF0_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF1_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF1_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF2_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF2_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF3_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF3_SHIFT 6 + u8 flags3; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF4_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF4_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF5_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF5_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF6_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF6_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_FLUSH_Q0_CF_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_FLUSH_Q0_CF_SHIFT 6 + u8 flags4; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF8_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF8_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF9_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF9_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF10_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF10_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF11_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF11_SHIFT 6 + u8 flags5; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF12_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF12_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF13_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF13_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF14_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF14_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF15_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF15_SHIFT 6 + u8 flags6; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF16_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF16_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF17_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF17_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF18_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF18_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF19_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF19_SHIFT 6 + u8 flags7; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF20_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF20_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF21_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF21_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_SLOW_PATH_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_SLOW_PATH_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF0EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF0EN_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF1EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF1EN_SHIFT 7 + u8 flags8; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF2EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF2EN_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF3EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF3EN_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF4EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF4EN_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF5EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF5EN_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF6EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF6EN_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_FLUSH_Q0_CF_EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_FLUSH_Q0_CF_EN_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF8EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF8EN_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF9EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF9EN_SHIFT 7 + u8 flags9; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF10EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF10EN_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF11EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF11EN_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF12EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF12EN_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF13EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF13EN_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF14EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF14EN_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF15EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF15EN_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF16EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF16EN_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF17EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF17EN_SHIFT 7 + u8 flags10; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF18EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF18EN_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF19EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF19EN_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF20EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF20EN_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF21EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF21EN_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_SLOW_PATH_EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_SLOW_PATH_EN_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF23EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF23EN_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE0EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE0EN_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE1EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE1EN_SHIFT 7 + u8 flags11; +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE2EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE2EN_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE3EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE3EN_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE4EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE4EN_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE5EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE5EN_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE6EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE6EN_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE7EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE7EN_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED1_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED1_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE9EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE9EN_SHIFT 7 + u8 flags12; +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE10EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE10EN_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE11EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE11EN_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED2_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED2_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED3_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED3_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE14EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE14EN_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE15EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE15EN_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE16EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE16EN_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE17EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE17EN_SHIFT 7 + u8 flags13; +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE18EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE18EN_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE19EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE19EN_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED4_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED4_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED5_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED5_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED6_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED6_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED7_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED7_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED8_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED8_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED9_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED9_SHIFT 7 + u8 flags14; +#define XSTORMROCECONNAGCTXDQEXTLDPART_MIGRATION_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_MIGRATION_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT17_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT17_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_DPM_PORT_NUM_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_DPM_PORT_NUM_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RESERVED_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RESERVED_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_ROCE_EDPM_ENABLE_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_ROCE_EDPM_ENABLE_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF23_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF23_SHIFT 6 + u8 byte2; + __le16 physical_q0; + __le16 word1; + __le16 word2; + __le16 word3; + __le16 word4; + __le16 word5; + __le16 conn_dpi; + u8 byte3; + u8 byte4; + u8 byte5; + u8 byte6; + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 snd_nxt_psn; + __le32 reg4; +}; + struct mstorm_rdma_conn_ag_ctx { u8 byte0; u8 byte1; @@ -6438,233 +7071,6 @@ struct ustorm_rdma_conn_ag_ctx { __le16 word3; }; -struct xstorm_roce_conn_ag_ctx_dq_ext_ld_part { - u8 reserved0; - u8 state; - u8 flags0; -#define XSTORMROCECONNAGCTXDQEXTLDPART_EXIST_IN_QM0_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_EXIST_IN_QM0_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT1_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT1_SHIFT 1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT2_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT2_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_EXIST_IN_QM3_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_EXIST_IN_QM3_SHIFT 3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT4_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT4_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT5_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT5_SHIFT 5 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT6_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT6_SHIFT 6 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT7_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT7_SHIFT 7 - u8 flags1; -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT8_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT8_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT9_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT9_SHIFT 1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT10_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT10_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT11_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT11_SHIFT 3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT12_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT12_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT13_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT13_SHIFT 5 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT14_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT14_SHIFT 6 -#define XSTORMROCECONNAGCTXDQEXTLDPART_YSTORM_FLUSH_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_YSTORM_FLUSH_SHIFT 7 - u8 flags2; -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF0_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF0_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF1_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF1_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF2_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF2_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF3_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF3_SHIFT 6 - u8 flags3; -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF4_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF4_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF5_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF5_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF6_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF6_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_FLUSH_Q0_CF_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_FLUSH_Q0_CF_SHIFT 6 - u8 flags4; -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF8_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF8_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF9_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF9_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF10_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF10_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF11_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF11_SHIFT 6 - u8 flags5; -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF12_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF12_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF13_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF13_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF14_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF14_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF15_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF15_SHIFT 6 - u8 flags6; -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF16_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF16_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF17_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF17_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF18_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF18_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF19_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF19_SHIFT 6 - u8 flags7; -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF20_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF20_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF21_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF21_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_SLOW_PATH_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_SLOW_PATH_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF0EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF0EN_SHIFT 6 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF1EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF1EN_SHIFT 7 - u8 flags8; -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF2EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF2EN_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF3EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF3EN_SHIFT 1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF4EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF4EN_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF5EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF5EN_SHIFT 3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF6EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF6EN_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_FLUSH_Q0_CF_EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_FLUSH_Q0_CF_EN_SHIFT 5 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF8EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF8EN_SHIFT 6 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF9EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF9EN_SHIFT 7 - u8 flags9; -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF10EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF10EN_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF11EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF11EN_SHIFT 1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF12EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF12EN_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF13EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF13EN_SHIFT 3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF14EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF14EN_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF15EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF15EN_SHIFT 5 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF16EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF16EN_SHIFT 6 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF17EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF17EN_SHIFT 7 - u8 flags10; -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF18EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF18EN_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF19EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF19EN_SHIFT 1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF20EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF20EN_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF21EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF21EN_SHIFT 3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_SLOW_PATH_EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_SLOW_PATH_EN_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF23EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF23EN_SHIFT 5 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE0EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE0EN_SHIFT 6 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE1EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE1EN_SHIFT 7 - u8 flags11; -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE2EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE2EN_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE3EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE3EN_SHIFT 1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE4EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE4EN_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE5EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE5EN_SHIFT 3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE6EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE6EN_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE7EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE7EN_SHIFT 5 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED1_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED1_SHIFT 6 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE9EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE9EN_SHIFT 7 - u8 flags12; -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE10EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE10EN_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE11EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE11EN_SHIFT 1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED2_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED2_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED3_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED3_SHIFT 3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE14EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE14EN_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE15EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE15EN_SHIFT 5 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE16EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE16EN_SHIFT 6 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE17EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE17EN_SHIFT 7 - u8 flags13; -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE18EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE18EN_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE19EN_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE19EN_SHIFT 1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED4_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED4_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED5_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED5_SHIFT 3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED6_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED6_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED7_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED7_SHIFT 5 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED8_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED8_SHIFT 6 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED9_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED9_SHIFT 7 - u8 flags14; -#define XSTORMROCECONNAGCTXDQEXTLDPART_MIGRATION_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_MIGRATION_SHIFT 0 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT17_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT17_SHIFT 1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_DPM_PORT_NUM_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_DPM_PORT_NUM_SHIFT 2 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RESERVED_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_RESERVED_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_ROCE_EDPM_ENABLE_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_ROCE_EDPM_ENABLE_SHIFT 5 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF23_MASK 0x3 -#define XSTORMROCECONNAGCTXDQEXTLDPART_CF23_SHIFT 6 - u8 byte2; - __le16 physical_q0; - __le16 word1; - __le16 word2; - __le16 word3; - __le16 word4; - __le16 word5; - __le16 conn_dpi; - u8 byte3; - u8 byte4; - u8 byte5; - u8 byte6; - __le32 reg0; - __le32 reg1; - __le32 reg2; - __le32 snd_nxt_psn; - __le32 reg4; -}; - struct xstorm_rdma_conn_ag_ctx { u8 reserved0; u8 state; @@ -6696,8 +7102,8 @@ struct xstorm_rdma_conn_ag_ctx { #define XSTORM_RDMA_CONN_AG_CTX_BIT11_SHIFT 3 #define XSTORM_RDMA_CONN_AG_CTX_BIT12_MASK 0x1 #define XSTORM_RDMA_CONN_AG_CTX_BIT12_SHIFT 4 -#define XSTORM_RDMA_CONN_AG_CTX_BIT13_MASK 0x1 -#define XSTORM_RDMA_CONN_AG_CTX_BIT13_SHIFT 5 +#define XSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_SHIFT 5 #define XSTORM_RDMA_CONN_AG_CTX_BIT14_MASK 0x1 #define XSTORM_RDMA_CONN_AG_CTX_BIT14_SHIFT 6 #define XSTORM_RDMA_CONN_AG_CTX_YSTORM_FLUSH_MASK 0x1 @@ -7093,16 +7499,35 @@ struct roce_destroy_qp_resp_ramrod_data { struct regpair output_params_addr; }; +struct roce_events_stats { + __le16 silent_drops; + __le16 rnr_naks_sent; + __le32 retransmit_count; + __le32 icrc_error_count; + __le32 reserved; +}; + enum roce_event_opcode { ROCE_EVENT_CREATE_QP = 11, ROCE_EVENT_MODIFY_QP, ROCE_EVENT_QUERY_QP, ROCE_EVENT_DESTROY_QP, + ROCE_EVENT_CREATE_UD_QP, + ROCE_EVENT_DESTROY_UD_QP, MAX_ROCE_EVENT_OPCODE }; +struct roce_init_func_params { + u8 ll2_queue_id; + u8 cnp_vlan_priority; + u8 cnp_dscp; + u8 reserved; + __le32 cnp_send_timeout; +}; + struct roce_init_func_ramrod_data { struct rdma_init_func_ramrod_data rdma; + struct roce_init_func_params roce; }; struct roce_modify_qp_req_ramrod_data { @@ -7222,6 +7647,8 @@ enum roce_ramrod_cmd_id { ROCE_RAMROD_MODIFY_QP, ROCE_RAMROD_QUERY_QP, ROCE_RAMROD_DESTROY_QP, + ROCE_RAMROD_CREATE_UD_QP, + ROCE_RAMROD_DESTROY_UD_QP, MAX_ROCE_RAMROD_CMD_ID }; @@ -7299,13 +7726,6 @@ struct mstorm_roce_resp_conn_ag_ctx { __le32 reg1; }; -enum roce_flavor { - PLAIN_ROCE /* RoCE v1 */ , - RROCE_IPV4 /* RoCE v2 (Routable RoCE) over ipv4 */ , - RROCE_IPV6 /* RoCE v2 (Routable RoCE) over ipv6 */ , - MAX_ROCE_FLAVOR -}; - struct tstorm_roce_req_conn_ag_ctx { u8 reserved0; u8 state; @@ -7416,8 +7836,8 @@ struct tstorm_roce_resp_conn_ag_ctx { u8 flags0; #define TSTORM_ROCE_RESP_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 #define TSTORM_ROCE_RESP_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 -#define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT1_MASK 0x1 -#define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT1_SHIFT 1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RX_ERROR_NOTIFY_REQUESTER_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RX_ERROR_NOTIFY_REQUESTER_SHIFT 1 #define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT2_MASK 0x1 #define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT2_SHIFT 2 #define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT3_MASK 0x1 @@ -8097,7 +8517,7 @@ struct xstorm_roce_resp_conn_ag_ctx { __le16 irq_prod; __le16 word3; __le16 word4; - __le16 word5; + __le16 ereserved1; __le16 irq_cons; u8 rxmit_opcode; u8 byte4; @@ -8200,6 +8620,812 @@ struct ystorm_roce_resp_conn_ag_ctx { __le32 reg3; }; +enum roce_flavor { + PLAIN_ROCE, + RROCE_IPV4, + RROCE_IPV6, + MAX_ROCE_FLAVOR +}; + +struct ystorm_iwarp_conn_st_ctx { + __le32 reserved[4]; +}; + +struct pstorm_iwarp_conn_st_ctx { + __le32 reserved[36]; +}; + +struct xstorm_iwarp_conn_st_ctx { + __le32 reserved[44]; +}; + +struct xstorm_iwarp_conn_ag_ctx { + u8 reserved0; + u8 state; + u8 flags0; +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM1_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM1_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM2_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM2_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM3_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM3_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_BIT4_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT4_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_RESERVED2_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RESERVED2_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_BIT6_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT6_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_BIT7_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT7_SHIFT 7 + u8 flags1; +#define XSTORM_IWARP_CONN_AG_CTX_BIT8_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT8_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_BIT9_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT9_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT10_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT10_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_BIT11_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT11_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_BIT12_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT12_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_BIT13_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT13_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_BIT14_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT14_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_YSTORM_FLUSH_OR_REWIND_SND_MAX_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_YSTORM_FLUSH_OR_REWIND_SND_MAX_SHIFT 7 + u8 flags2; +#define XSTORM_IWARP_CONN_AG_CTX_CF0_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF0_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_CF1_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF1_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_CF2_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF2_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_SHIFT 6 + u8 flags3; +#define XSTORM_IWARP_CONN_AG_CTX_CF4_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF4_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_CF5_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF5_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_CF6_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF6_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_CF7_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF7_SHIFT 6 + u8 flags4; +#define XSTORM_IWARP_CONN_AG_CTX_CF8_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF8_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_CF9_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF9_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_CF10_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF10_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_CF11_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF11_SHIFT 6 + u8 flags5; +#define XSTORM_IWARP_CONN_AG_CTX_CF12_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF12_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_CF13_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF13_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_SQ_FLUSH_CF_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_SQ_FLUSH_CF_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_CF15_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF15_SHIFT 6 + u8 flags6; +#define XSTORM_IWARP_CONN_AG_CTX_MPA_OR_ERROR_WAKEUP_TRIGGER_CF_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_MPA_OR_ERROR_WAKEUP_TRIGGER_CF_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_CF17_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF17_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_CF18_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF18_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_DQ_FLUSH_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_DQ_FLUSH_SHIFT 6 + u8 flags7; +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q1_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q1_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_SLOW_PATH_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_SLOW_PATH_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_CF0EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF0EN_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_CF1EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF1EN_SHIFT 7 + u8 flags8; +#define XSTORM_IWARP_CONN_AG_CTX_CF2EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF2EN_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_EN_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_CF4EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF4EN_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_CF5EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF5EN_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_CF6EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF6EN_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_CF7EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF7EN_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_CF8EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF8EN_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_CF9EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF9EN_SHIFT 7 + u8 flags9; +#define XSTORM_IWARP_CONN_AG_CTX_CF10EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF10EN_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_CF11EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF11EN_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_CF12EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF12EN_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_CF13EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF13EN_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_SQ_FLUSH_CF_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_SQ_FLUSH_CF_EN_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_CF15EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF15EN_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_MPA_OR_ERROR_WAKEUP_TRIGGER_CF_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_MPA_OR_ERROR_WAKEUP_TRIGGER_CF_EN_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_CF17EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF17EN_SHIFT 7 + u8 flags10; +#define XSTORM_IWARP_CONN_AG_CTX_CF18EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF18EN_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_DQ_FLUSH_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_DQ_FLUSH_EN_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q1_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q1_EN_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_SLOW_PATH_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_SLOW_PATH_EN_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_CF23EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF23EN_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE0EN_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_MORE_TO_SEND_RULE_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_MORE_TO_SEND_RULE_EN_SHIFT 7 + u8 flags11; +#define XSTORM_IWARP_CONN_AG_CTX_TX_BLOCKED_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_TX_BLOCKED_EN_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE3EN_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_RESERVED3_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RESERVED3_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE5EN_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE6EN_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE7EN_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED1_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED1_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_RULE9EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE9EN_SHIFT 7 + u8 flags12; +#define XSTORM_IWARP_CONN_AG_CTX_SQ_NOT_EMPTY_RULE_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_SQ_NOT_EMPTY_RULE_EN_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_RULE11EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE11EN_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED2_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED2_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED3_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED3_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_SQ_FENCE_RULE_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_SQ_FENCE_RULE_EN_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_RULE15EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE15EN_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_RULE16EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE16EN_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_RULE17EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE17EN_SHIFT 7 + u8 flags13; +#define XSTORM_IWARP_CONN_AG_CTX_IRQ_NOT_EMPTY_RULE_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_IRQ_NOT_EMPTY_RULE_EN_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_HQ_NOT_FULL_RULE_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_HQ_NOT_FULL_RULE_EN_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_ORQ_RD_FENCE_RULE_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_ORQ_RD_FENCE_RULE_EN_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_RULE21EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE21EN_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED6_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED6_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_ORQ_NOT_FULL_RULE_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_ORQ_NOT_FULL_RULE_EN_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED8_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED8_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED9_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED9_SHIFT 7 + u8 flags14; +#define XSTORM_IWARP_CONN_AG_CTX_BIT16_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT16_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_BIT17_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT17_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT18_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT18_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_E5_RESERVED1_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_E5_RESERVED1_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_E5_RESERVED2_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_E5_RESERVED2_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_E5_RESERVED3_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_E5_RESERVED3_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_CF23_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF23_SHIFT 6 + u8 byte2; + __le16 physical_q0; + __le16 physical_q1; + __le16 sq_comp_cons; + __le16 sq_tx_cons; + __le16 sq_prod; + __le16 word5; + __le16 conn_dpi; + u8 byte3; + u8 byte4; + u8 byte5; + u8 byte6; + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 more_to_send_seq; + __le32 reg4; + __le32 rewinded_snd_max; + __le32 rd_msn; + __le16 irq_prod_via_msdm; + __le16 irq_cons; + __le16 hq_cons_th_or_mpa_data; + __le16 hq_cons; + __le32 atom_msn; + __le32 orq_cons; + __le32 orq_cons_th; + u8 byte7; + u8 max_ord; + u8 wqe_data_pad_bytes; + u8 former_hq_prod; + u8 irq_prod_via_msem; + u8 byte12; + u8 max_pkt_pdu_size_lo; + u8 max_pkt_pdu_size_hi; + u8 byte15; + u8 e5_reserved; + __le16 e5_reserved4; + __le32 reg10; + __le32 reg11; + __le32 shared_queue_page_addr_lo; + __le32 shared_queue_page_addr_hi; + __le32 reg14; + __le32 reg15; + __le32 reg16; + __le32 reg17; +}; + +struct tstorm_iwarp_conn_ag_ctx { + u8 reserved0; + u8 state; + u8 flags0; +#define TSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define TSTORM_IWARP_CONN_AG_CTX_BIT1_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_BIT1_SHIFT 1 +#define TSTORM_IWARP_CONN_AG_CTX_BIT2_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_BIT2_SHIFT 2 +#define TSTORM_IWARP_CONN_AG_CTX_MSTORM_FLUSH_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_MSTORM_FLUSH_SHIFT 3 +#define TSTORM_IWARP_CONN_AG_CTX_BIT4_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_BIT4_SHIFT 4 +#define TSTORM_IWARP_CONN_AG_CTX_CACHED_ORQ_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_CACHED_ORQ_SHIFT 5 +#define TSTORM_IWARP_CONN_AG_CTX_CF0_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_CF0_SHIFT 6 + u8 flags1; +#define TSTORM_IWARP_CONN_AG_CTX_RQ_POST_CF_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_RQ_POST_CF_SHIFT 0 +#define TSTORM_IWARP_CONN_AG_CTX_MPA_TIMEOUT_CF_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_MPA_TIMEOUT_CF_SHIFT 2 +#define TSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_SHIFT 4 +#define TSTORM_IWARP_CONN_AG_CTX_CF4_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_CF4_SHIFT 6 + u8 flags2; +#define TSTORM_IWARP_CONN_AG_CTX_CF5_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_CF5_SHIFT 0 +#define TSTORM_IWARP_CONN_AG_CTX_CF6_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_CF6_SHIFT 2 +#define TSTORM_IWARP_CONN_AG_CTX_CF7_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_CF7_SHIFT 4 +#define TSTORM_IWARP_CONN_AG_CTX_CF8_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_CF8_SHIFT 6 + u8 flags3; +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_SHIFT 0 +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_OR_ERROR_DETECTED_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_OR_ERROR_DETECTED_SHIFT 2 +#define TSTORM_IWARP_CONN_AG_CTX_CF0EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_CF0EN_SHIFT 4 +#define TSTORM_IWARP_CONN_AG_CTX_RQ_POST_CF_EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RQ_POST_CF_EN_SHIFT 5 +#define TSTORM_IWARP_CONN_AG_CTX_MPA_TIMEOUT_CF_EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_MPA_TIMEOUT_CF_EN_SHIFT 6 +#define TSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_EN_SHIFT 7 + u8 flags4; +#define TSTORM_IWARP_CONN_AG_CTX_CF4EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_CF4EN_SHIFT 0 +#define TSTORM_IWARP_CONN_AG_CTX_CF5EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_CF5EN_SHIFT 1 +#define TSTORM_IWARP_CONN_AG_CTX_CF6EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_CF6EN_SHIFT 2 +#define TSTORM_IWARP_CONN_AG_CTX_CF7EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_CF7EN_SHIFT 3 +#define TSTORM_IWARP_CONN_AG_CTX_CF8EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_CF8EN_SHIFT 4 +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT 5 +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_OR_ERROR_DETECTED_EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_OR_ERROR_DETECTED_EN_SHIFT 6 +#define TSTORM_IWARP_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE0EN_SHIFT 7 + u8 flags5; +#define TSTORM_IWARP_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define TSTORM_IWARP_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define TSTORM_IWARP_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define TSTORM_IWARP_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define TSTORM_IWARP_CONN_AG_CTX_SND_SQ_CONS_RULE_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_SND_SQ_CONS_RULE_SHIFT 5 +#define TSTORM_IWARP_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define TSTORM_IWARP_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE8EN_SHIFT 7 + __le32 reg0; + __le32 reg1; + __le32 unaligned_nxt_seq; + __le32 reg3; + __le32 reg4; + __le32 reg5; + __le32 reg6; + __le32 reg7; + __le32 reg8; + u8 orq_cache_idx; + u8 hq_prod; + __le16 sq_tx_cons_th; + u8 orq_prod; + u8 irq_cons; + __le16 sq_tx_cons; + __le16 conn_dpi; + __le16 rq_prod; + __le32 snd_seq; + __le32 last_hq_sequence; +}; + +struct tstorm_iwarp_conn_st_ctx { + __le32 reserved[60]; +}; + +struct mstorm_iwarp_conn_st_ctx { + __le32 reserved[32]; +}; + +struct ustorm_iwarp_conn_st_ctx { + __le32 reserved[24]; +}; + +struct iwarp_conn_context { + struct ystorm_iwarp_conn_st_ctx ystorm_st_context; + struct regpair ystorm_st_padding[2]; + struct pstorm_iwarp_conn_st_ctx pstorm_st_context; + struct regpair pstorm_st_padding[2]; + struct xstorm_iwarp_conn_st_ctx xstorm_st_context; + struct regpair xstorm_st_padding[2]; + struct xstorm_iwarp_conn_ag_ctx xstorm_ag_context; + struct tstorm_iwarp_conn_ag_ctx tstorm_ag_context; + struct timers_context timer_context; + struct ustorm_rdma_conn_ag_ctx ustorm_ag_context; + struct tstorm_iwarp_conn_st_ctx tstorm_st_context; + struct regpair tstorm_st_padding[2]; + struct mstorm_iwarp_conn_st_ctx mstorm_st_context; + struct ustorm_iwarp_conn_st_ctx ustorm_st_context; +}; + +struct iwarp_create_qp_ramrod_data { + u8 flags; +#define IWARP_CREATE_QP_RAMROD_DATA_FMR_AND_RESERVED_EN_MASK 0x1 +#define IWARP_CREATE_QP_RAMROD_DATA_FMR_AND_RESERVED_EN_SHIFT 0 +#define IWARP_CREATE_QP_RAMROD_DATA_SIGNALED_COMP_MASK 0x1 +#define IWARP_CREATE_QP_RAMROD_DATA_SIGNALED_COMP_SHIFT 1 +#define IWARP_CREATE_QP_RAMROD_DATA_RDMA_RD_EN_MASK 0x1 +#define IWARP_CREATE_QP_RAMROD_DATA_RDMA_RD_EN_SHIFT 2 +#define IWARP_CREATE_QP_RAMROD_DATA_RDMA_WR_EN_MASK 0x1 +#define IWARP_CREATE_QP_RAMROD_DATA_RDMA_WR_EN_SHIFT 3 +#define IWARP_CREATE_QP_RAMROD_DATA_ATOMIC_EN_MASK 0x1 +#define IWARP_CREATE_QP_RAMROD_DATA_ATOMIC_EN_SHIFT 4 +#define IWARP_CREATE_QP_RAMROD_DATA_SRQ_FLG_MASK 0x1 +#define IWARP_CREATE_QP_RAMROD_DATA_SRQ_FLG_SHIFT 5 +#define IWARP_CREATE_QP_RAMROD_DATA_RESERVED0_MASK 0x3 +#define IWARP_CREATE_QP_RAMROD_DATA_RESERVED0_SHIFT 6 + u8 reserved1; + __le16 pd; + __le16 sq_num_pages; + __le16 rq_num_pages; + __le32 reserved3[2]; + struct regpair qp_handle_for_cqe; + struct rdma_srq_id srq_id; + __le32 cq_cid_for_sq; + __le32 cq_cid_for_rq; + __le16 dpi; + __le16 physical_q0; + __le16 physical_q1; + u8 reserved2[6]; +}; + +enum iwarp_eqe_async_opcode { + IWARP_EVENT_TYPE_ASYNC_CONNECT_COMPLETE, + IWARP_EVENT_TYPE_ASYNC_ENHANCED_MPA_REPLY_ARRIVED, + IWARP_EVENT_TYPE_ASYNC_MPA_HANDSHAKE_COMPLETE, + IWARP_EVENT_TYPE_ASYNC_CID_CLEANED, + IWARP_EVENT_TYPE_ASYNC_EXCEPTION_DETECTED, + IWARP_EVENT_TYPE_ASYNC_QP_IN_ERROR_STATE, + IWARP_EVENT_TYPE_ASYNC_CQ_OVERFLOW, + MAX_IWARP_EQE_ASYNC_OPCODE +}; + +struct iwarp_eqe_data_mpa_async_completion { + __le16 ulp_data_len; + u8 reserved[6]; +}; + +struct iwarp_eqe_data_tcp_async_completion { + __le16 ulp_data_len; + u8 mpa_handshake_mode; + u8 reserved[5]; +}; + +enum iwarp_eqe_sync_opcode { + IWARP_EVENT_TYPE_TCP_OFFLOAD = + 11, + IWARP_EVENT_TYPE_MPA_OFFLOAD, + IWARP_EVENT_TYPE_MPA_OFFLOAD_SEND_RTR, + IWARP_EVENT_TYPE_CREATE_QP, + IWARP_EVENT_TYPE_QUERY_QP, + IWARP_EVENT_TYPE_MODIFY_QP, + IWARP_EVENT_TYPE_DESTROY_QP, + MAX_IWARP_EQE_SYNC_OPCODE +}; + +enum iwarp_fw_return_code { + IWARP_CONN_ERROR_TCP_CONNECT_INVALID_PACKET = 5, + IWARP_CONN_ERROR_TCP_CONNECTION_RST, + IWARP_CONN_ERROR_TCP_CONNECT_TIMEOUT, + IWARP_CONN_ERROR_MPA_ERROR_REJECT, + IWARP_CONN_ERROR_MPA_NOT_SUPPORTED_VER, + IWARP_CONN_ERROR_MPA_RST, + IWARP_CONN_ERROR_MPA_FIN, + IWARP_CONN_ERROR_MPA_RTR_MISMATCH, + IWARP_CONN_ERROR_MPA_INSUF_IRD, + IWARP_CONN_ERROR_MPA_INVALID_PACKET, + IWARP_CONN_ERROR_MPA_LOCAL_ERROR, + IWARP_CONN_ERROR_MPA_TIMEOUT, + IWARP_CONN_ERROR_MPA_TERMINATE, + IWARP_QP_IN_ERROR_GOOD_CLOSE, + IWARP_QP_IN_ERROR_BAD_CLOSE, + IWARP_EXCEPTION_DETECTED_LLP_CLOSED, + IWARP_EXCEPTION_DETECTED_LLP_RESET, + IWARP_EXCEPTION_DETECTED_IRQ_FULL, + IWARP_EXCEPTION_DETECTED_RQ_EMPTY, + IWARP_EXCEPTION_DETECTED_LLP_TIMEOUT, + IWARP_EXCEPTION_DETECTED_REMOTE_PROTECTION_ERROR, + IWARP_EXCEPTION_DETECTED_CQ_OVERFLOW, + IWARP_EXCEPTION_DETECTED_LOCAL_CATASTROPHIC, + IWARP_EXCEPTION_DETECTED_LOCAL_ACCESS_ERROR, + IWARP_EXCEPTION_DETECTED_REMOTE_OPERATION_ERROR, + IWARP_EXCEPTION_DETECTED_TERMINATE_RECEIVED, + MAX_IWARP_FW_RETURN_CODE +}; + +struct iwarp_init_func_params { + u8 ll2_ooo_q_index; + u8 reserved1[7]; +}; + +struct iwarp_init_func_ramrod_data { + struct rdma_init_func_ramrod_data rdma; + struct tcp_init_params tcp; + struct iwarp_init_func_params iwarp; +}; + +enum iwarp_modify_qp_new_state_type { + IWARP_MODIFY_QP_STATE_CLOSING = 1, + IWARP_MODIFY_QP_STATE_ERROR = + 2, + MAX_IWARP_MODIFY_QP_NEW_STATE_TYPE +}; + +struct iwarp_modify_qp_ramrod_data { + __le16 transition_to_state; + __le16 flags; +#define IWARP_MODIFY_QP_RAMROD_DATA_RDMA_RD_EN_MASK 0x1 +#define IWARP_MODIFY_QP_RAMROD_DATA_RDMA_RD_EN_SHIFT 0 +#define IWARP_MODIFY_QP_RAMROD_DATA_RDMA_WR_EN_MASK 0x1 +#define IWARP_MODIFY_QP_RAMROD_DATA_RDMA_WR_EN_SHIFT 1 +#define IWARP_MODIFY_QP_RAMROD_DATA_ATOMIC_EN_MASK 0x1 +#define IWARP_MODIFY_QP_RAMROD_DATA_ATOMIC_EN_SHIFT 2 +#define IWARP_MODIFY_QP_RAMROD_DATA_STATE_TRANS_EN_MASK 0x1 +#define IWARP_MODIFY_QP_RAMROD_DATA_STATE_TRANS_EN_SHIFT 3 +#define IWARP_MODIFY_QP_RAMROD_DATA_RDMA_OPS_EN_FLG_MASK 0x1 +#define IWARP_MODIFY_QP_RAMROD_DATA_RDMA_OPS_EN_FLG_SHIFT 4 +#define IWARP_MODIFY_QP_RAMROD_DATA_RESERVED_MASK 0x7FF +#define IWARP_MODIFY_QP_RAMROD_DATA_RESERVED_SHIFT 5 + __le32 reserved3[3]; + __le32 reserved4[8]; +}; + +struct mpa_rq_params { + __le32 ird; + __le32 ord; +}; + +struct mpa_ulp_buffer { + struct regpair addr; + __le16 len; + __le16 reserved[3]; +}; + +struct mpa_outgoing_params { + u8 crc_needed; + u8 reject; + u8 reserved[6]; + struct mpa_rq_params out_rq; + struct mpa_ulp_buffer outgoing_ulp_buffer; +}; + +struct iwarp_mpa_offload_ramrod_data { + struct mpa_outgoing_params common; + __le32 tcp_cid; + u8 mode; + u8 tcp_connect_side; + u8 rtr_pref; +#define IWARP_MPA_OFFLOAD_RAMROD_DATA_RTR_SUPPORTED_MASK 0x7 +#define IWARP_MPA_OFFLOAD_RAMROD_DATA_RTR_SUPPORTED_SHIFT 0 +#define IWARP_MPA_OFFLOAD_RAMROD_DATA_RESERVED1_MASK 0x1F +#define IWARP_MPA_OFFLOAD_RAMROD_DATA_RESERVED1_SHIFT 3 + u8 reserved2; + struct mpa_ulp_buffer incoming_ulp_buffer; + struct regpair async_eqe_output_buf; + struct regpair handle_for_async; + struct regpair shared_queue_addr; + u8 stats_counter_id; + u8 reserved3[15]; +}; + +struct iwarp_offload_params { + struct mpa_ulp_buffer incoming_ulp_buffer; + struct regpair async_eqe_output_buf; + struct regpair handle_for_async; + __le16 physical_q0; + __le16 physical_q1; + u8 stats_counter_id; + u8 mpa_mode; + u8 reserved[10]; +}; + +struct iwarp_query_qp_output_params { + __le32 flags; +#define IWARP_QUERY_QP_OUTPUT_PARAMS_ERROR_FLG_MASK 0x1 +#define IWARP_QUERY_QP_OUTPUT_PARAMS_ERROR_FLG_SHIFT 0 +#define IWARP_QUERY_QP_OUTPUT_PARAMS_RESERVED0_MASK 0x7FFFFFFF +#define IWARP_QUERY_QP_OUTPUT_PARAMS_RESERVED0_SHIFT 1 + u8 reserved1[4]; +}; + +struct iwarp_query_qp_ramrod_data { + struct regpair output_params_addr; +}; + +enum iwarp_ramrod_cmd_id { + IWARP_RAMROD_CMD_ID_TCP_OFFLOAD = + 11, + IWARP_RAMROD_CMD_ID_MPA_OFFLOAD, + IWARP_RAMROD_CMD_ID_MPA_OFFLOAD_SEND_RTR, + IWARP_RAMROD_CMD_ID_CREATE_QP, + IWARP_RAMROD_CMD_ID_QUERY_QP, + IWARP_RAMROD_CMD_ID_MODIFY_QP, + IWARP_RAMROD_CMD_ID_DESTROY_QP, + MAX_IWARP_RAMROD_CMD_ID +}; + +struct iwarp_rxmit_stats_drv { + struct regpair tx_go_to_slow_start_event_cnt; + struct regpair tx_fast_retransmit_event_cnt; +}; + +struct iwarp_tcp_offload_ramrod_data { + struct iwarp_offload_params iwarp; + struct tcp_offload_params_opt2 tcp; +}; + +enum mpa_negotiation_mode { + MPA_NEGOTIATION_TYPE_BASIC = 1, + MPA_NEGOTIATION_TYPE_ENHANCED = 2, + MAX_MPA_NEGOTIATION_MODE +}; + +enum mpa_rtr_type { + MPA_RTR_TYPE_NONE = 0, + MPA_RTR_TYPE_ZERO_SEND = 1, + MPA_RTR_TYPE_ZERO_WRITE = 2, + MPA_RTR_TYPE_ZERO_SEND_AND_WRITE = 3, + MPA_RTR_TYPE_ZERO_READ = 4, + MPA_RTR_TYPE_ZERO_SEND_AND_READ = 5, + MPA_RTR_TYPE_ZERO_WRITE_AND_READ = 6, + MPA_RTR_TYPE_ZERO_SEND_AND_WRITE_AND_READ = 7, + MAX_MPA_RTR_TYPE +}; + +struct unaligned_opaque_data { + __le16 first_mpa_offset; + u8 tcp_payload_offset; + u8 flags; +#define UNALIGNED_OPAQUE_DATA_PKT_REACHED_WIN_RIGHT_EDGE_MASK 0x1 +#define UNALIGNED_OPAQUE_DATA_PKT_REACHED_WIN_RIGHT_EDGE_SHIFT 0 +#define UNALIGNED_OPAQUE_DATA_CONNECTION_CLOSED_MASK 0x1 +#define UNALIGNED_OPAQUE_DATA_CONNECTION_CLOSED_SHIFT 1 +#define UNALIGNED_OPAQUE_DATA_RESERVED_MASK 0x3F +#define UNALIGNED_OPAQUE_DATA_RESERVED_SHIFT 2 + __le32 cid; +}; + +struct mstorm_iwarp_conn_ag_ctx { + u8 reserved; + u8 state; + u8 flags0; +#define MSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define MSTORM_IWARP_CONN_AG_CTX_BIT1_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_BIT1_SHIFT 1 +#define MSTORM_IWARP_CONN_AG_CTX_INV_STAG_DONE_CF_MASK 0x3 +#define MSTORM_IWARP_CONN_AG_CTX_INV_STAG_DONE_CF_SHIFT 2 +#define MSTORM_IWARP_CONN_AG_CTX_CF1_MASK 0x3 +#define MSTORM_IWARP_CONN_AG_CTX_CF1_SHIFT 4 +#define MSTORM_IWARP_CONN_AG_CTX_CF2_MASK 0x3 +#define MSTORM_IWARP_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define MSTORM_IWARP_CONN_AG_CTX_INV_STAG_DONE_CF_EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_INV_STAG_DONE_CF_EN_SHIFT 0 +#define MSTORM_IWARP_CONN_AG_CTX_CF1EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_CF1EN_SHIFT 1 +#define MSTORM_IWARP_CONN_AG_CTX_CF2EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_CF2EN_SHIFT 2 +#define MSTORM_IWARP_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define MSTORM_IWARP_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define MSTORM_IWARP_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define MSTORM_IWARP_CONN_AG_CTX_RCQ_CONS_EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_RCQ_CONS_EN_SHIFT 6 +#define MSTORM_IWARP_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_RULE4EN_SHIFT 7 + __le16 rcq_cons; + __le16 rcq_cons_th; + __le32 reg0; + __le32 reg1; +}; + +struct ustorm_iwarp_conn_ag_ctx { + u8 reserved; + u8 byte1; + u8 flags0; +#define USTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define USTORM_IWARP_CONN_AG_CTX_BIT1_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_BIT1_SHIFT 1 +#define USTORM_IWARP_CONN_AG_CTX_CF0_MASK 0x3 +#define USTORM_IWARP_CONN_AG_CTX_CF0_SHIFT 2 +#define USTORM_IWARP_CONN_AG_CTX_CF1_MASK 0x3 +#define USTORM_IWARP_CONN_AG_CTX_CF1_SHIFT 4 +#define USTORM_IWARP_CONN_AG_CTX_CF2_MASK 0x3 +#define USTORM_IWARP_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define USTORM_IWARP_CONN_AG_CTX_CF3_MASK 0x3 +#define USTORM_IWARP_CONN_AG_CTX_CF3_SHIFT 0 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_SE_CF_MASK 0x3 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_SE_CF_SHIFT 2 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_CF_MASK 0x3 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_CF_SHIFT 4 +#define USTORM_IWARP_CONN_AG_CTX_CF6_MASK 0x3 +#define USTORM_IWARP_CONN_AG_CTX_CF6_SHIFT 6 + u8 flags2; +#define USTORM_IWARP_CONN_AG_CTX_CF0EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CF0EN_SHIFT 0 +#define USTORM_IWARP_CONN_AG_CTX_CF1EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CF1EN_SHIFT 1 +#define USTORM_IWARP_CONN_AG_CTX_CF2EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CF2EN_SHIFT 2 +#define USTORM_IWARP_CONN_AG_CTX_CF3EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CF3EN_SHIFT 3 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_SE_CF_EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_SE_CF_EN_SHIFT 4 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_CF_EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_CF_EN_SHIFT 5 +#define USTORM_IWARP_CONN_AG_CTX_CF6EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CF6EN_SHIFT 6 +#define USTORM_IWARP_CONN_AG_CTX_CQ_SE_EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CQ_SE_EN_SHIFT 7 + u8 flags3; +#define USTORM_IWARP_CONN_AG_CTX_CQ_EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CQ_EN_SHIFT 0 +#define USTORM_IWARP_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define USTORM_IWARP_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define USTORM_IWARP_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define USTORM_IWARP_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define USTORM_IWARP_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define USTORM_IWARP_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define USTORM_IWARP_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_RULE8EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le16 word1; + __le32 cq_cons; + __le32 cq_se_prod; + __le32 cq_prod; + __le32 reg3; + __le16 word2; + __le16 word3; +}; + +struct ystorm_iwarp_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define YSTORM_IWARP_CONN_AG_CTX_BIT0_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_BIT0_SHIFT 0 +#define YSTORM_IWARP_CONN_AG_CTX_BIT1_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_BIT1_SHIFT 1 +#define YSTORM_IWARP_CONN_AG_CTX_CF0_MASK 0x3 +#define YSTORM_IWARP_CONN_AG_CTX_CF0_SHIFT 2 +#define YSTORM_IWARP_CONN_AG_CTX_CF1_MASK 0x3 +#define YSTORM_IWARP_CONN_AG_CTX_CF1_SHIFT 4 +#define YSTORM_IWARP_CONN_AG_CTX_CF2_MASK 0x3 +#define YSTORM_IWARP_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define YSTORM_IWARP_CONN_AG_CTX_CF0EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_CF0EN_SHIFT 0 +#define YSTORM_IWARP_CONN_AG_CTX_CF1EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_CF1EN_SHIFT 1 +#define YSTORM_IWARP_CONN_AG_CTX_CF2EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_CF2EN_SHIFT 2 +#define YSTORM_IWARP_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define YSTORM_IWARP_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define YSTORM_IWARP_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define YSTORM_IWARP_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define YSTORM_IWARP_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_RULE4EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le32 reg0; + __le32 reg1; + __le16 word1; + __le16 word2; + __le16 word3; + __le16 word4; + __le32 reg2; + __le32 reg3; +}; + struct ystorm_fcoe_conn_st_ctx { u8 func_mode; u8 cos; @@ -9222,7 +10448,7 @@ struct xstorm_iscsi_conn_ag_ctx { u8 byte13; u8 byte14; u8 byte15; - u8 byte16; + u8 ereserved; __le16 word11; __le32 reg10; __le32 reg11; @@ -10285,9 +11511,11 @@ struct public_drv_mb { #define DRV_MSG_CODE_BW_UPDATE_ACK 0x32000000 #define DRV_MSG_CODE_NIG_DRAIN 0x30000000 +#define DRV_MSG_CODE_S_TAG_UPDATE_ACK 0x3b000000 #define DRV_MSG_CODE_INITIATE_PF_FLR 0x02010000 #define DRV_MSG_CODE_VF_DISABLED_DONE 0xc0000000 #define DRV_MSG_CODE_CFG_VF_MSIX 0xc0010000 +#define DRV_MSG_CODE_CFG_PF_VFS_MSIX 0xc0020000 #define DRV_MSG_CODE_NVM_GET_FILE_ATT 0x00030000 #define DRV_MSG_CODE_NVM_READ_NVRAM 0x00050000 #define DRV_MSG_CODE_MCP_RESET 0x00090000 @@ -10444,6 +11672,7 @@ struct public_drv_mb { #define FW_MSG_CODE_RESOURCE_ALLOC_OK 0x34000000 #define FW_MSG_CODE_RESOURCE_ALLOC_UNKNOWN 0x35000000 #define FW_MSG_CODE_RESOURCE_ALLOC_DEPRECATED 0x36000000 +#define FW_MSG_CODE_S_TAG_UPDATE_ACK_DONE 0x3b000000 #define FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE 0xb0010000 #define FW_MSG_CODE_NVM_OK 0x00010000 @@ -10451,7 +11680,7 @@ struct public_drv_mb { #define FW_MSG_CODE_OS_WOL_SUPPORTED 0x00800000 #define FW_MSG_CODE_OS_WOL_NOT_SUPPORTED 0x00810000 - +#define FW_MSG_CODE_DRV_CFG_PF_VFS_MSIX_DONE 0x00870000 #define FW_MSG_SEQ_NUMBER_MASK 0x0000ffff u32 fw_mb_param; @@ -10466,6 +11695,8 @@ struct public_drv_mb { #define FW_MB_PARAM_GET_PF_RDMA_IWARP 0x2 #define FW_MB_PARAM_GET_PF_RDMA_BOTH 0x3 +#define FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR (1 << 0) + u32 drv_pulse_mb; #define DRV_PULSE_SEQ_MASK 0x00007fff #define DRV_PULSE_SYSTEM_TIME_MASK 0xffff0000 @@ -10489,7 +11720,7 @@ enum MFW_DRV_MSG_TYPE { MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED, MFW_DRV_MSG_RESERVED4, MFW_DRV_MSG_BW_UPDATE, - MFW_DRV_MSG_BW_UPDATE5, + MFW_DRV_MSG_S_TAG_UPDATE, MFW_DRV_MSG_GET_LAN_STATS, MFW_DRV_MSG_GET_FCOE_STATS, MFW_DRV_MSG_GET_ISCSI_STATS, @@ -10591,6 +11822,12 @@ struct nvm_cfg1_glob { u32 led_global_settings; u32 generic_cont1; u32 mbi_version; +#define NVM_CFG1_GLOB_MBI_VERSION_0_MASK 0x000000FF +#define NVM_CFG1_GLOB_MBI_VERSION_0_OFFSET 0 +#define NVM_CFG1_GLOB_MBI_VERSION_1_MASK 0x0000FF00 +#define NVM_CFG1_GLOB_MBI_VERSION_1_OFFSET 8 +#define NVM_CFG1_GLOB_MBI_VERSION_2_MASK 0x00FF0000 +#define NVM_CFG1_GLOB_MBI_VERSION_2_OFFSET 16 u32 mbi_date; u32 misc_sig; u32 device_capabilities; @@ -10758,6 +11995,8 @@ struct static_init { u32 rsrv_persist[5]; /* Persist reserved for MFW upgrades */ }; +#define NVM_MAGIC_VALUE 0x669955aa + enum nvm_image_type { NVM_TYPE_TIM1 = 0x01, NVM_TYPE_TIM2 = 0x02, diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c index 0a8fde629991..b069ad088269 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c @@ -40,31 +40,17 @@ #include "qed_init_ops.h" #include "qed_reg_addr.h" -enum cminterface { - MCM_SEC, - MCM_PRI, - UCM_SEC, - UCM_PRI, - TCM_SEC, - TCM_PRI, - YCM_SEC, - YCM_PRI, - XCM_SEC, - XCM_PRI, - NUM_OF_CM_INTERFACES -}; - -/* general constants */ +/* General constants */ #define QM_PQ_MEM_4KB(pq_size) (pq_size ? DIV_ROUND_UP((pq_size + 1) * \ QM_PQ_ELEMENT_SIZE, \ 0x1000) : 0) #define QM_PQ_SIZE_256B(pq_size) (pq_size ? DIV_ROUND_UP(pq_size, \ 0x100) - 1 : 0) #define QM_INVALID_PQ_ID 0xffff -/* feature enable */ +/* Feature enable */ #define QM_BYPASS_EN 1 #define QM_BYTE_CRD_EN 1 -/* other PQ constants */ +/* Other PQ constants */ #define QM_OTHER_PQS_PER_PF 4 /* WFQ constants */ #define QM_WFQ_UPPER_BOUND 62500000 @@ -106,20 +92,21 @@ enum cminterface { #define BTB_PURE_LB_FACTOR 10 #define BTB_PURE_LB_RATIO 7 /* QM stop command constants */ -#define QM_STOP_PQ_MASK_WIDTH 32 -#define QM_STOP_CMD_ADDR 0x2 -#define QM_STOP_CMD_STRUCT_SIZE 2 +#define QM_STOP_PQ_MASK_WIDTH 32 +#define QM_STOP_CMD_ADDR 2 +#define QM_STOP_CMD_STRUCT_SIZE 2 #define QM_STOP_CMD_PAUSE_MASK_OFFSET 0 #define QM_STOP_CMD_PAUSE_MASK_SHIFT 0 -#define QM_STOP_CMD_PAUSE_MASK_MASK -1 -#define QM_STOP_CMD_GROUP_ID_OFFSET 1 -#define QM_STOP_CMD_GROUP_ID_SHIFT 16 -#define QM_STOP_CMD_GROUP_ID_MASK 15 -#define QM_STOP_CMD_PQ_TYPE_OFFSET 1 -#define QM_STOP_CMD_PQ_TYPE_SHIFT 24 -#define QM_STOP_CMD_PQ_TYPE_MASK 1 -#define QM_STOP_CMD_MAX_POLL_COUNT 100 -#define QM_STOP_CMD_POLL_PERIOD_US 500 +#define QM_STOP_CMD_PAUSE_MASK_MASK -1 +#define QM_STOP_CMD_GROUP_ID_OFFSET 1 +#define QM_STOP_CMD_GROUP_ID_SHIFT 16 +#define QM_STOP_CMD_GROUP_ID_MASK 15 +#define QM_STOP_CMD_PQ_TYPE_OFFSET 1 +#define QM_STOP_CMD_PQ_TYPE_SHIFT 24 +#define QM_STOP_CMD_PQ_TYPE_MASK 1 +#define QM_STOP_CMD_MAX_POLL_COUNT 100 +#define QM_STOP_CMD_POLL_PERIOD_US 500 + /* QM command macros */ #define QM_CMD_STRUCT_SIZE(cmd) cmd ## \ _STRUCT_SIZE @@ -146,16 +133,17 @@ static void qed_enable_pf_rl(struct qed_hwfn *p_hwfn, bool pf_rl_en) { STORE_RT_REG(p_hwfn, QM_REG_RLPFENABLE_RT_OFFSET, pf_rl_en ? 1 : 0); if (pf_rl_en) { - /* enable RLs for all VOQs */ + /* Enable RLs for all VOQs */ STORE_RT_REG(p_hwfn, QM_REG_RLPFVOQENABLE_RT_OFFSET, (1 << MAX_NUM_VOQS) - 1); - /* write RL period */ + /* Write RL period */ STORE_RT_REG(p_hwfn, QM_REG_RLPFPERIOD_RT_OFFSET, QM_RL_PERIOD_CLK_25M); STORE_RT_REG(p_hwfn, QM_REG_RLPFPERIODTIMER_RT_OFFSET, QM_RL_PERIOD_CLK_25M); - /* set credit threshold for QM bypass flow */ + + /* Set credit threshold for QM bypass flow */ if (QM_BYPASS_EN) STORE_RT_REG(p_hwfn, QM_REG_AFULLQMBYPTHRPFRL_RT_OFFSET, @@ -167,7 +155,8 @@ static void qed_enable_pf_rl(struct qed_hwfn *p_hwfn, bool pf_rl_en) static void qed_enable_pf_wfq(struct qed_hwfn *p_hwfn, bool pf_wfq_en) { STORE_RT_REG(p_hwfn, QM_REG_WFQPFENABLE_RT_OFFSET, pf_wfq_en ? 1 : 0); - /* set credit threshold for QM bypass flow */ + + /* Set credit threshold for QM bypass flow */ if (pf_wfq_en && QM_BYPASS_EN) STORE_RT_REG(p_hwfn, QM_REG_AFULLQMBYPTHRPFWFQ_RT_OFFSET, @@ -180,14 +169,15 @@ static void qed_enable_vport_rl(struct qed_hwfn *p_hwfn, bool vport_rl_en) STORE_RT_REG(p_hwfn, QM_REG_RLGLBLENABLE_RT_OFFSET, vport_rl_en ? 1 : 0); if (vport_rl_en) { - /* write RL period (use timer 0 only) */ + /* Write RL period (use timer 0 only) */ STORE_RT_REG(p_hwfn, QM_REG_RLGLBLPERIOD_0_RT_OFFSET, QM_RL_PERIOD_CLK_25M); STORE_RT_REG(p_hwfn, QM_REG_RLGLBLPERIODTIMER_0_RT_OFFSET, QM_RL_PERIOD_CLK_25M); - /* set credit threshold for QM bypass flow */ + + /* Set credit threshold for QM bypass flow */ if (QM_BYPASS_EN) STORE_RT_REG(p_hwfn, QM_REG_AFULLQMBYPTHRGLBLRL_RT_OFFSET, @@ -200,7 +190,8 @@ static void qed_enable_vport_wfq(struct qed_hwfn *p_hwfn, bool vport_wfq_en) { STORE_RT_REG(p_hwfn, QM_REG_WFQVPENABLE_RT_OFFSET, vport_wfq_en ? 1 : 0); - /* set credit threshold for QM bypass flow */ + + /* Set credit threshold for QM bypass flow */ if (vport_wfq_en && QM_BYPASS_EN) STORE_RT_REG(p_hwfn, QM_REG_AFULLQMBYPTHRVPWFQ_RT_OFFSET, @@ -208,7 +199,7 @@ static void qed_enable_vport_wfq(struct qed_hwfn *p_hwfn, bool vport_wfq_en) } /* Prepare runtime init values to allocate PBF command queue lines for - * the specified VOQ + * the specified VOQ. */ static void qed_cmdq_lines_voq_rt_init(struct qed_hwfn *p_hwfn, u8 voq, u16 cmdq_lines) @@ -232,7 +223,7 @@ static void qed_cmdq_lines_rt_init( { u8 tc, voq, port_id, num_tcs_in_port; - /* clear PBF lines for all VOQs */ + /* Clear PBF lines for all VOQs */ for (voq = 0; voq < MAX_NUM_VOQS; voq++) STORE_RT_REG(p_hwfn, PBF_CMDQ_LINES_RT_OFFSET(voq), 0); for (port_id = 0; port_id < max_ports_per_engine; port_id++) { @@ -285,7 +276,7 @@ static void qed_btb_blocks_rt_init( if (!port_params[port_id].active) continue; - /* subtract headroom blocks */ + /* Subtract headroom blocks */ usable_blocks = port_params[port_id].num_btb_blocks - BTB_HEADROOM_BLOCKS; @@ -305,7 +296,7 @@ static void qed_btb_blocks_rt_init( phys_blocks = (usable_blocks - pure_lb_blocks) / num_tcs_in_port; - /* init physical TCs */ + /* Init physical TCs */ for (tc = 0; tc < NUM_OF_PHYS_TCS; tc++) { if (((port_params[port_id].active_phys_tcs >> tc) & 0x1) != 1) @@ -317,7 +308,7 @@ static void qed_btb_blocks_rt_init( phys_blocks); } - /* init pure LB TC */ + /* Init pure LB TC */ temp = LB_VOQ(port_id); STORE_RT_REG(p_hwfn, PBF_BTB_GUARANTEED_RT_OFFSET(temp), pure_lb_blocks); @@ -338,24 +329,24 @@ static void qed_tx_pq_map_rt_init( QM_PF_QUEUE_GROUP_SIZE; u16 i, pq_id, pq_group; - /* a bit per Tx PQ indicating if the PQ is associated with a VF */ + /* A bit per Tx PQ indicating if the PQ is associated with a VF */ u32 tx_pq_vf_mask[MAX_QM_TX_QUEUES / QM_PF_QUEUE_GROUP_SIZE] = { 0 }; u32 num_tx_pq_vf_masks = MAX_QM_TX_QUEUES / QM_PF_QUEUE_GROUP_SIZE; u32 pq_mem_4kb = QM_PQ_MEM_4KB(p_params->num_pf_cids); u32 vport_pq_mem_4kb = QM_PQ_MEM_4KB(p_params->num_vf_cids); u32 mem_addr_4kb = base_mem_addr_4kb; - /* set mapping from PQ group to PF */ + /* Set mapping from PQ group to PF */ for (pq_group = first_pq_group; pq_group <= last_pq_group; pq_group++) STORE_RT_REG(p_hwfn, QM_REG_PQTX2PF_0_RT_OFFSET + pq_group, (u32)(p_params->pf_id)); - /* set PQ sizes */ + /* Set PQ sizes */ STORE_RT_REG(p_hwfn, QM_REG_MAXPQSIZE_0_RT_OFFSET, QM_PQ_SIZE_256B(p_params->num_pf_cids)); STORE_RT_REG(p_hwfn, QM_REG_MAXPQSIZE_1_RT_OFFSET, QM_PQ_SIZE_256B(p_params->num_vf_cids)); - /* go over all Tx PQs */ + /* Go over all Tx PQs */ for (i = 0, pq_id = p_params->start_pq; i < num_pqs; i++, pq_id++) { u8 voq = VOQ(p_params->port_id, p_params->pq_params[i].tc_id, p_params->max_phys_tcs_per_port); @@ -366,17 +357,18 @@ static void qed_tx_pq_map_rt_init( (p_params->pq_params[i].vport_id < MAX_QM_GLOBAL_RLS); - /* update first Tx PQ of VPORT/TC */ + /* Update first Tx PQ of VPORT/TC */ u8 vport_id_in_pf = p_params->pq_params[i].vport_id - p_params->start_vport; u16 *pq_ids = &vport_params[vport_id_in_pf].first_tx_pq_id[0]; u16 first_tx_pq_id = pq_ids[p_params->pq_params[i].tc_id]; if (first_tx_pq_id == QM_INVALID_PQ_ID) { - /* create new VP PQ */ + /* Create new VP PQ */ pq_ids[p_params->pq_params[i].tc_id] = pq_id; first_tx_pq_id = pq_id; - /* map VP PQ to VOQ and PF */ + + /* Map VP PQ to VOQ and PF */ STORE_RT_REG(p_hwfn, QM_REG_WFQVPMAP_RT_OFFSET + first_tx_pq_id, @@ -388,7 +380,7 @@ static void qed_tx_pq_map_rt_init( if (p_params->pq_params[i].rl_valid && !rl_valid) DP_NOTICE(p_hwfn, "Invalid VPORT ID for rate limiter configuration"); - /* fill PQ map entry */ + /* Fill PQ map entry */ memset(&tx_pq_map, 0, sizeof(tx_pq_map)); SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_PQ_VALID, 1); SET_FIELD(tx_pq_map.reg, @@ -400,18 +392,16 @@ static void qed_tx_pq_map_rt_init( SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_VOQ, voq); SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_WRR_WEIGHT_GROUP, p_params->pq_params[i].wrr_group); - /* write PQ map entry to CAM */ + /* Write PQ map entry to CAM */ STORE_RT_REG(p_hwfn, QM_REG_TXPQMAP_RT_OFFSET + pq_id, *((u32 *)&tx_pq_map)); - /* set base address */ + /* Set base address */ STORE_RT_REG(p_hwfn, QM_REG_BASEADDRTXPQ_RT_OFFSET + pq_id, mem_addr_4kb); - /* check if VF PQ */ + + /* If VF PQ, add indication to PQ VF mask */ if (is_vf_pq) { - /* if PQ is associated with a VF, add indication - * to PQ VF mask - */ tx_pq_vf_mask[pq_id / QM_PF_QUEUE_GROUP_SIZE] |= BIT((pq_id % QM_PF_QUEUE_GROUP_SIZE)); @@ -421,16 +411,12 @@ static void qed_tx_pq_map_rt_init( } } - /* store Tx PQ VF mask to size select register */ - for (i = 0; i < num_tx_pq_vf_masks; i++) { - if (tx_pq_vf_mask[i]) { - u32 addr; - - addr = QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET + i; - STORE_RT_REG(p_hwfn, addr, + /* Store Tx PQ VF mask to size select register */ + for (i = 0; i < num_tx_pq_vf_masks; i++) + if (tx_pq_vf_mask[i]) + STORE_RT_REG(p_hwfn, + QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET + i, tx_pq_vf_mask[i]); - } - } } /* Prepare Other PQ mapping runtime init values for the specified PF */ @@ -440,23 +426,25 @@ static void qed_other_pq_map_rt_init(struct qed_hwfn *p_hwfn, u32 num_pf_cids, u32 num_tids, u32 base_mem_addr_4kb) { - u16 i, pq_id; + u32 pq_size, pq_mem_4kb, mem_addr_4kb; + u16 i, pq_id, pq_group; /* a single other PQ group is used in each PF, * where PQ group i is used in PF i. */ - u16 pq_group = pf_id; - u32 pq_size = num_pf_cids + num_tids; - u32 pq_mem_4kb = QM_PQ_MEM_4KB(pq_size); - u32 mem_addr_4kb = base_mem_addr_4kb; + pq_group = pf_id; + pq_size = num_pf_cids + num_tids; + pq_mem_4kb = QM_PQ_MEM_4KB(pq_size); + mem_addr_4kb = base_mem_addr_4kb; - /* map PQ group to PF */ + /* Map PQ group to PF */ STORE_RT_REG(p_hwfn, QM_REG_PQOTHER2PF_0_RT_OFFSET + pq_group, (u32)(pf_id)); - /* set PQ sizes */ + /* Set PQ sizes */ STORE_RT_REG(p_hwfn, QM_REG_MAXPQSIZE_2_RT_OFFSET, QM_PQ_SIZE_256B(pq_size)); - /* set base address */ + + /* Set base address */ for (i = 0, pq_id = pf_id * QM_PF_QUEUE_GROUP_SIZE; i < QM_OTHER_PQS_PER_PF; i++, pq_id++) { STORE_RT_REG(p_hwfn, @@ -485,7 +473,7 @@ static int qed_pf_wfq_rt_init(struct qed_hwfn *p_hwfn, inc_val = QM_WFQ_INC_VAL(p_params->pf_wfq); if (!inc_val || inc_val > QM_WFQ_MAX_INC_VAL) { - DP_NOTICE(p_hwfn, "Invalid PF WFQ weight configuration"); + DP_NOTICE(p_hwfn, "Invalid PF WFQ weight configuration\n"); return -1; } @@ -514,7 +502,7 @@ static int qed_pf_rl_rt_init(struct qed_hwfn *p_hwfn, u8 pf_id, u32 pf_rl) u32 inc_val = QM_RL_INC_VAL(pf_rl); if (inc_val > QM_RL_MAX_INC_VAL) { - DP_NOTICE(p_hwfn, "Invalid PF rate limit configuration"); + DP_NOTICE(p_hwfn, "Invalid PF rate limit configuration\n"); return -1; } STORE_RT_REG(p_hwfn, QM_REG_RLPFCRD_RT_OFFSET + pf_id, @@ -535,7 +523,7 @@ static int qed_vp_wfq_rt_init(struct qed_hwfn *p_hwfn, u32 inc_val; u8 tc, i; - /* go over all PF VPORTs */ + /* Go over all PF VPORTs */ for (i = 0; i < num_vports; i++) { if (!vport_params[i].vport_wfq) @@ -544,7 +532,7 @@ static int qed_vp_wfq_rt_init(struct qed_hwfn *p_hwfn, inc_val = QM_WFQ_INC_VAL(vport_params[i].vport_wfq); if (inc_val > QM_WFQ_MAX_INC_VAL) { DP_NOTICE(p_hwfn, - "Invalid VPORT WFQ weight configuration"); + "Invalid VPORT WFQ weight configuration\n"); return -1; } @@ -578,17 +566,17 @@ static int qed_vport_rl_rt_init(struct qed_hwfn *p_hwfn, if (start_vport + num_vports >= MAX_QM_GLOBAL_RLS) { DP_NOTICE(p_hwfn, - "Invalid VPORT ID for rate limiter configuration"); + "Invalid VPORT ID for rate limiter configuration\n"); return -1; } - /* go over all PF VPORTs */ + /* Go over all PF VPORTs */ for (i = 0, vport_id = start_vport; i < num_vports; i++, vport_id++) { u32 inc_val = QM_RL_INC_VAL(vport_params[i].vport_rl); if (inc_val > QM_RL_MAX_INC_VAL) { DP_NOTICE(p_hwfn, - "Invalid VPORT rate-limit configuration"); + "Invalid VPORT rate-limit configuration\n"); return -1; } @@ -617,7 +605,7 @@ static bool qed_poll_on_qm_cmd_ready(struct qed_hwfn *p_hwfn, reg_val = qed_rd(p_hwfn, p_ptt, QM_REG_SDMCMDREADY); } - /* check if timeout while waiting for SDM command ready */ + /* Check if timeout while waiting for SDM command ready */ if (i == QM_STOP_CMD_MAX_POLL_COUNT) { DP_VERBOSE(p_hwfn, NETIF_MSG_HW, "Timeout when waiting for QM SDM command ready signal\n"); @@ -701,16 +689,16 @@ int qed_qm_pf_rt_init(struct qed_hwfn *p_hwfn, QM_OTHER_PQS_PER_PF; u8 tc, i; - /* clear first Tx PQ ID array for each VPORT */ + /* Clear first Tx PQ ID array for each VPORT */ for (i = 0; i < p_params->num_vports; i++) for (tc = 0; tc < NUM_OF_TCS; tc++) vport_params[i].first_tx_pq_id[tc] = QM_INVALID_PQ_ID; - /* map Other PQs (if any) */ + /* Map Other PQs (if any) */ qed_other_pq_map_rt_init(p_hwfn, p_params->port_id, p_params->pf_id, p_params->num_pf_cids, p_params->num_tids, 0); - /* map Tx PQs */ + /* Map Tx PQs */ qed_tx_pq_map_rt_init(p_hwfn, p_ptt, p_params, other_mem_size_4kb); if (p_params->pf_wfq) @@ -736,7 +724,7 @@ int qed_init_pf_wfq(struct qed_hwfn *p_hwfn, u32 inc_val = QM_WFQ_INC_VAL(pf_wfq); if (!inc_val || inc_val > QM_WFQ_MAX_INC_VAL) { - DP_NOTICE(p_hwfn, "Invalid PF WFQ weight configuration"); + DP_NOTICE(p_hwfn, "Invalid PF WFQ weight configuration\n"); return -1; } @@ -750,7 +738,7 @@ int qed_init_pf_rl(struct qed_hwfn *p_hwfn, u32 inc_val = QM_RL_INC_VAL(pf_rl); if (inc_val > QM_RL_MAX_INC_VAL) { - DP_NOTICE(p_hwfn, "Invalid PF rate limit configuration"); + DP_NOTICE(p_hwfn, "Invalid PF rate limit configuration\n"); return -1; } @@ -766,17 +754,18 @@ int qed_init_vport_wfq(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u16 first_tx_pq_id[NUM_OF_TCS], u16 vport_wfq) { - u32 inc_val = QM_WFQ_INC_VAL(vport_wfq); + u16 vport_pq_id; + u32 inc_val; u8 tc; + inc_val = QM_WFQ_INC_VAL(vport_wfq); if (!inc_val || inc_val > QM_WFQ_MAX_INC_VAL) { - DP_NOTICE(p_hwfn, "Invalid VPORT WFQ weight configuration"); + DP_NOTICE(p_hwfn, "Invalid VPORT WFQ weight configuration\n"); return -1; } for (tc = 0; tc < NUM_OF_TCS; tc++) { - u16 vport_pq_id = first_tx_pq_id[tc]; - + vport_pq_id = first_tx_pq_id[tc]; if (vport_pq_id != QM_INVALID_PQ_ID) qed_wr(p_hwfn, p_ptt, QM_REG_WFQVPWEIGHT + vport_pq_id * 4, @@ -793,12 +782,12 @@ int qed_init_vport_rl(struct qed_hwfn *p_hwfn, if (vport_id >= MAX_QM_GLOBAL_RLS) { DP_NOTICE(p_hwfn, - "Invalid VPORT ID for rate limiter configuration"); + "Invalid VPORT ID for rate limiter configuration\n"); return -1; } if (inc_val > QM_RL_MAX_INC_VAL) { - DP_NOTICE(p_hwfn, "Invalid VPORT rate-limit configuration"); + DP_NOTICE(p_hwfn, "Invalid VPORT rate-limit configuration\n"); return -1; } @@ -818,15 +807,15 @@ bool qed_send_qm_stop_cmd(struct qed_hwfn *p_hwfn, u32 cmd_arr[QM_CMD_STRUCT_SIZE(QM_STOP_CMD)] = { 0 }; u32 pq_mask = 0, last_pq = start_pq + num_pqs - 1, pq_id; - /* set command's PQ type */ + /* Set command's PQ type */ QM_CMD_SET_FIELD(cmd_arr, QM_STOP_CMD, PQ_TYPE, is_tx_pq ? 0 : 1); for (pq_id = start_pq; pq_id <= last_pq; pq_id++) { - /* set PQ bit in mask (stop command only) */ + /* Set PQ bit in mask (stop command only) */ if (!is_release_cmd) pq_mask |= (1 << (pq_id % QM_STOP_PQ_MASK_WIDTH)); - /* if last PQ or end of PQ mask, write command */ + /* If last PQ or end of PQ mask, write command */ if ((pq_id == last_pq) || (pq_id % QM_STOP_PQ_MASK_WIDTH == (QM_STOP_PQ_MASK_WIDTH - 1))) { @@ -962,8 +951,10 @@ void qed_set_geneve_enable(struct qed_hwfn *p_hwfn, ip_geneve_enable ? 1 : 0); } +#define T_ETH_PACKET_ACTION_GFT_EVENTID 23 +#define PARSER_ETH_CONN_GFT_ACTION_CM_HDR 272 #define T_ETH_PACKET_MATCH_RFS_EVENTID 25 -#define PARSER_ETH_CONN_CM_HDR (0x0) +#define PARSER_ETH_CONN_CM_HDR 0 #define CAM_LINE_SIZE sizeof(u32) #define RAM_LINE_SIZE sizeof(u64) #define REG_SIZE sizeof(u32) @@ -971,40 +962,26 @@ void qed_set_geneve_enable(struct qed_hwfn *p_hwfn, void qed_set_rfs_mode_disable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u16 pf_id) { - union gft_cam_line_union camline; - struct gft_ram_line ramline; - u32 *p_ramline, i; - - p_ramline = (u32 *)&ramline; + u32 hw_addr = PRS_REG_GFT_PROFILE_MASK_RAM + + pf_id * RAM_LINE_SIZE; /*stop using gft logic */ qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_GFT, 0); qed_wr(p_hwfn, p_ptt, PRS_REG_CM_HDR_GFT, 0x0); - memset(&camline, 0, sizeof(union gft_cam_line_union)); - qed_wr(p_hwfn, p_ptt, PRS_REG_GFT_CAM + CAM_LINE_SIZE * pf_id, - camline.cam_line_mapped.camline); - memset(&ramline, 0, sizeof(ramline)); - - for (i = 0; i < RAM_LINE_SIZE / REG_SIZE; i++) { - u32 hw_addr = PRS_REG_GFT_PROFILE_MASK_RAM; - - hw_addr += (RAM_LINE_SIZE * pf_id + i * REG_SIZE); - - qed_wr(p_hwfn, p_ptt, hw_addr, *(p_ramline + i)); - } + qed_wr(p_hwfn, p_ptt, PRS_REG_GFT_CAM + CAM_LINE_SIZE * pf_id, 0); + qed_wr(p_hwfn, p_ptt, hw_addr, 0); + qed_wr(p_hwfn, p_ptt, hw_addr + 4, 0); } void qed_set_rfs_mode_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u16 pf_id, bool tcp, bool udp, bool ipv4, bool ipv6) { - u32 rfs_cm_hdr_event_id, *p_ramline; union gft_cam_line_union camline; struct gft_ram_line ramline; - int i; + u32 rfs_cm_hdr_event_id; rfs_cm_hdr_event_id = qed_rd(p_hwfn, p_ptt, PRS_REG_CM_HDR_GFT); - p_ramline = (u32 *)&ramline; if (!ipv6 && !ipv4) DP_NOTICE(p_hwfn, @@ -1024,18 +1001,20 @@ void qed_set_rfs_mode_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, qed_wr(p_hwfn, p_ptt, PRS_REG_LOAD_L2_FILTER, 0); camline.cam_line_mapped.camline = 0; - /* cam line is now valid!! */ + /* Cam line is now valid!! */ SET_FIELD(camline.cam_line_mapped.camline, GFT_CAM_LINE_MAPPED_VALID, 1); /* filters are per PF!! */ SET_FIELD(camline.cam_line_mapped.camline, - GFT_CAM_LINE_MAPPED_PF_ID_MASK, 1); + GFT_CAM_LINE_MAPPED_PF_ID_MASK, + GFT_CAM_LINE_MAPPED_PF_ID_MASK_MASK); SET_FIELD(camline.cam_line_mapped.camline, GFT_CAM_LINE_MAPPED_PF_ID, pf_id); if (!(tcp && udp)) { SET_FIELD(camline.cam_line_mapped.camline, - GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK, 1); + GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK, + GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK_MASK); if (tcp) SET_FIELD(camline.cam_line_mapped.camline, GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE, @@ -1059,34 +1038,38 @@ void qed_set_rfs_mode_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, GFT_PROFILE_IPV6); } - /* write characteristics to cam */ + /* Write characteristics to cam */ qed_wr(p_hwfn, p_ptt, PRS_REG_GFT_CAM + CAM_LINE_SIZE * pf_id, camline.cam_line_mapped.camline); camline.cam_line_mapped.camline = qed_rd(p_hwfn, p_ptt, PRS_REG_GFT_CAM + CAM_LINE_SIZE * pf_id); - /* write line to RAM - compare to filter 4 tuple */ - ramline.low32bits = 0; - ramline.high32bits = 0; - SET_FIELD(ramline.high32bits, GFT_RAM_LINE_DST_IP, 1); - SET_FIELD(ramline.high32bits, GFT_RAM_LINE_SRC_IP, 1); - SET_FIELD(ramline.low32bits, GFT_RAM_LINE_SRC_PORT, 1); - SET_FIELD(ramline.low32bits, GFT_RAM_LINE_DST_PORT, 1); - - /* each iteration write to reg */ - for (i = 0; i < RAM_LINE_SIZE / REG_SIZE; i++) - qed_wr(p_hwfn, p_ptt, - PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id + - i * REG_SIZE, *(p_ramline + i)); - - /* set default profile so that no filter match will happen */ - ramline.low32bits = 0xffff; - ramline.high32bits = 0xffff; - - for (i = 0; i < RAM_LINE_SIZE / REG_SIZE; i++) - qed_wr(p_hwfn, p_ptt, - PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * - PRS_GFT_CAM_LINES_NO_MATCH + i * REG_SIZE, - *(p_ramline + i)); + /* Write line to RAM - compare to filter 4 tuple */ + ramline.lo = 0; + ramline.hi = 0; + SET_FIELD(ramline.hi, GFT_RAM_LINE_DST_IP, 1); + SET_FIELD(ramline.hi, GFT_RAM_LINE_SRC_IP, 1); + SET_FIELD(ramline.hi, GFT_RAM_LINE_OVER_IP_PROTOCOL, 1); + SET_FIELD(ramline.lo, GFT_RAM_LINE_ETHERTYPE, 1); + SET_FIELD(ramline.lo, GFT_RAM_LINE_SRC_PORT, 1); + SET_FIELD(ramline.lo, GFT_RAM_LINE_DST_PORT, 1); + + /* Each iteration write to reg */ + qed_wr(p_hwfn, p_ptt, + PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id, + ramline.lo); + qed_wr(p_hwfn, p_ptt, + PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id + 4, + ramline.hi); + + /* Set default profile so that no filter match will happen */ + qed_wr(p_hwfn, p_ptt, + PRS_REG_GFT_PROFILE_MASK_RAM + + RAM_LINE_SIZE * PRS_GFT_CAM_LINES_NO_MATCH, + ramline.lo); + qed_wr(p_hwfn, p_ptt, + PRS_REG_GFT_PROFILE_MASK_RAM + + RAM_LINE_SIZE * PRS_GFT_CAM_LINES_NO_MATCH + 4, + ramline.hi); } diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c index 4a2e7be5bf72..e3f368882f46 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c @@ -158,6 +158,7 @@ int qed_init_alloc(struct qed_hwfn *p_hwfn) GFP_KERNEL); if (!rt_data->init_val) { kfree(rt_data->b_valid); + rt_data->b_valid = NULL; return -ENOMEM; } @@ -167,7 +168,9 @@ int qed_init_alloc(struct qed_hwfn *p_hwfn) void qed_init_free(struct qed_hwfn *p_hwfn) { kfree(p_hwfn->rt_data.init_val); + p_hwfn->rt_data.init_val = NULL; kfree(p_hwfn->rt_data.b_valid); + p_hwfn->rt_data.b_valid = NULL; } static int qed_init_array_dmae(struct qed_hwfn *p_hwfn, @@ -525,6 +528,7 @@ int qed_init_run(struct qed_hwfn *p_hwfn, } kfree(p_hwfn->unzip_buf); + p_hwfn->unzip_buf = NULL; return rc; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 40f057edeafc..719cdbfe1695 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -90,6 +90,12 @@ struct aeu_invert_reg_bit { /* Multiple bits start with this offset */ #define ATTENTION_OFFSET_MASK (0x000ff000) #define ATTENTION_OFFSET_SHIFT (12) + +#define ATTENTION_BB_MASK (0x00700000) +#define ATTENTION_BB_SHIFT (20) +#define ATTENTION_BB(value) (value << ATTENTION_BB_SHIFT) +#define ATTENTION_BB_DIFFERENT BIT(23) + unsigned int flags; /* Callback to call if attention will be triggered */ @@ -105,1215 +111,6 @@ struct aeu_invert_reg { #define MAX_ATTN_GRPS (8) #define NUM_ATTN_REGS (9) -/* HW Attention register */ -struct attn_hw_reg { - u16 reg_idx; /* Index of this register in its block */ - u16 num_of_bits; /* number of valid attention bits */ - u32 sts_addr; /* Address of the STS register */ - u32 sts_clr_addr; /* Address of the STS_CLR register */ - u32 sts_wr_addr; /* Address of the STS_WR register */ - u32 mask_addr; /* Address of the MASK register */ -}; - -/* HW block attention registers */ -struct attn_hw_regs { - u16 num_of_int_regs; /* Number of interrupt regs */ - u16 num_of_prty_regs; /* Number of parity regs */ - struct attn_hw_reg **int_regs; /* interrupt regs */ - struct attn_hw_reg **prty_regs; /* parity regs */ -}; - -/* HW block attention registers */ -struct attn_hw_block { - const char *name; /* Block name */ - struct attn_hw_regs chip_regs[1]; -}; - -static struct attn_hw_reg grc_int0_bb_b0 = { - 0, 4, 0x50180, 0x5018c, 0x50188, 0x50184}; - -static struct attn_hw_reg *grc_int_bb_b0_regs[1] = { - &grc_int0_bb_b0}; - -static struct attn_hw_reg grc_prty1_bb_b0 = { - 0, 2, 0x50200, 0x5020c, 0x50208, 0x50204}; - -static struct attn_hw_reg *grc_prty_bb_b0_regs[1] = { - &grc_prty1_bb_b0}; - -static struct attn_hw_reg miscs_int0_bb_b0 = { - 0, 3, 0x9180, 0x918c, 0x9188, 0x9184}; - -static struct attn_hw_reg miscs_int1_bb_b0 = { - 1, 11, 0x9190, 0x919c, 0x9198, 0x9194}; - -static struct attn_hw_reg *miscs_int_bb_b0_regs[2] = { - &miscs_int0_bb_b0, &miscs_int1_bb_b0}; - -static struct attn_hw_reg miscs_prty0_bb_b0 = { - 0, 1, 0x91a0, 0x91ac, 0x91a8, 0x91a4}; - -static struct attn_hw_reg *miscs_prty_bb_b0_regs[1] = { - &miscs_prty0_bb_b0}; - -static struct attn_hw_reg misc_int0_bb_b0 = { - 0, 1, 0x8180, 0x818c, 0x8188, 0x8184}; - -static struct attn_hw_reg *misc_int_bb_b0_regs[1] = { - &misc_int0_bb_b0}; - -static struct attn_hw_reg pglue_b_int0_bb_b0 = { - 0, 23, 0x2a8180, 0x2a818c, 0x2a8188, 0x2a8184}; - -static struct attn_hw_reg *pglue_b_int_bb_b0_regs[1] = { - &pglue_b_int0_bb_b0}; - -static struct attn_hw_reg pglue_b_prty0_bb_b0 = { - 0, 1, 0x2a8190, 0x2a819c, 0x2a8198, 0x2a8194}; - -static struct attn_hw_reg pglue_b_prty1_bb_b0 = { - 1, 22, 0x2a8200, 0x2a820c, 0x2a8208, 0x2a8204}; - -static struct attn_hw_reg *pglue_b_prty_bb_b0_regs[2] = { - &pglue_b_prty0_bb_b0, &pglue_b_prty1_bb_b0}; - -static struct attn_hw_reg cnig_int0_bb_b0 = { - 0, 6, 0x2182e8, 0x2182f4, 0x2182f0, 0x2182ec}; - -static struct attn_hw_reg *cnig_int_bb_b0_regs[1] = { - &cnig_int0_bb_b0}; - -static struct attn_hw_reg cnig_prty0_bb_b0 = { - 0, 2, 0x218348, 0x218354, 0x218350, 0x21834c}; - -static struct attn_hw_reg *cnig_prty_bb_b0_regs[1] = { - &cnig_prty0_bb_b0}; - -static struct attn_hw_reg cpmu_int0_bb_b0 = { - 0, 1, 0x303e0, 0x303ec, 0x303e8, 0x303e4}; - -static struct attn_hw_reg *cpmu_int_bb_b0_regs[1] = { - &cpmu_int0_bb_b0}; - -static struct attn_hw_reg ncsi_int0_bb_b0 = { - 0, 1, 0x404cc, 0x404d8, 0x404d4, 0x404d0}; - -static struct attn_hw_reg *ncsi_int_bb_b0_regs[1] = { - &ncsi_int0_bb_b0}; - -static struct attn_hw_reg ncsi_prty1_bb_b0 = { - 0, 1, 0x40000, 0x4000c, 0x40008, 0x40004}; - -static struct attn_hw_reg *ncsi_prty_bb_b0_regs[1] = { - &ncsi_prty1_bb_b0}; - -static struct attn_hw_reg opte_prty1_bb_b0 = { - 0, 11, 0x53000, 0x5300c, 0x53008, 0x53004}; - -static struct attn_hw_reg opte_prty0_bb_b0 = { - 1, 1, 0x53208, 0x53214, 0x53210, 0x5320c}; - -static struct attn_hw_reg *opte_prty_bb_b0_regs[2] = { - &opte_prty1_bb_b0, &opte_prty0_bb_b0}; - -static struct attn_hw_reg bmb_int0_bb_b0 = { - 0, 16, 0x5400c0, 0x5400cc, 0x5400c8, 0x5400c4}; - -static struct attn_hw_reg bmb_int1_bb_b0 = { - 1, 28, 0x5400d8, 0x5400e4, 0x5400e0, 0x5400dc}; - -static struct attn_hw_reg bmb_int2_bb_b0 = { - 2, 26, 0x5400f0, 0x5400fc, 0x5400f8, 0x5400f4}; - -static struct attn_hw_reg bmb_int3_bb_b0 = { - 3, 31, 0x540108, 0x540114, 0x540110, 0x54010c}; - -static struct attn_hw_reg bmb_int4_bb_b0 = { - 4, 27, 0x540120, 0x54012c, 0x540128, 0x540124}; - -static struct attn_hw_reg bmb_int5_bb_b0 = { - 5, 29, 0x540138, 0x540144, 0x540140, 0x54013c}; - -static struct attn_hw_reg bmb_int6_bb_b0 = { - 6, 30, 0x540150, 0x54015c, 0x540158, 0x540154}; - -static struct attn_hw_reg bmb_int7_bb_b0 = { - 7, 32, 0x540168, 0x540174, 0x540170, 0x54016c}; - -static struct attn_hw_reg bmb_int8_bb_b0 = { - 8, 32, 0x540184, 0x540190, 0x54018c, 0x540188}; - -static struct attn_hw_reg bmb_int9_bb_b0 = { - 9, 32, 0x54019c, 0x5401a8, 0x5401a4, 0x5401a0}; - -static struct attn_hw_reg bmb_int10_bb_b0 = { - 10, 3, 0x5401b4, 0x5401c0, 0x5401bc, 0x5401b8}; - -static struct attn_hw_reg bmb_int11_bb_b0 = { - 11, 4, 0x5401cc, 0x5401d8, 0x5401d4, 0x5401d0}; - -static struct attn_hw_reg *bmb_int_bb_b0_regs[12] = { - &bmb_int0_bb_b0, &bmb_int1_bb_b0, &bmb_int2_bb_b0, &bmb_int3_bb_b0, - &bmb_int4_bb_b0, &bmb_int5_bb_b0, &bmb_int6_bb_b0, &bmb_int7_bb_b0, - &bmb_int8_bb_b0, &bmb_int9_bb_b0, &bmb_int10_bb_b0, &bmb_int11_bb_b0}; - -static struct attn_hw_reg bmb_prty0_bb_b0 = { - 0, 5, 0x5401dc, 0x5401e8, 0x5401e4, 0x5401e0}; - -static struct attn_hw_reg bmb_prty1_bb_b0 = { - 1, 31, 0x540400, 0x54040c, 0x540408, 0x540404}; - -static struct attn_hw_reg bmb_prty2_bb_b0 = { - 2, 15, 0x540410, 0x54041c, 0x540418, 0x540414}; - -static struct attn_hw_reg *bmb_prty_bb_b0_regs[3] = { - &bmb_prty0_bb_b0, &bmb_prty1_bb_b0, &bmb_prty2_bb_b0}; - -static struct attn_hw_reg pcie_prty1_bb_b0 = { - 0, 17, 0x54000, 0x5400c, 0x54008, 0x54004}; - -static struct attn_hw_reg *pcie_prty_bb_b0_regs[1] = { - &pcie_prty1_bb_b0}; - -static struct attn_hw_reg mcp2_prty0_bb_b0 = { - 0, 1, 0x52040, 0x5204c, 0x52048, 0x52044}; - -static struct attn_hw_reg mcp2_prty1_bb_b0 = { - 1, 12, 0x52204, 0x52210, 0x5220c, 0x52208}; - -static struct attn_hw_reg *mcp2_prty_bb_b0_regs[2] = { - &mcp2_prty0_bb_b0, &mcp2_prty1_bb_b0}; - -static struct attn_hw_reg pswhst_int0_bb_b0 = { - 0, 18, 0x2a0180, 0x2a018c, 0x2a0188, 0x2a0184}; - -static struct attn_hw_reg *pswhst_int_bb_b0_regs[1] = { - &pswhst_int0_bb_b0}; - -static struct attn_hw_reg pswhst_prty0_bb_b0 = { - 0, 1, 0x2a0190, 0x2a019c, 0x2a0198, 0x2a0194}; - -static struct attn_hw_reg pswhst_prty1_bb_b0 = { - 1, 17, 0x2a0200, 0x2a020c, 0x2a0208, 0x2a0204}; - -static struct attn_hw_reg *pswhst_prty_bb_b0_regs[2] = { - &pswhst_prty0_bb_b0, &pswhst_prty1_bb_b0}; - -static struct attn_hw_reg pswhst2_int0_bb_b0 = { - 0, 5, 0x29e180, 0x29e18c, 0x29e188, 0x29e184}; - -static struct attn_hw_reg *pswhst2_int_bb_b0_regs[1] = { - &pswhst2_int0_bb_b0}; - -static struct attn_hw_reg pswhst2_prty0_bb_b0 = { - 0, 1, 0x29e190, 0x29e19c, 0x29e198, 0x29e194}; - -static struct attn_hw_reg *pswhst2_prty_bb_b0_regs[1] = { - &pswhst2_prty0_bb_b0}; - -static struct attn_hw_reg pswrd_int0_bb_b0 = { - 0, 3, 0x29c180, 0x29c18c, 0x29c188, 0x29c184}; - -static struct attn_hw_reg *pswrd_int_bb_b0_regs[1] = { - &pswrd_int0_bb_b0}; - -static struct attn_hw_reg pswrd_prty0_bb_b0 = { - 0, 1, 0x29c190, 0x29c19c, 0x29c198, 0x29c194}; - -static struct attn_hw_reg *pswrd_prty_bb_b0_regs[1] = { - &pswrd_prty0_bb_b0}; - -static struct attn_hw_reg pswrd2_int0_bb_b0 = { - 0, 5, 0x29d180, 0x29d18c, 0x29d188, 0x29d184}; - -static struct attn_hw_reg *pswrd2_int_bb_b0_regs[1] = { - &pswrd2_int0_bb_b0}; - -static struct attn_hw_reg pswrd2_prty0_bb_b0 = { - 0, 1, 0x29d190, 0x29d19c, 0x29d198, 0x29d194}; - -static struct attn_hw_reg pswrd2_prty1_bb_b0 = { - 1, 31, 0x29d200, 0x29d20c, 0x29d208, 0x29d204}; - -static struct attn_hw_reg pswrd2_prty2_bb_b0 = { - 2, 3, 0x29d210, 0x29d21c, 0x29d218, 0x29d214}; - -static struct attn_hw_reg *pswrd2_prty_bb_b0_regs[3] = { - &pswrd2_prty0_bb_b0, &pswrd2_prty1_bb_b0, &pswrd2_prty2_bb_b0}; - -static struct attn_hw_reg pswwr_int0_bb_b0 = { - 0, 16, 0x29a180, 0x29a18c, 0x29a188, 0x29a184}; - -static struct attn_hw_reg *pswwr_int_bb_b0_regs[1] = { - &pswwr_int0_bb_b0}; - -static struct attn_hw_reg pswwr_prty0_bb_b0 = { - 0, 1, 0x29a190, 0x29a19c, 0x29a198, 0x29a194}; - -static struct attn_hw_reg *pswwr_prty_bb_b0_regs[1] = { - &pswwr_prty0_bb_b0}; - -static struct attn_hw_reg pswwr2_int0_bb_b0 = { - 0, 19, 0x29b180, 0x29b18c, 0x29b188, 0x29b184}; - -static struct attn_hw_reg *pswwr2_int_bb_b0_regs[1] = { - &pswwr2_int0_bb_b0}; - -static struct attn_hw_reg pswwr2_prty0_bb_b0 = { - 0, 1, 0x29b190, 0x29b19c, 0x29b198, 0x29b194}; - -static struct attn_hw_reg pswwr2_prty1_bb_b0 = { - 1, 31, 0x29b200, 0x29b20c, 0x29b208, 0x29b204}; - -static struct attn_hw_reg pswwr2_prty2_bb_b0 = { - 2, 31, 0x29b210, 0x29b21c, 0x29b218, 0x29b214}; - -static struct attn_hw_reg pswwr2_prty3_bb_b0 = { - 3, 31, 0x29b220, 0x29b22c, 0x29b228, 0x29b224}; - -static struct attn_hw_reg pswwr2_prty4_bb_b0 = { - 4, 20, 0x29b230, 0x29b23c, 0x29b238, 0x29b234}; - -static struct attn_hw_reg *pswwr2_prty_bb_b0_regs[5] = { - &pswwr2_prty0_bb_b0, &pswwr2_prty1_bb_b0, &pswwr2_prty2_bb_b0, - &pswwr2_prty3_bb_b0, &pswwr2_prty4_bb_b0}; - -static struct attn_hw_reg pswrq_int0_bb_b0 = { - 0, 21, 0x280180, 0x28018c, 0x280188, 0x280184}; - -static struct attn_hw_reg *pswrq_int_bb_b0_regs[1] = { - &pswrq_int0_bb_b0}; - -static struct attn_hw_reg pswrq_prty0_bb_b0 = { - 0, 1, 0x280190, 0x28019c, 0x280198, 0x280194}; - -static struct attn_hw_reg *pswrq_prty_bb_b0_regs[1] = { - &pswrq_prty0_bb_b0}; - -static struct attn_hw_reg pswrq2_int0_bb_b0 = { - 0, 15, 0x240180, 0x24018c, 0x240188, 0x240184}; - -static struct attn_hw_reg *pswrq2_int_bb_b0_regs[1] = { - &pswrq2_int0_bb_b0}; - -static struct attn_hw_reg pswrq2_prty1_bb_b0 = { - 0, 9, 0x240200, 0x24020c, 0x240208, 0x240204}; - -static struct attn_hw_reg *pswrq2_prty_bb_b0_regs[1] = { - &pswrq2_prty1_bb_b0}; - -static struct attn_hw_reg pglcs_int0_bb_b0 = { - 0, 1, 0x1d00, 0x1d0c, 0x1d08, 0x1d04}; - -static struct attn_hw_reg *pglcs_int_bb_b0_regs[1] = { - &pglcs_int0_bb_b0}; - -static struct attn_hw_reg dmae_int0_bb_b0 = { - 0, 2, 0xc180, 0xc18c, 0xc188, 0xc184}; - -static struct attn_hw_reg *dmae_int_bb_b0_regs[1] = { - &dmae_int0_bb_b0}; - -static struct attn_hw_reg dmae_prty1_bb_b0 = { - 0, 3, 0xc200, 0xc20c, 0xc208, 0xc204}; - -static struct attn_hw_reg *dmae_prty_bb_b0_regs[1] = { - &dmae_prty1_bb_b0}; - -static struct attn_hw_reg ptu_int0_bb_b0 = { - 0, 8, 0x560180, 0x56018c, 0x560188, 0x560184}; - -static struct attn_hw_reg *ptu_int_bb_b0_regs[1] = { - &ptu_int0_bb_b0}; - -static struct attn_hw_reg ptu_prty1_bb_b0 = { - 0, 18, 0x560200, 0x56020c, 0x560208, 0x560204}; - -static struct attn_hw_reg *ptu_prty_bb_b0_regs[1] = { - &ptu_prty1_bb_b0}; - -static struct attn_hw_reg tcm_int0_bb_b0 = { - 0, 8, 0x1180180, 0x118018c, 0x1180188, 0x1180184}; - -static struct attn_hw_reg tcm_int1_bb_b0 = { - 1, 32, 0x1180190, 0x118019c, 0x1180198, 0x1180194}; - -static struct attn_hw_reg tcm_int2_bb_b0 = { - 2, 1, 0x11801a0, 0x11801ac, 0x11801a8, 0x11801a4}; - -static struct attn_hw_reg *tcm_int_bb_b0_regs[3] = { - &tcm_int0_bb_b0, &tcm_int1_bb_b0, &tcm_int2_bb_b0}; - -static struct attn_hw_reg tcm_prty1_bb_b0 = { - 0, 31, 0x1180200, 0x118020c, 0x1180208, 0x1180204}; - -static struct attn_hw_reg tcm_prty2_bb_b0 = { - 1, 2, 0x1180210, 0x118021c, 0x1180218, 0x1180214}; - -static struct attn_hw_reg *tcm_prty_bb_b0_regs[2] = { - &tcm_prty1_bb_b0, &tcm_prty2_bb_b0}; - -static struct attn_hw_reg mcm_int0_bb_b0 = { - 0, 14, 0x1200180, 0x120018c, 0x1200188, 0x1200184}; - -static struct attn_hw_reg mcm_int1_bb_b0 = { - 1, 26, 0x1200190, 0x120019c, 0x1200198, 0x1200194}; - -static struct attn_hw_reg mcm_int2_bb_b0 = { - 2, 1, 0x12001a0, 0x12001ac, 0x12001a8, 0x12001a4}; - -static struct attn_hw_reg *mcm_int_bb_b0_regs[3] = { - &mcm_int0_bb_b0, &mcm_int1_bb_b0, &mcm_int2_bb_b0}; - -static struct attn_hw_reg mcm_prty1_bb_b0 = { - 0, 31, 0x1200200, 0x120020c, 0x1200208, 0x1200204}; - -static struct attn_hw_reg mcm_prty2_bb_b0 = { - 1, 4, 0x1200210, 0x120021c, 0x1200218, 0x1200214}; - -static struct attn_hw_reg *mcm_prty_bb_b0_regs[2] = { - &mcm_prty1_bb_b0, &mcm_prty2_bb_b0}; - -static struct attn_hw_reg ucm_int0_bb_b0 = { - 0, 17, 0x1280180, 0x128018c, 0x1280188, 0x1280184}; - -static struct attn_hw_reg ucm_int1_bb_b0 = { - 1, 29, 0x1280190, 0x128019c, 0x1280198, 0x1280194}; - -static struct attn_hw_reg ucm_int2_bb_b0 = { - 2, 1, 0x12801a0, 0x12801ac, 0x12801a8, 0x12801a4}; - -static struct attn_hw_reg *ucm_int_bb_b0_regs[3] = { - &ucm_int0_bb_b0, &ucm_int1_bb_b0, &ucm_int2_bb_b0}; - -static struct attn_hw_reg ucm_prty1_bb_b0 = { - 0, 31, 0x1280200, 0x128020c, 0x1280208, 0x1280204}; - -static struct attn_hw_reg ucm_prty2_bb_b0 = { - 1, 7, 0x1280210, 0x128021c, 0x1280218, 0x1280214}; - -static struct attn_hw_reg *ucm_prty_bb_b0_regs[2] = { - &ucm_prty1_bb_b0, &ucm_prty2_bb_b0}; - -static struct attn_hw_reg xcm_int0_bb_b0 = { - 0, 16, 0x1000180, 0x100018c, 0x1000188, 0x1000184}; - -static struct attn_hw_reg xcm_int1_bb_b0 = { - 1, 25, 0x1000190, 0x100019c, 0x1000198, 0x1000194}; - -static struct attn_hw_reg xcm_int2_bb_b0 = { - 2, 8, 0x10001a0, 0x10001ac, 0x10001a8, 0x10001a4}; - -static struct attn_hw_reg *xcm_int_bb_b0_regs[3] = { - &xcm_int0_bb_b0, &xcm_int1_bb_b0, &xcm_int2_bb_b0}; - -static struct attn_hw_reg xcm_prty1_bb_b0 = { - 0, 31, 0x1000200, 0x100020c, 0x1000208, 0x1000204}; - -static struct attn_hw_reg xcm_prty2_bb_b0 = { - 1, 11, 0x1000210, 0x100021c, 0x1000218, 0x1000214}; - -static struct attn_hw_reg *xcm_prty_bb_b0_regs[2] = { - &xcm_prty1_bb_b0, &xcm_prty2_bb_b0}; - -static struct attn_hw_reg ycm_int0_bb_b0 = { - 0, 13, 0x1080180, 0x108018c, 0x1080188, 0x1080184}; - -static struct attn_hw_reg ycm_int1_bb_b0 = { - 1, 23, 0x1080190, 0x108019c, 0x1080198, 0x1080194}; - -static struct attn_hw_reg ycm_int2_bb_b0 = { - 2, 1, 0x10801a0, 0x10801ac, 0x10801a8, 0x10801a4}; - -static struct attn_hw_reg *ycm_int_bb_b0_regs[3] = { - &ycm_int0_bb_b0, &ycm_int1_bb_b0, &ycm_int2_bb_b0}; - -static struct attn_hw_reg ycm_prty1_bb_b0 = { - 0, 31, 0x1080200, 0x108020c, 0x1080208, 0x1080204}; - -static struct attn_hw_reg ycm_prty2_bb_b0 = { - 1, 3, 0x1080210, 0x108021c, 0x1080218, 0x1080214}; - -static struct attn_hw_reg *ycm_prty_bb_b0_regs[2] = { - &ycm_prty1_bb_b0, &ycm_prty2_bb_b0}; - -static struct attn_hw_reg pcm_int0_bb_b0 = { - 0, 5, 0x1100180, 0x110018c, 0x1100188, 0x1100184}; - -static struct attn_hw_reg pcm_int1_bb_b0 = { - 1, 14, 0x1100190, 0x110019c, 0x1100198, 0x1100194}; - -static struct attn_hw_reg pcm_int2_bb_b0 = { - 2, 1, 0x11001a0, 0x11001ac, 0x11001a8, 0x11001a4}; - -static struct attn_hw_reg *pcm_int_bb_b0_regs[3] = { - &pcm_int0_bb_b0, &pcm_int1_bb_b0, &pcm_int2_bb_b0}; - -static struct attn_hw_reg pcm_prty1_bb_b0 = { - 0, 11, 0x1100200, 0x110020c, 0x1100208, 0x1100204}; - -static struct attn_hw_reg *pcm_prty_bb_b0_regs[1] = { - &pcm_prty1_bb_b0}; - -static struct attn_hw_reg qm_int0_bb_b0 = { - 0, 22, 0x2f0180, 0x2f018c, 0x2f0188, 0x2f0184}; - -static struct attn_hw_reg *qm_int_bb_b0_regs[1] = { - &qm_int0_bb_b0}; - -static struct attn_hw_reg qm_prty0_bb_b0 = { - 0, 11, 0x2f0190, 0x2f019c, 0x2f0198, 0x2f0194}; - -static struct attn_hw_reg qm_prty1_bb_b0 = { - 1, 31, 0x2f0200, 0x2f020c, 0x2f0208, 0x2f0204}; - -static struct attn_hw_reg qm_prty2_bb_b0 = { - 2, 31, 0x2f0210, 0x2f021c, 0x2f0218, 0x2f0214}; - -static struct attn_hw_reg qm_prty3_bb_b0 = { - 3, 11, 0x2f0220, 0x2f022c, 0x2f0228, 0x2f0224}; - -static struct attn_hw_reg *qm_prty_bb_b0_regs[4] = { - &qm_prty0_bb_b0, &qm_prty1_bb_b0, &qm_prty2_bb_b0, &qm_prty3_bb_b0}; - -static struct attn_hw_reg tm_int0_bb_b0 = { - 0, 32, 0x2c0180, 0x2c018c, 0x2c0188, 0x2c0184}; - -static struct attn_hw_reg tm_int1_bb_b0 = { - 1, 11, 0x2c0190, 0x2c019c, 0x2c0198, 0x2c0194}; - -static struct attn_hw_reg *tm_int_bb_b0_regs[2] = { - &tm_int0_bb_b0, &tm_int1_bb_b0}; - -static struct attn_hw_reg tm_prty1_bb_b0 = { - 0, 17, 0x2c0200, 0x2c020c, 0x2c0208, 0x2c0204}; - -static struct attn_hw_reg *tm_prty_bb_b0_regs[1] = { - &tm_prty1_bb_b0}; - -static struct attn_hw_reg dorq_int0_bb_b0 = { - 0, 9, 0x100180, 0x10018c, 0x100188, 0x100184}; - -static struct attn_hw_reg *dorq_int_bb_b0_regs[1] = { - &dorq_int0_bb_b0}; - -static struct attn_hw_reg dorq_prty0_bb_b0 = { - 0, 1, 0x100190, 0x10019c, 0x100198, 0x100194}; - -static struct attn_hw_reg dorq_prty1_bb_b0 = { - 1, 6, 0x100200, 0x10020c, 0x100208, 0x100204}; - -static struct attn_hw_reg *dorq_prty_bb_b0_regs[2] = { - &dorq_prty0_bb_b0, &dorq_prty1_bb_b0}; - -static struct attn_hw_reg brb_int0_bb_b0 = { - 0, 32, 0x3400c0, 0x3400cc, 0x3400c8, 0x3400c4}; - -static struct attn_hw_reg brb_int1_bb_b0 = { - 1, 30, 0x3400d8, 0x3400e4, 0x3400e0, 0x3400dc}; - -static struct attn_hw_reg brb_int2_bb_b0 = { - 2, 28, 0x3400f0, 0x3400fc, 0x3400f8, 0x3400f4}; - -static struct attn_hw_reg brb_int3_bb_b0 = { - 3, 31, 0x340108, 0x340114, 0x340110, 0x34010c}; - -static struct attn_hw_reg brb_int4_bb_b0 = { - 4, 27, 0x340120, 0x34012c, 0x340128, 0x340124}; - -static struct attn_hw_reg brb_int5_bb_b0 = { - 5, 1, 0x340138, 0x340144, 0x340140, 0x34013c}; - -static struct attn_hw_reg brb_int6_bb_b0 = { - 6, 8, 0x340150, 0x34015c, 0x340158, 0x340154}; - -static struct attn_hw_reg brb_int7_bb_b0 = { - 7, 32, 0x340168, 0x340174, 0x340170, 0x34016c}; - -static struct attn_hw_reg brb_int8_bb_b0 = { - 8, 17, 0x340184, 0x340190, 0x34018c, 0x340188}; - -static struct attn_hw_reg brb_int9_bb_b0 = { - 9, 1, 0x34019c, 0x3401a8, 0x3401a4, 0x3401a0}; - -static struct attn_hw_reg brb_int10_bb_b0 = { - 10, 14, 0x3401b4, 0x3401c0, 0x3401bc, 0x3401b8}; - -static struct attn_hw_reg brb_int11_bb_b0 = { - 11, 8, 0x3401cc, 0x3401d8, 0x3401d4, 0x3401d0}; - -static struct attn_hw_reg *brb_int_bb_b0_regs[12] = { - &brb_int0_bb_b0, &brb_int1_bb_b0, &brb_int2_bb_b0, &brb_int3_bb_b0, - &brb_int4_bb_b0, &brb_int5_bb_b0, &brb_int6_bb_b0, &brb_int7_bb_b0, - &brb_int8_bb_b0, &brb_int9_bb_b0, &brb_int10_bb_b0, &brb_int11_bb_b0}; - -static struct attn_hw_reg brb_prty0_bb_b0 = { - 0, 5, 0x3401dc, 0x3401e8, 0x3401e4, 0x3401e0}; - -static struct attn_hw_reg brb_prty1_bb_b0 = { - 1, 31, 0x340400, 0x34040c, 0x340408, 0x340404}; - -static struct attn_hw_reg brb_prty2_bb_b0 = { - 2, 14, 0x340410, 0x34041c, 0x340418, 0x340414}; - -static struct attn_hw_reg *brb_prty_bb_b0_regs[3] = { - &brb_prty0_bb_b0, &brb_prty1_bb_b0, &brb_prty2_bb_b0}; - -static struct attn_hw_reg src_int0_bb_b0 = { - 0, 1, 0x2381d8, 0x2381dc, 0x2381e0, 0x2381e4}; - -static struct attn_hw_reg *src_int_bb_b0_regs[1] = { - &src_int0_bb_b0}; - -static struct attn_hw_reg prs_int0_bb_b0 = { - 0, 2, 0x1f0040, 0x1f004c, 0x1f0048, 0x1f0044}; - -static struct attn_hw_reg *prs_int_bb_b0_regs[1] = { - &prs_int0_bb_b0}; - -static struct attn_hw_reg prs_prty0_bb_b0 = { - 0, 2, 0x1f0050, 0x1f005c, 0x1f0058, 0x1f0054}; - -static struct attn_hw_reg prs_prty1_bb_b0 = { - 1, 31, 0x1f0204, 0x1f0210, 0x1f020c, 0x1f0208}; - -static struct attn_hw_reg prs_prty2_bb_b0 = { - 2, 5, 0x1f0214, 0x1f0220, 0x1f021c, 0x1f0218}; - -static struct attn_hw_reg *prs_prty_bb_b0_regs[3] = { - &prs_prty0_bb_b0, &prs_prty1_bb_b0, &prs_prty2_bb_b0}; - -static struct attn_hw_reg tsdm_int0_bb_b0 = { - 0, 26, 0xfb0040, 0xfb004c, 0xfb0048, 0xfb0044}; - -static struct attn_hw_reg *tsdm_int_bb_b0_regs[1] = { - &tsdm_int0_bb_b0}; - -static struct attn_hw_reg tsdm_prty1_bb_b0 = { - 0, 10, 0xfb0200, 0xfb020c, 0xfb0208, 0xfb0204}; - -static struct attn_hw_reg *tsdm_prty_bb_b0_regs[1] = { - &tsdm_prty1_bb_b0}; - -static struct attn_hw_reg msdm_int0_bb_b0 = { - 0, 26, 0xfc0040, 0xfc004c, 0xfc0048, 0xfc0044}; - -static struct attn_hw_reg *msdm_int_bb_b0_regs[1] = { - &msdm_int0_bb_b0}; - -static struct attn_hw_reg msdm_prty1_bb_b0 = { - 0, 11, 0xfc0200, 0xfc020c, 0xfc0208, 0xfc0204}; - -static struct attn_hw_reg *msdm_prty_bb_b0_regs[1] = { - &msdm_prty1_bb_b0}; - -static struct attn_hw_reg usdm_int0_bb_b0 = { - 0, 26, 0xfd0040, 0xfd004c, 0xfd0048, 0xfd0044}; - -static struct attn_hw_reg *usdm_int_bb_b0_regs[1] = { - &usdm_int0_bb_b0}; - -static struct attn_hw_reg usdm_prty1_bb_b0 = { - 0, 10, 0xfd0200, 0xfd020c, 0xfd0208, 0xfd0204}; - -static struct attn_hw_reg *usdm_prty_bb_b0_regs[1] = { - &usdm_prty1_bb_b0}; - -static struct attn_hw_reg xsdm_int0_bb_b0 = { - 0, 26, 0xf80040, 0xf8004c, 0xf80048, 0xf80044}; - -static struct attn_hw_reg *xsdm_int_bb_b0_regs[1] = { - &xsdm_int0_bb_b0}; - -static struct attn_hw_reg xsdm_prty1_bb_b0 = { - 0, 10, 0xf80200, 0xf8020c, 0xf80208, 0xf80204}; - -static struct attn_hw_reg *xsdm_prty_bb_b0_regs[1] = { - &xsdm_prty1_bb_b0}; - -static struct attn_hw_reg ysdm_int0_bb_b0 = { - 0, 26, 0xf90040, 0xf9004c, 0xf90048, 0xf90044}; - -static struct attn_hw_reg *ysdm_int_bb_b0_regs[1] = { - &ysdm_int0_bb_b0}; - -static struct attn_hw_reg ysdm_prty1_bb_b0 = { - 0, 9, 0xf90200, 0xf9020c, 0xf90208, 0xf90204}; - -static struct attn_hw_reg *ysdm_prty_bb_b0_regs[1] = { - &ysdm_prty1_bb_b0}; - -static struct attn_hw_reg psdm_int0_bb_b0 = { - 0, 26, 0xfa0040, 0xfa004c, 0xfa0048, 0xfa0044}; - -static struct attn_hw_reg *psdm_int_bb_b0_regs[1] = { - &psdm_int0_bb_b0}; - -static struct attn_hw_reg psdm_prty1_bb_b0 = { - 0, 9, 0xfa0200, 0xfa020c, 0xfa0208, 0xfa0204}; - -static struct attn_hw_reg *psdm_prty_bb_b0_regs[1] = { - &psdm_prty1_bb_b0}; - -static struct attn_hw_reg tsem_int0_bb_b0 = { - 0, 32, 0x1700040, 0x170004c, 0x1700048, 0x1700044}; - -static struct attn_hw_reg tsem_int1_bb_b0 = { - 1, 13, 0x1700050, 0x170005c, 0x1700058, 0x1700054}; - -static struct attn_hw_reg tsem_fast_memory_int0_bb_b0 = { - 2, 1, 0x1740040, 0x174004c, 0x1740048, 0x1740044}; - -static struct attn_hw_reg *tsem_int_bb_b0_regs[3] = { - &tsem_int0_bb_b0, &tsem_int1_bb_b0, &tsem_fast_memory_int0_bb_b0}; - -static struct attn_hw_reg tsem_prty0_bb_b0 = { - 0, 3, 0x17000c8, 0x17000d4, 0x17000d0, 0x17000cc}; - -static struct attn_hw_reg tsem_prty1_bb_b0 = { - 1, 6, 0x1700200, 0x170020c, 0x1700208, 0x1700204}; - -static struct attn_hw_reg tsem_fast_memory_vfc_config_prty1_bb_b0 = { - 2, 6, 0x174a200, 0x174a20c, 0x174a208, 0x174a204}; - -static struct attn_hw_reg *tsem_prty_bb_b0_regs[3] = { - &tsem_prty0_bb_b0, &tsem_prty1_bb_b0, - &tsem_fast_memory_vfc_config_prty1_bb_b0}; - -static struct attn_hw_reg msem_int0_bb_b0 = { - 0, 32, 0x1800040, 0x180004c, 0x1800048, 0x1800044}; - -static struct attn_hw_reg msem_int1_bb_b0 = { - 1, 13, 0x1800050, 0x180005c, 0x1800058, 0x1800054}; - -static struct attn_hw_reg msem_fast_memory_int0_bb_b0 = { - 2, 1, 0x1840040, 0x184004c, 0x1840048, 0x1840044}; - -static struct attn_hw_reg *msem_int_bb_b0_regs[3] = { - &msem_int0_bb_b0, &msem_int1_bb_b0, &msem_fast_memory_int0_bb_b0}; - -static struct attn_hw_reg msem_prty0_bb_b0 = { - 0, 3, 0x18000c8, 0x18000d4, 0x18000d0, 0x18000cc}; - -static struct attn_hw_reg msem_prty1_bb_b0 = { - 1, 6, 0x1800200, 0x180020c, 0x1800208, 0x1800204}; - -static struct attn_hw_reg *msem_prty_bb_b0_regs[2] = { - &msem_prty0_bb_b0, &msem_prty1_bb_b0}; - -static struct attn_hw_reg usem_int0_bb_b0 = { - 0, 32, 0x1900040, 0x190004c, 0x1900048, 0x1900044}; - -static struct attn_hw_reg usem_int1_bb_b0 = { - 1, 13, 0x1900050, 0x190005c, 0x1900058, 0x1900054}; - -static struct attn_hw_reg usem_fast_memory_int0_bb_b0 = { - 2, 1, 0x1940040, 0x194004c, 0x1940048, 0x1940044}; - -static struct attn_hw_reg *usem_int_bb_b0_regs[3] = { - &usem_int0_bb_b0, &usem_int1_bb_b0, &usem_fast_memory_int0_bb_b0}; - -static struct attn_hw_reg usem_prty0_bb_b0 = { - 0, 3, 0x19000c8, 0x19000d4, 0x19000d0, 0x19000cc}; - -static struct attn_hw_reg usem_prty1_bb_b0 = { - 1, 6, 0x1900200, 0x190020c, 0x1900208, 0x1900204}; - -static struct attn_hw_reg *usem_prty_bb_b0_regs[2] = { - &usem_prty0_bb_b0, &usem_prty1_bb_b0}; - -static struct attn_hw_reg xsem_int0_bb_b0 = { - 0, 32, 0x1400040, 0x140004c, 0x1400048, 0x1400044}; - -static struct attn_hw_reg xsem_int1_bb_b0 = { - 1, 13, 0x1400050, 0x140005c, 0x1400058, 0x1400054}; - -static struct attn_hw_reg xsem_fast_memory_int0_bb_b0 = { - 2, 1, 0x1440040, 0x144004c, 0x1440048, 0x1440044}; - -static struct attn_hw_reg *xsem_int_bb_b0_regs[3] = { - &xsem_int0_bb_b0, &xsem_int1_bb_b0, &xsem_fast_memory_int0_bb_b0}; - -static struct attn_hw_reg xsem_prty0_bb_b0 = { - 0, 3, 0x14000c8, 0x14000d4, 0x14000d0, 0x14000cc}; - -static struct attn_hw_reg xsem_prty1_bb_b0 = { - 1, 7, 0x1400200, 0x140020c, 0x1400208, 0x1400204}; - -static struct attn_hw_reg *xsem_prty_bb_b0_regs[2] = { - &xsem_prty0_bb_b0, &xsem_prty1_bb_b0}; - -static struct attn_hw_reg ysem_int0_bb_b0 = { - 0, 32, 0x1500040, 0x150004c, 0x1500048, 0x1500044}; - -static struct attn_hw_reg ysem_int1_bb_b0 = { - 1, 13, 0x1500050, 0x150005c, 0x1500058, 0x1500054}; - -static struct attn_hw_reg ysem_fast_memory_int0_bb_b0 = { - 2, 1, 0x1540040, 0x154004c, 0x1540048, 0x1540044}; - -static struct attn_hw_reg *ysem_int_bb_b0_regs[3] = { - &ysem_int0_bb_b0, &ysem_int1_bb_b0, &ysem_fast_memory_int0_bb_b0}; - -static struct attn_hw_reg ysem_prty0_bb_b0 = { - 0, 3, 0x15000c8, 0x15000d4, 0x15000d0, 0x15000cc}; - -static struct attn_hw_reg ysem_prty1_bb_b0 = { - 1, 7, 0x1500200, 0x150020c, 0x1500208, 0x1500204}; - -static struct attn_hw_reg *ysem_prty_bb_b0_regs[2] = { - &ysem_prty0_bb_b0, &ysem_prty1_bb_b0}; - -static struct attn_hw_reg psem_int0_bb_b0 = { - 0, 32, 0x1600040, 0x160004c, 0x1600048, 0x1600044}; - -static struct attn_hw_reg psem_int1_bb_b0 = { - 1, 13, 0x1600050, 0x160005c, 0x1600058, 0x1600054}; - -static struct attn_hw_reg psem_fast_memory_int0_bb_b0 = { - 2, 1, 0x1640040, 0x164004c, 0x1640048, 0x1640044}; - -static struct attn_hw_reg *psem_int_bb_b0_regs[3] = { - &psem_int0_bb_b0, &psem_int1_bb_b0, &psem_fast_memory_int0_bb_b0}; - -static struct attn_hw_reg psem_prty0_bb_b0 = { - 0, 3, 0x16000c8, 0x16000d4, 0x16000d0, 0x16000cc}; - -static struct attn_hw_reg psem_prty1_bb_b0 = { - 1, 6, 0x1600200, 0x160020c, 0x1600208, 0x1600204}; - -static struct attn_hw_reg psem_fast_memory_vfc_config_prty1_bb_b0 = { - 2, 6, 0x164a200, 0x164a20c, 0x164a208, 0x164a204}; - -static struct attn_hw_reg *psem_prty_bb_b0_regs[3] = { - &psem_prty0_bb_b0, &psem_prty1_bb_b0, - &psem_fast_memory_vfc_config_prty1_bb_b0}; - -static struct attn_hw_reg rss_int0_bb_b0 = { - 0, 12, 0x238980, 0x23898c, 0x238988, 0x238984}; - -static struct attn_hw_reg *rss_int_bb_b0_regs[1] = { - &rss_int0_bb_b0}; - -static struct attn_hw_reg rss_prty1_bb_b0 = { - 0, 4, 0x238a00, 0x238a0c, 0x238a08, 0x238a04}; - -static struct attn_hw_reg *rss_prty_bb_b0_regs[1] = { - &rss_prty1_bb_b0}; - -static struct attn_hw_reg tmld_int0_bb_b0 = { - 0, 6, 0x4d0180, 0x4d018c, 0x4d0188, 0x4d0184}; - -static struct attn_hw_reg *tmld_int_bb_b0_regs[1] = { - &tmld_int0_bb_b0}; - -static struct attn_hw_reg tmld_prty1_bb_b0 = { - 0, 8, 0x4d0200, 0x4d020c, 0x4d0208, 0x4d0204}; - -static struct attn_hw_reg *tmld_prty_bb_b0_regs[1] = { - &tmld_prty1_bb_b0}; - -static struct attn_hw_reg muld_int0_bb_b0 = { - 0, 6, 0x4e0180, 0x4e018c, 0x4e0188, 0x4e0184}; - -static struct attn_hw_reg *muld_int_bb_b0_regs[1] = { - &muld_int0_bb_b0}; - -static struct attn_hw_reg muld_prty1_bb_b0 = { - 0, 10, 0x4e0200, 0x4e020c, 0x4e0208, 0x4e0204}; - -static struct attn_hw_reg *muld_prty_bb_b0_regs[1] = { - &muld_prty1_bb_b0}; - -static struct attn_hw_reg yuld_int0_bb_b0 = { - 0, 6, 0x4c8180, 0x4c818c, 0x4c8188, 0x4c8184}; - -static struct attn_hw_reg *yuld_int_bb_b0_regs[1] = { - &yuld_int0_bb_b0}; - -static struct attn_hw_reg yuld_prty1_bb_b0 = { - 0, 6, 0x4c8200, 0x4c820c, 0x4c8208, 0x4c8204}; - -static struct attn_hw_reg *yuld_prty_bb_b0_regs[1] = { - &yuld_prty1_bb_b0}; - -static struct attn_hw_reg xyld_int0_bb_b0 = { - 0, 6, 0x4c0180, 0x4c018c, 0x4c0188, 0x4c0184}; - -static struct attn_hw_reg *xyld_int_bb_b0_regs[1] = { - &xyld_int0_bb_b0}; - -static struct attn_hw_reg xyld_prty1_bb_b0 = { - 0, 9, 0x4c0200, 0x4c020c, 0x4c0208, 0x4c0204}; - -static struct attn_hw_reg *xyld_prty_bb_b0_regs[1] = { - &xyld_prty1_bb_b0}; - -static struct attn_hw_reg prm_int0_bb_b0 = { - 0, 11, 0x230040, 0x23004c, 0x230048, 0x230044}; - -static struct attn_hw_reg *prm_int_bb_b0_regs[1] = { - &prm_int0_bb_b0}; - -static struct attn_hw_reg prm_prty0_bb_b0 = { - 0, 1, 0x230050, 0x23005c, 0x230058, 0x230054}; - -static struct attn_hw_reg prm_prty1_bb_b0 = { - 1, 24, 0x230200, 0x23020c, 0x230208, 0x230204}; - -static struct attn_hw_reg *prm_prty_bb_b0_regs[2] = { - &prm_prty0_bb_b0, &prm_prty1_bb_b0}; - -static struct attn_hw_reg pbf_pb1_int0_bb_b0 = { - 0, 9, 0xda0040, 0xda004c, 0xda0048, 0xda0044}; - -static struct attn_hw_reg *pbf_pb1_int_bb_b0_regs[1] = { - &pbf_pb1_int0_bb_b0}; - -static struct attn_hw_reg pbf_pb1_prty0_bb_b0 = { - 0, 1, 0xda0050, 0xda005c, 0xda0058, 0xda0054}; - -static struct attn_hw_reg *pbf_pb1_prty_bb_b0_regs[1] = { - &pbf_pb1_prty0_bb_b0}; - -static struct attn_hw_reg pbf_pb2_int0_bb_b0 = { - 0, 9, 0xda4040, 0xda404c, 0xda4048, 0xda4044}; - -static struct attn_hw_reg *pbf_pb2_int_bb_b0_regs[1] = { - &pbf_pb2_int0_bb_b0}; - -static struct attn_hw_reg pbf_pb2_prty0_bb_b0 = { - 0, 1, 0xda4050, 0xda405c, 0xda4058, 0xda4054}; - -static struct attn_hw_reg *pbf_pb2_prty_bb_b0_regs[1] = { - &pbf_pb2_prty0_bb_b0}; - -static struct attn_hw_reg rpb_int0_bb_b0 = { - 0, 9, 0x23c040, 0x23c04c, 0x23c048, 0x23c044}; - -static struct attn_hw_reg *rpb_int_bb_b0_regs[1] = { - &rpb_int0_bb_b0}; - -static struct attn_hw_reg rpb_prty0_bb_b0 = { - 0, 1, 0x23c050, 0x23c05c, 0x23c058, 0x23c054}; - -static struct attn_hw_reg *rpb_prty_bb_b0_regs[1] = { - &rpb_prty0_bb_b0}; - -static struct attn_hw_reg btb_int0_bb_b0 = { - 0, 16, 0xdb00c0, 0xdb00cc, 0xdb00c8, 0xdb00c4}; - -static struct attn_hw_reg btb_int1_bb_b0 = { - 1, 16, 0xdb00d8, 0xdb00e4, 0xdb00e0, 0xdb00dc}; - -static struct attn_hw_reg btb_int2_bb_b0 = { - 2, 4, 0xdb00f0, 0xdb00fc, 0xdb00f8, 0xdb00f4}; - -static struct attn_hw_reg btb_int3_bb_b0 = { - 3, 32, 0xdb0108, 0xdb0114, 0xdb0110, 0xdb010c}; - -static struct attn_hw_reg btb_int4_bb_b0 = { - 4, 23, 0xdb0120, 0xdb012c, 0xdb0128, 0xdb0124}; - -static struct attn_hw_reg btb_int5_bb_b0 = { - 5, 32, 0xdb0138, 0xdb0144, 0xdb0140, 0xdb013c}; - -static struct attn_hw_reg btb_int6_bb_b0 = { - 6, 1, 0xdb0150, 0xdb015c, 0xdb0158, 0xdb0154}; - -static struct attn_hw_reg btb_int8_bb_b0 = { - 7, 1, 0xdb0184, 0xdb0190, 0xdb018c, 0xdb0188}; - -static struct attn_hw_reg btb_int9_bb_b0 = { - 8, 1, 0xdb019c, 0xdb01a8, 0xdb01a4, 0xdb01a0}; - -static struct attn_hw_reg btb_int10_bb_b0 = { - 9, 1, 0xdb01b4, 0xdb01c0, 0xdb01bc, 0xdb01b8}; - -static struct attn_hw_reg btb_int11_bb_b0 = { - 10, 2, 0xdb01cc, 0xdb01d8, 0xdb01d4, 0xdb01d0}; - -static struct attn_hw_reg *btb_int_bb_b0_regs[11] = { - &btb_int0_bb_b0, &btb_int1_bb_b0, &btb_int2_bb_b0, &btb_int3_bb_b0, - &btb_int4_bb_b0, &btb_int5_bb_b0, &btb_int6_bb_b0, &btb_int8_bb_b0, - &btb_int9_bb_b0, &btb_int10_bb_b0, &btb_int11_bb_b0}; - -static struct attn_hw_reg btb_prty0_bb_b0 = { - 0, 5, 0xdb01dc, 0xdb01e8, 0xdb01e4, 0xdb01e0}; - -static struct attn_hw_reg btb_prty1_bb_b0 = { - 1, 23, 0xdb0400, 0xdb040c, 0xdb0408, 0xdb0404}; - -static struct attn_hw_reg *btb_prty_bb_b0_regs[2] = { - &btb_prty0_bb_b0, &btb_prty1_bb_b0}; - -static struct attn_hw_reg pbf_int0_bb_b0 = { - 0, 1, 0xd80180, 0xd8018c, 0xd80188, 0xd80184}; - -static struct attn_hw_reg *pbf_int_bb_b0_regs[1] = { - &pbf_int0_bb_b0}; - -static struct attn_hw_reg pbf_prty0_bb_b0 = { - 0, 1, 0xd80190, 0xd8019c, 0xd80198, 0xd80194}; - -static struct attn_hw_reg pbf_prty1_bb_b0 = { - 1, 31, 0xd80200, 0xd8020c, 0xd80208, 0xd80204}; - -static struct attn_hw_reg pbf_prty2_bb_b0 = { - 2, 27, 0xd80210, 0xd8021c, 0xd80218, 0xd80214}; - -static struct attn_hw_reg *pbf_prty_bb_b0_regs[3] = { - &pbf_prty0_bb_b0, &pbf_prty1_bb_b0, &pbf_prty2_bb_b0}; - -static struct attn_hw_reg rdif_int0_bb_b0 = { - 0, 8, 0x300180, 0x30018c, 0x300188, 0x300184}; - -static struct attn_hw_reg *rdif_int_bb_b0_regs[1] = { - &rdif_int0_bb_b0}; - -static struct attn_hw_reg rdif_prty0_bb_b0 = { - 0, 1, 0x300190, 0x30019c, 0x300198, 0x300194}; - -static struct attn_hw_reg *rdif_prty_bb_b0_regs[1] = { - &rdif_prty0_bb_b0}; - -static struct attn_hw_reg tdif_int0_bb_b0 = { - 0, 8, 0x310180, 0x31018c, 0x310188, 0x310184}; - -static struct attn_hw_reg *tdif_int_bb_b0_regs[1] = { - &tdif_int0_bb_b0}; - -static struct attn_hw_reg tdif_prty0_bb_b0 = { - 0, 1, 0x310190, 0x31019c, 0x310198, 0x310194}; - -static struct attn_hw_reg tdif_prty1_bb_b0 = { - 1, 11, 0x310200, 0x31020c, 0x310208, 0x310204}; - -static struct attn_hw_reg *tdif_prty_bb_b0_regs[2] = { - &tdif_prty0_bb_b0, &tdif_prty1_bb_b0}; - -static struct attn_hw_reg cdu_int0_bb_b0 = { - 0, 8, 0x5801c0, 0x5801c4, 0x5801c8, 0x5801cc}; - -static struct attn_hw_reg *cdu_int_bb_b0_regs[1] = { - &cdu_int0_bb_b0}; - -static struct attn_hw_reg cdu_prty1_bb_b0 = { - 0, 5, 0x580200, 0x58020c, 0x580208, 0x580204}; - -static struct attn_hw_reg *cdu_prty_bb_b0_regs[1] = { - &cdu_prty1_bb_b0}; - -static struct attn_hw_reg ccfc_int0_bb_b0 = { - 0, 2, 0x2e0180, 0x2e018c, 0x2e0188, 0x2e0184}; - -static struct attn_hw_reg *ccfc_int_bb_b0_regs[1] = { - &ccfc_int0_bb_b0}; - -static struct attn_hw_reg ccfc_prty1_bb_b0 = { - 0, 2, 0x2e0200, 0x2e020c, 0x2e0208, 0x2e0204}; - -static struct attn_hw_reg ccfc_prty0_bb_b0 = { - 1, 6, 0x2e05e4, 0x2e05f0, 0x2e05ec, 0x2e05e8}; - -static struct attn_hw_reg *ccfc_prty_bb_b0_regs[2] = { - &ccfc_prty1_bb_b0, &ccfc_prty0_bb_b0}; - -static struct attn_hw_reg tcfc_int0_bb_b0 = { - 0, 2, 0x2d0180, 0x2d018c, 0x2d0188, 0x2d0184}; - -static struct attn_hw_reg *tcfc_int_bb_b0_regs[1] = { - &tcfc_int0_bb_b0}; - -static struct attn_hw_reg tcfc_prty1_bb_b0 = { - 0, 2, 0x2d0200, 0x2d020c, 0x2d0208, 0x2d0204}; - -static struct attn_hw_reg tcfc_prty0_bb_b0 = { - 1, 6, 0x2d05e4, 0x2d05f0, 0x2d05ec, 0x2d05e8}; - -static struct attn_hw_reg *tcfc_prty_bb_b0_regs[2] = { - &tcfc_prty1_bb_b0, &tcfc_prty0_bb_b0}; - -static struct attn_hw_reg igu_int0_bb_b0 = { - 0, 11, 0x180180, 0x18018c, 0x180188, 0x180184}; - -static struct attn_hw_reg *igu_int_bb_b0_regs[1] = { - &igu_int0_bb_b0}; - -static struct attn_hw_reg igu_prty0_bb_b0 = { - 0, 1, 0x180190, 0x18019c, 0x180198, 0x180194}; - -static struct attn_hw_reg igu_prty1_bb_b0 = { - 1, 31, 0x180200, 0x18020c, 0x180208, 0x180204}; - -static struct attn_hw_reg igu_prty2_bb_b0 = { - 2, 1, 0x180210, 0x18021c, 0x180218, 0x180214}; - -static struct attn_hw_reg *igu_prty_bb_b0_regs[3] = { - &igu_prty0_bb_b0, &igu_prty1_bb_b0, &igu_prty2_bb_b0}; - -static struct attn_hw_reg cau_int0_bb_b0 = { - 0, 11, 0x1c00d4, 0x1c00d8, 0x1c00dc, 0x1c00e0}; - -static struct attn_hw_reg *cau_int_bb_b0_regs[1] = { - &cau_int0_bb_b0}; - -static struct attn_hw_reg cau_prty1_bb_b0 = { - 0, 13, 0x1c0200, 0x1c020c, 0x1c0208, 0x1c0204}; - -static struct attn_hw_reg *cau_prty_bb_b0_regs[1] = { - &cau_prty1_bb_b0}; - -static struct attn_hw_reg dbg_int0_bb_b0 = { - 0, 1, 0x10180, 0x1018c, 0x10188, 0x10184}; - -static struct attn_hw_reg *dbg_int_bb_b0_regs[1] = { - &dbg_int0_bb_b0}; - -static struct attn_hw_reg dbg_prty1_bb_b0 = { - 0, 1, 0x10200, 0x1020c, 0x10208, 0x10204}; - -static struct attn_hw_reg *dbg_prty_bb_b0_regs[1] = { - &dbg_prty1_bb_b0}; - -static struct attn_hw_reg nig_int0_bb_b0 = { - 0, 12, 0x500040, 0x50004c, 0x500048, 0x500044}; - -static struct attn_hw_reg nig_int1_bb_b0 = { - 1, 32, 0x500050, 0x50005c, 0x500058, 0x500054}; - -static struct attn_hw_reg nig_int2_bb_b0 = { - 2, 20, 0x500060, 0x50006c, 0x500068, 0x500064}; - -static struct attn_hw_reg nig_int3_bb_b0 = { - 3, 18, 0x500070, 0x50007c, 0x500078, 0x500074}; - -static struct attn_hw_reg nig_int4_bb_b0 = { - 4, 20, 0x500080, 0x50008c, 0x500088, 0x500084}; - -static struct attn_hw_reg nig_int5_bb_b0 = { - 5, 18, 0x500090, 0x50009c, 0x500098, 0x500094}; - -static struct attn_hw_reg *nig_int_bb_b0_regs[6] = { - &nig_int0_bb_b0, &nig_int1_bb_b0, &nig_int2_bb_b0, &nig_int3_bb_b0, - &nig_int4_bb_b0, &nig_int5_bb_b0}; - -static struct attn_hw_reg nig_prty0_bb_b0 = { - 0, 1, 0x5000a0, 0x5000ac, 0x5000a8, 0x5000a4}; - -static struct attn_hw_reg nig_prty1_bb_b0 = { - 1, 31, 0x500200, 0x50020c, 0x500208, 0x500204}; - -static struct attn_hw_reg nig_prty2_bb_b0 = { - 2, 31, 0x500210, 0x50021c, 0x500218, 0x500214}; - -static struct attn_hw_reg nig_prty3_bb_b0 = { - 3, 31, 0x500220, 0x50022c, 0x500228, 0x500224}; - -static struct attn_hw_reg nig_prty4_bb_b0 = { - 4, 17, 0x500230, 0x50023c, 0x500238, 0x500234}; - -static struct attn_hw_reg *nig_prty_bb_b0_regs[5] = { - &nig_prty0_bb_b0, &nig_prty1_bb_b0, &nig_prty2_bb_b0, - &nig_prty3_bb_b0, &nig_prty4_bb_b0}; - -static struct attn_hw_reg ipc_int0_bb_b0 = { - 0, 13, 0x2050c, 0x20518, 0x20514, 0x20510}; - -static struct attn_hw_reg *ipc_int_bb_b0_regs[1] = { - &ipc_int0_bb_b0}; - -static struct attn_hw_reg ipc_prty0_bb_b0 = { - 0, 1, 0x2051c, 0x20528, 0x20524, 0x20520}; - -static struct attn_hw_reg *ipc_prty_bb_b0_regs[1] = { - &ipc_prty0_bb_b0}; - -static struct attn_hw_block attn_blocks[] = { - {"grc", {{1, 1, grc_int_bb_b0_regs, grc_prty_bb_b0_regs} } }, - {"miscs", {{2, 1, miscs_int_bb_b0_regs, miscs_prty_bb_b0_regs} } }, - {"misc", {{1, 0, misc_int_bb_b0_regs, NULL} } }, - {"dbu", {{0, 0, NULL, NULL} } }, - {"pglue_b", {{1, 2, pglue_b_int_bb_b0_regs, - pglue_b_prty_bb_b0_regs} } }, - {"cnig", {{1, 1, cnig_int_bb_b0_regs, cnig_prty_bb_b0_regs} } }, - {"cpmu", {{1, 0, cpmu_int_bb_b0_regs, NULL} } }, - {"ncsi", {{1, 1, ncsi_int_bb_b0_regs, ncsi_prty_bb_b0_regs} } }, - {"opte", {{0, 2, NULL, opte_prty_bb_b0_regs} } }, - {"bmb", {{12, 3, bmb_int_bb_b0_regs, bmb_prty_bb_b0_regs} } }, - {"pcie", {{0, 1, NULL, pcie_prty_bb_b0_regs} } }, - {"mcp", {{0, 0, NULL, NULL} } }, - {"mcp2", {{0, 2, NULL, mcp2_prty_bb_b0_regs} } }, - {"pswhst", {{1, 2, pswhst_int_bb_b0_regs, pswhst_prty_bb_b0_regs} } }, - {"pswhst2", {{1, 1, pswhst2_int_bb_b0_regs, - pswhst2_prty_bb_b0_regs} } }, - {"pswrd", {{1, 1, pswrd_int_bb_b0_regs, pswrd_prty_bb_b0_regs} } }, - {"pswrd2", {{1, 3, pswrd2_int_bb_b0_regs, pswrd2_prty_bb_b0_regs} } }, - {"pswwr", {{1, 1, pswwr_int_bb_b0_regs, pswwr_prty_bb_b0_regs} } }, - {"pswwr2", {{1, 5, pswwr2_int_bb_b0_regs, pswwr2_prty_bb_b0_regs} } }, - {"pswrq", {{1, 1, pswrq_int_bb_b0_regs, pswrq_prty_bb_b0_regs} } }, - {"pswrq2", {{1, 1, pswrq2_int_bb_b0_regs, pswrq2_prty_bb_b0_regs} } }, - {"pglcs", {{1, 0, pglcs_int_bb_b0_regs, NULL} } }, - {"dmae", {{1, 1, dmae_int_bb_b0_regs, dmae_prty_bb_b0_regs} } }, - {"ptu", {{1, 1, ptu_int_bb_b0_regs, ptu_prty_bb_b0_regs} } }, - {"tcm", {{3, 2, tcm_int_bb_b0_regs, tcm_prty_bb_b0_regs} } }, - {"mcm", {{3, 2, mcm_int_bb_b0_regs, mcm_prty_bb_b0_regs} } }, - {"ucm", {{3, 2, ucm_int_bb_b0_regs, ucm_prty_bb_b0_regs} } }, - {"xcm", {{3, 2, xcm_int_bb_b0_regs, xcm_prty_bb_b0_regs} } }, - {"ycm", {{3, 2, ycm_int_bb_b0_regs, ycm_prty_bb_b0_regs} } }, - {"pcm", {{3, 1, pcm_int_bb_b0_regs, pcm_prty_bb_b0_regs} } }, - {"qm", {{1, 4, qm_int_bb_b0_regs, qm_prty_bb_b0_regs} } }, - {"tm", {{2, 1, tm_int_bb_b0_regs, tm_prty_bb_b0_regs} } }, - {"dorq", {{1, 2, dorq_int_bb_b0_regs, dorq_prty_bb_b0_regs} } }, - {"brb", {{12, 3, brb_int_bb_b0_regs, brb_prty_bb_b0_regs} } }, - {"src", {{1, 0, src_int_bb_b0_regs, NULL} } }, - {"prs", {{1, 3, prs_int_bb_b0_regs, prs_prty_bb_b0_regs} } }, - {"tsdm", {{1, 1, tsdm_int_bb_b0_regs, tsdm_prty_bb_b0_regs} } }, - {"msdm", {{1, 1, msdm_int_bb_b0_regs, msdm_prty_bb_b0_regs} } }, - {"usdm", {{1, 1, usdm_int_bb_b0_regs, usdm_prty_bb_b0_regs} } }, - {"xsdm", {{1, 1, xsdm_int_bb_b0_regs, xsdm_prty_bb_b0_regs} } }, - {"ysdm", {{1, 1, ysdm_int_bb_b0_regs, ysdm_prty_bb_b0_regs} } }, - {"psdm", {{1, 1, psdm_int_bb_b0_regs, psdm_prty_bb_b0_regs} } }, - {"tsem", {{3, 3, tsem_int_bb_b0_regs, tsem_prty_bb_b0_regs} } }, - {"msem", {{3, 2, msem_int_bb_b0_regs, msem_prty_bb_b0_regs} } }, - {"usem", {{3, 2, usem_int_bb_b0_regs, usem_prty_bb_b0_regs} } }, - {"xsem", {{3, 2, xsem_int_bb_b0_regs, xsem_prty_bb_b0_regs} } }, - {"ysem", {{3, 2, ysem_int_bb_b0_regs, ysem_prty_bb_b0_regs} } }, - {"psem", {{3, 3, psem_int_bb_b0_regs, psem_prty_bb_b0_regs} } }, - {"rss", {{1, 1, rss_int_bb_b0_regs, rss_prty_bb_b0_regs} } }, - {"tmld", {{1, 1, tmld_int_bb_b0_regs, tmld_prty_bb_b0_regs} } }, - {"muld", {{1, 1, muld_int_bb_b0_regs, muld_prty_bb_b0_regs} } }, - {"yuld", {{1, 1, yuld_int_bb_b0_regs, yuld_prty_bb_b0_regs} } }, - {"xyld", {{1, 1, xyld_int_bb_b0_regs, xyld_prty_bb_b0_regs} } }, - {"prm", {{1, 2, prm_int_bb_b0_regs, prm_prty_bb_b0_regs} } }, - {"pbf_pb1", {{1, 1, pbf_pb1_int_bb_b0_regs, - pbf_pb1_prty_bb_b0_regs} } }, - {"pbf_pb2", {{1, 1, pbf_pb2_int_bb_b0_regs, - pbf_pb2_prty_bb_b0_regs} } }, - {"rpb", { {1, 1, rpb_int_bb_b0_regs, rpb_prty_bb_b0_regs} } }, - {"btb", { {11, 2, btb_int_bb_b0_regs, btb_prty_bb_b0_regs} } }, - {"pbf", { {1, 3, pbf_int_bb_b0_regs, pbf_prty_bb_b0_regs} } }, - {"rdif", { {1, 1, rdif_int_bb_b0_regs, rdif_prty_bb_b0_regs} } }, - {"tdif", { {1, 2, tdif_int_bb_b0_regs, tdif_prty_bb_b0_regs} } }, - {"cdu", { {1, 1, cdu_int_bb_b0_regs, cdu_prty_bb_b0_regs} } }, - {"ccfc", { {1, 2, ccfc_int_bb_b0_regs, ccfc_prty_bb_b0_regs} } }, - {"tcfc", { {1, 2, tcfc_int_bb_b0_regs, tcfc_prty_bb_b0_regs} } }, - {"igu", { {1, 3, igu_int_bb_b0_regs, igu_prty_bb_b0_regs} } }, - {"cau", { {1, 1, cau_int_bb_b0_regs, cau_prty_bb_b0_regs} } }, - {"umac", { {0, 0, NULL, NULL} } }, - {"xmac", { {0, 0, NULL, NULL} } }, - {"dbg", { {1, 1, dbg_int_bb_b0_regs, dbg_prty_bb_b0_regs} } }, - {"nig", { {6, 5, nig_int_bb_b0_regs, nig_prty_bb_b0_regs} } }, - {"wol", { {0, 0, NULL, NULL} } }, - {"bmbn", { {0, 0, NULL, NULL} } }, - {"ipc", { {1, 1, ipc_int_bb_b0_regs, ipc_prty_bb_b0_regs} } }, - {"nwm", { {0, 0, NULL, NULL} } }, - {"nws", { {0, 0, NULL, NULL} } }, - {"ms", { {0, 0, NULL, NULL} } }, - {"phy_pcie", { {0, 0, NULL, NULL} } }, - {"misc_aeu", { {0, 0, NULL, NULL} } }, - {"bar0_map", { {0, 0, NULL, NULL} } },}; - /* Specific HW attention callbacks */ static int qed_mcp_attn_cb(struct qed_hwfn *p_hwfn) { @@ -1590,6 +387,25 @@ static int qed_dorq_attn_cb(struct qed_hwfn *p_hwfn) return -EINVAL; } +/* Instead of major changes to the data-structure, we have a some 'special' + * identifiers for sources that changed meaning between adapters. + */ +enum aeu_invert_reg_special_type { + AEU_INVERT_REG_SPECIAL_CNIG_0, + AEU_INVERT_REG_SPECIAL_CNIG_1, + AEU_INVERT_REG_SPECIAL_CNIG_2, + AEU_INVERT_REG_SPECIAL_CNIG_3, + AEU_INVERT_REG_SPECIAL_MAX, +}; + +static struct aeu_invert_reg_bit +aeu_descs_special[AEU_INVERT_REG_SPECIAL_MAX] = { + {"CNIG port 0", ATTENTION_SINGLE, NULL, BLOCK_CNIG}, + {"CNIG port 1", ATTENTION_SINGLE, NULL, BLOCK_CNIG}, + {"CNIG port 2", ATTENTION_SINGLE, NULL, BLOCK_CNIG}, + {"CNIG port 3", ATTENTION_SINGLE, NULL, BLOCK_CNIG}, +}; + /* Notice aeu_invert_reg must be defined in the same order of bits as HW; */ static struct aeu_invert_reg aeu_descs[NUM_ATTN_REGS] = { { @@ -1636,8 +452,22 @@ static struct aeu_invert_reg aeu_descs[NUM_ATTN_REGS] = { (33 << ATTENTION_OFFSET_SHIFT), NULL, MAX_BLOCK_ID}, {"General Attention 35", ATTENTION_SINGLE, NULL, MAX_BLOCK_ID}, - {"CNIG port %d", (4 << ATTENTION_LENGTH_SHIFT), - NULL, BLOCK_CNIG}, + {"NWS Parity", + ATTENTION_PAR | ATTENTION_BB_DIFFERENT | + ATTENTION_BB(AEU_INVERT_REG_SPECIAL_CNIG_0), + NULL, BLOCK_NWS}, + {"NWS Interrupt", + ATTENTION_SINGLE | ATTENTION_BB_DIFFERENT | + ATTENTION_BB(AEU_INVERT_REG_SPECIAL_CNIG_1), + NULL, BLOCK_NWS}, + {"NWM Parity", + ATTENTION_PAR | ATTENTION_BB_DIFFERENT | + ATTENTION_BB(AEU_INVERT_REG_SPECIAL_CNIG_2), + NULL, BLOCK_NWM}, + {"NWM Interrupt", + ATTENTION_SINGLE | ATTENTION_BB_DIFFERENT | + ATTENTION_BB(AEU_INVERT_REG_SPECIAL_CNIG_3), + NULL, BLOCK_NWM}, {"MCP CPU", ATTENTION_SINGLE, qed_mcp_attn_cb, MAX_BLOCK_ID}, {"MCP Watchdog timer", ATTENTION_SINGLE, @@ -1775,6 +605,27 @@ static struct aeu_invert_reg aeu_descs[NUM_ATTN_REGS] = { }, }; +static struct aeu_invert_reg_bit * +qed_int_aeu_translate(struct qed_hwfn *p_hwfn, + struct aeu_invert_reg_bit *p_bit) +{ + if (!QED_IS_BB(p_hwfn->cdev)) + return p_bit; + + if (!(p_bit->flags & ATTENTION_BB_DIFFERENT)) + return p_bit; + + return &aeu_descs_special[(p_bit->flags & ATTENTION_BB_MASK) >> + ATTENTION_BB_SHIFT]; +} + +static bool qed_int_is_parity_flag(struct qed_hwfn *p_hwfn, + struct aeu_invert_reg_bit *p_bit) +{ + return !!(qed_int_aeu_translate(p_hwfn, p_bit)->flags & + ATTENTION_PARITY); +} + #define ATTN_STATE_BITS (0xfff) #define ATTN_BITS_MASKABLE (0x3ff) struct qed_sb_attn_info { @@ -1863,26 +714,23 @@ static int qed_int_assertion(struct qed_hwfn *p_hwfn, u16 asserted_bits) return 0; } -static void qed_int_deassertion_print_bit(struct qed_hwfn *p_hwfn, - struct attn_hw_reg *p_reg_desc, - struct attn_hw_block *p_block, - enum qed_attention_type type, - u32 val, u32 mask) +static void qed_int_attn_print(struct qed_hwfn *p_hwfn, + enum block_id id, + enum dbg_attn_type type, bool b_clear) { - int j; + struct dbg_attn_block_result attn_results; + enum dbg_status status; - for (j = 0; j < p_reg_desc->num_of_bits; j++) { - if (!(val & (1 << j))) - continue; + memset(&attn_results, 0, sizeof(attn_results)); + status = qed_dbg_read_attn(p_hwfn, p_hwfn->p_dpc_ptt, id, type, + b_clear, &attn_results); + if (status != DBG_STATUS_OK) DP_NOTICE(p_hwfn, - "%s (%s): reg %d [0x%08x], bit %d [%s]\n", - p_block->name, - type == QED_ATTN_TYPE_ATTN ? "Interrupt" : - "Parity", - p_reg_desc->reg_idx, p_reg_desc->sts_addr, - j, (mask & (1 << j)) ? " [MASKED]" : ""); - } + "Failed to parse attention information [status: %s]\n", + qed_dbg_get_status_str(status)); + else + qed_dbg_parse_attn(p_hwfn, &attn_results); } /** @@ -1901,53 +749,30 @@ static int qed_int_deassertion_aeu_bit(struct qed_hwfn *p_hwfn, struct aeu_invert_reg_bit *p_aeu, u32 aeu_en_reg, - u32 bitmask) + const char *p_bit_name, u32 bitmask) { + bool b_fatal = false; int rc = -EINVAL; u32 val; DP_INFO(p_hwfn, "Deasserted attention `%s'[%08x]\n", - p_aeu->bit_name, bitmask); + p_bit_name, bitmask); /* Call callback before clearing the interrupt status */ if (p_aeu->cb) { DP_INFO(p_hwfn, "`%s (attention)': Calling Callback function\n", - p_aeu->bit_name); + p_bit_name); rc = p_aeu->cb(p_hwfn); } - /* Handle HW block interrupt registers */ - if (p_aeu->block_index != MAX_BLOCK_ID) { - struct attn_hw_block *p_block; - u32 mask; - int i; - - p_block = &attn_blocks[p_aeu->block_index]; - - /* Handle each interrupt register */ - for (i = 0; i < p_block->chip_regs[0].num_of_int_regs; i++) { - struct attn_hw_reg *p_reg_desc; - u32 sts_addr; + if (rc) + b_fatal = true; - p_reg_desc = p_block->chip_regs[0].int_regs[i]; + /* Print HW block interrupt registers */ + if (p_aeu->block_index != MAX_BLOCK_ID) + qed_int_attn_print(p_hwfn, p_aeu->block_index, + ATTN_TYPE_INTERRUPT, !b_fatal); - /* In case of fatal attention, don't clear the status - * so it would appear in following idle check. - */ - if (rc == 0) - sts_addr = p_reg_desc->sts_clr_addr; - else - sts_addr = p_reg_desc->sts_addr; - - val = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, sts_addr); - mask = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, - p_reg_desc->mask_addr); - qed_int_deassertion_print_bit(p_hwfn, p_reg_desc, - p_block, - QED_ATTN_TYPE_ATTN, - val, mask); - } - } /* If the attention is benign, no need to prevent it */ if (!rc) @@ -1957,66 +782,48 @@ qed_int_deassertion_aeu_bit(struct qed_hwfn *p_hwfn, val = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en_reg); qed_wr(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en_reg, (val & ~bitmask)); DP_INFO(p_hwfn, "`%s' - Disabled future attentions\n", - p_aeu->bit_name); + p_bit_name); out: return rc; } -static void qed_int_parity_print(struct qed_hwfn *p_hwfn, - struct aeu_invert_reg_bit *p_aeu, - struct attn_hw_block *p_block, - u8 bit_index) -{ - int i; - - for (i = 0; i < p_block->chip_regs[0].num_of_prty_regs; i++) { - struct attn_hw_reg *p_reg_desc; - u32 val, mask; - - p_reg_desc = p_block->chip_regs[0].prty_regs[i]; - - val = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, - p_reg_desc->sts_clr_addr); - mask = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, - p_reg_desc->mask_addr); - qed_int_deassertion_print_bit(p_hwfn, p_reg_desc, - p_block, - QED_ATTN_TYPE_PARITY, - val, mask); - } -} - /** * @brief qed_int_deassertion_parity - handle a single parity AEU source * * @param p_hwfn * @param p_aeu - descriptor of an AEU bit which caused the parity + * @param aeu_en_reg - address of the AEU enable register * @param bit_index */ static void qed_int_deassertion_parity(struct qed_hwfn *p_hwfn, struct aeu_invert_reg_bit *p_aeu, - u8 bit_index) + u32 aeu_en_reg, u8 bit_index) { - u32 block_id = p_aeu->block_index; + u32 block_id = p_aeu->block_index, mask, val; - DP_INFO(p_hwfn->cdev, "%s[%d] parity attention is set\n", - p_aeu->bit_name, bit_index); + DP_NOTICE(p_hwfn->cdev, + "%s parity attention is set [address 0x%08x, bit %d]\n", + p_aeu->bit_name, aeu_en_reg, bit_index); if (block_id != MAX_BLOCK_ID) { - qed_int_parity_print(p_hwfn, p_aeu, &attn_blocks[block_id], - bit_index); + qed_int_attn_print(p_hwfn, block_id, ATTN_TYPE_PARITY, false); /* In BB, there's a single parity bit for several blocks */ if (block_id == BLOCK_BTB) { - qed_int_parity_print(p_hwfn, p_aeu, - &attn_blocks[BLOCK_OPTE], - bit_index); - qed_int_parity_print(p_hwfn, p_aeu, - &attn_blocks[BLOCK_MCP], - bit_index); + qed_int_attn_print(p_hwfn, BLOCK_OPTE, + ATTN_TYPE_PARITY, false); + qed_int_attn_print(p_hwfn, BLOCK_MCP, + ATTN_TYPE_PARITY, false); } } + + /* Prevent this parity error from being re-asserted */ + mask = ~BIT(bit_index); + val = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en_reg); + qed_wr(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en_reg, val & mask); + DP_INFO(p_hwfn, "`%s' - Disabled future parity errors\n", + p_aeu->bit_name); } /** @@ -2031,7 +838,7 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, u16 deasserted_bits) { struct qed_sb_attn_info *sb_attn_sw = p_hwfn->p_sb_attn; - u32 aeu_inv_arr[NUM_ATTN_REGS], aeu_mask; + u32 aeu_inv_arr[NUM_ATTN_REGS], aeu_mask, aeu_en, en; u8 i, j, k, bit_idx; int rc = 0; @@ -2048,11 +855,11 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, /* Find parity attentions first */ for (i = 0; i < NUM_ATTN_REGS; i++) { struct aeu_invert_reg *p_aeu = &sb_attn_sw->p_aeu_desc[i]; - u32 en = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, - MISC_REG_AEU_ENABLE1_IGU_OUT_0 + - i * sizeof(u32)); u32 parities; + aeu_en = MISC_REG_AEU_ENABLE1_IGU_OUT_0 + i * sizeof(u32); + en = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en); + /* Skip register in which no parity bit is currently set */ parities = sb_attn_sw->parity_mask[i] & aeu_inv_arr[i] & en; if (!parities) @@ -2061,10 +868,10 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, for (j = 0, bit_idx = 0; bit_idx < 32; j++) { struct aeu_invert_reg_bit *p_bit = &p_aeu->bits[j]; - if ((p_bit->flags & ATTENTION_PARITY) && + if (qed_int_is_parity_flag(p_hwfn, p_bit) && !!(parities & BIT(bit_idx))) qed_int_deassertion_parity(p_hwfn, p_bit, - bit_idx); + aeu_en, bit_idx); bit_idx += ATTENTION_LENGTH(p_bit->flags); } @@ -2079,10 +886,11 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, continue; for (i = 0; i < NUM_ATTN_REGS; i++) { - u32 aeu_en = MISC_REG_AEU_ENABLE1_IGU_OUT_0 + - i * sizeof(u32) + - k * sizeof(u32) * NUM_ATTN_REGS; - u32 en, bits; + u32 bits; + + aeu_en = MISC_REG_AEU_ENABLE1_IGU_OUT_0 + + i * sizeof(u32) + + k * sizeof(u32) * NUM_ATTN_REGS; en = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en); bits = aeu_inv_arr[i] & en; @@ -2096,29 +904,54 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, * previous assertion. */ for (j = 0, bit_idx = 0; bit_idx < 32; j++) { + long unsigned int bitmask; u8 bit, bit_len; - u32 bitmask; p_aeu = &sb_attn_sw->p_aeu_desc[i].bits[j]; - - /* No need to handle parity-only bits */ - if (p_aeu->flags == ATTENTION_PAR) - continue; + p_aeu = qed_int_aeu_translate(p_hwfn, p_aeu); bit = bit_idx; bit_len = ATTENTION_LENGTH(p_aeu->flags); - if (p_aeu->flags & ATTENTION_PAR_INT) { + if (qed_int_is_parity_flag(p_hwfn, p_aeu)) { /* Skip Parity */ bit++; bit_len--; } bitmask = bits & (((1 << bit_len) - 1) << bit); + bitmask >>= bit; + if (bitmask) { + u32 flags = p_aeu->flags; + char bit_name[30]; + u8 num; + + num = (u8)find_first_bit(&bitmask, + bit_len); + + /* Some bits represent more than a + * a single interrupt. Correctly print + * their name. + */ + if (ATTENTION_LENGTH(flags) > 2 || + ((flags & ATTENTION_PAR_INT) && + ATTENTION_LENGTH(flags) > 1)) + snprintf(bit_name, 30, + p_aeu->bit_name, num); + else + strncpy(bit_name, + p_aeu->bit_name, 30); + + /* We now need to pass bitmask in its + * correct position. + */ + bitmask <<= bit; + /* Handle source of the attention */ qed_int_deassertion_aeu_bit(p_hwfn, p_aeu, aeu_en, + bit_name, bitmask); } @@ -2328,6 +1161,7 @@ static void qed_int_sb_attn_free(struct qed_hwfn *p_hwfn) SB_ATTN_ALIGNED_SIZE(p_hwfn), p_sb->sb_attn, p_sb->sb_phys); kfree(p_sb); + p_hwfn->p_sb_attn = NULL; } static void qed_int_sb_attn_setup(struct qed_hwfn *p_hwfn, @@ -2365,12 +1199,13 @@ static void qed_int_sb_attn_init(struct qed_hwfn *p_hwfn, for (i = 0; i < NUM_ATTN_REGS; i++) { /* j is array index, k is bit index */ for (j = 0, k = 0; k < 32; j++) { - unsigned int flags = aeu_descs[i].bits[j].flags; + struct aeu_invert_reg_bit *p_aeu; - if (flags & ATTENTION_PARITY) + p_aeu = &aeu_descs[i].bits[j]; + if (qed_int_is_parity_flag(p_hwfn, p_aeu)) sb_info->parity_mask[i] |= 1 << k; - k += ATTENTION_LENGTH(flags); + k += ATTENTION_LENGTH(p_aeu->flags); } DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, "Attn Mask [Reg %d]: 0x%08x\n", @@ -2465,6 +1300,40 @@ void qed_init_cau_sb_entry(struct qed_hwfn *p_hwfn, SET_FIELD(p_sb_entry->data, CAU_SB_ENTRY_STATE1, cau_state); } +static void qed_int_cau_conf_pi(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u16 igu_sb_id, + u32 pi_index, + enum qed_coalescing_fsm coalescing_fsm, + u8 timeset) +{ + struct cau_pi_entry pi_entry; + u32 sb_offset, pi_offset; + + if (IS_VF(p_hwfn->cdev)) + return; + + sb_offset = igu_sb_id * PIS_PER_SB; + memset(&pi_entry, 0, sizeof(struct cau_pi_entry)); + + SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_PI_TIMESET, timeset); + if (coalescing_fsm == QED_COAL_RX_STATE_MACHINE) + SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_FSM_SEL, 0); + else + SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_FSM_SEL, 1); + + pi_offset = sb_offset + pi_index; + if (p_hwfn->hw_init_done) { + qed_wr(p_hwfn, p_ptt, + CAU_REG_PI_MEMORY + pi_offset * sizeof(u32), + *((u32 *)&(pi_entry))); + } else { + STORE_RT_REG(p_hwfn, + CAU_REG_PI_MEMORY_RT_OFFSET + pi_offset, + *((u32 *)&(pi_entry))); + } +} + void qed_int_cau_conf_sb(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, dma_addr_t sb_phys, @@ -2531,40 +1400,6 @@ void qed_int_cau_conf_sb(struct qed_hwfn *p_hwfn, } } -void qed_int_cau_conf_pi(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u16 igu_sb_id, - u32 pi_index, - enum qed_coalescing_fsm coalescing_fsm, - u8 timeset) -{ - struct cau_pi_entry pi_entry; - u32 sb_offset, pi_offset; - - if (IS_VF(p_hwfn->cdev)) - return; - - sb_offset = igu_sb_id * PIS_PER_SB; - memset(&pi_entry, 0, sizeof(struct cau_pi_entry)); - - SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_PI_TIMESET, timeset); - if (coalescing_fsm == QED_COAL_RX_STATE_MACHINE) - SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_FSM_SEL, 0); - else - SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_FSM_SEL, 1); - - pi_offset = sb_offset + pi_index; - if (p_hwfn->hw_init_done) { - qed_wr(p_hwfn, p_ptt, - CAU_REG_PI_MEMORY + pi_offset * sizeof(u32), - *((u32 *)&(pi_entry))); - } else { - STORE_RT_REG(p_hwfn, - CAU_REG_PI_MEMORY_RT_OFFSET + pi_offset, - *((u32 *)&(pi_entry))); - } -} - void qed_int_sb_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_sb_info *sb_info) { @@ -2577,16 +1412,47 @@ void qed_int_sb_setup(struct qed_hwfn *p_hwfn, sb_info->igu_sb_id, 0, 0); } -/** - * @brief qed_get_igu_sb_id - given a sw sb_id return the - * igu_sb_id - * - * @param p_hwfn - * @param sb_id - * - * @return u16 - */ -static u16 qed_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) +struct qed_igu_block *qed_get_igu_free_sb(struct qed_hwfn *p_hwfn, bool b_is_pf) +{ + struct qed_igu_block *p_block; + u16 igu_id; + + for (igu_id = 0; igu_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); + igu_id++) { + p_block = &p_hwfn->hw_info.p_igu_info->entry[igu_id]; + + if (!(p_block->status & QED_IGU_STATUS_VALID) || + !(p_block->status & QED_IGU_STATUS_FREE)) + continue; + + if (!!(p_block->status & QED_IGU_STATUS_PF) == b_is_pf) + return p_block; + } + + return NULL; +} + +static u16 qed_get_pf_igu_sb_id(struct qed_hwfn *p_hwfn, u16 vector_id) +{ + struct qed_igu_block *p_block; + u16 igu_id; + + for (igu_id = 0; igu_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); + igu_id++) { + p_block = &p_hwfn->hw_info.p_igu_info->entry[igu_id]; + + if (!(p_block->status & QED_IGU_STATUS_VALID) || + !p_block->is_pf || + p_block->vector_number != vector_id) + continue; + + return igu_id; + } + + return QED_SB_INVALID_IDX; +} + +u16 qed_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) { u16 igu_sb_id; @@ -2594,7 +1460,7 @@ static u16 qed_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) if (sb_id == QED_SP_SB_ID) igu_sb_id = p_hwfn->hw_info.p_igu_info->igu_dsb_id; else if (IS_PF(p_hwfn->cdev)) - igu_sb_id = sb_id + p_hwfn->hw_info.p_igu_info->igu_base_sb; + igu_sb_id = qed_get_pf_igu_sb_id(p_hwfn, sb_id + 1); else igu_sb_id = qed_vf_get_igu_sb_id(p_hwfn, sb_id); @@ -2619,8 +1485,19 @@ int qed_int_sb_init(struct qed_hwfn *p_hwfn, sb_info->igu_sb_id = qed_get_igu_sb_id(p_hwfn, sb_id); if (sb_id != QED_SP_SB_ID) { - p_hwfn->sbs_info[sb_id] = sb_info; - p_hwfn->num_sbs++; + if (IS_PF(p_hwfn->cdev)) { + struct qed_igu_info *p_info; + struct qed_igu_block *p_block; + + p_info = p_hwfn->hw_info.p_igu_info; + p_block = &p_info->entry[sb_info->igu_sb_id]; + + p_block->sb_info = sb_info; + p_block->status &= ~QED_IGU_STATUS_FREE; + p_info->usage.free_cnt--; + } else { + qed_vf_set_sb_info(p_hwfn, sb_id, sb_info); + } } sb_info->cdev = p_hwfn->cdev; @@ -2649,20 +1526,35 @@ int qed_int_sb_init(struct qed_hwfn *p_hwfn, int qed_int_sb_release(struct qed_hwfn *p_hwfn, struct qed_sb_info *sb_info, u16 sb_id) { - if (sb_id == QED_SP_SB_ID) { - DP_ERR(p_hwfn, "Do Not free sp sb using this function"); - return -EINVAL; - } + struct qed_igu_block *p_block; + struct qed_igu_info *p_info; + + if (!sb_info) + return 0; /* zero status block and ack counter */ sb_info->sb_ack = 0; memset(sb_info->sb_virt, 0, sizeof(*sb_info->sb_virt)); - if (p_hwfn->sbs_info[sb_id] != NULL) { - p_hwfn->sbs_info[sb_id] = NULL; - p_hwfn->num_sbs--; + if (IS_VF(p_hwfn->cdev)) { + qed_vf_set_sb_info(p_hwfn, sb_id, NULL); + return 0; } + p_info = p_hwfn->hw_info.p_igu_info; + p_block = &p_info->entry[sb_info->igu_sb_id]; + + /* Vector 0 is reserved to Default SB */ + if (!p_block->vector_number) { + DP_ERR(p_hwfn, "Do Not free sp sb using this function"); + return -EINVAL; + } + + /* Lose reference to client's SB info, and fix counters */ + p_block->sb_info = NULL; + p_block->status |= QED_IGU_STATUS_FREE; + p_info->usage.free_cnt++; + return 0; } @@ -2679,6 +1571,7 @@ static void qed_int_sp_sb_free(struct qed_hwfn *p_hwfn) p_sb->sb_info.sb_virt, p_sb->sb_info.sb_phys); kfree(p_sb); + p_hwfn->p_sp_sb = NULL; } static int qed_int_sp_sb_alloc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) @@ -2780,10 +1673,9 @@ void qed_int_igu_enable_int(struct qed_hwfn *p_hwfn, qed_wr(p_hwfn, p_ptt, IGU_REG_PF_CONFIGURATION, igu_pf_conf); } -int qed_int_igu_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - enum qed_int_mode int_mode) +static void qed_int_igu_enable_attn(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) { - int rc = 0; /* Configure AEU signal change to produce attentions */ qed_wr(p_hwfn, p_ptt, IGU_REG_ATTENTION_ENABLE, 0); @@ -2796,6 +1688,16 @@ int qed_int_igu_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, /* Unmask AEU signals toward IGU */ qed_wr(p_hwfn, p_ptt, MISC_REG_AEU_MASK_ATTN_IGU, 0xff); +} + +int +qed_int_igu_enable(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, enum qed_int_mode int_mode) +{ + int rc = 0; + + qed_int_igu_enable_attn(p_hwfn, p_ptt); + if ((int_mode != QED_INT_MODE_INTA) || IS_LEAD_HWFN(p_hwfn)) { rc = qed_slowpath_irq_req(p_hwfn); if (rc) { @@ -2824,10 +1726,11 @@ void qed_int_igu_disable_int(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) #define IGU_CLEANUP_SLEEP_LENGTH (1000) static void qed_int_igu_cleanup_sb(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - u32 sb_id, bool cleanup_set, u16 opaque_fid) + u16 igu_sb_id, + bool cleanup_set, u16 opaque_fid) { u32 cmd_ctrl = 0, val = 0, sb_bit = 0, sb_bit_addr = 0, data = 0; - u32 pxp_addr = IGU_CMD_INT_ACK_BASE + sb_id; + u32 pxp_addr = IGU_CMD_INT_ACK_BASE + igu_sb_id; u32 sleep_cnt = IGU_CLEANUP_SLEEP_LENGTH; /* Set the data field */ @@ -2850,8 +1753,8 @@ static void qed_int_igu_cleanup_sb(struct qed_hwfn *p_hwfn, mmiowb(); /* calculate where to read the status bit from */ - sb_bit = 1 << (sb_id % 32); - sb_bit_addr = sb_id / 32 * sizeof(u32); + sb_bit = 1 << (igu_sb_id % 32); + sb_bit_addr = igu_sb_id / 32 * sizeof(u32); sb_bit_addr += IGU_REG_CLEANUP_STATUS_0; @@ -2868,29 +1771,38 @@ static void qed_int_igu_cleanup_sb(struct qed_hwfn *p_hwfn, if (!sleep_cnt) DP_NOTICE(p_hwfn, "Timeout waiting for clear status 0x%08x [for sb %d]\n", - val, sb_id); + val, igu_sb_id); } void qed_int_igu_init_pure_rt_single(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - u32 sb_id, u16 opaque, bool b_set) + u16 igu_sb_id, u16 opaque, bool b_set) { + struct qed_igu_block *p_block; int pi, i; + p_block = &p_hwfn->hw_info.p_igu_info->entry[igu_sb_id]; + DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, + "Cleaning SB [%04x]: func_id= %d is_pf = %d vector_num = 0x%0x\n", + igu_sb_id, + p_block->function_id, + p_block->is_pf, p_block->vector_number); + /* Set */ if (b_set) - qed_int_igu_cleanup_sb(p_hwfn, p_ptt, sb_id, 1, opaque); + qed_int_igu_cleanup_sb(p_hwfn, p_ptt, igu_sb_id, 1, opaque); /* Clear */ - qed_int_igu_cleanup_sb(p_hwfn, p_ptt, sb_id, 0, opaque); + qed_int_igu_cleanup_sb(p_hwfn, p_ptt, igu_sb_id, 0, opaque); /* Wait for the IGU SB to cleanup */ for (i = 0; i < IGU_CLEANUP_SLEEP_LENGTH; i++) { u32 val; val = qed_rd(p_hwfn, p_ptt, - IGU_REG_WRITE_DONE_PENDING + ((sb_id / 32) * 4)); - if (val & (1 << (sb_id % 32))) + IGU_REG_WRITE_DONE_PENDING + + ((igu_sb_id / 32) * 4)); + if (val & BIT((igu_sb_id % 32))) usleep_range(10, 20); else break; @@ -2898,84 +1810,205 @@ void qed_int_igu_init_pure_rt_single(struct qed_hwfn *p_hwfn, if (i == IGU_CLEANUP_SLEEP_LENGTH) DP_NOTICE(p_hwfn, "Failed SB[0x%08x] still appearing in WRITE_DONE_PENDING\n", - sb_id); + igu_sb_id); /* Clear the CAU for the SB */ for (pi = 0; pi < 12; pi++) qed_wr(p_hwfn, p_ptt, - CAU_REG_PI_MEMORY + (sb_id * 12 + pi) * 4, 0); + CAU_REG_PI_MEMORY + (igu_sb_id * 12 + pi) * 4, 0); } void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_set, bool b_slowpath) { - u32 igu_base_sb = p_hwfn->hw_info.p_igu_info->igu_base_sb; - u32 igu_sb_cnt = p_hwfn->hw_info.p_igu_info->igu_sb_cnt; - u32 sb_id = 0, val = 0; + struct qed_igu_info *p_info = p_hwfn->hw_info.p_igu_info; + struct qed_igu_block *p_block; + u16 igu_sb_id = 0; + u32 val = 0; val = qed_rd(p_hwfn, p_ptt, IGU_REG_BLOCK_CONFIGURATION); val |= IGU_REG_BLOCK_CONFIGURATION_VF_CLEANUP_EN; val &= ~IGU_REG_BLOCK_CONFIGURATION_PXP_TPH_INTERFACE_EN; qed_wr(p_hwfn, p_ptt, IGU_REG_BLOCK_CONFIGURATION, val); - DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, - "IGU cleaning SBs [%d,...,%d]\n", - igu_base_sb, igu_base_sb + igu_sb_cnt - 1); + for (igu_sb_id = 0; + igu_sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); igu_sb_id++) { + p_block = &p_info->entry[igu_sb_id]; - for (sb_id = igu_base_sb; sb_id < igu_base_sb + igu_sb_cnt; sb_id++) - qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, sb_id, + if (!(p_block->status & QED_IGU_STATUS_VALID) || + !p_block->is_pf || + (p_block->status & QED_IGU_STATUS_DSB)) + continue; + + qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, igu_sb_id, p_hwfn->hw_info.opaque_fid, b_set); + } - if (!b_slowpath) - return; - - sb_id = p_hwfn->hw_info.p_igu_info->igu_dsb_id; - DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, - "IGU cleaning slowpath SB [%d]\n", sb_id); - qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, sb_id, - p_hwfn->hw_info.opaque_fid, b_set); + if (b_slowpath) + qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, + p_info->igu_dsb_id, + p_hwfn->hw_info.opaque_fid, + b_set); } -static u32 qed_int_igu_read_cam_block(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, u16 sb_id) +int qed_int_igu_reset_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { - u32 val = qed_rd(p_hwfn, p_ptt, - IGU_REG_MAPPING_MEMORY + sizeof(u32) * sb_id); + struct qed_igu_info *p_info = p_hwfn->hw_info.p_igu_info; struct qed_igu_block *p_block; + int pf_sbs, vf_sbs; + u16 igu_sb_id; + u32 val, rval; - p_block = &p_hwfn->hw_info.p_igu_info->igu_map.igu_blocks[sb_id]; + if (!RESC_NUM(p_hwfn, QED_SB)) { + p_info->b_allow_pf_vf_change = false; + } else { + /* Use the numbers the MFW have provided - + * don't forget MFW accounts for the default SB as well. + */ + p_info->b_allow_pf_vf_change = true; + + if (p_info->usage.cnt != RESC_NUM(p_hwfn, QED_SB) - 1) { + DP_INFO(p_hwfn, + "MFW notifies of 0x%04x PF SBs; IGU indicates of only 0x%04x\n", + RESC_NUM(p_hwfn, QED_SB) - 1, + p_info->usage.cnt); + p_info->usage.cnt = RESC_NUM(p_hwfn, QED_SB) - 1; + } - /* stop scanning when hit first invalid PF entry */ - if (!GET_FIELD(val, IGU_MAPPING_LINE_VALID) && - GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID)) - goto out; + if (IS_PF_SRIOV(p_hwfn)) { + u16 vfs = p_hwfn->cdev->p_iov_info->total_vfs; - /* Fill the block information */ - p_block->status = QED_IGU_STATUS_VALID; - p_block->function_id = GET_FIELD(val, - IGU_MAPPING_LINE_FUNCTION_NUMBER); - p_block->is_pf = GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID); - p_block->vector_number = GET_FIELD(val, - IGU_MAPPING_LINE_VECTOR_NUMBER); + if (vfs != p_info->usage.iov_cnt) + DP_VERBOSE(p_hwfn, + NETIF_MSG_INTR, + "0x%04x VF SBs in IGU CAM != PCI configuration 0x%04x\n", + p_info->usage.iov_cnt, vfs); - DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, - "IGU_BLOCK: [SB 0x%04x, Value in CAM 0x%08x] func_id = %d is_pf = %d vector_num = 0x%x\n", - sb_id, val, p_block->function_id, - p_block->is_pf, p_block->vector_number); + /* At this point we know how many SBs we have totally + * in IGU + number of PF SBs. So we can validate that + * we'd have sufficient for VF. + */ + if (vfs > p_info->usage.free_cnt + + p_info->usage.free_cnt_iov - p_info->usage.cnt) { + DP_NOTICE(p_hwfn, + "Not enough SBs for VFs - 0x%04x SBs, from which %04x PFs and %04x are required\n", + p_info->usage.free_cnt + + p_info->usage.free_cnt_iov, + p_info->usage.cnt, vfs); + return -EINVAL; + } -out: - return val; + /* Currently cap the number of VFs SBs by the + * number of VFs. + */ + p_info->usage.iov_cnt = vfs; + } + } + + /* Mark all SBs as free, now in the right PF/VFs division */ + p_info->usage.free_cnt = p_info->usage.cnt; + p_info->usage.free_cnt_iov = p_info->usage.iov_cnt; + p_info->usage.orig = p_info->usage.cnt; + p_info->usage.iov_orig = p_info->usage.iov_cnt; + + /* We now proceed to re-configure the IGU cam to reflect the initial + * configuration. We can start with the Default SB. + */ + pf_sbs = p_info->usage.cnt; + vf_sbs = p_info->usage.iov_cnt; + + for (igu_sb_id = p_info->igu_dsb_id; + igu_sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); igu_sb_id++) { + p_block = &p_info->entry[igu_sb_id]; + val = 0; + + if (!(p_block->status & QED_IGU_STATUS_VALID)) + continue; + + if (p_block->status & QED_IGU_STATUS_DSB) { + p_block->function_id = p_hwfn->rel_pf_id; + p_block->is_pf = 1; + p_block->vector_number = 0; + p_block->status = QED_IGU_STATUS_VALID | + QED_IGU_STATUS_PF | + QED_IGU_STATUS_DSB; + } else if (pf_sbs) { + pf_sbs--; + p_block->function_id = p_hwfn->rel_pf_id; + p_block->is_pf = 1; + p_block->vector_number = p_info->usage.cnt - pf_sbs; + p_block->status = QED_IGU_STATUS_VALID | + QED_IGU_STATUS_PF | + QED_IGU_STATUS_FREE; + } else if (vf_sbs) { + p_block->function_id = + p_hwfn->cdev->p_iov_info->first_vf_in_pf + + p_info->usage.iov_cnt - vf_sbs; + p_block->is_pf = 0; + p_block->vector_number = 0; + p_block->status = QED_IGU_STATUS_VALID | + QED_IGU_STATUS_FREE; + vf_sbs--; + } else { + p_block->function_id = 0; + p_block->is_pf = 0; + p_block->vector_number = 0; + } + + SET_FIELD(val, IGU_MAPPING_LINE_FUNCTION_NUMBER, + p_block->function_id); + SET_FIELD(val, IGU_MAPPING_LINE_PF_VALID, p_block->is_pf); + SET_FIELD(val, IGU_MAPPING_LINE_VECTOR_NUMBER, + p_block->vector_number); + + /* VF entries would be enabled when VF is initializaed */ + SET_FIELD(val, IGU_MAPPING_LINE_VALID, p_block->is_pf); + + rval = qed_rd(p_hwfn, p_ptt, + IGU_REG_MAPPING_MEMORY + sizeof(u32) * igu_sb_id); + + if (rval != val) { + qed_wr(p_hwfn, p_ptt, + IGU_REG_MAPPING_MEMORY + + sizeof(u32) * igu_sb_id, val); + + DP_VERBOSE(p_hwfn, + NETIF_MSG_INTR, + "IGU reset: [SB 0x%04x] func_id = %d is_pf = %d vector_num = 0x%x [%08x -> %08x]\n", + igu_sb_id, + p_block->function_id, + p_block->is_pf, + p_block->vector_number, rval, val); + } + } + + return 0; +} + +static void qed_int_igu_read_cam_block(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u16 igu_sb_id) +{ + u32 val = qed_rd(p_hwfn, p_ptt, + IGU_REG_MAPPING_MEMORY + sizeof(u32) * igu_sb_id); + struct qed_igu_block *p_block; + + p_block = &p_hwfn->hw_info.p_igu_info->entry[igu_sb_id]; + + /* Fill the block information */ + p_block->function_id = GET_FIELD(val, IGU_MAPPING_LINE_FUNCTION_NUMBER); + p_block->is_pf = GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID); + p_block->vector_number = GET_FIELD(val, IGU_MAPPING_LINE_VECTOR_NUMBER); + p_block->igu_sb_id = igu_sb_id; } int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { struct qed_igu_info *p_igu_info; - u32 val, min_vf = 0, max_vf = 0; - u16 sb_id, last_iov_sb_id = 0; - struct qed_igu_block *blk; - u16 prev_sb_id = 0xFF; + struct qed_igu_block *p_block; + u32 min_vf = 0, max_vf = 0; + u16 igu_sb_id; p_hwfn->hw_info.p_igu_info = kzalloc(sizeof(*p_igu_info), GFP_KERNEL); if (!p_hwfn->hw_info.p_igu_info) @@ -2983,12 +2016,10 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) p_igu_info = p_hwfn->hw_info.p_igu_info; - /* Initialize base sb / sb cnt for PFs and VFs */ - p_igu_info->igu_base_sb = 0xffff; - p_igu_info->igu_sb_cnt = 0; - p_igu_info->igu_dsb_id = 0xffff; - p_igu_info->igu_base_sb_iov = 0xffff; + /* Distinguish between existent and non-existent default SB */ + p_igu_info->igu_dsb_id = QED_SB_INVALID_IDX; + /* Find the range of VF ids whose SB belong to this PF */ if (p_hwfn->cdev->p_iov_info) { struct qed_hw_sriov_info *p_iov = p_hwfn->cdev->p_iov_info; @@ -2996,113 +2027,69 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) max_vf = p_iov->first_vf_in_pf + p_iov->total_vfs; } - for (sb_id = 0; sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); - sb_id++) { - blk = &p_igu_info->igu_map.igu_blocks[sb_id]; - - val = qed_int_igu_read_cam_block(p_hwfn, p_ptt, sb_id); - - /* stop scanning when hit first invalid PF entry */ - if (!GET_FIELD(val, IGU_MAPPING_LINE_VALID) && - GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID)) - break; - - if (blk->is_pf) { - if (blk->function_id == p_hwfn->rel_pf_id) { - blk->status |= QED_IGU_STATUS_PF; - - if (blk->vector_number == 0) { - if (p_igu_info->igu_dsb_id == 0xffff) - p_igu_info->igu_dsb_id = sb_id; - } else { - if (p_igu_info->igu_base_sb == - 0xffff) { - p_igu_info->igu_base_sb = sb_id; - } else if (prev_sb_id != sb_id - 1) { - DP_NOTICE(p_hwfn->cdev, - "consecutive igu vectors for HWFN %x broken", - p_hwfn->rel_pf_id); - break; - } - prev_sb_id = sb_id; - /* we don't count the default */ - (p_igu_info->igu_sb_cnt)++; - } - } - } else { - if ((blk->function_id >= min_vf) && - (blk->function_id < max_vf)) { - /* Available for VFs of this PF */ - if (p_igu_info->igu_base_sb_iov == 0xffff) { - p_igu_info->igu_base_sb_iov = sb_id; - } else if (last_iov_sb_id != sb_id - 1) { - if (!val) { - DP_VERBOSE(p_hwfn->cdev, - NETIF_MSG_INTR, - "First uninitialized IGU CAM entry at index 0x%04x\n", - sb_id); - } else { - DP_NOTICE(p_hwfn->cdev, - "Consecutive igu vectors for HWFN %x vfs is broken [jumps from %04x to %04x]\n", - p_hwfn->rel_pf_id, - last_iov_sb_id, - sb_id); } - break; - } - blk->status |= QED_IGU_STATUS_FREE; - p_hwfn->hw_info.p_igu_info->free_blks++; - last_iov_sb_id = sb_id; - } + for (igu_sb_id = 0; + igu_sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); igu_sb_id++) { + /* Read current entry; Notice it might not belong to this PF */ + qed_int_igu_read_cam_block(p_hwfn, p_ptt, igu_sb_id); + p_block = &p_igu_info->entry[igu_sb_id]; + + if ((p_block->is_pf) && + (p_block->function_id == p_hwfn->rel_pf_id)) { + p_block->status = QED_IGU_STATUS_PF | + QED_IGU_STATUS_VALID | + QED_IGU_STATUS_FREE; + + if (p_igu_info->igu_dsb_id != QED_SB_INVALID_IDX) + p_igu_info->usage.cnt++; + } else if (!(p_block->is_pf) && + (p_block->function_id >= min_vf) && + (p_block->function_id < max_vf)) { + /* Available for VFs of this PF */ + p_block->status = QED_IGU_STATUS_VALID | + QED_IGU_STATUS_FREE; + + if (p_igu_info->igu_dsb_id != QED_SB_INVALID_IDX) + p_igu_info->usage.iov_cnt++; } - } - /* There's a possibility the igu_sb_cnt_iov doesn't properly reflect - * the number of VF SBs [especially for first VF on engine, as we can't - * differentiate between empty entries and its entries]. - * Since we don't really support more SBs than VFs today, prevent any - * such configuration by sanitizing the number of SBs to equal the - * number of VFs. - */ - if (IS_PF_SRIOV(p_hwfn)) { - u16 total_vfs = p_hwfn->cdev->p_iov_info->total_vfs; + /* Mark the First entry belonging to the PF or its VFs + * as the default SB [we'll reset IGU prior to first usage]. + */ + if ((p_block->status & QED_IGU_STATUS_VALID) && + (p_igu_info->igu_dsb_id == QED_SB_INVALID_IDX)) { + p_igu_info->igu_dsb_id = igu_sb_id; + p_block->status |= QED_IGU_STATUS_DSB; + } - if (total_vfs < p_igu_info->free_blks) { - DP_VERBOSE(p_hwfn, - (NETIF_MSG_INTR | QED_MSG_IOV), - "Limiting number of SBs for IOV - %04x --> %04x\n", - p_igu_info->free_blks, - p_hwfn->cdev->p_iov_info->total_vfs); - p_igu_info->free_blks = total_vfs; - } else if (total_vfs > p_igu_info->free_blks) { - DP_NOTICE(p_hwfn, - "IGU has only %04x SBs for VFs while the device has %04x VFs\n", - p_igu_info->free_blks, total_vfs); - return -EINVAL; + /* limit number of prints by having each PF print only its + * entries with the exception of PF0 which would print + * everything. + */ + if ((p_block->status & QED_IGU_STATUS_VALID) || + (p_hwfn->abs_pf_id == 0)) { + DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, + "IGU_BLOCK: [SB 0x%04x] func_id = %d is_pf = %d vector_num = 0x%x\n", + igu_sb_id, p_block->function_id, + p_block->is_pf, p_block->vector_number); } } - p_igu_info->igu_sb_cnt_iov = p_igu_info->free_blks; - - DP_VERBOSE( - p_hwfn, - NETIF_MSG_INTR, - "IGU igu_base_sb=0x%x [IOV 0x%x] igu_sb_cnt=%d [IOV 0x%x] igu_dsb_id=0x%x\n", - p_igu_info->igu_base_sb, - p_igu_info->igu_base_sb_iov, - p_igu_info->igu_sb_cnt, - p_igu_info->igu_sb_cnt_iov, - p_igu_info->igu_dsb_id); - - if (p_igu_info->igu_base_sb == 0xffff || - p_igu_info->igu_dsb_id == 0xffff || - p_igu_info->igu_sb_cnt == 0) { + + if (p_igu_info->igu_dsb_id == QED_SB_INVALID_IDX) { DP_NOTICE(p_hwfn, - "IGU CAM returned invalid values igu_base_sb=0x%x igu_sb_cnt=%d igu_dsb_id=0x%x\n", - p_igu_info->igu_base_sb, - p_igu_info->igu_sb_cnt, - p_igu_info->igu_dsb_id); + "IGU CAM returned invalid values igu_dsb_id=0x%x\n", + p_igu_info->igu_dsb_id); return -EINVAL; } + /* All non default SB are considered free at this point */ + p_igu_info->usage.free_cnt = p_igu_info->usage.cnt; + p_igu_info->usage.free_cnt_iov = p_igu_info->usage.iov_cnt; + + DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, + "igu_dsb_id=0x%x, num Free SBs - PF: %04x VF: %04x [might change after resource allocation]\n", + p_igu_info->igu_dsb_id, + p_igu_info->usage.cnt, p_igu_info->usage.iov_cnt); + return 0; } @@ -3157,6 +2144,7 @@ static int qed_int_sp_dpc_alloc(struct qed_hwfn *p_hwfn) static void qed_int_sp_dpc_free(struct qed_hwfn *p_hwfn) { kfree(p_hwfn->sp_dpc); + p_hwfn->sp_dpc = NULL; } int qed_int_alloc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) @@ -3198,31 +2186,7 @@ void qed_int_get_num_sbs(struct qed_hwfn *p_hwfn, if (!info || !p_sb_cnt_info) return; - p_sb_cnt_info->sb_cnt = info->igu_sb_cnt; - p_sb_cnt_info->sb_iov_cnt = info->igu_sb_cnt_iov; - p_sb_cnt_info->sb_free_blk = info->free_blks; -} - -u16 qed_int_queue_id_from_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) -{ - struct qed_igu_info *p_info = p_hwfn->hw_info.p_igu_info; - - /* Determine origin of SB id */ - if ((sb_id >= p_info->igu_base_sb) && - (sb_id < p_info->igu_base_sb + p_info->igu_sb_cnt)) { - return sb_id - p_info->igu_base_sb; - } else if ((sb_id >= p_info->igu_base_sb_iov) && - (sb_id < p_info->igu_base_sb_iov + p_info->igu_sb_cnt_iov)) { - /* We want the first VF queue to be adjacent to the - * last PF queue. Since L2 queues can be partial to - * SBs, we'll use the feature instead. - */ - return sb_id - p_info->igu_base_sb_iov + - FEAT_NUM(p_hwfn, QED_PF_L2_QUE); - } else { - DP_NOTICE(p_hwfn, "SB %d not in range for function\n", sb_id); - return 0; - } + memcpy(p_sb_cnt_info, &info->usage, sizeof(*p_sb_cnt_info)); } void qed_int_disable_post_isr_release(struct qed_dev *cdev) diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h index 0ae0bb4593ef..5199634ed630 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.h +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -79,24 +79,6 @@ enum qed_coalescing_fsm { }; /** - * @brief qed_int_cau_conf_pi - configure cau for a given - * status block - * - * @param p_hwfn - * @param p_ptt - * @param igu_sb_id - * @param pi_index - * @param state - * @param timeset - */ -void qed_int_cau_conf_pi(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u16 igu_sb_id, - u32 pi_index, - enum qed_coalescing_fsm coalescing_fsm, - u8 timeset); - -/** * @brief qed_int_igu_enable_int - enable device interrupts * * @param p_hwfn @@ -217,32 +199,63 @@ void qed_int_disable_post_isr_release(struct qed_dev *cdev); #define SB_ALIGNED_SIZE(p_hwfn) \ ALIGNED_TYPE_SIZE(struct status_block, p_hwfn) +#define QED_SB_INVALID_IDX 0xffff + struct qed_igu_block { - u8 status; + u8 status; #define QED_IGU_STATUS_FREE 0x01 #define QED_IGU_STATUS_VALID 0x02 #define QED_IGU_STATUS_PF 0x04 +#define QED_IGU_STATUS_DSB 0x08 - u8 vector_number; - u8 function_id; - u8 is_pf; -}; + u8 vector_number; + u8 function_id; + u8 is_pf; + + /* Index inside IGU [meant for back reference] */ + u16 igu_sb_id; -struct qed_igu_map { - struct qed_igu_block igu_blocks[MAX_TOT_SB_PER_PATH]; + struct qed_sb_info *sb_info; }; struct qed_igu_info { - struct qed_igu_map igu_map; - u16 igu_dsb_id; - u16 igu_base_sb; - u16 igu_base_sb_iov; - u16 igu_sb_cnt; - u16 igu_sb_cnt_iov; - u16 free_blks; + struct qed_igu_block entry[MAX_TOT_SB_PER_PATH]; + u16 igu_dsb_id; + + struct qed_sb_cnt_info usage; + + bool b_allow_pf_vf_change; }; -/* TODO Names of function may change... */ +/** + * @brief - Make sure the IGU CAM reflects the resources provided by MFW + * + * @param p_hwfn + * @param p_ptt + */ +int qed_int_igu_reset_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); + +/** + * @brief Translate the weakly-defined client sb-id into an IGU sb-id + * + * @param p_hwfn + * @param sb_id - user provided sb_id + * + * @return an index inside IGU CAM where the SB resides + */ +u16 qed_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id); + +/** + * @brief return a pointer to an unused valid SB + * + * @param p_hwfn + * @param b_is_pf - true iff we want a SB belonging to a PF + * + * @return point to an igu_block, NULL if none is available + */ +struct qed_igu_block *qed_get_igu_free_sb(struct qed_hwfn *p_hwfn, + bool b_is_pf); + void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_set, @@ -321,13 +334,13 @@ u16 qed_int_get_sp_sb_id(struct qed_hwfn *p_hwfn); * * @param p_hwfn * @param p_ptt - * @param sb_id - igu status block id + * @param igu_sb_id - igu status block id * @param opaque - opaque fid of the sb owner. * @param b_set - set(1) / clear(0) */ void qed_int_igu_init_pure_rt_single(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - u32 sb_id, + u16 igu_sb_id, u16 opaque, bool b_set); @@ -377,16 +390,6 @@ void qed_int_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); /** - * @brief - Returns an Rx queue index appropriate for usage with given SB. - * - * @param p_hwfn - * @param sb_id - absolute index of SB - * - * @return index of Rx queue - */ -u16 qed_int_queue_id_from_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id); - -/** * @brief - Enable Interrupt & Attention for hw function * * @param p_hwfn diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c index 339c91dfa658..6103723d7118 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c @@ -44,7 +44,6 @@ #include <linux/slab.h> #include <linux/stddef.h> #include <linux/string.h> -#include <linux/version.h> #include <linux/workqueue.h> #include <linux/errno.h> #include <linux/list.h> @@ -186,7 +185,7 @@ qed_sp_iscsi_func_start(struct qed_hwfn *p_hwfn, DP_ERR(p_hwfn, "Cannot satisfy CQ amount. Queues requested %d, CQs available %d. Aborting function start\n", p_params->num_queues, - p_hwfn->hw_info.resc_num[QED_ISCSI_CQ]); + p_hwfn->hw_info.feat_num[QED_ISCSI_CQ]); return -EINVAL; } @@ -221,7 +220,7 @@ qed_sp_iscsi_func_start(struct qed_hwfn *p_hwfn, p_queue->cmdq_sb_pi = p_params->gl_cmd_pi; for (i = 0; i < p_params->num_queues; i++) { - val = p_hwfn->sbs_info[i]->igu_sb_id; + val = qed_get_igu_sb_id(p_hwfn, i); p_queue->cq_cmdq_sb_num_arr[i] = cpu_to_le16(val); } @@ -375,7 +374,6 @@ static int qed_sp_iscsi_conn_offload(struct qed_hwfn *p_hwfn, p_tcp->ss_thresh = cpu_to_le32(p_conn->ss_thresh); p_tcp->srtt = cpu_to_le16(p_conn->srtt); p_tcp->rtt_var = cpu_to_le16(p_conn->rtt_var); - p_tcp->ts_time = cpu_to_le32(p_conn->ts_time); p_tcp->ts_recent = cpu_to_le32(p_conn->ts_recent); p_tcp->ts_recent_age = cpu_to_le32(p_conn->ts_recent_age); p_tcp->total_rt = cpu_to_le32(p_conn->total_rt); @@ -400,8 +398,6 @@ static int qed_sp_iscsi_conn_offload(struct qed_hwfn *p_hwfn, p_tcp->mss = cpu_to_le16(p_conn->mss); p_tcp->snd_wnd_scale = p_conn->snd_wnd_scale; p_tcp->rcv_wnd_scale = p_conn->rcv_wnd_scale; - dval = p_conn->ts_ticks_per_second; - p_tcp->ts_ticks_per_second = cpu_to_le32(dval); wval = p_conn->da_timeout_value; p_tcp->da_timeout_value = cpu_to_le16(wval); p_tcp->ack_frequency = p_conn->ack_frequency; @@ -492,6 +488,54 @@ static int qed_sp_iscsi_conn_update(struct qed_hwfn *p_hwfn, return qed_spq_post(p_hwfn, p_ent, NULL); } +static int +qed_sp_iscsi_mac_update(struct qed_hwfn *p_hwfn, + struct qed_iscsi_conn *p_conn, + enum spq_mode comp_mode, + struct qed_spq_comp_cb *p_comp_addr) +{ + struct iscsi_spe_conn_mac_update *p_ramrod = NULL; + struct qed_spq_entry *p_ent = NULL; + struct qed_sp_init_data init_data; + int rc = -EINVAL; + u8 ucval; + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = p_conn->icid; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = comp_mode; + init_data.p_comp_data = p_comp_addr; + + rc = qed_sp_init_request(p_hwfn, &p_ent, + ISCSI_RAMROD_CMD_ID_MAC_UPDATE, + PROTOCOLID_ISCSI, &init_data); + if (rc) + return rc; + + p_ramrod = &p_ent->ramrod.iscsi_conn_mac_update; + p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_MAC_UPDATE; + SET_FIELD(p_ramrod->hdr.flags, + ISCSI_SLOW_PATH_HDR_LAYER_CODE, p_conn->layer_code); + + p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id); + p_ramrod->fw_cid = cpu_to_le32(p_conn->icid); + ucval = p_conn->remote_mac[1]; + ((u8 *)(&p_ramrod->remote_mac_addr_hi))[0] = ucval; + ucval = p_conn->remote_mac[0]; + ((u8 *)(&p_ramrod->remote_mac_addr_hi))[1] = ucval; + ucval = p_conn->remote_mac[3]; + ((u8 *)(&p_ramrod->remote_mac_addr_mid))[0] = ucval; + ucval = p_conn->remote_mac[2]; + ((u8 *)(&p_ramrod->remote_mac_addr_mid))[1] = ucval; + ucval = p_conn->remote_mac[5]; + ((u8 *)(&p_ramrod->remote_mac_addr_lo))[0] = ucval; + ucval = p_conn->remote_mac[4]; + ((u8 *)(&p_ramrod->remote_mac_addr_lo))[1] = ucval; + + return qed_spq_post(p_hwfn, p_ent, NULL); +} + static int qed_sp_iscsi_conn_terminate(struct qed_hwfn *p_hwfn, struct qed_iscsi_conn *p_conn, enum spq_mode comp_mode, @@ -822,29 +866,32 @@ void qed_iscsi_free_connection(struct qed_hwfn *p_hwfn, kfree(p_conn); } -struct qed_iscsi_info *qed_iscsi_alloc(struct qed_hwfn *p_hwfn) +int qed_iscsi_alloc(struct qed_hwfn *p_hwfn) { struct qed_iscsi_info *p_iscsi_info; p_iscsi_info = kzalloc(sizeof(*p_iscsi_info), GFP_KERNEL); if (!p_iscsi_info) - return NULL; + return -ENOMEM; INIT_LIST_HEAD(&p_iscsi_info->free_list); - return p_iscsi_info; + + p_hwfn->p_iscsi_info = p_iscsi_info; + return 0; } -void qed_iscsi_setup(struct qed_hwfn *p_hwfn, - struct qed_iscsi_info *p_iscsi_info) +void qed_iscsi_setup(struct qed_hwfn *p_hwfn) { - spin_lock_init(&p_iscsi_info->lock); + spin_lock_init(&p_hwfn->p_iscsi_info->lock); } -void qed_iscsi_free(struct qed_hwfn *p_hwfn, - struct qed_iscsi_info *p_iscsi_info) +void qed_iscsi_free(struct qed_hwfn *p_hwfn) { struct qed_iscsi_conn *p_conn = NULL; + if (!p_hwfn->p_iscsi_info) + return; + while (!list_empty(&p_hwfn->p_iscsi_info->free_list)) { p_conn = list_first_entry(&p_hwfn->p_iscsi_info->free_list, struct qed_iscsi_conn, list_entry); @@ -854,7 +901,8 @@ void qed_iscsi_free(struct qed_hwfn *p_hwfn, } } - kfree(p_iscsi_info); + kfree(p_hwfn->p_iscsi_info); + p_hwfn->p_iscsi_info = NULL; } static void _qed_iscsi_get_tstats(struct qed_hwfn *p_hwfn, @@ -1324,6 +1372,23 @@ static int qed_iscsi_stats(struct qed_dev *cdev, struct qed_iscsi_stats *stats) return qed_iscsi_get_stats(QED_LEADING_HWFN(cdev), stats); } +static int qed_iscsi_change_mac(struct qed_dev *cdev, + u32 handle, const u8 *mac) +{ + struct qed_hash_iscsi_con *hash_con; + + hash_con = qed_iscsi_get_hash(cdev, handle); + if (!hash_con) { + DP_NOTICE(cdev, "Failed to find connection for handle %d\n", + handle); + return -EINVAL; + } + + return qed_sp_iscsi_mac_update(QED_LEADING_HWFN(cdev), + hash_con->con, + QED_SPQ_MODE_EBLOCK, NULL); +} + void qed_get_protocol_stats_iscsi(struct qed_dev *cdev, struct qed_mcp_iscsi_stats *stats) { @@ -1358,6 +1423,7 @@ static const struct qed_iscsi_ops qed_iscsi_ops_pass = { .destroy_conn = &qed_iscsi_destroy_conn, .clear_sq = &qed_iscsi_clear_conn_sq, .get_stats = &qed_iscsi_stats, + .change_mac = &qed_iscsi_change_mac, }; const struct qed_iscsi_ops *qed_get_iscsi_ops(void) diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.h b/drivers/net/ethernet/qlogic/qed/qed_iscsi.h index ae98f772cbc0..225c75b02a06 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.h @@ -57,13 +57,11 @@ extern const struct qed_ll2_ops qed_ll2_ops_pass; #endif #if IS_ENABLED(CONFIG_QED_ISCSI) -struct qed_iscsi_info *qed_iscsi_alloc(struct qed_hwfn *p_hwfn); +int qed_iscsi_alloc(struct qed_hwfn *p_hwfn); -void qed_iscsi_setup(struct qed_hwfn *p_hwfn, - struct qed_iscsi_info *p_iscsi_info); +void qed_iscsi_setup(struct qed_hwfn *p_hwfn); -void qed_iscsi_free(struct qed_hwfn *p_hwfn, - struct qed_iscsi_info *p_iscsi_info); +void qed_iscsi_free(struct qed_hwfn *p_hwfn); /** * @brief - Fills provided statistics struct with statistics. @@ -74,12 +72,15 @@ void qed_iscsi_free(struct qed_hwfn *p_hwfn, void qed_get_protocol_stats_iscsi(struct qed_dev *cdev, struct qed_mcp_iscsi_stats *stats); #else /* IS_ENABLED(CONFIG_QED_ISCSI) */ -static inline struct qed_iscsi_info *qed_iscsi_alloc( - struct qed_hwfn *p_hwfn) { return NULL; } -static inline void qed_iscsi_setup(struct qed_hwfn *p_hwfn, - struct qed_iscsi_info *p_iscsi_info) {} -static inline void qed_iscsi_free(struct qed_hwfn *p_hwfn, - struct qed_iscsi_info *p_iscsi_info) {} +static inline int qed_iscsi_alloc(struct qed_hwfn *p_hwfn) +{ + return -EINVAL; +} + +static inline void qed_iscsi_setup(struct qed_hwfn *p_hwfn) {} + +static inline void qed_iscsi_free(struct qed_hwfn *p_hwfn) {} + static inline void qed_get_protocol_stats_iscsi(struct qed_dev *cdev, struct qed_mcp_iscsi_stats *stats) {} diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 746fed4099c8..cb8b05dbfc6e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -43,7 +43,6 @@ #include <linux/slab.h> #include <linux/stddef.h> #include <linux/string.h> -#include <linux/version.h> #include <linux/workqueue.h> #include <linux/bitops.h> #include <linux/bug.h> @@ -66,26 +65,162 @@ #define QED_MAX_SGES_NUM 16 #define CRC32_POLY 0x1edc6f41 +struct qed_l2_info { + u32 queues; + unsigned long **pp_qid_usage; + + /* The lock is meant to synchronize access to the qid usage */ + struct mutex lock; +}; + +int qed_l2_alloc(struct qed_hwfn *p_hwfn) +{ + struct qed_l2_info *p_l2_info; + unsigned long **pp_qids; + u32 i; + + if (p_hwfn->hw_info.personality != QED_PCI_ETH && + p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE) + return 0; + + p_l2_info = kzalloc(sizeof(*p_l2_info), GFP_KERNEL); + if (!p_l2_info) + return -ENOMEM; + p_hwfn->p_l2_info = p_l2_info; + + if (IS_PF(p_hwfn->cdev)) { + p_l2_info->queues = RESC_NUM(p_hwfn, QED_L2_QUEUE); + } else { + u8 rx = 0, tx = 0; + + qed_vf_get_num_rxqs(p_hwfn, &rx); + qed_vf_get_num_txqs(p_hwfn, &tx); + + p_l2_info->queues = max_t(u8, rx, tx); + } + + pp_qids = kzalloc(sizeof(unsigned long *) * p_l2_info->queues, + GFP_KERNEL); + if (!pp_qids) + return -ENOMEM; + p_l2_info->pp_qid_usage = pp_qids; + + for (i = 0; i < p_l2_info->queues; i++) { + pp_qids[i] = kzalloc(MAX_QUEUES_PER_QZONE / 8, GFP_KERNEL); + if (!pp_qids[i]) + return -ENOMEM; + } + + return 0; +} + +void qed_l2_setup(struct qed_hwfn *p_hwfn) +{ + if (p_hwfn->hw_info.personality != QED_PCI_ETH && + p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE) + return; + + mutex_init(&p_hwfn->p_l2_info->lock); +} + +void qed_l2_free(struct qed_hwfn *p_hwfn) +{ + u32 i; + + if (p_hwfn->hw_info.personality != QED_PCI_ETH && + p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE) + return; + + if (!p_hwfn->p_l2_info) + return; + + if (!p_hwfn->p_l2_info->pp_qid_usage) + goto out_l2_info; + + /* Free until hit first uninitialized entry */ + for (i = 0; i < p_hwfn->p_l2_info->queues; i++) { + if (!p_hwfn->p_l2_info->pp_qid_usage[i]) + break; + kfree(p_hwfn->p_l2_info->pp_qid_usage[i]); + } + + kfree(p_hwfn->p_l2_info->pp_qid_usage); + +out_l2_info: + kfree(p_hwfn->p_l2_info); + p_hwfn->p_l2_info = NULL; +} + +static bool qed_eth_queue_qid_usage_add(struct qed_hwfn *p_hwfn, + struct qed_queue_cid *p_cid) +{ + struct qed_l2_info *p_l2_info = p_hwfn->p_l2_info; + u16 queue_id = p_cid->rel.queue_id; + bool b_rc = true; + u8 first; + + mutex_lock(&p_l2_info->lock); + + if (queue_id > p_l2_info->queues) { + DP_NOTICE(p_hwfn, + "Requested to increase usage for qzone %04x out of %08x\n", + queue_id, p_l2_info->queues); + b_rc = false; + goto out; + } + + first = (u8)find_first_zero_bit(p_l2_info->pp_qid_usage[queue_id], + MAX_QUEUES_PER_QZONE); + if (first >= MAX_QUEUES_PER_QZONE) { + b_rc = false; + goto out; + } + + __set_bit(first, p_l2_info->pp_qid_usage[queue_id]); + p_cid->qid_usage_idx = first; + +out: + mutex_unlock(&p_l2_info->lock); + return b_rc; +} + +static void qed_eth_queue_qid_usage_del(struct qed_hwfn *p_hwfn, + struct qed_queue_cid *p_cid) +{ + mutex_lock(&p_hwfn->p_l2_info->lock); + + clear_bit(p_cid->qid_usage_idx, + p_hwfn->p_l2_info->pp_qid_usage[p_cid->rel.queue_id]); + + mutex_unlock(&p_hwfn->p_l2_info->lock); +} + void qed_eth_queue_cid_release(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid) { - /* VFs' CIDs are 0-based in PF-view, and uninitialized on VF */ - if (!p_cid->is_vf && IS_PF(p_hwfn->cdev)) - qed_cxt_release_cid(p_hwfn, p_cid->cid); + bool b_legacy_vf = !!(p_cid->vf_legacy & QED_QCID_LEGACY_VF_CID); + + if (IS_PF(p_hwfn->cdev) && !b_legacy_vf) + _qed_cxt_release_cid(p_hwfn, p_cid->cid, p_cid->vfid); + + /* For PF's VFs we maintain the index inside queue-zone in IOV */ + if (p_cid->vfid == QED_QUEUE_CID_SELF) + qed_eth_queue_qid_usage_del(p_hwfn, p_cid); + vfree(p_cid); } /* The internal is only meant to be directly called by PFs initializeing CIDs * for their VFs. */ -struct qed_queue_cid * +static struct qed_queue_cid * _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, u16 opaque_fid, u32 cid, - u8 vf_qid, - struct qed_queue_start_common_params *p_params) + struct qed_queue_start_common_params *p_params, + bool b_is_rx, + struct qed_queue_cid_vf_params *p_vf_params) { - bool b_is_same = (p_hwfn->hw_info.opaque_fid == opaque_fid); struct qed_queue_cid *p_cid; int rc; @@ -96,10 +231,25 @@ _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, p_cid->opaque_fid = opaque_fid; p_cid->cid = cid; - p_cid->vf_qid = vf_qid; - p_cid->rel = *p_params; p_cid->p_owner = p_hwfn; + /* Fill in parameters */ + p_cid->rel.vport_id = p_params->vport_id; + p_cid->rel.queue_id = p_params->queue_id; + p_cid->rel.stats_id = p_params->stats_id; + p_cid->sb_igu_id = p_params->p_sb->igu_sb_id; + p_cid->b_is_rx = b_is_rx; + p_cid->sb_idx = p_params->sb_idx; + + /* Fill-in bits related to VFs' queues if information was provided */ + if (p_vf_params) { + p_cid->vfid = p_vf_params->vfid; + p_cid->vf_qid = p_vf_params->vf_qid; + p_cid->vf_legacy = p_vf_params->vf_legacy; + } else { + p_cid->vfid = QED_QUEUE_CID_SELF; + } + /* Don't try calculating the absolute indices for VFs */ if (IS_VF(p_hwfn->cdev)) { p_cid->abs = p_cid->rel; @@ -121,7 +271,7 @@ _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, /* In case of a PF configuring its VF's queues, the stats-id is already * absolute [since there's a single index that's suitable per-VF]. */ - if (b_is_same) { + if (p_cid->vfid == QED_QUEUE_CID_SELF) { rc = qed_fw_vport(p_hwfn, p_cid->rel.stats_id, &p_cid->abs.stats_id); if (rc) @@ -130,27 +280,29 @@ _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, p_cid->abs.stats_id = p_cid->rel.stats_id; } - /* SBs relevant information was already provided as absolute */ - p_cid->abs.sb = p_cid->rel.sb; - p_cid->abs.sb_idx = p_cid->rel.sb_idx; - - /* This is tricky - we're actually interested in whehter this is a PF - * entry meant for the VF. - */ - if (!b_is_same) - p_cid->is_vf = true; out: + /* VF-images have provided the qid_usage_idx on their own. + * Otherwise, we need to allocate a unique one. + */ + if (!p_vf_params) { + if (!qed_eth_queue_qid_usage_add(p_hwfn, p_cid)) + goto fail; + } else { + p_cid->qid_usage_idx = p_vf_params->qid_usage_idx; + } + DP_VERBOSE(p_hwfn, QED_MSG_SP, - "opaque_fid: %04x CID %08x vport %02x [%02x] qzone %04x [%04x] stats %02x [%02x] SB %04x PI %02x\n", + "opaque_fid: %04x CID %08x vport %02x [%02x] qzone %04x.%02x [%04x] stats %02x [%02x] SB %04x PI %02x\n", p_cid->opaque_fid, p_cid->cid, p_cid->rel.vport_id, p_cid->abs.vport_id, p_cid->rel.queue_id, + p_cid->qid_usage_idx, p_cid->abs.queue_id, p_cid->rel.stats_id, - p_cid->abs.stats_id, p_cid->abs.sb, p_cid->abs.sb_idx); + p_cid->abs.stats_id, p_cid->sb_igu_id, p_cid->sb_idx); return p_cid; @@ -159,32 +311,61 @@ fail: return NULL; } -static struct qed_queue_cid *qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, - u16 opaque_fid, struct - qed_queue_start_common_params - *p_params) +struct qed_queue_cid * +qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, + u16 opaque_fid, + struct qed_queue_start_common_params *p_params, + bool b_is_rx, + struct qed_queue_cid_vf_params *p_vf_params) { struct qed_queue_cid *p_cid; + u8 vfid = QED_CXT_PF_CID; + bool b_legacy_vf = false; u32 cid = 0; + /* In case of legacy VFs, The CID can be derived from the additional + * VF parameters - the VF assumes queue X uses CID X, so we can simply + * use the vf_qid for this purpose as well. + */ + if (p_vf_params) { + vfid = p_vf_params->vfid; + + if (p_vf_params->vf_legacy & QED_QCID_LEGACY_VF_CID) { + b_legacy_vf = true; + cid = p_vf_params->vf_qid; + } + } + /* Get a unique firmware CID for this queue, in case it's a PF. * VF's don't need a CID as the queue configuration will be done * by PF. */ - if (IS_PF(p_hwfn->cdev)) { - if (qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_ETH, &cid)) { + if (IS_PF(p_hwfn->cdev) && !b_legacy_vf) { + if (_qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_ETH, + &cid, vfid)) { DP_NOTICE(p_hwfn, "Failed to acquire cid\n"); return NULL; } } - p_cid = _qed_eth_queue_to_cid(p_hwfn, opaque_fid, cid, 0, p_params); - if (!p_cid && IS_PF(p_hwfn->cdev)) - qed_cxt_release_cid(p_hwfn, cid); + p_cid = _qed_eth_queue_to_cid(p_hwfn, opaque_fid, cid, + p_params, b_is_rx, p_vf_params); + if (!p_cid && IS_PF(p_hwfn->cdev) && !b_legacy_vf) + _qed_cxt_release_cid(p_hwfn, cid, vfid); return p_cid; } +static struct qed_queue_cid * +qed_eth_queue_to_cid_pf(struct qed_hwfn *p_hwfn, + u16 opaque_fid, + bool b_is_rx, + struct qed_queue_start_common_params *p_params) +{ + return qed_eth_queue_to_cid(p_hwfn, opaque_fid, p_params, b_is_rx, + NULL); +} + int qed_sp_eth_vport_start(struct qed_hwfn *p_hwfn, struct qed_sp_vport_start_params *p_params) { @@ -682,7 +863,7 @@ int qed_eth_rxq_start_ramrod(struct qed_hwfn *p_hwfn, DP_VERBOSE(p_hwfn, QED_MSG_SP, "opaque_fid=0x%x, cid=0x%x, rx_qzone=0x%x, vport_id=0x%x, sb_id=0x%x\n", p_cid->opaque_fid, p_cid->cid, - p_cid->abs.queue_id, p_cid->abs.vport_id, p_cid->abs.sb); + p_cid->abs.queue_id, p_cid->abs.vport_id, p_cid->sb_igu_id); /* Get SPQ entry */ memset(&init_data, 0, sizeof(init_data)); @@ -698,8 +879,8 @@ int qed_eth_rxq_start_ramrod(struct qed_hwfn *p_hwfn, p_ramrod = &p_ent->ramrod.rx_queue_start; - p_ramrod->sb_id = cpu_to_le16(p_cid->abs.sb); - p_ramrod->sb_index = p_cid->abs.sb_idx; + p_ramrod->sb_id = cpu_to_le16(p_cid->sb_igu_id); + p_ramrod->sb_index = p_cid->sb_idx; p_ramrod->vport_id = p_cid->abs.vport_id; p_ramrod->stats_counter_id = p_cid->abs.stats_id; p_ramrod->rx_queue_id = cpu_to_le16(p_cid->abs.queue_id); @@ -712,13 +893,15 @@ int qed_eth_rxq_start_ramrod(struct qed_hwfn *p_hwfn, p_ramrod->num_of_pbl_pages = cpu_to_le16(cqe_pbl_size); DMA_REGPAIR_LE(p_ramrod->cqe_pbl_addr, cqe_pbl_addr); - if (p_cid->is_vf) { + if (p_cid->vfid != QED_QUEUE_CID_SELF) { + bool b_legacy_vf = !!(p_cid->vf_legacy & + QED_QCID_LEGACY_VF_RX_PROD); + p_ramrod->vf_rx_prod_index = p_cid->vf_qid; DP_VERBOSE(p_hwfn, QED_MSG_SP, "Queue%s is meant for VF rxq[%02x]\n", - !!p_cid->b_legacy_vf ? " [legacy]" : "", - p_cid->vf_qid); - p_ramrod->vf_rx_prod_use_zone_a = !!p_cid->b_legacy_vf; + b_legacy_vf ? " [legacy]" : "", p_cid->vf_qid); + p_ramrod->vf_rx_prod_use_zone_a = b_legacy_vf; } return qed_spq_post(p_hwfn, p_ent, NULL); @@ -762,7 +945,7 @@ qed_eth_rx_queue_start(struct qed_hwfn *p_hwfn, int rc; /* Allocate a CID for the queue */ - p_cid = qed_eth_queue_to_cid(p_hwfn, opaque_fid, p_params); + p_cid = qed_eth_queue_to_cid_pf(p_hwfn, opaque_fid, true, p_params); if (!p_cid) return -ENOMEM; @@ -864,10 +1047,11 @@ qed_eth_pf_rx_queue_stop(struct qed_hwfn *p_hwfn, /* Cleaning the queue requires the completion to arrive there. * In addition, VFs require the answer to come as eqe to PF. */ - p_ramrod->complete_cqe_flg = (!p_cid->is_vf && + p_ramrod->complete_cqe_flg = ((p_cid->vfid == QED_QUEUE_CID_SELF) && !b_eq_completion_only) || b_cqe_completion; - p_ramrod->complete_event_flg = p_cid->is_vf || b_eq_completion_only; + p_ramrod->complete_event_flg = (p_cid->vfid != QED_QUEUE_CID_SELF) || + b_eq_completion_only; return qed_spq_post(p_hwfn, p_ent, NULL); } @@ -916,8 +1100,8 @@ qed_eth_txq_start_ramrod(struct qed_hwfn *p_hwfn, p_ramrod = &p_ent->ramrod.tx_queue_start; p_ramrod->vport_id = p_cid->abs.vport_id; - p_ramrod->sb_id = cpu_to_le16(p_cid->abs.sb); - p_ramrod->sb_index = p_cid->abs.sb_idx; + p_ramrod->sb_id = cpu_to_le16(p_cid->sb_igu_id); + p_ramrod->sb_index = p_cid->sb_idx; p_ramrod->stats_counter_id = p_cid->abs.stats_id; p_ramrod->queue_zone_id = cpu_to_le16(p_cid->abs.queue_id); @@ -966,7 +1150,7 @@ qed_eth_tx_queue_start(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid; int rc; - p_cid = qed_eth_queue_to_cid(p_hwfn, opaque_fid, p_params); + p_cid = qed_eth_queue_to_cid_pf(p_hwfn, opaque_fid, false, p_params); if (!p_cid) return -EINVAL; @@ -1935,15 +2119,26 @@ static int qed_fill_eth_dev_info(struct qed_dev *cdev, ether_addr_copy(info->port_mac, cdev->hwfns[0].hw_info.hw_mac_addr); + + info->xdp_supported = true; } else { - qed_vf_get_num_rxqs(QED_LEADING_HWFN(cdev), &info->num_queues); - if (cdev->num_hwfns > 1) { - u8 queues = 0; + u16 total_cids = 0; - qed_vf_get_num_rxqs(&cdev->hwfns[1], &queues); + /* Determine queues & XDP support */ + for_each_hwfn(cdev, i) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + u8 queues, cids; + + qed_vf_get_num_cids(p_hwfn, &cids); + qed_vf_get_num_rxqs(p_hwfn, &queues); info->num_queues += queues; + total_cids += cids; } + /* Enable VF XDP in case PF guarntees sufficient connections */ + if (total_cids >= info->num_queues * 3) + info->xdp_supported = true; + qed_vf_get_num_vlan_filters(&cdev->hwfns[0], (u8 *)&info->num_vlan_filters); qed_vf_get_num_mac_filters(&cdev->hwfns[0], @@ -2194,9 +2389,9 @@ static int qed_start_rxq(struct qed_dev *cdev, } DP_VERBOSE(cdev, (QED_MSG_SPQ | NETIF_MSG_IFUP), - "Started RX-Q %d [rss_num %d] on V-PORT %d and SB %d\n", + "Started RX-Q %d [rss_num %d] on V-PORT %d and SB igu %d\n", p_params->queue_id, rss_num, p_params->vport_id, - p_params->sb); + p_params->p_sb->igu_sb_id); return 0; } @@ -2244,9 +2439,9 @@ static int qed_start_txq(struct qed_dev *cdev, } DP_VERBOSE(cdev, (QED_MSG_SPQ | NETIF_MSG_IFUP), - "Started TX-Q %d [rss_num %d] on V-PORT %d and SB %d\n", + "Started TX-Q %d [rss_num %d] on V-PORT %d and SB igu %d\n", p_params->queue_id, rss_num, p_params->vport_id, - p_params->sb); + p_params->p_sb->igu_sb_id); return 0; } @@ -2301,14 +2496,25 @@ static int qed_tunn_configure(struct qed_dev *cdev, for_each_hwfn(cdev, i) { struct qed_hwfn *hwfn = &cdev->hwfns[i]; + struct qed_ptt *p_ptt; struct qed_tunnel_info *tun; tun = &hwfn->cdev->tunnel; + if (IS_PF(cdev)) { + p_ptt = qed_ptt_acquire(hwfn); + if (!p_ptt) + return -EAGAIN; + } else { + p_ptt = NULL; + } - rc = qed_sp_pf_update_tunn_cfg(hwfn, &tunn_info, + rc = qed_sp_pf_update_tunn_cfg(hwfn, p_ptt, &tunn_info, QED_SPQ_MODE_EBLOCK, NULL); - if (rc) + if (rc) { + if (IS_PF(cdev)) + qed_ptt_release(hwfn, p_ptt); return rc; + } if (IS_PF_SRIOV(hwfn)) { u16 vxlan_port, geneve_port; @@ -2325,6 +2531,8 @@ static int qed_tunn_configure(struct qed_dev *cdev, qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG); } + if (IS_PF(cdev)) + qed_ptt_release(hwfn, p_ptt); } return 0; diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.h b/drivers/net/ethernet/qlogic/qed/qed_l2.h index 6f44229899eb..f8f09aadced7 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.h @@ -277,40 +277,87 @@ void qed_get_vport_stats(struct qed_dev *cdev, struct qed_eth_stats *stats); void qed_reset_vport_stats(struct qed_dev *cdev); -struct qed_queue_cid { - /* 'Relative' is a relative term ;-). Usually the indices [not counting - * SBs] would be PF-relative, but there are some cases where that isn't - * the case - specifically for a PF configuring its VF indices it's - * possible some fields [E.g., stats-id] in 'rel' would already be abs. +#define MAX_QUEUES_PER_QZONE (sizeof(unsigned long) * 8) +#define QED_QUEUE_CID_SELF (0xff) + +/* Almost identical to the qed_queue_start_common_params, + * but here we maintain the SB index in IGU CAM. + */ +struct qed_queue_cid_params { + u8 vport_id; + u16 queue_id; + u8 stats_id; +}; + +/* Additional parameters required for initialization of the queue_cid + * and are relevant only for a PF initializing one for its VFs. + */ +struct qed_queue_cid_vf_params { + /* Should match the VF's relative index */ + u8 vfid; + + /* 0-based queue index. Should reflect the relative qzone the + * VF thinks is associated with it [in its range]. + */ + u8 vf_qid; + + /* Indicates a VF is legacy, making it differ in several things: + * - Producers would be placed in a different place. + * - Makes assumptions regarding the CIDs. */ - struct qed_queue_start_common_params rel; - struct qed_queue_start_common_params abs; + u8 vf_legacy; + + u8 qid_usage_idx; +}; + +struct qed_queue_cid { + /* For stats-id, the `rel' is actually absolute as well */ + struct qed_queue_cid_params rel; + struct qed_queue_cid_params abs; + + /* These have no 'relative' meaning */ + u16 sb_igu_id; + u8 sb_idx; + u32 cid; u16 opaque_fid; + bool b_is_rx; + /* VFs queues are mapped differently, so we need to know the * relative queue associated with them [0-based]. * Notice this is relevant on the *PF* queue-cid of its VF's queues, * and not on the VF itself. */ - bool is_vf; + u8 vfid; u8 vf_qid; - /* Legacy VFs might have Rx producer located elsewhere */ - bool b_legacy_vf; + /* We need an additional index to differentiate between queues opened + * for same queue-zone, as VFs would have to communicate the info + * to the PF [otherwise PF has no way to differentiate]. + */ + u8 qid_usage_idx; + + u8 vf_legacy; +#define QED_QCID_LEGACY_VF_RX_PROD (BIT(0)) +#define QED_QCID_LEGACY_VF_CID (BIT(1)) struct qed_hwfn *p_owner; }; +int qed_l2_alloc(struct qed_hwfn *p_hwfn); +void qed_l2_setup(struct qed_hwfn *p_hwfn); +void qed_l2_free(struct qed_hwfn *p_hwfn); + void qed_eth_queue_cid_release(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid); -struct qed_queue_cid *_qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, - u16 opaque_fid, - u32 cid, - u8 vf_qid, - struct qed_queue_start_common_params - *p_params); +struct qed_queue_cid * +qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, + u16 opaque_fid, + struct qed_queue_start_common_params *p_params, + bool b_is_rx, + struct qed_queue_cid_vf_params *p_vf_params); int qed_sp_eth_vport_start(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index 09c86411918c..f67ed6d39dfd 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -38,7 +38,6 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/stddef.h> -#include <linux/version.h> #include <linux/workqueue.h> #include <net/ipv6.h> #include <linux/bitops.h> @@ -1921,7 +1920,7 @@ void qed_ll2_release_connection(struct qed_hwfn *p_hwfn, u8 connection_handle) mutex_unlock(&p_ll2_conn->mutex); } -struct qed_ll2_info *qed_ll2_alloc(struct qed_hwfn *p_hwfn) +int qed_ll2_alloc(struct qed_hwfn *p_hwfn) { struct qed_ll2_info *p_ll2_connections; u8 i; @@ -1931,28 +1930,31 @@ struct qed_ll2_info *qed_ll2_alloc(struct qed_hwfn *p_hwfn) sizeof(struct qed_ll2_info), GFP_KERNEL); if (!p_ll2_connections) { DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_ll2'\n"); - return NULL; + return -ENOMEM; } for (i = 0; i < QED_MAX_NUM_OF_LL2_CONNECTIONS; i++) p_ll2_connections[i].my_id = i; - return p_ll2_connections; + p_hwfn->p_ll2_info = p_ll2_connections; + return 0; } -void qed_ll2_setup(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_connections) +void qed_ll2_setup(struct qed_hwfn *p_hwfn) { int i; for (i = 0; i < QED_MAX_NUM_OF_LL2_CONNECTIONS; i++) - mutex_init(&p_ll2_connections[i].mutex); + mutex_init(&p_hwfn->p_ll2_info[i].mutex); } -void qed_ll2_free(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_connections) +void qed_ll2_free(struct qed_hwfn *p_hwfn) { - kfree(p_ll2_connections); + if (!p_hwfn->p_ll2_info) + return; + + kfree(p_hwfn->p_ll2_info); + p_hwfn->p_ll2_info = NULL; } static void _qed_ll2_get_tstats(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h b/drivers/net/ethernet/qlogic/qed/qed_ll2.h index 31a409033c41..2c07d0ed971a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h @@ -306,27 +306,24 @@ int qed_ll2_get_stats(struct qed_hwfn *p_hwfn, * * @param p_hwfn * - * @return pointer to alocated qed_ll2_info or NULL + * @return int */ -struct qed_ll2_info *qed_ll2_alloc(struct qed_hwfn *p_hwfn); +int qed_ll2_alloc(struct qed_hwfn *p_hwfn); /** * @brief qed_ll2_setup - Inits LL2 connections set * * @param p_hwfn - * @param p_ll2_connections * */ -void qed_ll2_setup(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_connections); +void qed_ll2_setup(struct qed_hwfn *p_hwfn); /** * @brief qed_ll2_free - Releases LL2 connections set * * @param p_hwfn - * @param p_ll2_connections * */ -void qed_ll2_free(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_connections); +void qed_ll2_free(struct qed_hwfn *p_hwfn); + #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 715b3aaf83ac..16cc30b11cce 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -34,7 +34,6 @@ #include <linux/pci.h> #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/version.h> #include <linux/delay.h> #include <asm/byteorder.h> #include <linux/dma-mapping.h> @@ -123,7 +122,7 @@ static void qed_free_pci(struct qed_dev *cdev) { struct pci_dev *pdev = cdev->pdev; - if (cdev->doorbells) + if (cdev->doorbells && cdev->db_size) iounmap(cdev->doorbells); if (cdev->regview) iounmap(cdev->regview); @@ -207,16 +206,24 @@ static int qed_init_pci(struct qed_dev *cdev, struct pci_dev *pdev) goto err2; } - if (IS_PF(cdev)) { - cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2); - cdev->db_size = pci_resource_len(cdev->pdev, 2); - cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size); - if (!cdev->doorbells) { - DP_NOTICE(cdev, "Cannot map doorbell space\n"); - return -ENOMEM; + cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2); + cdev->db_size = pci_resource_len(cdev->pdev, 2); + if (!cdev->db_size) { + if (IS_PF(cdev)) { + DP_NOTICE(cdev, "No Doorbell bar available\n"); + return -EINVAL; + } else { + return 0; } } + cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size); + + if (!cdev->doorbells) { + DP_NOTICE(cdev, "Cannot map doorbell space\n"); + return -ENOMEM; + } + return 0; err2: @@ -270,6 +277,8 @@ int qed_fill_dev_info(struct qed_dev *cdev, if (QED_LEADING_HWFN(cdev)->hw_info.b_wol_support == QED_WOL_SUPPORT_PME) dev_info->wol_support = true; + + dev_info->abs_pf_id = QED_LEADING_HWFN(cdev)->abs_pf_id; } else { qed_vf_get_fw_version(&cdev->hwfns[0], &dev_info->fw_major, &dev_info->fw_minor, &dev_info->fw_rev, @@ -282,6 +291,9 @@ int qed_fill_dev_info(struct qed_dev *cdev, qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), ptt, &dev_info->mfw_rev, NULL); + qed_mcp_get_mbi_ver(QED_LEADING_HWFN(cdev), ptt, + &dev_info->mbi_version); + qed_mcp_get_flash_size(QED_LEADING_HWFN(cdev), ptt, &dev_info->flash_size); @@ -336,6 +348,7 @@ static struct qed_dev *qed_probe(struct pci_dev *pdev, if (!cdev) goto err0; + cdev->drv_type = DRV_ID_DRV_TYPE_LINUX; cdev->protocol = params->protocol; if (params->is_vf) @@ -607,6 +620,18 @@ int qed_slowpath_irq_req(struct qed_hwfn *hwfn) return rc; } +static void qed_slowpath_tasklet_flush(struct qed_hwfn *p_hwfn) +{ + /* Calling the disable function will make sure that any + * currently-running function is completed. The following call to the + * enable function makes this sequence a flush-like operation. + */ + if (p_hwfn->b_sp_dpc_enabled) { + tasklet_disable(p_hwfn->sp_dpc); + tasklet_enable(p_hwfn->sp_dpc); + } +} + void qed_slowpath_irq_sync(struct qed_hwfn *p_hwfn) { struct qed_dev *cdev = p_hwfn->cdev; @@ -618,6 +643,8 @@ void qed_slowpath_irq_sync(struct qed_hwfn *p_hwfn) synchronize_irq(cdev->int_params.msix_table[id].vector); else synchronize_irq(cdev->pdev->irq); + + qed_slowpath_tasklet_flush(p_hwfn); } static void qed_slowpath_irq_free(struct qed_dev *cdev) @@ -745,7 +772,7 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev, for_each_hwfn(cdev, i) { memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); qed_int_get_num_sbs(&cdev->hwfns[i], &sb_cnt_info); - cdev->int_params.in.num_vectors += sb_cnt_info.sb_cnt; + cdev->int_params.in.num_vectors += sb_cnt_info.cnt; cdev->int_params.in.num_vectors++; /* slowpath */ } @@ -1112,17 +1139,13 @@ static int qed_slowpath_stop(struct qed_dev *cdev) return 0; } -static void qed_set_id(struct qed_dev *cdev, char name[NAME_SIZE], - char ver_str[VER_SIZE]) +static void qed_set_name(struct qed_dev *cdev, char name[NAME_SIZE]) { int i; memcpy(cdev->name, name, NAME_SIZE); for_each_hwfn(cdev, i) snprintf(cdev->hwfns[i].name, NAME_SIZE, "%s-%d", name, i); - - memcpy(cdev->ver_str, ver_str, VER_SIZE); - cdev->drv_type = DRV_ID_DRV_TYPE_LINUX; } static u32 qed_sb_init(struct qed_dev *cdev, @@ -1520,6 +1543,21 @@ static int qed_drain(struct qed_dev *cdev) return 0; } +static int qed_nvm_get_image(struct qed_dev *cdev, enum qed_nvm_images type, + u8 *buf, u16 len) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_ptt *ptt = qed_ptt_acquire(hwfn); + int rc; + + if (!ptt) + return -EAGAIN; + + rc = qed_mcp_get_nvm_image(hwfn, ptt, type, buf, len); + qed_ptt_release(hwfn, ptt); + return rc; +} + static void qed_get_coalesce(struct qed_dev *cdev, u16 *rx_coal, u16 *tx_coal) { *rx_coal = cdev->rx_coalesce_usecs; @@ -1676,7 +1714,7 @@ const struct qed_common_ops qed_common_ops_pass = { .probe = &qed_probe, .remove = &qed_remove, .set_power_state = &qed_set_power_state, - .set_id = &qed_set_id, + .set_name = &qed_set_name, .update_pf_params = &qed_update_pf_params, .slowpath_start = &qed_slowpath_start, .slowpath_stop = &qed_slowpath_stop, @@ -1697,6 +1735,7 @@ const struct qed_common_ops qed_common_ops_pass = { .dbg_all_data_size = &qed_dbg_all_data_size, .chain_alloc = &qed_chain_alloc, .chain_free = &qed_chain_free, + .nvm_get_image = &qed_nvm_get_image, .get_coalesce = &qed_get_coalesce, .set_coalesce = &qed_set_coalesce, .set_led = &qed_set_led, diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index 7266b36a2655..9da91045d167 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -177,6 +177,7 @@ int qed_mcp_free(struct qed_hwfn *p_hwfn) } kfree(p_hwfn->mcp_info); + p_hwfn->mcp_info = NULL; return 0; } @@ -1397,6 +1398,28 @@ static void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) ¶m); } +static void qed_mcp_update_stag(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + struct public_func shmem_info; + u32 resp = 0, param = 0; + + qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); + + p_hwfn->mcp_info->func_info.ovlan = (u16)shmem_info.ovlan_stag & + FUNC_MF_CFG_OV_STAG_MASK; + p_hwfn->hw_info.ovlan = p_hwfn->mcp_info->func_info.ovlan; + if ((p_hwfn->hw_info.hw_mode & BIT(MODE_MF_SD)) && + (p_hwfn->hw_info.ovlan != QED_MCP_VLAN_UNSET)) { + qed_wr(p_hwfn, p_ptt, + NIG_REG_LLH_FUNC_TAG_VALUE, p_hwfn->hw_info.ovlan); + qed_sp_pf_update_stag(p_hwfn); + } + + /* Acknowledge the MFW */ + qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_S_TAG_UPDATE_ACK, 0, + &resp, ¶m); +} + int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { @@ -1452,6 +1475,10 @@ int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, case MFW_DRV_MSG_BW_UPDATE: qed_mcp_update_bw(p_hwfn, p_ptt); break; + case MFW_DRV_MSG_S_TAG_UPDATE: + qed_mcp_update_stag(p_hwfn, p_ptt); + break; + break; default: DP_INFO(p_hwfn, "Unimplemented MFW message %d\n", i); rc = -EINVAL; @@ -1522,6 +1549,36 @@ int qed_mcp_get_mfw_ver(struct qed_hwfn *p_hwfn, return 0; } +int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u32 *p_mbi_ver) +{ + u32 nvm_cfg_addr, nvm_cfg1_offset, mbi_ver_addr; + + if (IS_VF(p_hwfn->cdev)) + return -EINVAL; + + /* Read the address of the nvm_cfg */ + nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); + if (!nvm_cfg_addr) { + DP_NOTICE(p_hwfn, "Shared memory not initialized\n"); + return -EINVAL; + } + + /* Read the offset of nvm_cfg1 */ + nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); + + mbi_ver_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + + offsetof(struct nvm_cfg1, glob) + + offsetof(struct nvm_cfg1_glob, mbi_version); + *p_mbi_ver = qed_rd(p_hwfn, p_ptt, + mbi_ver_addr) & + (NVM_CFG1_GLOB_MBI_VERSION_0_MASK | + NVM_CFG1_GLOB_MBI_VERSION_1_MASK | + NVM_CFG1_GLOB_MBI_VERSION_2_MASK); + + return 0; +} + int qed_mcp_get_media_type(struct qed_dev *cdev, u32 *p_media_type) { struct qed_hwfn *p_hwfn = &cdev->hwfns[0]; @@ -1679,10 +1736,10 @@ int qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn, DP_NOTICE(p_hwfn, "MAC is 0 in shmem\n"); } - info->wwn_port = (u64)shmem_info.fcoe_wwn_port_name_upper | - (((u64)shmem_info.fcoe_wwn_port_name_lower) << 32); - info->wwn_node = (u64)shmem_info.fcoe_wwn_node_name_upper | - (((u64)shmem_info.fcoe_wwn_node_name_lower) << 32); + info->wwn_port = (u64)shmem_info.fcoe_wwn_port_name_lower | + (((u64)shmem_info.fcoe_wwn_port_name_upper) << 32); + info->wwn_node = (u64)shmem_info.fcoe_wwn_node_name_lower | + (((u64)shmem_info.fcoe_wwn_node_name_upper) << 32); info->ovlan = (u16)(shmem_info.ovlan_stag & FUNC_MF_CFG_OV_STAG_MASK); @@ -1770,8 +1827,9 @@ int qed_mcp_get_flash_size(struct qed_hwfn *p_hwfn, return 0; } -int qed_mcp_config_vf_msix(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, u8 vf_id, u8 num) +static int +qed_mcp_config_vf_msix_bb(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u8 vf_id, u8 num) { u32 resp = 0, param = 0, rc_param = 0; int rc; @@ -1801,6 +1859,36 @@ int qed_mcp_config_vf_msix(struct qed_hwfn *p_hwfn, return rc; } +static int +qed_mcp_config_vf_msix_ah(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u8 num) +{ + u32 resp = 0, param = num, rc_param = 0; + int rc; + + rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_PF_VFS_MSIX, + param, &resp, &rc_param); + + if (resp != FW_MSG_CODE_DRV_CFG_PF_VFS_MSIX_DONE) { + DP_NOTICE(p_hwfn, "MFW failed to set MSI-X for VFs\n"); + rc = -EINVAL; + } else { + DP_VERBOSE(p_hwfn, QED_MSG_IOV, + "Requested 0x%02x MSI-x interrupts for VFs\n", num); + } + + return rc; +} + +int qed_mcp_config_vf_msix(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u8 vf_id, u8 num) +{ + if (QED_IS_BB(p_hwfn->cdev)) + return qed_mcp_config_vf_msix_bb(p_hwfn, p_ptt, vf_id, num); + else + return qed_mcp_config_vf_msix_ah(p_hwfn, p_ptt, num); +} + int qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, @@ -2222,6 +2310,95 @@ int qed_mcp_bist_nvm_test_get_image_att(struct qed_hwfn *p_hwfn, return rc; } +static int +qed_mcp_get_nvm_image_att(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum qed_nvm_images image_id, + struct qed_nvm_image_att *p_image_att) +{ + struct bist_nvm_image_att mfw_image_att; + enum nvm_image_type type; + u32 num_images, i; + int rc; + + /* Translate image_id into MFW definitions */ + switch (image_id) { + case QED_NVM_IMAGE_ISCSI_CFG: + type = NVM_TYPE_ISCSI_CFG; + break; + case QED_NVM_IMAGE_FCOE_CFG: + type = NVM_TYPE_FCOE_CFG; + break; + default: + DP_NOTICE(p_hwfn, "Unknown request of image_id %08x\n", + image_id); + return -EINVAL; + } + + /* Learn number of images, then traverse and see if one fits */ + rc = qed_mcp_bist_nvm_test_get_num_images(p_hwfn, p_ptt, &num_images); + if (rc || !num_images) + return -EINVAL; + + for (i = 0; i < num_images; i++) { + rc = qed_mcp_bist_nvm_test_get_image_att(p_hwfn, p_ptt, + &mfw_image_att, i); + if (rc) + return rc; + + if (type == mfw_image_att.image_type) + break; + } + if (i == num_images) { + DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, + "Failed to find nvram image of type %08x\n", + image_id); + return -EINVAL; + } + + p_image_att->start_addr = mfw_image_att.nvm_start_addr; + p_image_att->length = mfw_image_att.len; + + return 0; +} + +int qed_mcp_get_nvm_image(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum qed_nvm_images image_id, + u8 *p_buffer, u32 buffer_len) +{ + struct qed_nvm_image_att image_att; + int rc; + + memset(p_buffer, 0, buffer_len); + + rc = qed_mcp_get_nvm_image_att(p_hwfn, p_ptt, image_id, &image_att); + if (rc) + return rc; + + /* Validate sizes - both the image's and the supplied buffer's */ + if (image_att.length <= 4) { + DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, + "Image [%d] is too small - only %d bytes\n", + image_id, image_att.length); + return -EINVAL; + } + + /* Each NVM image is suffixed by CRC; Upper-layer has no need for it */ + image_att.length -= 4; + + if (image_att.length > buffer_len) { + DP_VERBOSE(p_hwfn, + QED_MSG_STORAGE, + "Image [%d] is too big - %08x bytes where only %08x are available\n", + image_id, image_att.length, buffer_len); + return -ENOMEM; + } + + return qed_mcp_nvm_read(p_hwfn->cdev, image_att.start_addr, + p_buffer, image_att.length); +} + static enum resource_id_enum qed_mcp_get_mfw_res_id(enum qed_resources res_id) { enum resource_id_enum mfw_res_id = RESOURCE_NUM_INVALID; diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h index 2b09b8545236..af03b3651411 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h @@ -256,6 +256,18 @@ int qed_mcp_get_mfw_ver(struct qed_hwfn *p_hwfn, u32 *p_mfw_ver, u32 *p_running_bundle_id); /** + * @brief Get the MBI version value + * + * @param p_hwfn + * @param p_ptt + * @param p_mbi_ver - A pointer to a variable to be filled with the MBI version. + * + * @return int - 0 - operation was successful. + */ +int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u32 *p_mbi_ver); + +/** * @brief Get media type value of the port. * * @param cdev - qed dev pointer @@ -418,6 +430,27 @@ int qed_mcp_set_led(struct qed_hwfn *p_hwfn, */ int qed_mcp_nvm_read(struct qed_dev *cdev, u32 addr, u8 *p_buf, u32 len); +struct qed_nvm_image_att { + u32 start_addr; + u32 length; +}; + +/** + * @brief Allows reading a whole nvram image + * + * @param p_hwfn + * @param p_ptt + * @param image_id - image requested for reading + * @param p_buffer - allocated buffer into which to fill data + * @param buffer_len - length of the allocated buffer. + * + * @return 0 iff p_buffer now contains the nvram image. + */ +int qed_mcp_get_nvm_image(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum qed_nvm_images image_id, + u8 *p_buffer, u32 buffer_len); + /** * @brief Bist register test * @@ -482,7 +515,7 @@ int qed_mcp_bist_nvm_test_get_image_att(struct qed_hwfn *p_hwfn, #define MCP_PF_ID(p_hwfn) MCP_PF_ID_BY_REL(p_hwfn, (p_hwfn)->rel_pf_id) #define MFW_PORT(_p_hwfn) ((_p_hwfn)->abs_pf_id % \ - ((_p_hwfn)->cdev->num_ports_in_engines * \ + ((_p_hwfn)->cdev->num_ports_in_engine * \ qed_device_num_engines((_p_hwfn)->cdev))) struct qed_mcp_info { diff --git a/drivers/net/ethernet/qlogic/qed/qed_ooo.c b/drivers/net/ethernet/qlogic/qed/qed_ooo.c index db96670192c7..000636530111 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ooo.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ooo.c @@ -99,7 +99,7 @@ void qed_ooo_save_history_entry(struct qed_hwfn *p_hwfn, p_history->head_idx++; } -struct qed_ooo_info *qed_ooo_alloc(struct qed_hwfn *p_hwfn) +int qed_ooo_alloc(struct qed_hwfn *p_hwfn) { u16 max_num_archipelagos = 0, cid_base; struct qed_ooo_info *p_ooo_info; @@ -109,7 +109,7 @@ struct qed_ooo_info *qed_ooo_alloc(struct qed_hwfn *p_hwfn) if (p_hwfn->hw_info.personality != QED_PCI_ISCSI) { DP_NOTICE(p_hwfn, "Failed to allocate qed_ooo_info: unknown personality\n"); - return NULL; + return -EINVAL; } max_num_archipelagos = p_hwfn->pf_params.iscsi_pf_params.num_cons; @@ -119,12 +119,12 @@ struct qed_ooo_info *qed_ooo_alloc(struct qed_hwfn *p_hwfn) if (!max_num_archipelagos) { DP_NOTICE(p_hwfn, "Failed to allocate qed_ooo_info: unknown amount of connections\n"); - return NULL; + return -EINVAL; } p_ooo_info = kzalloc(sizeof(*p_ooo_info), GFP_KERNEL); if (!p_ooo_info) - return NULL; + return -ENOMEM; p_ooo_info->cid_base = cid_base; p_ooo_info->max_num_archipelagos = max_num_archipelagos; @@ -164,7 +164,8 @@ struct qed_ooo_info *qed_ooo_alloc(struct qed_hwfn *p_hwfn) p_ooo_info->ooo_history.num_of_cqes = QED_MAX_NUM_OOO_HISTORY_ENTRIES; - return p_ooo_info; + p_hwfn->p_ooo_info = p_ooo_info; + return 0; no_history_mem: kfree(p_ooo_info->p_archipelagos_mem); @@ -172,7 +173,7 @@ no_archipelagos_mem: kfree(p_ooo_info->p_isles_mem); no_isles_mem: kfree(p_ooo_info); - return NULL; + return -ENOMEM; } void qed_ooo_release_connection_isles(struct qed_hwfn *p_hwfn, @@ -249,19 +250,23 @@ void qed_ooo_release_all_isles(struct qed_hwfn *p_hwfn, &p_ooo_info->free_buffers_list); } -void qed_ooo_setup(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info) +void qed_ooo_setup(struct qed_hwfn *p_hwfn) { - qed_ooo_release_all_isles(p_hwfn, p_ooo_info); - memset(p_ooo_info->ooo_history.p_cqes, 0, - p_ooo_info->ooo_history.num_of_cqes * + qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); + memset(p_hwfn->p_ooo_info->ooo_history.p_cqes, 0, + p_hwfn->p_ooo_info->ooo_history.num_of_cqes * sizeof(struct ooo_opaque)); - p_ooo_info->ooo_history.head_idx = 0; + p_hwfn->p_ooo_info->ooo_history.head_idx = 0; } -void qed_ooo_free(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info) +void qed_ooo_free(struct qed_hwfn *p_hwfn) { + struct qed_ooo_info *p_ooo_info = p_hwfn->p_ooo_info; struct qed_ooo_buffer *p_buffer; + if (!p_ooo_info) + return; + qed_ooo_release_all_isles(p_hwfn, p_ooo_info); while (!list_empty(&p_ooo_info->free_buffers_list)) { p_buffer = list_first_entry(&p_ooo_info->free_buffers_list, @@ -282,6 +287,7 @@ void qed_ooo_free(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info) kfree(p_ooo_info->p_archipelagos_mem); kfree(p_ooo_info->ooo_history.p_cqes); kfree(p_ooo_info); + p_hwfn->p_ooo_info = NULL; } void qed_ooo_put_free_buffer(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_ooo.h b/drivers/net/ethernet/qlogic/qed/qed_ooo.h index 791ad0f8b759..e8ed40b848f5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ooo.h +++ b/drivers/net/ethernet/qlogic/qed/qed_ooo.h @@ -88,7 +88,11 @@ void qed_ooo_save_history_entry(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info, struct ooo_opaque *p_cqe); -struct qed_ooo_info *qed_ooo_alloc(struct qed_hwfn *p_hwfn); +int qed_ooo_alloc(struct qed_hwfn *p_hwfn); + +void qed_ooo_setup(struct qed_hwfn *p_hwfn); + +void qed_ooo_free(struct qed_hwfn *p_hwfn); void qed_ooo_release_connection_isles(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info, @@ -97,10 +101,6 @@ void qed_ooo_release_connection_isles(struct qed_hwfn *p_hwfn, void qed_ooo_release_all_isles(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info); -void qed_ooo_setup(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info); - -void qed_ooo_free(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info); - void qed_ooo_put_free_buffer(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info, struct qed_ooo_buffer *p_buffer); @@ -140,8 +140,14 @@ static inline void qed_ooo_save_history_entry(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info, struct ooo_opaque *p_cqe) {} -static inline struct qed_ooo_info *qed_ooo_alloc( - struct qed_hwfn *p_hwfn) { return NULL; } +static inline int qed_ooo_alloc(struct qed_hwfn *p_hwfn) +{ + return -EINVAL; +} + +static inline void qed_ooo_setup(struct qed_hwfn *p_hwfn) {} + +static inline void qed_ooo_free(struct qed_hwfn *p_hwfn) {} static inline void qed_ooo_release_connection_isles(struct qed_hwfn *p_hwfn, @@ -152,12 +158,6 @@ static inline void qed_ooo_release_all_isles(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info) {} -static inline void qed_ooo_setup(struct qed_hwfn *p_hwfn, - struct qed_ooo_info *p_ooo_info) {} - -static inline void qed_ooo_free(struct qed_hwfn *p_hwfn, - struct qed_ooo_info *p_ooo_info) {} - static inline void qed_ooo_put_free_buffer(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info, struct qed_ooo_buffer *p_buffer) {} diff --git a/drivers/net/ethernet/qlogic/qed/qed_ptp.c b/drivers/net/ethernet/qlogic/qed/qed_ptp.c index 434a164a76ed..5a90d69dc2f8 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ptp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ptp.c @@ -80,7 +80,7 @@ static int qed_ptp_res_lock(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) /* MFW doesn't support resource locking, first PF on the port * has lock ownership. */ - if (p_hwfn->abs_pf_id < p_hwfn->cdev->num_ports_in_engines) + if (p_hwfn->abs_pf_id < p_hwfn->cdev->num_ports_in_engine) return 0; DP_INFO(p_hwfn, "PF doesn't have lock ownership\n"); @@ -108,7 +108,7 @@ static int qed_ptp_res_unlock(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) rc = qed_mcp_resc_unlock(p_hwfn, p_ptt, ¶ms); if (rc == -EINVAL) { /* MFW doesn't support locking, first PF has lock ownership */ - if (p_hwfn->abs_pf_id < p_hwfn->cdev->num_ports_in_engines) { + if (p_hwfn->abs_pf_id < p_hwfn->cdev->num_ports_in_engine) { rc = 0; } else { DP_INFO(p_hwfn, "PF doesn't have lock ownership\n"); diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h index 1ae73b2d6d1e..7e4639c9207a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h @@ -242,6 +242,8 @@ 0x50196cUL #define NIG_REG_LLH_CLS_TYPE_DUALMODE \ 0x501964UL +#define NIG_REG_LLH_FUNC_TAG_EN 0x5019b0UL +#define NIG_REG_LLH_FUNC_TAG_VALUE 0x5019d0UL #define NIG_REG_LLH_FUNC_FILTER_VALUE \ 0x501a00UL #define NIG_REG_LLH_FUNC_FILTER_VALUE_SIZE \ @@ -558,6 +560,7 @@ 0x2aae60UL #define PGLUE_B_REG_PF_BAR1_SIZE \ 0x2aae64UL +#define PGLUE_B_REG_VF_BAR1_SIZE 0x2aae68UL #define PRS_REG_ENCAPSULATION_TYPE_EN 0x1f0730UL #define PRS_REG_GRE_PROTOCOL 0x1f0734UL #define PRS_REG_VXLAN_PORT 0x1f0738UL @@ -592,15 +595,15 @@ #define QM_REG_WFQPFWEIGHT 0x2f4e80UL #define QM_REG_WFQVPWEIGHT 0x2fa000UL -#define PGLCS_REG_DBG_SELECT \ +#define PGLCS_REG_DBG_SELECT_K2 \ 0x001d14UL -#define PGLCS_REG_DBG_DWORD_ENABLE \ +#define PGLCS_REG_DBG_DWORD_ENABLE_K2 \ 0x001d18UL -#define PGLCS_REG_DBG_SHIFT \ +#define PGLCS_REG_DBG_SHIFT_K2 \ 0x001d1cUL -#define PGLCS_REG_DBG_FORCE_VALID \ +#define PGLCS_REG_DBG_FORCE_VALID_K2 \ 0x001d20UL -#define PGLCS_REG_DBG_FORCE_FRAME \ +#define PGLCS_REG_DBG_FORCE_FRAME_K2 \ 0x001d24UL #define MISC_REG_RESET_PL_PDA_VMAIN_1 \ 0x008070UL @@ -612,7 +615,7 @@ 0x009050UL #define MISCS_REG_RESET_PL_HV \ 0x009060UL -#define MISCS_REG_RESET_PL_HV_2 \ +#define MISCS_REG_RESET_PL_HV_2_K2 \ 0x009150UL #define DMAE_REG_DBG_SELECT \ 0x00c510UL @@ -644,15 +647,15 @@ 0x0500b0UL #define GRC_REG_DBG_FORCE_FRAME \ 0x0500b4UL -#define UMAC_REG_DBG_SELECT \ +#define UMAC_REG_DBG_SELECT_K2 \ 0x051094UL -#define UMAC_REG_DBG_DWORD_ENABLE \ +#define UMAC_REG_DBG_DWORD_ENABLE_K2 \ 0x051098UL -#define UMAC_REG_DBG_SHIFT \ +#define UMAC_REG_DBG_SHIFT_K2 \ 0x05109cUL -#define UMAC_REG_DBG_FORCE_VALID \ +#define UMAC_REG_DBG_FORCE_VALID_K2 \ 0x0510a0UL -#define UMAC_REG_DBG_FORCE_FRAME \ +#define UMAC_REG_DBG_FORCE_FRAME_K2 \ 0x0510a4UL #define MCP2_REG_DBG_SELECT \ 0x052400UL @@ -924,15 +927,15 @@ 0x4c160cUL #define XYLD_REG_DBG_FORCE_FRAME \ 0x4c1610UL -#define YULD_REG_DBG_SELECT \ +#define YULD_REG_DBG_SELECT_BB_K2 \ 0x4c9600UL -#define YULD_REG_DBG_DWORD_ENABLE \ +#define YULD_REG_DBG_DWORD_ENABLE_BB_K2 \ 0x4c9604UL -#define YULD_REG_DBG_SHIFT \ +#define YULD_REG_DBG_SHIFT_BB_K2 \ 0x4c9608UL -#define YULD_REG_DBG_FORCE_VALID \ +#define YULD_REG_DBG_FORCE_VALID_BB_K2 \ 0x4c960cUL -#define YULD_REG_DBG_FORCE_FRAME \ +#define YULD_REG_DBG_FORCE_FRAME_BB_K2 \ 0x4c9610UL #define TMLD_REG_DBG_SELECT \ 0x4d1600UL @@ -994,35 +997,35 @@ 0x580710UL #define CDU_REG_DBG_FORCE_FRAME \ 0x580714UL -#define WOL_REG_DBG_SELECT \ +#define WOL_REG_DBG_SELECT_K2 \ 0x600140UL -#define WOL_REG_DBG_DWORD_ENABLE \ +#define WOL_REG_DBG_DWORD_ENABLE_K2 \ 0x600144UL -#define WOL_REG_DBG_SHIFT \ +#define WOL_REG_DBG_SHIFT_K2 \ 0x600148UL -#define WOL_REG_DBG_FORCE_VALID \ +#define WOL_REG_DBG_FORCE_VALID_K2 \ 0x60014cUL -#define WOL_REG_DBG_FORCE_FRAME \ +#define WOL_REG_DBG_FORCE_FRAME_K2 \ 0x600150UL -#define BMBN_REG_DBG_SELECT \ +#define BMBN_REG_DBG_SELECT_K2 \ 0x610140UL -#define BMBN_REG_DBG_DWORD_ENABLE \ +#define BMBN_REG_DBG_DWORD_ENABLE_K2 \ 0x610144UL -#define BMBN_REG_DBG_SHIFT \ +#define BMBN_REG_DBG_SHIFT_K2 \ 0x610148UL -#define BMBN_REG_DBG_FORCE_VALID \ +#define BMBN_REG_DBG_FORCE_VALID_K2 \ 0x61014cUL -#define BMBN_REG_DBG_FORCE_FRAME \ +#define BMBN_REG_DBG_FORCE_FRAME_K2 \ 0x610150UL -#define NWM_REG_DBG_SELECT \ +#define NWM_REG_DBG_SELECT_K2 \ 0x8000ecUL -#define NWM_REG_DBG_DWORD_ENABLE \ +#define NWM_REG_DBG_DWORD_ENABLE_K2 \ 0x8000f0UL -#define NWM_REG_DBG_SHIFT \ +#define NWM_REG_DBG_SHIFT_K2 \ 0x8000f4UL -#define NWM_REG_DBG_FORCE_VALID \ +#define NWM_REG_DBG_FORCE_VALID_K2 \ 0x8000f8UL -#define NWM_REG_DBG_FORCE_FRAME \ +#define NWM_REG_DBG_FORCE_FRAME_K2\ 0x8000fcUL #define PBF_REG_DBG_SELECT \ 0xd80060UL @@ -1244,35 +1247,35 @@ 0x1901534UL #define USEM_REG_DBG_FORCE_FRAME \ 0x1901538UL -#define NWS_REG_DBG_SELECT \ +#define NWS_REG_DBG_SELECT_K2 \ 0x700128UL -#define NWS_REG_DBG_DWORD_ENABLE \ +#define NWS_REG_DBG_DWORD_ENABLE_K2 \ 0x70012cUL -#define NWS_REG_DBG_SHIFT \ +#define NWS_REG_DBG_SHIFT_K2 \ 0x700130UL -#define NWS_REG_DBG_FORCE_VALID \ +#define NWS_REG_DBG_FORCE_VALID_K2 \ 0x700134UL -#define NWS_REG_DBG_FORCE_FRAME \ +#define NWS_REG_DBG_FORCE_FRAME_K2 \ 0x700138UL -#define MS_REG_DBG_SELECT \ +#define MS_REG_DBG_SELECT_K2 \ 0x6a0228UL -#define MS_REG_DBG_DWORD_ENABLE \ +#define MS_REG_DBG_DWORD_ENABLE_K2 \ 0x6a022cUL -#define MS_REG_DBG_SHIFT \ +#define MS_REG_DBG_SHIFT_K2 \ 0x6a0230UL -#define MS_REG_DBG_FORCE_VALID \ +#define MS_REG_DBG_FORCE_VALID_K2 \ 0x6a0234UL -#define MS_REG_DBG_FORCE_FRAME \ +#define MS_REG_DBG_FORCE_FRAME_K2 \ 0x6a0238UL -#define PCIE_REG_DBG_COMMON_SELECT \ +#define PCIE_REG_DBG_COMMON_SELECT_K2 \ 0x054398UL -#define PCIE_REG_DBG_COMMON_DWORD_ENABLE \ +#define PCIE_REG_DBG_COMMON_DWORD_ENABLE_K2 \ 0x05439cUL -#define PCIE_REG_DBG_COMMON_SHIFT \ +#define PCIE_REG_DBG_COMMON_SHIFT_K2 \ 0x0543a0UL -#define PCIE_REG_DBG_COMMON_FORCE_VALID \ +#define PCIE_REG_DBG_COMMON_FORCE_VALID_K2 \ 0x0543a4UL -#define PCIE_REG_DBG_COMMON_FORCE_FRAME \ +#define PCIE_REG_DBG_COMMON_FORCE_FRAME_K2 \ 0x0543a8UL #define MISC_REG_RESET_PL_UA \ 0x008050UL @@ -1328,85 +1331,85 @@ 0x128170cUL #define UCM_REG_SM_TASK_CTX \ 0x1281710UL -#define XSEM_REG_SLOW_DBG_EMPTY \ +#define XSEM_REG_SLOW_DBG_EMPTY_BB_K2 \ 0x1401140UL #define XSEM_REG_SYNC_DBG_EMPTY \ 0x1401160UL -#define XSEM_REG_SLOW_DBG_ACTIVE \ +#define XSEM_REG_SLOW_DBG_ACTIVE_BB_K2 \ 0x1401400UL -#define XSEM_REG_SLOW_DBG_MODE \ +#define XSEM_REG_SLOW_DBG_MODE_BB_K2 \ 0x1401404UL -#define XSEM_REG_DBG_FRAME_MODE \ +#define XSEM_REG_DBG_FRAME_MODE_BB_K2 \ 0x1401408UL -#define XSEM_REG_DBG_MODE1_CFG \ +#define XSEM_REG_DBG_MODE1_CFG_BB_K2 \ 0x1401420UL #define XSEM_REG_FAST_MEMORY \ 0x1440000UL #define YSEM_REG_SYNC_DBG_EMPTY \ 0x1501160UL -#define YSEM_REG_SLOW_DBG_ACTIVE \ +#define YSEM_REG_SLOW_DBG_ACTIVE_BB_K2 \ 0x1501400UL -#define YSEM_REG_SLOW_DBG_MODE \ +#define YSEM_REG_SLOW_DBG_MODE_BB_K2 \ 0x1501404UL -#define YSEM_REG_DBG_FRAME_MODE \ +#define YSEM_REG_DBG_FRAME_MODE_BB_K2 \ 0x1501408UL -#define YSEM_REG_DBG_MODE1_CFG \ +#define YSEM_REG_DBG_MODE1_CFG_BB_K2 \ 0x1501420UL #define YSEM_REG_FAST_MEMORY \ 0x1540000UL -#define PSEM_REG_SLOW_DBG_EMPTY \ +#define PSEM_REG_SLOW_DBG_EMPTY_BB_K2 \ 0x1601140UL #define PSEM_REG_SYNC_DBG_EMPTY \ 0x1601160UL -#define PSEM_REG_SLOW_DBG_ACTIVE \ +#define PSEM_REG_SLOW_DBG_ACTIVE_BB_K2 \ 0x1601400UL -#define PSEM_REG_SLOW_DBG_MODE \ +#define PSEM_REG_SLOW_DBG_MODE_BB_K2 \ 0x1601404UL -#define PSEM_REG_DBG_FRAME_MODE \ +#define PSEM_REG_DBG_FRAME_MODE_BB_K2 \ 0x1601408UL -#define PSEM_REG_DBG_MODE1_CFG \ +#define PSEM_REG_DBG_MODE1_CFG_BB_K2 \ 0x1601420UL #define PSEM_REG_FAST_MEMORY \ 0x1640000UL -#define TSEM_REG_SLOW_DBG_EMPTY \ +#define TSEM_REG_SLOW_DBG_EMPTY_BB_K2 \ 0x1701140UL #define TSEM_REG_SYNC_DBG_EMPTY \ 0x1701160UL -#define TSEM_REG_SLOW_DBG_ACTIVE \ +#define TSEM_REG_SLOW_DBG_ACTIVE_BB_K2 \ 0x1701400UL -#define TSEM_REG_SLOW_DBG_MODE \ +#define TSEM_REG_SLOW_DBG_MODE_BB_K2 \ 0x1701404UL -#define TSEM_REG_DBG_FRAME_MODE \ +#define TSEM_REG_DBG_FRAME_MODE_BB_K2 \ 0x1701408UL -#define TSEM_REG_DBG_MODE1_CFG \ +#define TSEM_REG_DBG_MODE1_CFG_BB_K2 \ 0x1701420UL #define TSEM_REG_FAST_MEMORY \ 0x1740000UL -#define MSEM_REG_SLOW_DBG_EMPTY \ +#define MSEM_REG_SLOW_DBG_EMPTY_BB_K2 \ 0x1801140UL #define MSEM_REG_SYNC_DBG_EMPTY \ 0x1801160UL -#define MSEM_REG_SLOW_DBG_ACTIVE \ +#define MSEM_REG_SLOW_DBG_ACTIVE_BB_K2 \ 0x1801400UL -#define MSEM_REG_SLOW_DBG_MODE \ +#define MSEM_REG_SLOW_DBG_MODE_BB_K2 \ 0x1801404UL -#define MSEM_REG_DBG_FRAME_MODE \ +#define MSEM_REG_DBG_FRAME_MODE_BB_K2 \ 0x1801408UL -#define MSEM_REG_DBG_MODE1_CFG \ +#define MSEM_REG_DBG_MODE1_CFG_BB_K2 \ 0x1801420UL #define MSEM_REG_FAST_MEMORY \ 0x1840000UL -#define USEM_REG_SLOW_DBG_EMPTY \ +#define USEM_REG_SLOW_DBG_EMPTY_BB_K2 \ 0x1901140UL #define USEM_REG_SYNC_DBG_EMPTY \ 0x1901160UL -#define USEM_REG_SLOW_DBG_ACTIVE \ +#define USEM_REG_SLOW_DBG_ACTIVE_BB_K2 \ 0x1901400UL -#define USEM_REG_SLOW_DBG_MODE \ +#define USEM_REG_SLOW_DBG_MODE_BB_K2 \ 0x1901404UL -#define USEM_REG_DBG_FRAME_MODE \ +#define USEM_REG_DBG_FRAME_MODE_BB_K2 \ 0x1901408UL -#define USEM_REG_DBG_MODE1_CFG \ +#define USEM_REG_DBG_MODE1_CFG_BB_K2 \ 0x1901420UL #define USEM_REG_FAST_MEMORY \ 0x1940000UL @@ -1430,7 +1433,7 @@ 0x340800UL #define BRB_REG_BIG_RAM_DATA \ 0x341500UL -#define SEM_FAST_REG_STALL_0 \ +#define SEM_FAST_REG_STALL_0_BB_K2 \ 0x000488UL #define SEM_FAST_REG_STALLED \ 0x000494UL @@ -1480,37 +1483,37 @@ 4 #define MISC_REG_BLOCK_256B_EN \ 0x008c14UL -#define NWS_REG_NWS_CMU \ +#define NWS_REG_NWS_CMU_K2 \ 0x720000UL -#define PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_7_0 \ +#define PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_7_0_K2 \ 0x000680UL -#define PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_15_8 \ +#define PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_15_8_K2 \ 0x000684UL -#define PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_7_0 \ +#define PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_7_0_K2 \ 0x0006c0UL -#define PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_11_8 \ +#define PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_11_8_K2 \ 0x0006c4UL -#define MS_REG_MS_CMU \ +#define MS_REG_MS_CMU_K2 \ 0x6a4000UL -#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X130 \ +#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X130_K2 \ 0x000208UL -#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X132 \ - 0x000210UL -#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X131 \ +#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X131_K2 \ 0x00020cUL -#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X133 \ +#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X132_K2 \ + 0x000210UL +#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X133_K2 \ 0x000214UL -#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X130 \ +#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X130_K2 \ 0x000208UL -#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X131 \ +#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X131_K2 \ 0x00020cUL -#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X132 \ +#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X132_K2 \ 0x000210UL -#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X133 \ +#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X133_K2 \ 0x000214UL -#define PHY_PCIE_REG_PHY0 \ +#define PHY_PCIE_REG_PHY0_K2 \ 0x620000UL -#define PHY_PCIE_REG_PHY1 \ +#define PHY_PCIE_REG_PHY1_K2 \ 0x624000UL #define NIG_REG_ROCE_DUPLICATE_TO_HOST 0x5088f0UL #define PRS_REG_LIGHT_L2_ETHERTYPE_EN 0x1f0968UL @@ -1557,6 +1560,7 @@ #define PGLUE_B_REG_PGL_ADDR_EC_F0_K2 0x2aaf9cUL #define PGLUE_B_REG_PGL_ADDR_F0_F0_K2 0x2aafa0UL #define PGLUE_B_REG_PGL_ADDR_F4_F0_K2 0x2aafa4UL +#define PGLUE_B_REG_MASTER_WRITE_PAD_ENABLE 0x2aae30UL #define NIG_REG_TSGEN_FREECNT_UPDATE_K2 0x509008UL #define CNIG_REG_NIG_PORT0_CONF_K2 0x218200UL diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index 56289d7cd306..b9434b707b08 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -581,6 +581,7 @@ static int qed_rdma_start_fw(struct qed_hwfn *p_hwfn, struct qed_sp_init_data init_data; struct qed_spq_entry *p_ent; u32 cnq_id, sb_id; + u16 igu_sb_id; int rc; DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Starting FW\n"); @@ -612,10 +613,10 @@ static int qed_rdma_start_fw(struct qed_hwfn *p_hwfn, for (cnq_id = 0; cnq_id < params->desired_cnq; cnq_id++) { sb_id = qed_rdma_get_sb_id(p_hwfn, cnq_id); + igu_sb_id = qed_get_igu_sb_id(p_hwfn, sb_id); + p_ramrod->cnq_params[cnq_id].sb_num = cpu_to_le16(igu_sb_id); p_cnq_params = &p_ramrod->cnq_params[cnq_id]; p_cnq_pbl_list = ¶ms->cnq_pbl_list[cnq_id]; - p_cnq_params->sb_num = - cpu_to_le16(p_hwfn->sbs_info[sb_id]->igu_sb_id); p_cnq_params->sb_index = p_hwfn->pf_params.rdma_pf_params.gl_pi; p_cnq_params->num_pbl_pages = p_cnq_pbl_list->num_pbl_pages; @@ -2432,10 +2433,6 @@ qed_rdma_register_tid(void *rdma_cxt, params->page_size_log - 12); SET_FIELD(p_ramrod->flags, - RDMA_REGISTER_TID_RAMROD_DATA_MAX_ID, - p_hwfn->p_rdma_info->last_tid); - - SET_FIELD(p_ramrod->flags, RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_READ, params->remote_read); diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h index 3357bbefa445..00dd50f8c42f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h @@ -120,6 +120,7 @@ union ramrod_data { struct iscsi_spe_func_dstry iscsi_destroy; struct iscsi_spe_conn_offload iscsi_conn_offload; struct iscsi_conn_update_ramrod_params iscsi_conn_update; + struct iscsi_spe_conn_mac_update iscsi_conn_mac_update; struct iscsi_spe_conn_termination iscsi_conn_terminate; struct vf_start_ramrod_data vf_start; @@ -270,28 +271,23 @@ void qed_spq_return_entry(struct qed_hwfn *p_hwfn, * @param p_hwfn * @param num_elem number of elements in the eq * - * @return struct qed_eq* - a newly allocated structure; NULL upon error. + * @return int */ -struct qed_eq *qed_eq_alloc(struct qed_hwfn *p_hwfn, - u16 num_elem); +int qed_eq_alloc(struct qed_hwfn *p_hwfn, u16 num_elem); /** - * @brief qed_eq_setup - Reset the SPQ to its start state. + * @brief qed_eq_setup - Reset the EQ to its start state. * * @param p_hwfn - * @param p_eq */ -void qed_eq_setup(struct qed_hwfn *p_hwfn, - struct qed_eq *p_eq); +void qed_eq_setup(struct qed_hwfn *p_hwfn); /** - * @brief qed_eq_deallocate - deallocates the given EQ struct. + * @brief qed_eq_free - deallocates the given EQ struct. * * @param p_hwfn - * @param p_eq */ -void qed_eq_free(struct qed_hwfn *p_hwfn, - struct qed_eq *p_eq); +void qed_eq_free(struct qed_hwfn *p_hwfn); /** * @brief qed_eq_prod_update - update the FW with default EQ producer @@ -342,28 +338,23 @@ u32 qed_spq_get_cid(struct qed_hwfn *p_hwfn); * * @param p_hwfn * - * @return struct qed_eq* - a newly allocated structure; NULL upon error. + * @return int */ -struct qed_consq *qed_consq_alloc(struct qed_hwfn *p_hwfn); +int qed_consq_alloc(struct qed_hwfn *p_hwfn); /** - * @brief qed_consq_setup - Reset the ConsQ to its start - * state. + * @brief qed_consq_setup - Reset the ConsQ to its start state. * * @param p_hwfn - * @param p_eq */ -void qed_consq_setup(struct qed_hwfn *p_hwfn, - struct qed_consq *p_consq); +void qed_consq_setup(struct qed_hwfn *p_hwfn); /** * @brief qed_consq_free - deallocates the given ConsQ struct. * * @param p_hwfn - * @param p_eq */ -void qed_consq_free(struct qed_hwfn *p_hwfn, - struct qed_consq *p_consq); +void qed_consq_free(struct qed_hwfn *p_hwfn); /** * @file @@ -401,6 +392,7 @@ int qed_sp_init_request(struct qed_hwfn *p_hwfn, * to the internal RAM of the UStorm by the Function Start Ramrod. * * @param p_hwfn + * @param p_ptt * @param p_tunn * @param mode * @param allow_npar_tx_switch @@ -409,6 +401,7 @@ int qed_sp_init_request(struct qed_hwfn *p_hwfn, */ int qed_sp_pf_start(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, struct qed_tunnel_info *p_tunn, enum qed_mf_mode mode, bool allow_npar_tx_switch); @@ -426,6 +419,15 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn, int qed_sp_pf_update(struct qed_hwfn *p_hwfn); /** + * @brief qed_sp_pf_update_stag - Update firmware of new outer tag + * + * @param p_hwfn + * + * @return int + */ +int qed_sp_pf_update_stag(struct qed_hwfn *p_hwfn); + +/** * @brief qed_sp_pf_stop - PF Function Stop Ramrod * * This ramrod is sent to close a Physical Function (PF). It is the last ramrod @@ -442,6 +444,7 @@ int qed_sp_pf_update(struct qed_hwfn *p_hwfn); int qed_sp_pf_stop(struct qed_hwfn *p_hwfn); int qed_sp_pf_update_tunn_cfg(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, struct qed_tunnel_info *p_tunn, enum spq_mode comp_mode, struct qed_spq_comp_cb *p_comp_data); diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c index bc3694e91b85..46d0c3cb83a5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c @@ -185,22 +185,20 @@ static void qed_set_tunn_ports(struct qed_tunnel_info *p_tun, } static void -__qed_set_ramrod_tunnel_param(u8 *p_tunn_cls, u8 *p_enable_tx_clas, +__qed_set_ramrod_tunnel_param(u8 *p_tunn_cls, struct qed_tunn_update_type *tun_type) { *p_tunn_cls = tun_type->tun_cls; - - if (tun_type->b_mode_enabled) - *p_enable_tx_clas = 1; } static void -qed_set_ramrod_tunnel_param(u8 *p_tunn_cls, u8 *p_enable_tx_clas, +qed_set_ramrod_tunnel_param(u8 *p_tunn_cls, struct qed_tunn_update_type *tun_type, - u8 *p_update_port, __le16 *p_port, + u8 *p_update_port, + __le16 *p_port, struct qed_tunn_update_udp_port *p_udp_port) { - __qed_set_ramrod_tunnel_param(p_tunn_cls, p_enable_tx_clas, tun_type); + __qed_set_ramrod_tunnel_param(p_tunn_cls, tun_type); if (p_udp_port->b_update_port) { *p_update_port = 1; *p_port = cpu_to_le16(p_udp_port->port); @@ -219,33 +217,27 @@ qed_tunn_set_pf_update_params(struct qed_hwfn *p_hwfn, qed_set_tunn_ports(p_tun, p_src); qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_vxlan, - &p_tunn_cfg->tx_enable_vxlan, &p_tun->vxlan, &p_tunn_cfg->set_vxlan_udp_port_flg, &p_tunn_cfg->vxlan_udp_port, &p_tun->vxlan_port); qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_l2geneve, - &p_tunn_cfg->tx_enable_l2geneve, &p_tun->l2_geneve, &p_tunn_cfg->set_geneve_udp_port_flg, &p_tunn_cfg->geneve_udp_port, &p_tun->geneve_port); __qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_ipgeneve, - &p_tunn_cfg->tx_enable_ipgeneve, &p_tun->ip_geneve); __qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_l2gre, - &p_tunn_cfg->tx_enable_l2gre, &p_tun->l2_gre); __qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_ipgre, - &p_tunn_cfg->tx_enable_ipgre, &p_tun->ip_gre); p_tunn_cfg->update_rx_pf_clss = p_tun->b_update_rx_cls; - p_tunn_cfg->update_tx_pf_clss = p_tun->b_update_tx_cls; } static void qed_set_hw_tunn_mode(struct qed_hwfn *p_hwfn, @@ -261,17 +253,18 @@ static void qed_set_hw_tunn_mode(struct qed_hwfn *p_hwfn, } static void qed_set_hw_tunn_mode_port(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, struct qed_tunnel_info *p_tunn) { if (p_tunn->vxlan_port.b_update_port) - qed_set_vxlan_dest_port(p_hwfn, p_hwfn->p_main_ptt, + qed_set_vxlan_dest_port(p_hwfn, p_ptt, p_tunn->vxlan_port.port); if (p_tunn->geneve_port.b_update_port) - qed_set_geneve_dest_port(p_hwfn, p_hwfn->p_main_ptt, + qed_set_geneve_dest_port(p_hwfn, p_ptt, p_tunn->geneve_port.port); - qed_set_hw_tunn_mode(p_hwfn, p_hwfn->p_main_ptt, p_tunn); + qed_set_hw_tunn_mode(p_hwfn, p_ptt, p_tunn); } static void @@ -289,33 +282,29 @@ qed_tunn_set_pf_start_params(struct qed_hwfn *p_hwfn, qed_set_tunn_ports(p_tun, p_src); qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_vxlan, - &p_tunn_cfg->tx_enable_vxlan, &p_tun->vxlan, &p_tunn_cfg->set_vxlan_udp_port_flg, &p_tunn_cfg->vxlan_udp_port, &p_tun->vxlan_port); qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_l2geneve, - &p_tunn_cfg->tx_enable_l2geneve, &p_tun->l2_geneve, &p_tunn_cfg->set_geneve_udp_port_flg, &p_tunn_cfg->geneve_udp_port, &p_tun->geneve_port); __qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_ipgeneve, - &p_tunn_cfg->tx_enable_ipgeneve, &p_tun->ip_geneve); __qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_l2gre, - &p_tunn_cfg->tx_enable_l2gre, &p_tun->l2_gre); __qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_ipgre, - &p_tunn_cfg->tx_enable_ipgre, &p_tun->ip_gre); } int qed_sp_pf_start(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, struct qed_tunnel_info *p_tunn, enum qed_mf_mode mode, bool allow_npar_tx_switch) { @@ -412,7 +401,8 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn, rc = qed_spq_post(p_hwfn, p_ent, NULL); if (p_tunn) - qed_set_hw_tunn_mode_port(p_hwfn, &p_hwfn->cdev->tunnel); + qed_set_hw_tunn_mode_port(p_hwfn, p_ptt, + &p_hwfn->cdev->tunnel); return rc; } @@ -443,6 +433,7 @@ int qed_sp_pf_update(struct qed_hwfn *p_hwfn) /* Set pf update ramrod command params */ int qed_sp_pf_update_tunn_cfg(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, struct qed_tunnel_info *p_tunn, enum spq_mode comp_mode, struct qed_spq_comp_cb *p_comp_data) @@ -477,7 +468,7 @@ int qed_sp_pf_update_tunn_cfg(struct qed_hwfn *p_hwfn, if (rc) return rc; - qed_set_hw_tunn_mode_port(p_hwfn, &p_hwfn->cdev->tunnel); + qed_set_hw_tunn_mode_port(p_hwfn, p_ptt, &p_hwfn->cdev->tunnel); return rc; } @@ -523,3 +514,27 @@ int qed_sp_heartbeat_ramrod(struct qed_hwfn *p_hwfn) return qed_spq_post(p_hwfn, p_ent, NULL); } + +int qed_sp_pf_update_stag(struct qed_hwfn *p_hwfn) +{ + struct qed_spq_entry *p_ent = NULL; + struct qed_sp_init_data init_data; + int rc = -EINVAL; + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = qed_spq_get_cid(p_hwfn); + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_CB; + + rc = qed_sp_init_request(p_hwfn, &p_ent, + COMMON_RAMROD_PF_UPDATE, PROTOCOLID_COMMON, + &init_data); + if (rc) + return rc; + + p_ent->ramrod.pf_update.update_mf_vlan_flag = true; + p_ent->ramrod.pf_update.mf_vlan = cpu_to_le16(p_hwfn->hw_info.ovlan); + + return qed_spq_post(p_hwfn, p_ent, NULL); +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c index f6423a139ca0..dede73f41e61 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c @@ -403,14 +403,14 @@ int qed_eq_completion(struct qed_hwfn *p_hwfn, void *cookie) return rc; } -struct qed_eq *qed_eq_alloc(struct qed_hwfn *p_hwfn, u16 num_elem) +int qed_eq_alloc(struct qed_hwfn *p_hwfn, u16 num_elem) { struct qed_eq *p_eq; /* Allocate EQ struct */ p_eq = kzalloc(sizeof(*p_eq), GFP_KERNEL); if (!p_eq) - return NULL; + return -ENOMEM; /* Allocate and initialize EQ chain*/ if (qed_chain_alloc(p_hwfn->cdev, @@ -426,24 +426,28 @@ struct qed_eq *qed_eq_alloc(struct qed_hwfn *p_hwfn, u16 num_elem) qed_int_register_cb(p_hwfn, qed_eq_completion, p_eq, &p_eq->eq_sb_index, &p_eq->p_fw_cons); - return p_eq; + p_hwfn->p_eq = p_eq; + return 0; eq_allocate_fail: - qed_eq_free(p_hwfn, p_eq); - return NULL; + kfree(p_eq); + return -ENOMEM; } -void qed_eq_setup(struct qed_hwfn *p_hwfn, struct qed_eq *p_eq) +void qed_eq_setup(struct qed_hwfn *p_hwfn) { - qed_chain_reset(&p_eq->chain); + qed_chain_reset(&p_hwfn->p_eq->chain); } -void qed_eq_free(struct qed_hwfn *p_hwfn, struct qed_eq *p_eq) +void qed_eq_free(struct qed_hwfn *p_hwfn) { - if (!p_eq) + if (!p_hwfn->p_eq) return; - qed_chain_free(p_hwfn->cdev, &p_eq->chain); - kfree(p_eq); + + qed_chain_free(p_hwfn->cdev, &p_hwfn->p_eq->chain); + + kfree(p_hwfn->p_eq); + p_hwfn->p_eq = NULL; } /*************************************************************************** @@ -583,8 +587,8 @@ void qed_spq_free(struct qed_hwfn *p_hwfn) } qed_chain_free(p_hwfn->cdev, &p_spq->chain); - ; kfree(p_spq); + p_hwfn->p_spq = NULL; } int qed_spq_get_entry(struct qed_hwfn *p_hwfn, struct qed_spq_entry **pp_ent) @@ -934,14 +938,14 @@ int qed_spq_completion(struct qed_hwfn *p_hwfn, return rc; } -struct qed_consq *qed_consq_alloc(struct qed_hwfn *p_hwfn) +int qed_consq_alloc(struct qed_hwfn *p_hwfn) { struct qed_consq *p_consq; /* Allocate ConsQ struct */ p_consq = kzalloc(sizeof(*p_consq), GFP_KERNEL); if (!p_consq) - return NULL; + return -ENOMEM; /* Allocate and initialize EQ chain*/ if (qed_chain_alloc(p_hwfn->cdev, @@ -952,22 +956,26 @@ struct qed_consq *qed_consq_alloc(struct qed_hwfn *p_hwfn) 0x80, &p_consq->chain)) goto consq_allocate_fail; - return p_consq; + p_hwfn->p_consq = p_consq; + return 0; consq_allocate_fail: - qed_consq_free(p_hwfn, p_consq); - return NULL; + kfree(p_consq); + return -ENOMEM; } -void qed_consq_setup(struct qed_hwfn *p_hwfn, struct qed_consq *p_consq) +void qed_consq_setup(struct qed_hwfn *p_hwfn) { - qed_chain_reset(&p_consq->chain); + qed_chain_reset(&p_hwfn->p_consq->chain); } -void qed_consq_free(struct qed_hwfn *p_hwfn, struct qed_consq *p_consq) +void qed_consq_free(struct qed_hwfn *p_hwfn) { - if (!p_consq) + if (!p_hwfn->p_consq) return; - qed_chain_free(p_hwfn->cdev, &p_consq->chain); - kfree(p_consq); + + qed_chain_free(p_hwfn->cdev, &p_hwfn->p_consq->chain); + + kfree(p_hwfn->p_consq); + p_hwfn->p_consq = NULL; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index f5ed54d611ec..e39ad22947cf 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -45,6 +45,21 @@ #include "qed_sriov.h" #include "qed_vf.h" +static u8 qed_vf_calculate_legacy(struct qed_vf_info *p_vf) +{ + u8 legacy = 0; + + if (p_vf->acquire.vfdev_info.eth_fp_hsi_minor == + ETH_HSI_VER_NO_PKT_LEN_TUNN) + legacy |= QED_QCID_LEGACY_VF_RX_PROD; + + if (!(p_vf->acquire.vfdev_info.capabilities & + VFPF_ACQUIRE_CAP_QUEUE_QIDS)) + legacy |= QED_QCID_LEGACY_VF_CID; + + return legacy; +} + /* IOV ramrods */ static int qed_sp_vf_start(struct qed_hwfn *p_hwfn, struct qed_vf_info *p_vf) { @@ -178,6 +193,19 @@ static struct qed_vf_info *qed_iov_get_vf_info(struct qed_hwfn *p_hwfn, return vf; } +static struct qed_queue_cid * +qed_iov_get_vf_rx_queue_cid(struct qed_vf_queue *p_queue) +{ + int i; + + for (i = 0; i < MAX_QUEUES_PER_QZONE; i++) { + if (p_queue->cids[i].p_cid && !p_queue->cids[i].b_is_tx) + return p_queue->cids[i].p_cid; + } + + return NULL; +} + enum qed_iov_validate_q_mode { QED_IOV_VALIDATE_Q_NA, QED_IOV_VALIDATE_Q_ENABLE, @@ -190,12 +218,24 @@ static bool qed_iov_validate_queue_mode(struct qed_hwfn *p_hwfn, enum qed_iov_validate_q_mode mode, bool b_is_tx) { + int i; + if (mode == QED_IOV_VALIDATE_Q_NA) return true; - if ((b_is_tx && p_vf->vf_queues[qid].p_tx_cid) || - (!b_is_tx && p_vf->vf_queues[qid].p_rx_cid)) + for (i = 0; i < MAX_QUEUES_PER_QZONE; i++) { + struct qed_vf_queue_cid *p_qcid; + + p_qcid = &p_vf->vf_queues[qid].cids[i]; + + if (!p_qcid->p_cid) + continue; + + if (p_qcid->b_is_tx != b_is_tx) + continue; + return mode == QED_IOV_VALIDATE_Q_ENABLE; + } /* In case we haven't found any valid cid, then its disabled */ return mode == QED_IOV_VALIDATE_Q_DISABLE; @@ -378,33 +418,6 @@ static int qed_iov_pci_cfg_info(struct qed_dev *cdev) return 0; } -static void qed_iov_clear_vf_igu_blocks(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt) -{ - struct qed_igu_block *p_sb; - u16 sb_id; - u32 val; - - if (!p_hwfn->hw_info.p_igu_info) { - DP_ERR(p_hwfn, - "qed_iov_clear_vf_igu_blocks IGU Info not initialized\n"); - return; - } - - for (sb_id = 0; sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); - sb_id++) { - p_sb = &p_hwfn->hw_info.p_igu_info->igu_map.igu_blocks[sb_id]; - if ((p_sb->status & QED_IGU_STATUS_FREE) && - !(p_sb->status & QED_IGU_STATUS_PF)) { - val = qed_rd(p_hwfn, p_ptt, - IGU_REG_MAPPING_MEMORY + sb_id * 4); - SET_FIELD(val, IGU_MAPPING_LINE_VALID, 0); - qed_wr(p_hwfn, p_ptt, - IGU_REG_MAPPING_MEMORY + 4 * sb_id, val); - } - } -} - static void qed_iov_setup_vfdb(struct qed_hwfn *p_hwfn) { struct qed_hw_sriov_info *p_iov = p_hwfn->cdev->p_iov_info; @@ -555,13 +568,12 @@ int qed_iov_alloc(struct qed_hwfn *p_hwfn) return qed_iov_allocate_vfdb(p_hwfn); } -void qed_iov_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +void qed_iov_setup(struct qed_hwfn *p_hwfn) { if (!IS_PF_SRIOV(p_hwfn) || !IS_PF_SRIOV_ALLOC(p_hwfn)) return; qed_iov_setup_vfdb(p_hwfn); - qed_iov_clear_vf_igu_blocks(p_hwfn, p_ptt); } void qed_iov_free(struct qed_hwfn *p_hwfn) @@ -747,6 +759,35 @@ static void qed_iov_vf_igu_set_int(struct qed_hwfn *p_hwfn, qed_fid_pretend(p_hwfn, p_ptt, (u16) p_hwfn->hw_info.concrete_fid); } +static int +qed_iov_enable_vf_access_msix(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u8 abs_vf_id, u8 num_sbs) +{ + u8 current_max = 0; + int i; + + /* For AH onward, configuration is per-PF. Find maximum of all + * the currently enabled child VFs, and set the number to be that. + */ + if (!QED_IS_BB(p_hwfn->cdev)) { + qed_for_each_vf(p_hwfn, i) { + struct qed_vf_info *p_vf; + + p_vf = qed_iov_get_vf_info(p_hwfn, (u16)i, true); + if (!p_vf) + continue; + + current_max = max_t(u8, current_max, p_vf->num_sbs); + } + } + + if (num_sbs > current_max) + return qed_mcp_config_vf_msix(p_hwfn, p_ptt, + abs_vf_id, num_sbs); + + return 0; +} + static int qed_iov_enable_vf_access(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_vf_info *vf) @@ -771,7 +812,8 @@ static int qed_iov_enable_vf_access(struct qed_hwfn *p_hwfn, qed_iov_vf_igu_reset(p_hwfn, p_ptt, vf); - rc = qed_mcp_config_vf_msix(p_hwfn, p_ptt, vf->abs_vf_id, vf->num_sbs); + rc = qed_iov_enable_vf_access_msix(p_hwfn, p_ptt, + vf->abs_vf_id, vf->num_sbs); if (rc) return rc; @@ -838,45 +880,36 @@ static u8 qed_iov_alloc_vf_igu_sbs(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_vf_info *vf, u16 num_rx_queues) { - struct qed_igu_block *igu_blocks; - int qid = 0, igu_id = 0; + struct qed_igu_block *p_block; + struct cau_sb_entry sb_entry; + int qid = 0; u32 val = 0; - igu_blocks = p_hwfn->hw_info.p_igu_info->igu_map.igu_blocks; - - if (num_rx_queues > p_hwfn->hw_info.p_igu_info->free_blks) - num_rx_queues = p_hwfn->hw_info.p_igu_info->free_blks; - p_hwfn->hw_info.p_igu_info->free_blks -= num_rx_queues; + if (num_rx_queues > p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov) + num_rx_queues = p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov; + p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov -= num_rx_queues; SET_FIELD(val, IGU_MAPPING_LINE_FUNCTION_NUMBER, vf->abs_vf_id); SET_FIELD(val, IGU_MAPPING_LINE_VALID, 1); SET_FIELD(val, IGU_MAPPING_LINE_PF_VALID, 0); - while ((qid < num_rx_queues) && - (igu_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev))) { - if (igu_blocks[igu_id].status & QED_IGU_STATUS_FREE) { - struct cau_sb_entry sb_entry; - - vf->igu_sbs[qid] = (u16)igu_id; - igu_blocks[igu_id].status &= ~QED_IGU_STATUS_FREE; - - SET_FIELD(val, IGU_MAPPING_LINE_VECTOR_NUMBER, qid); - - qed_wr(p_hwfn, p_ptt, - IGU_REG_MAPPING_MEMORY + sizeof(u32) * igu_id, - val); - - /* Configure igu sb in CAU which were marked valid */ - qed_init_cau_sb_entry(p_hwfn, &sb_entry, - p_hwfn->rel_pf_id, - vf->abs_vf_id, 1); - qed_dmae_host2grc(p_hwfn, p_ptt, - (u64)(uintptr_t)&sb_entry, - CAU_REG_SB_VAR_MEMORY + - igu_id * sizeof(u64), 2, 0); - qid++; - } - igu_id++; + for (qid = 0; qid < num_rx_queues; qid++) { + p_block = qed_get_igu_free_sb(p_hwfn, false); + vf->igu_sbs[qid] = p_block->igu_sb_id; + p_block->status &= ~QED_IGU_STATUS_FREE; + SET_FIELD(val, IGU_MAPPING_LINE_VECTOR_NUMBER, qid); + + qed_wr(p_hwfn, p_ptt, + IGU_REG_MAPPING_MEMORY + + sizeof(u32) * p_block->igu_sb_id, val); + + /* Configure igu sb in CAU which were marked valid */ + qed_init_cau_sb_entry(p_hwfn, &sb_entry, + p_hwfn->rel_pf_id, vf->abs_vf_id, 1); + qed_dmae_host2grc(p_hwfn, p_ptt, + (u64)(uintptr_t)&sb_entry, + CAU_REG_SB_VAR_MEMORY + + p_block->igu_sb_id * sizeof(u64), 2, 0); } vf->num_sbs = (u8) num_rx_queues; @@ -901,10 +934,8 @@ static void qed_iov_free_vf_igu_sbs(struct qed_hwfn *p_hwfn, SET_FIELD(val, IGU_MAPPING_LINE_VALID, 0); qed_wr(p_hwfn, p_ptt, addr, val); - p_info->igu_map.igu_blocks[igu_id].status |= - QED_IGU_STATUS_FREE; - - p_hwfn->hw_info.p_igu_info->free_blks++; + p_info->entry[igu_id].status |= QED_IGU_STATUS_FREE; + p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov++; } vf->num_sbs = 0; @@ -1028,20 +1059,15 @@ static int qed_iov_init_hw_for_vf(struct qed_hwfn *p_hwfn, vf->num_txqs = num_of_vf_avaiable_chains; for (i = 0; i < vf->num_rxqs; i++) { - struct qed_vf_q_info *p_queue = &vf->vf_queues[i]; + struct qed_vf_queue *p_queue = &vf->vf_queues[i]; p_queue->fw_rx_qid = p_params->req_rx_queue[i]; p_queue->fw_tx_qid = p_params->req_tx_queue[i]; - /* CIDs are per-VF, so no problem having them 0-based. */ - p_queue->fw_cid = i; - DP_VERBOSE(p_hwfn, QED_MSG_IOV, - "VF[%d] - Q[%d] SB %04x, qid [Rx %04x Tx %04x] CID %04x\n", - vf->relative_vf_id, - i, vf->igu_sbs[i], - p_queue->fw_rx_qid, - p_queue->fw_tx_qid, p_queue->fw_cid); + "VF[%d] - Q[%d] SB %04x, qid [Rx %04x Tx %04x]\n", + vf->relative_vf_id, i, vf->igu_sbs[i], + p_queue->fw_rx_qid, p_queue->fw_tx_qid); } /* Update the link configuration in bulletin */ @@ -1328,7 +1354,7 @@ static void qed_iov_clean_vf(struct qed_hwfn *p_hwfn, u8 vfid) static void qed_iov_vf_cleanup(struct qed_hwfn *p_hwfn, struct qed_vf_info *p_vf) { - u32 i; + u32 i, j; p_vf->vf_bulletin = 0; p_vf->vport_instance = 0; @@ -1341,16 +1367,15 @@ static void qed_iov_vf_cleanup(struct qed_hwfn *p_hwfn, p_vf->num_active_rxqs = 0; for (i = 0; i < QED_MAX_VF_CHAINS_PER_PF; i++) { - struct qed_vf_q_info *p_queue = &p_vf->vf_queues[i]; + struct qed_vf_queue *p_queue = &p_vf->vf_queues[i]; - if (p_queue->p_rx_cid) { - qed_eth_queue_cid_release(p_hwfn, p_queue->p_rx_cid); - p_queue->p_rx_cid = NULL; - } + for (j = 0; j < MAX_QUEUES_PER_QZONE; j++) { + if (!p_queue->cids[j].p_cid) + continue; - if (p_queue->p_tx_cid) { - qed_eth_queue_cid_release(p_hwfn, p_queue->p_tx_cid); - p_queue->p_tx_cid = NULL; + qed_eth_queue_cid_release(p_hwfn, + p_queue->cids[j].p_cid); + p_queue->cids[j].p_cid = NULL; } } @@ -1359,13 +1384,67 @@ static void qed_iov_vf_cleanup(struct qed_hwfn *p_hwfn, qed_iov_clean_vf(p_hwfn, p_vf->relative_vf_id); } +/* Returns either 0, or log(size) */ +static u32 qed_iov_vf_db_bar_size(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + u32 val = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_VF_BAR1_SIZE); + + if (val) + return val + 11; + return 0; +} + +static void +qed_iov_vf_mbx_acquire_resc_cids(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_vf_info *p_vf, + struct vf_pf_resc_request *p_req, + struct pf_vf_resc *p_resp) +{ + u8 num_vf_cons = p_hwfn->pf_params.eth_pf_params.num_vf_cons; + u8 db_size = qed_db_addr_vf(1, DQ_DEMS_LEGACY) - + qed_db_addr_vf(0, DQ_DEMS_LEGACY); + u32 bar_size; + + p_resp->num_cids = min_t(u8, p_req->num_cids, num_vf_cons); + + /* If VF didn't bother asking for QIDs than don't bother limiting + * number of CIDs. The VF doesn't care about the number, and this + * has the likely result of causing an additional acquisition. + */ + if (!(p_vf->acquire.vfdev_info.capabilities & + VFPF_ACQUIRE_CAP_QUEUE_QIDS)) + return; + + /* If doorbell bar was mapped by VF, limit the VF CIDs to an amount + * that would make sure doorbells for all CIDs fall within the bar. + * If it doesn't, make sure regview window is sufficient. + */ + if (p_vf->acquire.vfdev_info.capabilities & + VFPF_ACQUIRE_CAP_PHYSICAL_BAR) { + bar_size = qed_iov_vf_db_bar_size(p_hwfn, p_ptt); + if (bar_size) + bar_size = 1 << bar_size; + + if (p_hwfn->cdev->num_hwfns > 1) + bar_size /= 2; + } else { + bar_size = PXP_VF_BAR0_DQ_LENGTH; + } + + if (bar_size / db_size < 256) + p_resp->num_cids = min_t(u8, p_resp->num_cids, + (u8)(bar_size / db_size)); +} + static u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_vf_info *p_vf, struct vf_pf_resc_request *p_req, struct pf_vf_resc *p_resp) { - int i; + u8 i; /* Queue related information */ p_resp->num_rxqs = p_vf->num_rxqs; @@ -1383,7 +1462,7 @@ static u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn, for (i = 0; i < p_resp->num_rxqs; i++) { qed_fw_l2_queue(p_hwfn, p_vf->vf_queues[i].fw_rx_qid, (u16 *)&p_resp->hw_qid[i]); - p_resp->cid[i] = p_vf->vf_queues[i].fw_cid; + p_resp->cid[i] = i; } /* Filter related information */ @@ -1392,6 +1471,8 @@ static u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn, p_resp->num_vlan_filters = min_t(u8, p_vf->num_vlan_filters, p_req->num_vlan_filters); + qed_iov_vf_mbx_acquire_resc_cids(p_hwfn, p_ptt, p_vf, p_req, p_resp); + /* This isn't really needed/enforced, but some legacy VFs might depend * on the correct filling of this field. */ @@ -1403,10 +1484,11 @@ static u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn, p_resp->num_sbs < p_req->num_sbs || p_resp->num_mac_filters < p_req->num_mac_filters || p_resp->num_vlan_filters < p_req->num_vlan_filters || - p_resp->num_mc_filters < p_req->num_mc_filters) { + p_resp->num_mc_filters < p_req->num_mc_filters || + p_resp->num_cids < p_req->num_cids) { DP_VERBOSE(p_hwfn, QED_MSG_IOV, - "VF[%d] - Insufficient resources: rxq [%02x/%02x] txq [%02x/%02x] sbs [%02x/%02x] mac [%02x/%02x] vlan [%02x/%02x] mc [%02x/%02x]\n", + "VF[%d] - Insufficient resources: rxq [%02x/%02x] txq [%02x/%02x] sbs [%02x/%02x] mac [%02x/%02x] vlan [%02x/%02x] mc [%02x/%02x] cids [%02x/%02x]\n", p_vf->abs_vf_id, p_req->num_rxqs, p_resp->num_rxqs, @@ -1418,7 +1500,9 @@ static u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn, p_resp->num_mac_filters, p_req->num_vlan_filters, p_resp->num_vlan_filters, - p_req->num_mc_filters, p_resp->num_mc_filters); + p_req->num_mc_filters, + p_resp->num_mc_filters, + p_req->num_cids, p_resp->num_cids); /* Some legacy OSes are incapable of correctly handling this * failure. @@ -1534,6 +1618,15 @@ static void qed_iov_vf_mbx_acquire(struct qed_hwfn *p_hwfn, if (p_hwfn->cdev->num_hwfns > 1) pfdev_info->capabilities |= PFVF_ACQUIRE_CAP_100G; + /* Share our ability to use multiple queue-ids only with VFs + * that request it. + */ + if (req->vfdev_info.capabilities & VFPF_ACQUIRE_CAP_QUEUE_QIDS) + pfdev_info->capabilities |= PFVF_ACQUIRE_CAP_QUEUE_QIDS; + + /* Share the sizes of the bars with VF */ + resp->pfdev_info.bar_size = qed_iov_vf_db_bar_size(p_hwfn, p_ptt); + qed_iov_vf_mbx_acquire_stats(p_hwfn, &pfdev_info->stats_info); memcpy(pfdev_info->port_mac, p_hwfn->hw_info.hw_mac_addr, ETH_ALEN); @@ -1758,9 +1851,11 @@ static int qed_iov_configure_vport_forced(struct qed_hwfn *p_hwfn, /* Update all the Rx queues */ for (i = 0; i < QED_MAX_VF_CHAINS_PER_PF; i++) { - struct qed_queue_cid *p_cid; + struct qed_vf_queue *p_queue = &p_vf->vf_queues[i]; + struct qed_queue_cid *p_cid = NULL; - p_cid = p_vf->vf_queues[i].p_rx_cid; + /* There can be at most 1 Rx queue on qzone. Find it */ + p_cid = qed_iov_get_vf_rx_queue_cid(p_queue); if (!p_cid) continue; @@ -1951,16 +2046,55 @@ static void qed_iov_vf_mbx_start_rxq_resp(struct qed_hwfn *p_hwfn, qed_iov_send_response(p_hwfn, p_ptt, vf, length, status); } +static u8 qed_iov_vf_mbx_qid(struct qed_hwfn *p_hwfn, + struct qed_vf_info *p_vf, bool b_is_tx) +{ + struct qed_iov_vf_mbx *p_mbx = &p_vf->vf_mbx; + struct vfpf_qid_tlv *p_qid_tlv; + + /* Search for the qid if the VF published its going to provide it */ + if (!(p_vf->acquire.vfdev_info.capabilities & + VFPF_ACQUIRE_CAP_QUEUE_QIDS)) { + if (b_is_tx) + return QED_IOV_LEGACY_QID_TX; + else + return QED_IOV_LEGACY_QID_RX; + } + + p_qid_tlv = (struct vfpf_qid_tlv *) + qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, + CHANNEL_TLV_QID); + if (!p_qid_tlv) { + DP_VERBOSE(p_hwfn, QED_MSG_IOV, + "VF[%2x]: Failed to provide qid\n", + p_vf->relative_vf_id); + + return QED_IOV_QID_INVALID; + } + + if (p_qid_tlv->qid >= MAX_QUEUES_PER_QZONE) { + DP_VERBOSE(p_hwfn, QED_MSG_IOV, + "VF[%02x]: Provided qid out-of-bounds %02x\n", + p_vf->relative_vf_id, p_qid_tlv->qid); + return QED_IOV_QID_INVALID; + } + + return p_qid_tlv->qid; +} + static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_vf_info *vf) { struct qed_queue_start_common_params params; + struct qed_queue_cid_vf_params vf_params; struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; u8 status = PFVF_STATUS_NO_RESOURCE; - struct qed_vf_q_info *p_queue; + u8 qid_usage_idx, vf_legacy = 0; struct vfpf_start_rxq_tlv *req; - bool b_legacy_vf = false; + struct qed_vf_queue *p_queue; + struct qed_queue_cid *p_cid; + struct qed_sb_info sb_dummy; int rc; req = &mbx->req_virt->start_rxq; @@ -1970,53 +2104,64 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, !qed_iov_validate_sb(p_hwfn, vf, req->hw_sb)) goto out; - /* Acquire a new queue-cid */ + qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, false); + if (qid_usage_idx == QED_IOV_QID_INVALID) + goto out; + p_queue = &vf->vf_queues[req->rx_qid]; + if (p_queue->cids[qid_usage_idx].p_cid) + goto out; + vf_legacy = qed_vf_calculate_legacy(vf); + + /* Acquire a new queue-cid */ memset(¶ms, 0, sizeof(params)); params.queue_id = p_queue->fw_rx_qid; params.vport_id = vf->vport_id; params.stats_id = vf->abs_vf_id + 0x10; - params.sb = req->hw_sb; + /* Since IGU index is passed via sb_info, construct a dummy one */ + memset(&sb_dummy, 0, sizeof(sb_dummy)); + sb_dummy.igu_sb_id = req->hw_sb; + params.p_sb = &sb_dummy; params.sb_idx = req->sb_index; - p_queue->p_rx_cid = _qed_eth_queue_to_cid(p_hwfn, - vf->opaque_fid, - p_queue->fw_cid, - req->rx_qid, ¶ms); - if (!p_queue->p_rx_cid) + memset(&vf_params, 0, sizeof(vf_params)); + vf_params.vfid = vf->relative_vf_id; + vf_params.vf_qid = (u8)req->rx_qid; + vf_params.vf_legacy = vf_legacy; + vf_params.qid_usage_idx = qid_usage_idx; + p_cid = qed_eth_queue_to_cid(p_hwfn, vf->opaque_fid, + ¶ms, true, &vf_params); + if (!p_cid) goto out; /* Legacy VFs have their Producers in a different location, which they * calculate on their own and clean the producer prior to this. */ - if (vf->acquire.vfdev_info.eth_fp_hsi_minor == - ETH_HSI_VER_NO_PKT_LEN_TUNN) { - b_legacy_vf = true; - } else { + if (!(vf_legacy & QED_QCID_LEGACY_VF_RX_PROD)) REG_WR(p_hwfn, GTT_BAR0_MAP_REG_MSDM_RAM + MSTORM_ETH_VF_PRODS_OFFSET(vf->abs_vf_id, req->rx_qid), 0); - } - p_queue->p_rx_cid->b_legacy_vf = b_legacy_vf; - rc = qed_eth_rxq_start_ramrod(p_hwfn, - p_queue->p_rx_cid, + rc = qed_eth_rxq_start_ramrod(p_hwfn, p_cid, req->bd_max_bytes, req->rxq_addr, req->cqe_pbl_addr, req->cqe_pbl_size); if (rc) { status = PFVF_STATUS_FAILURE; - qed_eth_queue_cid_release(p_hwfn, p_queue->p_rx_cid); - p_queue->p_rx_cid = NULL; + qed_eth_queue_cid_release(p_hwfn, p_cid); } else { + p_queue->cids[qid_usage_idx].p_cid = p_cid; + p_queue->cids[qid_usage_idx].b_is_tx = false; status = PFVF_STATUS_SUCCESS; vf->num_active_rxqs++; } out: - qed_iov_vf_mbx_start_rxq_resp(p_hwfn, p_ptt, vf, status, b_legacy_vf); + qed_iov_vf_mbx_start_rxq_resp(p_hwfn, p_ptt, vf, status, + !!(vf_legacy & + QED_QCID_LEGACY_VF_RX_PROD)); } static void @@ -2209,7 +2354,7 @@ static void qed_iov_vf_mbx_update_tunn_param(struct qed_hwfn *p_hwfn, if (b_update_required) { u16 geneve_port; - rc = qed_sp_pf_update_tunn_cfg(p_hwfn, &tunn, + rc = qed_sp_pf_update_tunn_cfg(p_hwfn, p_ptt, &tunn, QED_SPQ_MODE_EBLOCK, NULL); if (rc) status = PFVF_STATUS_FAILURE; @@ -2235,7 +2380,8 @@ send_resp: static void qed_iov_vf_mbx_start_txq_resp(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - struct qed_vf_info *p_vf, u8 status) + struct qed_vf_info *p_vf, + u32 cid, u8 status) { struct qed_iov_vf_mbx *mbx = &p_vf->vf_mbx; struct pfvf_start_queue_resp_tlv *p_tlv; @@ -2263,12 +2409,8 @@ static void qed_iov_vf_mbx_start_txq_resp(struct qed_hwfn *p_hwfn, sizeof(struct channel_list_end_tlv)); /* Update the TLV with the response */ - if ((status == PFVF_STATUS_SUCCESS) && !b_legacy) { - u16 qid = mbx->req_virt->start_txq.tx_qid; - - p_tlv->offset = qed_db_addr_vf(p_vf->vf_queues[qid].fw_cid, - DQ_DEMS_LEGACY); - } + if ((status == PFVF_STATUS_SUCCESS) && !b_legacy) + p_tlv->offset = qed_db_addr_vf(cid, DQ_DEMS_LEGACY); qed_iov_send_response(p_hwfn, p_ptt, p_vf, length, status); } @@ -2278,10 +2420,15 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, struct qed_vf_info *vf) { struct qed_queue_start_common_params params; + struct qed_queue_cid_vf_params vf_params; struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; u8 status = PFVF_STATUS_NO_RESOURCE; struct vfpf_start_txq_tlv *req; - struct qed_vf_q_info *p_queue; + struct qed_vf_queue *p_queue; + struct qed_queue_cid *p_cid; + struct qed_sb_info sb_dummy; + u8 qid_usage_idx, vf_legacy; + u32 cid = 0; int rc; u16 pq; @@ -2289,89 +2436,126 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, req = &mbx->req_virt->start_txq; if (!qed_iov_validate_txq(p_hwfn, vf, req->tx_qid, - QED_IOV_VALIDATE_Q_DISABLE) || + QED_IOV_VALIDATE_Q_NA) || !qed_iov_validate_sb(p_hwfn, vf, req->hw_sb)) goto out; - /* Acquire a new queue-cid */ + qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, true); + if (qid_usage_idx == QED_IOV_QID_INVALID) + goto out; + p_queue = &vf->vf_queues[req->tx_qid]; + if (p_queue->cids[qid_usage_idx].p_cid) + goto out; + vf_legacy = qed_vf_calculate_legacy(vf); + + /* Acquire a new queue-cid */ params.queue_id = p_queue->fw_tx_qid; params.vport_id = vf->vport_id; params.stats_id = vf->abs_vf_id + 0x10; - params.sb = req->hw_sb; + + /* Since IGU index is passed via sb_info, construct a dummy one */ + memset(&sb_dummy, 0, sizeof(sb_dummy)); + sb_dummy.igu_sb_id = req->hw_sb; + params.p_sb = &sb_dummy; params.sb_idx = req->sb_index; - p_queue->p_tx_cid = _qed_eth_queue_to_cid(p_hwfn, - vf->opaque_fid, - p_queue->fw_cid, - req->tx_qid, ¶ms); - if (!p_queue->p_tx_cid) + memset(&vf_params, 0, sizeof(vf_params)); + vf_params.vfid = vf->relative_vf_id; + vf_params.vf_qid = (u8)req->tx_qid; + vf_params.vf_legacy = vf_legacy; + vf_params.qid_usage_idx = qid_usage_idx; + + p_cid = qed_eth_queue_to_cid(p_hwfn, vf->opaque_fid, + ¶ms, false, &vf_params); + if (!p_cid) goto out; pq = qed_get_cm_pq_idx_vf(p_hwfn, vf->relative_vf_id); - rc = qed_eth_txq_start_ramrod(p_hwfn, p_queue->p_tx_cid, + rc = qed_eth_txq_start_ramrod(p_hwfn, p_cid, req->pbl_addr, req->pbl_size, pq); if (rc) { status = PFVF_STATUS_FAILURE; - qed_eth_queue_cid_release(p_hwfn, p_queue->p_tx_cid); - p_queue->p_tx_cid = NULL; + qed_eth_queue_cid_release(p_hwfn, p_cid); } else { status = PFVF_STATUS_SUCCESS; + p_queue->cids[qid_usage_idx].p_cid = p_cid; + p_queue->cids[qid_usage_idx].b_is_tx = true; + cid = p_cid->cid; } out: - qed_iov_vf_mbx_start_txq_resp(p_hwfn, p_ptt, vf, status); + qed_iov_vf_mbx_start_txq_resp(p_hwfn, p_ptt, vf, cid, status); } static int qed_iov_vf_stop_rxqs(struct qed_hwfn *p_hwfn, struct qed_vf_info *vf, - u16 rxq_id, bool cqe_completion) + u16 rxq_id, + u8 qid_usage_idx, bool cqe_completion) { - struct qed_vf_q_info *p_queue; + struct qed_vf_queue *p_queue; int rc = 0; - if (!qed_iov_validate_rxq(p_hwfn, vf, rxq_id, - QED_IOV_VALIDATE_Q_ENABLE)) { + if (!qed_iov_validate_rxq(p_hwfn, vf, rxq_id, QED_IOV_VALIDATE_Q_NA)) { DP_VERBOSE(p_hwfn, QED_MSG_IOV, - "VF[%d] Tried Closing Rx 0x%04x which is inactive\n", - vf->relative_vf_id, rxq_id); + "VF[%d] Tried Closing Rx 0x%04x.%02x which is inactive\n", + vf->relative_vf_id, rxq_id, qid_usage_idx); return -EINVAL; } p_queue = &vf->vf_queues[rxq_id]; + /* We've validated the index and the existence of the active RXQ - + * now we need to make sure that it's using the correct qid. + */ + if (!p_queue->cids[qid_usage_idx].p_cid || + p_queue->cids[qid_usage_idx].b_is_tx) { + struct qed_queue_cid *p_cid; + + p_cid = qed_iov_get_vf_rx_queue_cid(p_queue); + DP_VERBOSE(p_hwfn, + QED_MSG_IOV, + "VF[%d] - Tried Closing Rx 0x%04x.%02x, but Rx is at %04x.%02x\n", + vf->relative_vf_id, + rxq_id, qid_usage_idx, rxq_id, p_cid->qid_usage_idx); + return -EINVAL; + } + + /* Now that we know we have a valid Rx-queue - close it */ rc = qed_eth_rx_queue_stop(p_hwfn, - p_queue->p_rx_cid, + p_queue->cids[qid_usage_idx].p_cid, false, cqe_completion); if (rc) return rc; - p_queue->p_rx_cid = NULL; + p_queue->cids[qid_usage_idx].p_cid = NULL; vf->num_active_rxqs--; return 0; } static int qed_iov_vf_stop_txqs(struct qed_hwfn *p_hwfn, - struct qed_vf_info *vf, u16 txq_id) + struct qed_vf_info *vf, + u16 txq_id, u8 qid_usage_idx) { - struct qed_vf_q_info *p_queue; + struct qed_vf_queue *p_queue; int rc = 0; - if (!qed_iov_validate_txq(p_hwfn, vf, txq_id, - QED_IOV_VALIDATE_Q_ENABLE)) + if (!qed_iov_validate_txq(p_hwfn, vf, txq_id, QED_IOV_VALIDATE_Q_NA)) return -EINVAL; p_queue = &vf->vf_queues[txq_id]; + if (!p_queue->cids[qid_usage_idx].p_cid || + !p_queue->cids[qid_usage_idx].b_is_tx) + return -EINVAL; - rc = qed_eth_tx_queue_stop(p_hwfn, p_queue->p_tx_cid); + rc = qed_eth_tx_queue_stop(p_hwfn, p_queue->cids[qid_usage_idx].p_cid); if (rc) return rc; - p_queue->p_tx_cid = NULL; - + p_queue->cids[qid_usage_idx].p_cid = NULL; return 0; } @@ -2383,6 +2567,7 @@ static void qed_iov_vf_mbx_stop_rxqs(struct qed_hwfn *p_hwfn, struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; u8 status = PFVF_STATUS_FAILURE; struct vfpf_stop_rxqs_tlv *req; + u8 qid_usage_idx; int rc; /* There has never been an official driver that used this interface @@ -2398,8 +2583,13 @@ static void qed_iov_vf_mbx_stop_rxqs(struct qed_hwfn *p_hwfn, goto out; } + /* Find which qid-index is associated with the queue */ + qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, false); + if (qid_usage_idx == QED_IOV_QID_INVALID) + goto out; + rc = qed_iov_vf_stop_rxqs(p_hwfn, vf, req->rx_qid, - req->cqe_completion); + qid_usage_idx, req->cqe_completion); if (!rc) status = PFVF_STATUS_SUCCESS; out: @@ -2415,6 +2605,7 @@ static void qed_iov_vf_mbx_stop_txqs(struct qed_hwfn *p_hwfn, struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; u8 status = PFVF_STATUS_FAILURE; struct vfpf_stop_txqs_tlv *req; + u8 qid_usage_idx; int rc; /* There has never been an official driver that used this interface @@ -2429,7 +2620,13 @@ static void qed_iov_vf_mbx_stop_txqs(struct qed_hwfn *p_hwfn, status = PFVF_STATUS_NOT_SUPPORTED; goto out; } - rc = qed_iov_vf_stop_txqs(p_hwfn, vf, req->tx_qid); + + /* Find which qid-index is associated with the queue */ + qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, true); + if (qid_usage_idx == QED_IOV_QID_INVALID) + goto out; + + rc = qed_iov_vf_stop_txqs(p_hwfn, vf, req->tx_qid, qid_usage_idx); if (!rc) status = PFVF_STATUS_SUCCESS; @@ -2449,7 +2646,7 @@ static void qed_iov_vf_mbx_update_rxqs(struct qed_hwfn *p_hwfn, u8 status = PFVF_STATUS_FAILURE; u8 complete_event_flg; u8 complete_cqe_flg; - u16 qid; + u8 qid_usage_idx; int rc; u8 i; @@ -2457,19 +2654,42 @@ static void qed_iov_vf_mbx_update_rxqs(struct qed_hwfn *p_hwfn, complete_cqe_flg = !!(req->flags & VFPF_RXQ_UPD_COMPLETE_CQE_FLAG); complete_event_flg = !!(req->flags & VFPF_RXQ_UPD_COMPLETE_EVENT_FLAG); - /* Validate inputs */ - for (i = req->rx_qid; i < req->rx_qid + req->num_rxqs; i++) + qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, false); + if (qid_usage_idx == QED_IOV_QID_INVALID) + goto out; + + /* There shouldn't exist a VF that uses queue-qids yet uses this + * API with multiple Rx queues. Validate this. + */ + if ((vf->acquire.vfdev_info.capabilities & + VFPF_ACQUIRE_CAP_QUEUE_QIDS) && req->num_rxqs != 1) { + DP_VERBOSE(p_hwfn, QED_MSG_IOV, + "VF[%d] supports QIDs but sends multiple queues\n", + vf->relative_vf_id); + goto out; + } + + /* Validate inputs - for the legacy case this is still true since + * qid_usage_idx for each Rx queue would be LEGACY_QID_RX. + */ + for (i = req->rx_qid; i < req->rx_qid + req->num_rxqs; i++) { if (!qed_iov_validate_rxq(p_hwfn, vf, i, - QED_IOV_VALIDATE_Q_ENABLE)) { - DP_INFO(p_hwfn, "VF[%d]: Incorrect Rxqs [%04x, %02x]\n", - vf->relative_vf_id, req->rx_qid, req->num_rxqs); + QED_IOV_VALIDATE_Q_NA) || + !vf->vf_queues[i].cids[qid_usage_idx].p_cid || + vf->vf_queues[i].cids[qid_usage_idx].b_is_tx) { + DP_VERBOSE(p_hwfn, QED_MSG_IOV, + "VF[%d]: Incorrect Rxqs [%04x, %02x]\n", + vf->relative_vf_id, req->rx_qid, + req->num_rxqs); goto out; } + } /* Prepare the handlers */ for (i = 0; i < req->num_rxqs; i++) { - qid = req->rx_qid + i; - handlers[i] = vf->vf_queues[qid].p_rx_cid; + u16 qid = req->rx_qid + i; + + handlers[i] = vf->vf_queues[qid].cids[qid_usage_idx].p_cid; } rc = qed_sp_eth_rx_queues_update(p_hwfn, (void **)&handlers, @@ -2683,6 +2903,8 @@ qed_iov_vp_update_rss_param(struct qed_hwfn *p_hwfn, (1 << p_rss_tlv->rss_table_size_log)); for (i = 0; i < table_size; i++) { + struct qed_queue_cid *p_cid; + q_idx = p_rss_tlv->rss_ind_table[i]; if (!qed_iov_validate_rxq(p_hwfn, vf, q_idx, QED_IOV_VALIDATE_Q_ENABLE)) { @@ -2694,7 +2916,8 @@ qed_iov_vp_update_rss_param(struct qed_hwfn *p_hwfn, goto out; } - p_rss->rss_ind_table[i] = vf->vf_queues[q_idx].p_rx_cid; + p_cid = qed_iov_get_vf_rx_queue_cid(&vf->vf_queues[q_idx]); + p_rss->rss_ind_table[i] = p_cid; } p_data->rss_params = p_rss; diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.h b/drivers/net/ethernet/qlogic/qed/qed_sriov.h index 81a497ce6585..95f55ae2ee8b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.h @@ -149,12 +149,21 @@ struct qed_iov_vf_mbx { struct vfpf_first_tlv first_tlv; }; -struct qed_vf_q_info { +#define QED_IOV_LEGACY_QID_RX (0) +#define QED_IOV_LEGACY_QID_TX (1) +#define QED_IOV_QID_INVALID (0xFE) + +struct qed_vf_queue_cid { + bool b_is_tx; + struct qed_queue_cid *p_cid; +}; + +/* Describes a qzone associated with the VF */ +struct qed_vf_queue { u16 fw_rx_qid; - struct qed_queue_cid *p_rx_cid; u16 fw_tx_qid; - struct qed_queue_cid *p_tx_cid; - u8 fw_cid; + + struct qed_vf_queue_cid cids[MAX_QUEUES_PER_QZONE]; }; enum vf_state { @@ -212,7 +221,8 @@ struct qed_vf_info { u8 num_mac_filters; u8 num_vlan_filters; - struct qed_vf_q_info vf_queues[QED_MAX_VF_CHAINS_PER_PF]; + + struct qed_vf_queue vf_queues[QED_MAX_VF_CHAINS_PER_PF]; u16 igu_sbs[QED_MAX_VF_CHAINS_PER_PF]; u8 num_active_rxqs; struct qed_public_vf_info p_vf_info; @@ -316,9 +326,8 @@ int qed_iov_alloc(struct qed_hwfn *p_hwfn); * @brief qed_iov_setup - setup sriov related resources * * @param p_hwfn - * @param p_ptt */ -void qed_iov_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); +void qed_iov_setup(struct qed_hwfn *p_hwfn); /** * @brief qed_iov_free - free sriov related resources @@ -397,7 +406,7 @@ static inline int qed_iov_alloc(struct qed_hwfn *p_hwfn) return 0; } -static inline void qed_iov_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +static inline void qed_iov_setup(struct qed_hwfn *p_hwfn) { } diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.c b/drivers/net/ethernet/qlogic/qed/qed_vf.c index 11d71e5eea14..1926d1ed439f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.c +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.c @@ -153,6 +153,77 @@ static int qed_send_msg2pf(struct qed_hwfn *p_hwfn, u8 *done, u32 resp_size) return rc; } +static void qed_vf_pf_add_qid(struct qed_hwfn *p_hwfn, + struct qed_queue_cid *p_cid) +{ + struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; + struct vfpf_qid_tlv *p_qid_tlv; + + /* Only add QIDs for the queue if it was negotiated with PF */ + if (!(p_iov->acquire_resp.pfdev_info.capabilities & + PFVF_ACQUIRE_CAP_QUEUE_QIDS)) + return; + + p_qid_tlv = qed_add_tlv(p_hwfn, &p_iov->offset, + CHANNEL_TLV_QID, sizeof(*p_qid_tlv)); + p_qid_tlv->qid = p_cid->qid_usage_idx; +} + +int _qed_vf_pf_release(struct qed_hwfn *p_hwfn, bool b_final) +{ + struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; + struct pfvf_def_resp_tlv *resp; + struct vfpf_first_tlv *req; + u32 size; + int rc; + + /* clear mailbox and prep first tlv */ + req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_RELEASE, sizeof(*req)); + + /* add list termination tlv */ + qed_add_tlv(p_hwfn, &p_iov->offset, + CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); + + resp = &p_iov->pf2vf_reply->default_resp; + rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp)); + + if (!rc && resp->hdr.status != PFVF_STATUS_SUCCESS) + rc = -EAGAIN; + + qed_vf_pf_req_end(p_hwfn, rc); + if (!b_final) + return rc; + + p_hwfn->b_int_enabled = 0; + + if (p_iov->vf2pf_request) + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(union vfpf_tlvs), + p_iov->vf2pf_request, + p_iov->vf2pf_request_phys); + if (p_iov->pf2vf_reply) + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(union pfvf_tlvs), + p_iov->pf2vf_reply, p_iov->pf2vf_reply_phys); + + if (p_iov->bulletin.p_virt) { + size = sizeof(struct qed_bulletin_content); + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + size, + p_iov->bulletin.p_virt, p_iov->bulletin.phys); + } + + kfree(p_hwfn->vf_iov_info); + p_hwfn->vf_iov_info = NULL; + + return rc; +} + +int qed_vf_pf_release(struct qed_hwfn *p_hwfn) +{ + return _qed_vf_pf_release(p_hwfn, true); +} + #define VF_ACQUIRE_THRESH 3 static void qed_vf_pf_acquire_reduce_resc(struct qed_hwfn *p_hwfn, struct vf_pf_resc_request *p_req, @@ -160,7 +231,7 @@ static void qed_vf_pf_acquire_reduce_resc(struct qed_hwfn *p_hwfn, { DP_VERBOSE(p_hwfn, QED_MSG_IOV, - "PF unwilling to fullill resource request: rxq [%02x/%02x] txq [%02x/%02x] sbs [%02x/%02x] mac [%02x/%02x] vlan [%02x/%02x] mc [%02x/%02x]. Try PF recommended amount\n", + "PF unwilling to fullill resource request: rxq [%02x/%02x] txq [%02x/%02x] sbs [%02x/%02x] mac [%02x/%02x] vlan [%02x/%02x] mc [%02x/%02x] cids [%02x/%02x]. Try PF recommended amount\n", p_req->num_rxqs, p_resp->num_rxqs, p_req->num_rxqs, @@ -171,7 +242,8 @@ static void qed_vf_pf_acquire_reduce_resc(struct qed_hwfn *p_hwfn, p_resp->num_mac_filters, p_req->num_vlan_filters, p_resp->num_vlan_filters, - p_req->num_mc_filters, p_resp->num_mc_filters); + p_req->num_mc_filters, + p_resp->num_mc_filters, p_req->num_cids, p_resp->num_cids); /* humble our request */ p_req->num_txqs = p_resp->num_txqs; @@ -180,6 +252,7 @@ static void qed_vf_pf_acquire_reduce_resc(struct qed_hwfn *p_hwfn, p_req->num_mac_filters = p_resp->num_mac_filters; p_req->num_vlan_filters = p_resp->num_vlan_filters; p_req->num_mc_filters = p_resp->num_mc_filters; + p_req->num_cids = p_resp->num_cids; } static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) @@ -204,6 +277,7 @@ static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) p_resc->num_sbs = QED_MAX_VF_CHAINS_PER_PF; p_resc->num_mac_filters = QED_ETH_VF_NUM_MAC_FILTERS; p_resc->num_vlan_filters = QED_ETH_VF_NUM_VLAN_FILTERS; + p_resc->num_cids = QED_ETH_VF_DEFAULT_NUM_CIDS; req->vfdev_info.os_type = VFPF_ACQUIRE_OS_LINUX; req->vfdev_info.fw_major = FW_MAJOR_VERSION; @@ -216,6 +290,13 @@ static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) /* Fill capability field with any non-deprecated config we support */ req->vfdev_info.capabilities |= VFPF_ACQUIRE_CAP_100G; + /* If we've mapped the doorbell bar, try using queue qids */ + if (p_iov->b_doorbell_bar) { + req->vfdev_info.capabilities |= VFPF_ACQUIRE_CAP_PHYSICAL_BAR | + VFPF_ACQUIRE_CAP_QUEUE_QIDS; + p_resc->num_cids = QED_ETH_VF_MAX_NUM_CIDS; + } + /* pf 2 vf bulletin board address */ req->bulletin_addr = p_iov->bulletin.phys; req->bulletin_size = p_iov->bulletin.size; @@ -307,6 +388,13 @@ static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) if (req->vfdev_info.capabilities & VFPF_ACQUIRE_CAP_PRE_FP_HSI) p_iov->b_pre_fp_hsi = true; + /* In case PF doesn't support multi-queue Tx, update the number of + * CIDs to reflect the number of queues [older PFs didn't fill that + * field]. + */ + if (!(resp->pfdev_info.capabilities & PFVF_ACQUIRE_CAP_QUEUE_QIDS)) + resp->resc.num_cids = resp->resc.num_rxqs + resp->resc.num_txqs; + /* Update bulletin board size with response from PF */ p_iov->bulletin.size = resp->bulletin_size; @@ -338,10 +426,27 @@ exit: return rc; } +u32 qed_vf_hw_bar_size(struct qed_hwfn *p_hwfn, enum BAR_ID bar_id) +{ + u32 bar_size; + + /* Regview size is fixed */ + if (bar_id == BAR_ID_0) + return 1 << 17; + + /* Doorbell is received from PF */ + bar_size = p_hwfn->vf_iov_info->acquire_resp.pfdev_info.bar_size; + if (bar_size) + return 1 << bar_size; + return 0; +} + int qed_vf_hw_prepare(struct qed_hwfn *p_hwfn) { + struct qed_hwfn *p_lead = QED_LEADING_HWFN(p_hwfn->cdev); struct qed_vf_iov *p_iov; u32 reg; + int rc; /* Set number of hwfns - might be overriden once leading hwfn learns * actual configuration from PF. @@ -349,10 +454,6 @@ int qed_vf_hw_prepare(struct qed_hwfn *p_hwfn) if (IS_LEAD_HWFN(p_hwfn)) p_hwfn->cdev->num_hwfns = 1; - /* Set the doorbell bar. Assumption: regview is set */ - p_hwfn->doorbells = (u8 __iomem *)p_hwfn->regview + - PXP_VF_BAR0_START_DQ; - reg = PXP_VF_BAR0_ME_OPAQUE_ADDRESS; p_hwfn->hw_info.opaque_fid = (u16)REG_RD(p_hwfn, reg); @@ -364,6 +465,30 @@ int qed_vf_hw_prepare(struct qed_hwfn *p_hwfn) if (!p_iov) return -ENOMEM; + /* Doorbells are tricky; Upper-layer has alreday set the hwfn doorbell + * value, but there are several incompatibily scenarios where that + * would be incorrect and we'd need to override it. + */ + if (!p_hwfn->doorbells) { + p_hwfn->doorbells = (u8 __iomem *)p_hwfn->regview + + PXP_VF_BAR0_START_DQ; + } else if (p_hwfn == p_lead) { + /* For leading hw-function, value is always correct, but need + * to handle scenario where legacy PF would not support 100g + * mapped bars later. + */ + p_iov->b_doorbell_bar = true; + } else { + /* here, value would be correct ONLY if the leading hwfn + * received indication that mapped-bars are supported. + */ + if (p_lead->vf_iov_info->b_doorbell_bar) + p_iov->b_doorbell_bar = true; + else + p_hwfn->doorbells = (u8 __iomem *) + p_hwfn->regview + PXP_VF_BAR0_START_DQ; + } + /* Allocate vf2pf msg */ p_iov->vf2pf_request = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, sizeof(union vfpf_tlvs), @@ -403,7 +528,33 @@ int qed_vf_hw_prepare(struct qed_hwfn *p_hwfn) p_hwfn->hw_info.personality = QED_PCI_ETH; - return qed_vf_pf_acquire(p_hwfn); + rc = qed_vf_pf_acquire(p_hwfn); + + /* If VF is 100g using a mapped bar and PF is too old to support that, + * acquisition would succeed - but the VF would have no way knowing + * the size of the doorbell bar configured in HW and thus will not + * know how to split it for 2nd hw-function. + * In this case we re-try without the indication of the mapped + * doorbell. + */ + if (!rc && p_iov->b_doorbell_bar && + !qed_vf_hw_bar_size(p_hwfn, BAR_ID_1) && + (p_hwfn->cdev->num_hwfns > 1)) { + rc = _qed_vf_pf_release(p_hwfn, false); + if (rc) + return rc; + + p_iov->b_doorbell_bar = false; + p_hwfn->doorbells = (u8 __iomem *)p_hwfn->regview + + PXP_VF_BAR0_START_DQ; + rc = qed_vf_pf_acquire(p_hwfn); + } + + DP_VERBOSE(p_hwfn, QED_MSG_IOV, + "Regview [%p], Doorbell [%p], Device-doorbell [%p]\n", + p_hwfn->regview, p_hwfn->doorbells, p_hwfn->cdev->doorbells); + + return rc; free_vf2pf_request: dma_free_coherent(&p_hwfn->cdev->pdev->dev, @@ -588,8 +739,8 @@ qed_vf_pf_rxq_start(struct qed_hwfn *p_hwfn, req->cqe_pbl_addr = cqe_pbl_addr; req->cqe_pbl_size = cqe_pbl_size; req->rxq_addr = bd_chain_phys_addr; - req->hw_sb = p_cid->rel.sb; - req->sb_index = p_cid->rel.sb_idx; + req->hw_sb = p_cid->sb_igu_id; + req->sb_index = p_cid->sb_idx; req->bd_max_bytes = bd_max_bytes; req->stat_id = -1; @@ -609,6 +760,9 @@ qed_vf_pf_rxq_start(struct qed_hwfn *p_hwfn, __internal_ram_wr(p_hwfn, *pp_prod, sizeof(u32), (u32 *)(&init_prod_val)); } + + qed_vf_pf_add_qid(p_hwfn, p_cid); + /* add list termination tlv */ qed_add_tlv(p_hwfn, &p_iov->offset, CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); @@ -657,6 +811,8 @@ int qed_vf_pf_rxq_stop(struct qed_hwfn *p_hwfn, req->num_rxqs = 1; req->cqe_completion = cqe_completion; + qed_vf_pf_add_qid(p_hwfn, p_cid); + /* add list termination tlv */ qed_add_tlv(p_hwfn, &p_iov->offset, CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); @@ -697,8 +853,10 @@ qed_vf_pf_txq_start(struct qed_hwfn *p_hwfn, /* Tx */ req->pbl_addr = pbl_addr; req->pbl_size = pbl_size; - req->hw_sb = p_cid->rel.sb; - req->sb_index = p_cid->rel.sb_idx; + req->hw_sb = p_cid->sb_igu_id; + req->sb_index = p_cid->sb_idx; + + qed_vf_pf_add_qid(p_hwfn, p_cid); /* add list termination tlv */ qed_add_tlv(p_hwfn, &p_iov->offset, @@ -728,8 +886,8 @@ qed_vf_pf_txq_start(struct qed_hwfn *p_hwfn, } DP_VERBOSE(p_hwfn, QED_MSG_IOV, - "Txq[0x%02x]: doorbell at %p [offset 0x%08x]\n", - qid, *pp_doorbell, resp->offset); + "Txq[0x%02x.%02x]: doorbell at %p [offset 0x%08x]\n", + qid, p_cid->qid_usage_idx, *pp_doorbell, resp->offset); exit: qed_vf_pf_req_end(p_hwfn, rc); @@ -749,6 +907,8 @@ int qed_vf_pf_txq_stop(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid) req->tx_qid = p_cid->rel.queue_id; req->num_txqs = 1; + qed_vf_pf_add_qid(p_hwfn, p_cid); + /* add list termination tlv */ qed_add_tlv(p_hwfn, &p_iov->offset, CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); @@ -792,9 +952,12 @@ int qed_vf_pf_vport_start(struct qed_hwfn *p_hwfn, req->only_untagged = only_untagged; /* status blocks */ - for (i = 0; i < p_hwfn->vf_iov_info->acquire_resp.resc.num_sbs; i++) - if (p_hwfn->sbs_info[i]) - req->sb_addr[i] = p_hwfn->sbs_info[i]->sb_phys; + for (i = 0; i < p_hwfn->vf_iov_info->acquire_resp.resc.num_sbs; i++) { + struct qed_sb_info *p_sb = p_hwfn->vf_iov_info->sbs_info[i]; + + if (p_sb) + req->sb_addr[i] = p_sb->sb_phys; + } /* add list termination tlv */ qed_add_tlv(p_hwfn, &p_iov->offset, @@ -1095,54 +1258,6 @@ exit: return rc; } -int qed_vf_pf_release(struct qed_hwfn *p_hwfn) -{ - struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; - struct pfvf_def_resp_tlv *resp; - struct vfpf_first_tlv *req; - u32 size; - int rc; - - /* clear mailbox and prep first tlv */ - req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_RELEASE, sizeof(*req)); - - /* add list termination tlv */ - qed_add_tlv(p_hwfn, &p_iov->offset, - CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); - - resp = &p_iov->pf2vf_reply->default_resp; - rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp)); - - if (!rc && resp->hdr.status != PFVF_STATUS_SUCCESS) - rc = -EAGAIN; - - qed_vf_pf_req_end(p_hwfn, rc); - - p_hwfn->b_int_enabled = 0; - - if (p_iov->vf2pf_request) - dma_free_coherent(&p_hwfn->cdev->pdev->dev, - sizeof(union vfpf_tlvs), - p_iov->vf2pf_request, - p_iov->vf2pf_request_phys); - if (p_iov->pf2vf_reply) - dma_free_coherent(&p_hwfn->cdev->pdev->dev, - sizeof(union pfvf_tlvs), - p_iov->pf2vf_reply, p_iov->pf2vf_reply_phys); - - if (p_iov->bulletin.p_virt) { - size = sizeof(struct qed_bulletin_content); - dma_free_coherent(&p_hwfn->cdev->pdev->dev, - size, - p_iov->bulletin.p_virt, p_iov->bulletin.phys); - } - - kfree(p_hwfn->vf_iov_info); - p_hwfn->vf_iov_info = NULL; - - return rc; -} - void qed_vf_pf_filter_mcast(struct qed_hwfn *p_hwfn, struct qed_filter_mcast *p_filter_cmd) { @@ -1240,6 +1355,24 @@ u16 qed_vf_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) return p_iov->acquire_resp.resc.hw_sbs[sb_id].hw_sb_id; } +void qed_vf_set_sb_info(struct qed_hwfn *p_hwfn, + u16 sb_id, struct qed_sb_info *p_sb) +{ + struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; + + if (!p_iov) { + DP_NOTICE(p_hwfn, "vf_sriov_info isn't initialized\n"); + return; + } + + if (sb_id >= PFVF_MAX_SBS_PER_VF) { + DP_NOTICE(p_hwfn, "Can't configure SB %04x\n", sb_id); + return; + } + + p_iov->sbs_info[sb_id] = p_sb; +} + int qed_vf_read_bulletin(struct qed_hwfn *p_hwfn, u8 *p_change) { struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; @@ -1342,6 +1475,16 @@ void qed_vf_get_num_rxqs(struct qed_hwfn *p_hwfn, u8 *num_rxqs) *num_rxqs = p_hwfn->vf_iov_info->acquire_resp.resc.num_rxqs; } +void qed_vf_get_num_txqs(struct qed_hwfn *p_hwfn, u8 *num_txqs) +{ + *num_txqs = p_hwfn->vf_iov_info->acquire_resp.resc.num_txqs; +} + +void qed_vf_get_num_cids(struct qed_hwfn *p_hwfn, u8 *num_cids) +{ + *num_cids = p_hwfn->vf_iov_info->acquire_resp.resc.num_cids; +} + void qed_vf_get_port_mac(struct qed_hwfn *p_hwfn, u8 *port_mac) { memcpy(port_mac, diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.h b/drivers/net/ethernet/qlogic/qed/qed_vf.h index 34ac70b0e5fe..b65bbc54a097 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.h +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.h @@ -46,7 +46,8 @@ struct vf_pf_resc_request { u8 num_mac_filters; u8 num_vlan_filters; u8 num_mc_filters; - u16 padding; + u8 num_cids; + u8 padding; }; struct hw_sb_info { @@ -113,6 +114,17 @@ struct vfpf_acquire_tlv { struct vf_pf_vfdev_info { #define VFPF_ACQUIRE_CAP_PRE_FP_HSI (1 << 0) /* VF pre-FP hsi version */ #define VFPF_ACQUIRE_CAP_100G (1 << 1) /* VF can support 100g */ + /* A requirement for supporting multi-Tx queues on a single queue-zone, + * VF would pass qids as additional information whenever passing queue + * references. + */ +#define VFPF_ACQUIRE_CAP_QUEUE_QIDS BIT(2) + + /* The VF is using the physical bar. While this is mostly internal + * to the VF, might affect the number of CIDs supported assuming + * QUEUE_QIDS is set. + */ +#define VFPF_ACQUIRE_CAP_PHYSICAL_BAR BIT(3) u64 capabilities; u8 fw_major; u8 fw_minor; @@ -185,6 +197,9 @@ struct pfvf_acquire_resp_tlv { */ #define PFVF_ACQUIRE_CAP_POST_FW_OVERRIDE BIT(2) + /* PF expects queues to be received with additional qids */ +#define PFVF_ACQUIRE_CAP_QUEUE_QIDS BIT(3) + u16 db_size; u8 indices_per_sb; u8 os_type; @@ -193,7 +208,8 @@ struct pfvf_acquire_resp_tlv { u16 chip_rev; u8 dev_type; - u8 padding; + /* Doorbell bar size configured in HW: log(size) or 0 */ + u8 bar_size; struct pfvf_stats_info stats_info; @@ -221,7 +237,8 @@ struct pfvf_acquire_resp_tlv { u8 num_mac_filters; u8 num_vlan_filters; u8 num_mc_filters; - u8 padding[2]; + u8 num_cids; + u8 padding; } resc; u32 bulletin_size; @@ -234,6 +251,16 @@ struct pfvf_start_queue_resp_tlv { u8 padding[4]; }; +/* Extended queue information - additional index for reference inside qzone. + * If commmunicated between VF/PF, each TLV relating to queues should be + * extended by one such [or have a future base TLV that already contains info]. + */ +struct vfpf_qid_tlv { + struct channel_tlv tl; + u8 qid; + u8 padding[3]; +}; + /* Setup Queue */ struct vfpf_start_rxq_tlv { struct vfpf_first_tlv first_tlv; @@ -597,6 +624,8 @@ enum { CHANNEL_TLV_VPORT_UPDATE_ACCEPT_ANY_VLAN, CHANNEL_TLV_VPORT_UPDATE_SGE_TPA, CHANNEL_TLV_UPDATE_TUNN_PARAM, + CHANNEL_TLV_RESERVED, + CHANNEL_TLV_QID, CHANNEL_TLV_MAX, /* Required for iterating over vport-update tlvs. @@ -605,6 +634,12 @@ enum { CHANNEL_TLV_VPORT_UPDATE_MAX = CHANNEL_TLV_VPORT_UPDATE_SGE_TPA + 1, }; +/* Default number of CIDs [total of both Rx and Tx] to be requested + * by default, and maximum possible number. + */ +#define QED_ETH_VF_DEFAULT_NUM_CIDS (32) +#define QED_ETH_VF_MAX_NUM_CIDS (250) + /* This data is held in the qed_hwfn structure for VFs only. */ struct qed_vf_iov { union vfpf_tlvs *vf2pf_request; @@ -627,6 +662,19 @@ struct qed_vf_iov { * this has to be propagated as it affects the fastpath. */ bool b_pre_fp_hsi; + + /* Current day VFs are passing the SBs physical address on vport + * start, and as they lack an IGU mapping they need to store the + * addresses of previously registered SBs. + * Even if we were to change configuration flow, due to backward + * compatibility [with older PFs] we'd still need to store these. + */ + struct qed_sb_info *sbs_info[PFVF_MAX_SBS_PER_VF]; + + /* Determines whether VF utilizes doorbells via limited register + * bar or via the doorbell bar. + */ + bool b_doorbell_bar; }; #ifdef CONFIG_QED_SRIOV @@ -676,6 +724,22 @@ void qed_vf_get_link_caps(struct qed_hwfn *p_hwfn, void qed_vf_get_num_rxqs(struct qed_hwfn *p_hwfn, u8 *num_rxqs); /** + * @brief Get number of Rx queues allocated for VF by qed + * + * @param p_hwfn + * @param num_txqs - allocated RX queues + */ +void qed_vf_get_num_txqs(struct qed_hwfn *p_hwfn, u8 *num_txqs); + +/** + * @brief Get number of available connections [both Rx and Tx] for VF + * + * @param p_hwfn + * @param num_cids - allocated number of connections + */ +void qed_vf_get_num_cids(struct qed_hwfn *p_hwfn, u8 *num_cids); + +/** * @brief Get port mac address for VF * * @param p_hwfn @@ -837,6 +901,16 @@ int qed_vf_pf_release(struct qed_hwfn *p_hwfn); u16 qed_vf_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id); /** + * @brief Stores [or removes] a configured sb_info. + * + * @param p_hwfn + * @param sb_id - zero-based SB index [for fastpath] + * @param sb_info - may be NULL [during removal]. + */ +void qed_vf_set_sb_info(struct qed_hwfn *p_hwfn, + u16 sb_id, struct qed_sb_info *p_sb); + +/** * @brief qed_vf_pf_vport_start - perform vport start for VF. * * @param p_hwfn @@ -917,6 +991,8 @@ void qed_iov_vf_task(struct work_struct *work); void qed_vf_set_vf_start_tunn_update_param(struct qed_tunnel_info *p_tun); int qed_vf_pf_tunnel_param_update(struct qed_hwfn *p_hwfn, struct qed_tunnel_info *p_tunn); + +u32 qed_vf_hw_bar_size(struct qed_hwfn *p_hwfn, enum BAR_ID bar_id); #else static inline void qed_vf_get_link_params(struct qed_hwfn *p_hwfn, struct qed_mcp_link_params *params) @@ -938,6 +1014,14 @@ static inline void qed_vf_get_num_rxqs(struct qed_hwfn *p_hwfn, u8 *num_rxqs) { } +static inline void qed_vf_get_num_txqs(struct qed_hwfn *p_hwfn, u8 *num_txqs) +{ +} + +static inline void qed_vf_get_num_cids(struct qed_hwfn *p_hwfn, u8 *num_cids) +{ +} + static inline void qed_vf_get_port_mac(struct qed_hwfn *p_hwfn, u8 *port_mac) { } @@ -1089,6 +1173,13 @@ static inline int qed_vf_pf_tunnel_param_update(struct qed_hwfn *p_hwfn, { return -EINVAL; } + +static inline u32 +qed_vf_hw_bar_size(struct qed_hwfn *p_hwfn, + enum BAR_ID bar_id) +{ + return 0; +} #endif #endif diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h index 9b4f08b6f9b9..694c09b8997e 100644 --- a/drivers/net/ethernet/qlogic/qede/qede.h +++ b/drivers/net/ethernet/qlogic/qede/qede.h @@ -197,7 +197,6 @@ struct qede_dev { #define QEDE_TSS_COUNT(edev) ((edev)->num_queues - (edev)->fp_num_rx) struct qed_int_info int_info; - unsigned char primary_mac[ETH_ALEN]; /* Smaller private varaiant of the RTNL lock */ struct mutex qede_lock; diff --git a/drivers/net/ethernet/qlogic/qede/qede_dcbnl.c b/drivers/net/ethernet/qlogic/qede/qede_dcbnl.c index a9e7379313db..6e7747b9b95e 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_dcbnl.c +++ b/drivers/net/ethernet/qlogic/qede/qede_dcbnl.c @@ -313,7 +313,6 @@ static const struct dcbnl_rtnl_ops qede_dcbnl_ops = { .ieee_setets = qede_dcbnl_ieee_setets, .ieee_getapp = qede_dcbnl_ieee_getapp, .ieee_setapp = qede_dcbnl_ieee_setapp, - .getdcbx = qede_dcbnl_getdcbx, .ieee_peer_getpfc = qede_dcbnl_ieee_peer_getpfc, .ieee_peer_getets = qede_dcbnl_ieee_peer_getets, .getstate = qede_dcbnl_getstate, diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 172b292241a5..6a03d3e66cff 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -506,6 +506,14 @@ static int qede_set_link_ksettings(struct net_device *dev, params.autoneg = false; params.forced_speed = base->speed; switch (base->speed) { + case SPEED_1000: + if (!(current_link.supported_caps & + QED_LM_1000baseT_Full_BIT)) { + DP_INFO(edev, "1G speed not supported\n"); + return -EINVAL; + } + params.adv_speeds = QED_LM_1000baseT_Full_BIT; + break; case SPEED_10000: if (!(current_link.supported_caps & QED_LM_10000baseKR_Full_BIT)) { @@ -1282,7 +1290,8 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev, struct qede_tx_queue *txq = NULL; struct eth_tx_1st_bd *first_bd; dma_addr_t mapping; - int i, idx, val; + int i, idx; + u16 val; for_each_queue(i) { if (edev->fp_array[i].type & QEDE_FASTPATH_TX) { @@ -1297,14 +1306,15 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev, } /* Fill the entry in the SW ring and the BDs in the FW ring */ - idx = txq->sw_tx_prod & NUM_TX_BDS_MAX; + idx = txq->sw_tx_prod; txq->sw_tx_ring.skbs[idx].skb = skb; first_bd = qed_chain_produce(&txq->tx_pbl); memset(first_bd, 0, sizeof(*first_bd)); val = 1 << ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT; first_bd->data.bd_flags.bitfields = val; val = skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK; - first_bd->data.bitfields |= (val << ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT); + val = val << ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT; + first_bd->data.bitfields |= cpu_to_le16(val); /* Map skb linear data for DMA and set in the first BD */ mapping = dma_map_single(&edev->pdev->dev, skb->data, @@ -1317,10 +1327,10 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev, /* update the first BD with the actual num BDs */ first_bd->data.nbds = 1; - txq->sw_tx_prod++; + txq->sw_tx_prod = (txq->sw_tx_prod + 1) % txq->num_tx_buffers; /* 'next page' entries are counted in the producer value */ - val = cpu_to_le16(qed_chain_get_prod_idx(&txq->tx_pbl)); - txq->tx_db.data.bd_prod = val; + val = qed_chain_get_prod_idx(&txq->tx_pbl); + txq->tx_db.data.bd_prod = cpu_to_le16(val); /* wmb makes sure that the BDs data is updated before updating the * producer, otherwise FW may read old data from the BDs. @@ -1351,7 +1361,7 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev, first_bd = (struct eth_tx_1st_bd *)qed_chain_consume(&txq->tx_pbl); dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd), BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE); - txq->sw_tx_cons++; + txq->sw_tx_cons = (txq->sw_tx_cons + 1) % txq->num_tx_buffers; txq->sw_tx_ring.skbs[idx].skb = NULL; return 0; diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c b/drivers/net/ethernet/qlogic/qede/qede_filter.c index 333876c19d7d..13955a3bd3b3 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_filter.c +++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c @@ -495,12 +495,16 @@ void qede_force_mac(void *dev, u8 *mac, bool forced) { struct qede_dev *edev = dev; + __qede_lock(edev); + /* MAC hints take effect only if we haven't set one already */ - if (is_valid_ether_addr(edev->ndev->dev_addr) && !forced) + if (is_valid_ether_addr(edev->ndev->dev_addr) && !forced) { + __qede_unlock(edev); return; + } ether_addr_copy(edev->ndev->dev_addr, mac); - ether_addr_copy(edev->primary_mac, mac); + __qede_unlock(edev); } void qede_fill_rss_params(struct qede_dev *edev, @@ -1061,41 +1065,51 @@ int qede_set_mac_addr(struct net_device *ndev, void *p) { struct qede_dev *edev = netdev_priv(ndev); struct sockaddr *addr = p; - int rc; - - ASSERT_RTNL(); /* @@@TBD To be removed */ + int rc = 0; - DP_INFO(edev, "Set_mac_addr called\n"); + /* Make sure the state doesn't transition while changing the MAC. + * Also, all flows accessing the dev_addr field are doing that under + * this lock. + */ + __qede_lock(edev); if (!is_valid_ether_addr(addr->sa_data)) { DP_NOTICE(edev, "The MAC address is not valid\n"); - return -EFAULT; + rc = -EFAULT; + goto out; } if (!edev->ops->check_mac(edev->cdev, addr->sa_data)) { - DP_NOTICE(edev, "qed prevents setting MAC\n"); - return -EINVAL; + DP_NOTICE(edev, "qed prevents setting MAC %pM\n", + addr->sa_data); + rc = -EINVAL; + goto out; + } + + if (edev->state == QEDE_STATE_OPEN) { + /* Remove the previous primary mac */ + rc = qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_DEL, + ndev->dev_addr); + if (rc) + goto out; } ether_addr_copy(ndev->dev_addr, addr->sa_data); + DP_INFO(edev, "Setting device MAC to %pM\n", addr->sa_data); - if (!netif_running(ndev)) { - DP_NOTICE(edev, "The device is currently down\n"); - return 0; + if (edev->state != QEDE_STATE_OPEN) { + DP_VERBOSE(edev, NETIF_MSG_IFDOWN, + "The device is currently down\n"); + goto out; } - /* Remove the previous primary mac */ - rc = qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_DEL, - edev->primary_mac); - if (rc) - return rc; - - edev->ops->common->update_mac(edev->cdev, addr->sa_data); + edev->ops->common->update_mac(edev->cdev, ndev->dev_addr); - /* Add MAC filter according to the new unicast HW MAC address */ - ether_addr_copy(edev->primary_mac, ndev->dev_addr); - return qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_ADD, - edev->primary_mac); + rc = qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_ADD, + ndev->dev_addr); +out: + __qede_unlock(edev); + return rc; } static int @@ -1200,7 +1214,7 @@ void qede_config_rx_mode(struct net_device *ndev) * (configrue / leave the primary mac) */ rc = qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_REPLACE, - edev->primary_mac); + edev->ndev->dev_addr); if (rc) goto out; diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c index 7b6f41d06245..892eb98290f6 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_fp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c @@ -99,7 +99,7 @@ int qede_alloc_rx_buffer(struct qede_rx_queue *rxq, bool allow_lazy) /* Unmap the data and free skb */ int qede_free_tx_pkt(struct qede_dev *edev, struct qede_tx_queue *txq, int *len) { - u16 idx = txq->sw_tx_cons & NUM_TX_BDS_MAX; + u16 idx = txq->sw_tx_cons; struct sk_buff *skb = txq->sw_tx_ring.skbs[idx].skb; struct eth_tx_1st_bd *first_bd; struct eth_tx_bd *tx_data_bd; @@ -156,7 +156,7 @@ static void qede_free_failed_tx_pkt(struct qede_tx_queue *txq, struct eth_tx_1st_bd *first_bd, int nbd, bool data_split) { - u16 idx = txq->sw_tx_prod & NUM_TX_BDS_MAX; + u16 idx = txq->sw_tx_prod; struct sk_buff *skb = txq->sw_tx_ring.skbs[idx].skb; struct eth_tx_bd *tx_data_bd; int i, split_bd_len = 0; @@ -333,8 +333,9 @@ static int qede_xdp_xmit(struct qede_dev *edev, struct qede_fastpath *fp, struct sw_rx_data *metadata, u16 padding, u16 length) { struct qede_tx_queue *txq = fp->xdp_tx; - u16 idx = txq->sw_tx_prod & NUM_TX_BDS_MAX; struct eth_tx_1st_bd *first_bd; + u16 idx = txq->sw_tx_prod; + u16 val; if (!qed_chain_get_elem_left(&txq->tx_pbl)) { txq->stopped_cnt++; @@ -346,9 +347,11 @@ static int qede_xdp_xmit(struct qede_dev *edev, struct qede_fastpath *fp, memset(first_bd, 0, sizeof(*first_bd)); first_bd->data.bd_flags.bitfields = BIT(ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT); - first_bd->data.bitfields |= - (length & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK) << - ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT; + + val = (length & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK) << + ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT; + + first_bd->data.bitfields |= cpu_to_le16(val); first_bd->data.nbds = 1; /* We can safely ignore the offset, as it's 0 for XDP */ @@ -363,7 +366,7 @@ static int qede_xdp_xmit(struct qede_dev *edev, struct qede_fastpath *fp, txq->sw_tx_ring.xdp[idx].page = metadata->data; txq->sw_tx_ring.xdp[idx].mapping = metadata->mapping; - txq->sw_tx_prod++; + txq->sw_tx_prod = (txq->sw_tx_prod + 1) % txq->num_tx_buffers; /* Mark the fastpath for future XDP doorbell */ fp->xdp_xmit = 1; @@ -393,14 +396,14 @@ static void qede_xdp_tx_int(struct qede_dev *edev, struct qede_tx_queue *txq) while (hw_bd_cons != qed_chain_get_cons_idx(&txq->tx_pbl)) { qed_chain_consume(&txq->tx_pbl); - idx = txq->sw_tx_cons & NUM_TX_BDS_MAX; + idx = txq->sw_tx_cons; dma_unmap_page(&edev->pdev->dev, txq->sw_tx_ring.xdp[idx].mapping, PAGE_SIZE, DMA_BIDIRECTIONAL); __free_page(txq->sw_tx_ring.xdp[idx].page); - txq->sw_tx_cons++; + txq->sw_tx_cons = (txq->sw_tx_cons + 1) % txq->num_tx_buffers; txq->xmit_pkts++; } } @@ -430,7 +433,7 @@ static int qede_tx_int(struct qede_dev *edev, struct qede_tx_queue *txq) bytes_compl += len; pkts_compl++; - txq->sw_tx_cons++; + txq->sw_tx_cons = (txq->sw_tx_cons + 1) % txq->num_tx_buffers; txq->xmit_pkts++; } @@ -1424,7 +1427,7 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct eth_tx_2nd_bd *second_bd = NULL; struct eth_tx_3rd_bd *third_bd = NULL; struct eth_tx_bd *tx_data_bd = NULL; - u16 txq_index; + u16 txq_index, val = 0; u8 nbd = 0; dma_addr_t mapping; int rc, frag_idx = 0, ipv6_ext = 0; @@ -1455,7 +1458,7 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev) #endif /* Fill the entry in the SW ring and the BDs in the FW ring */ - idx = txq->sw_tx_prod & NUM_TX_BDS_MAX; + idx = txq->sw_tx_prod; txq->sw_tx_ring.skbs[idx].skb = skb; first_bd = (struct eth_tx_1st_bd *) qed_chain_produce(&txq->tx_pbl); @@ -1513,8 +1516,8 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (xmit_type & XMIT_ENC) { first_bd->data.bd_flags.bitfields |= 1 << ETH_TX_1ST_BD_FLAGS_IP_CSUM_SHIFT; - first_bd->data.bitfields |= - 1 << ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT; + + val |= (1 << ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT); } /* Legacy FW had flipped behavior in regard to this bit - @@ -1522,8 +1525,7 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev) * packets when it didn't need to. */ if (unlikely(txq->is_legacy)) - first_bd->data.bitfields ^= - 1 << ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT; + val ^= (1 << ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT); /* If the packet is IPv6 with extension header, indicate that * to FW and pass few params, since the device cracker doesn't @@ -1587,11 +1589,12 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev) data_split = true; } } else { - first_bd->data.bitfields |= - (skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK) << - ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT; + val |= ((skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK) << + ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT); } + first_bd->data.bitfields = cpu_to_le16(val); + /* Handle fragmented skb */ /* special handle for frags inside 2nd and 3rd bds.. */ while (tx_data_bd && frag_idx < skb_shinfo(skb)->nr_frags) { @@ -1639,7 +1642,7 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* Advance packet producer only before sending the packet since mapping * of pages may fail. */ - txq->sw_tx_prod++; + txq->sw_tx_prod = (txq->sw_tx_prod + 1) % txq->num_tx_buffers; /* 'next page' entries are counted in the producer value */ txq->tx_db.data.bd_prod = diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 38b77bbfe4ee..fdf04bc5406e 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -259,7 +259,7 @@ static int qede_netdev_event(struct notifier_block *this, unsigned long event, /* Notify qed of the name change */ if (!edev->ops || !edev->ops->common) goto done; - edev->ops->common->set_id(edev->cdev, edev->ndev->name, "qede"); + edev->ops->common->set_name(edev->cdev, edev->ndev->name); break; case NETDEV_CHANGEADDR: edev = netdev_priv(ndev); @@ -580,6 +580,24 @@ static const struct net_device_ops qede_netdev_vf_ops = { .ndo_features_check = qede_features_check, }; +static const struct net_device_ops qede_netdev_vf_xdp_ops = { + .ndo_open = qede_open, + .ndo_stop = qede_close, + .ndo_start_xmit = qede_start_xmit, + .ndo_set_rx_mode = qede_set_rx_mode, + .ndo_set_mac_address = qede_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = qede_change_mtu, + .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid, + .ndo_set_features = qede_set_features, + .ndo_get_stats64 = qede_get_stats64, + .ndo_udp_tunnel_add = qede_udp_tunnel_add, + .ndo_udp_tunnel_del = qede_udp_tunnel_del, + .ndo_features_check = qede_features_check, + .ndo_xdp = qede_xdp, +}; + /* ------------------------------------------------------------------------- * START OF PROBE / REMOVE * ------------------------------------------------------------------------- @@ -618,6 +636,12 @@ static struct qede_dev *qede_alloc_etherdev(struct qed_dev *cdev, memset(&edev->stats, 0, sizeof(edev->stats)); memcpy(&edev->dev_info, info, sizeof(*info)); + /* As ethtool doesn't have the ability to show WoL behavior as + * 'default', if device supports it declare it's enabled. + */ + if (edev->dev_info.common.wol_support) + edev->wol_enabled = true; + INIT_LIST_HEAD(&edev->vlan_list); return edev; @@ -639,10 +663,14 @@ static void qede_init_ndev(struct qede_dev *edev) ndev->watchdog_timeo = TX_TIMEOUT; - if (IS_VF(edev)) - ndev->netdev_ops = &qede_netdev_vf_ops; - else + if (IS_VF(edev)) { + if (edev->dev_info.xdp_supported) + ndev->netdev_ops = &qede_netdev_vf_xdp_ops; + else + ndev->netdev_ops = &qede_netdev_vf_ops; + } else { ndev->netdev_ops = &qede_netdev_ops; + } qede_set_ethtool_ops(ndev); @@ -840,12 +868,55 @@ static void qede_update_pf_params(struct qed_dev *cdev) /* 64 rx + 64 tx + 64 XDP */ memset(&pf_params, 0, sizeof(struct qed_pf_params)); pf_params.eth_pf_params.num_cons = (MAX_SB_PER_PF_MIMD - 1) * 3; + + /* Same for VFs - make sure they'll have sufficient connections + * to support XDP Tx queues. + */ + pf_params.eth_pf_params.num_vf_cons = 48; + #ifdef CONFIG_RFS_ACCEL pf_params.eth_pf_params.num_arfs_filters = QEDE_RFS_MAX_FLTR; #endif qed_ops->common->update_pf_params(cdev, &pf_params); } +#define QEDE_FW_VER_STR_SIZE 80 + +static void qede_log_probe(struct qede_dev *edev) +{ + struct qed_dev_info *p_dev_info = &edev->dev_info.common; + u8 buf[QEDE_FW_VER_STR_SIZE]; + size_t left_size; + + snprintf(buf, QEDE_FW_VER_STR_SIZE, + "Storm FW %d.%d.%d.%d, Management FW %d.%d.%d.%d", + p_dev_info->fw_major, p_dev_info->fw_minor, p_dev_info->fw_rev, + p_dev_info->fw_eng, + (p_dev_info->mfw_rev & QED_MFW_VERSION_3_MASK) >> + QED_MFW_VERSION_3_OFFSET, + (p_dev_info->mfw_rev & QED_MFW_VERSION_2_MASK) >> + QED_MFW_VERSION_2_OFFSET, + (p_dev_info->mfw_rev & QED_MFW_VERSION_1_MASK) >> + QED_MFW_VERSION_1_OFFSET, + (p_dev_info->mfw_rev & QED_MFW_VERSION_0_MASK) >> + QED_MFW_VERSION_0_OFFSET); + + left_size = QEDE_FW_VER_STR_SIZE - strlen(buf); + if (p_dev_info->mbi_version && left_size) + snprintf(buf + strlen(buf), left_size, + " [MBI %d.%d.%d]", + (p_dev_info->mbi_version & QED_MBI_VERSION_2_MASK) >> + QED_MBI_VERSION_2_OFFSET, + (p_dev_info->mbi_version & QED_MBI_VERSION_1_MASK) >> + QED_MBI_VERSION_1_OFFSET, + (p_dev_info->mbi_version & QED_MBI_VERSION_0_MASK) >> + QED_MBI_VERSION_0_OFFSET); + + pr_info("qede %02x:%02x.%02x: %s [%s]\n", edev->pdev->bus->number, + PCI_SLOT(edev->pdev->devfn), PCI_FUNC(edev->pdev->devfn), + buf, edev->ndev->name); +} + enum qede_probe_mode { QEDE_PROBE_NORMAL, }; @@ -924,7 +995,7 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, goto err4; } - edev->ops->common->set_id(cdev, edev->ndev->name, DRV_MODULE_VERSION); + edev->ops->common->set_name(cdev, edev->ndev->name); /* PTP not supported on VFs */ if (!is_vf) @@ -939,8 +1010,7 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, edev->rx_copybreak = QEDE_RX_HDR_SIZE; - DP_INFO(edev, "Ending successfully qede probe\n"); - + qede_log_probe(edev); return 0; err4: @@ -1066,12 +1136,15 @@ static int qede_set_num_queues(struct qede_dev *edev) return rc; } -static void qede_free_mem_sb(struct qede_dev *edev, - struct qed_sb_info *sb_info) +static void qede_free_mem_sb(struct qede_dev *edev, struct qed_sb_info *sb_info, + u16 sb_id) { - if (sb_info->sb_virt) + if (sb_info->sb_virt) { + edev->ops->common->sb_release(edev->cdev, sb_info, sb_id); dma_free_coherent(&edev->pdev->dev, sizeof(*sb_info->sb_virt), (void *)sb_info->sb_virt, sb_info->sb_phys); + memset(sb_info, 0, sizeof(*sb_info)); + } } /* This function allocates fast-path status block memory */ @@ -1298,12 +1371,12 @@ static int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq) /* Allocate the parallel driver ring for Tx buffers */ if (txq->is_xdp) { - size = sizeof(*txq->sw_tx_ring.xdp) * TX_RING_SIZE; + size = sizeof(*txq->sw_tx_ring.xdp) * txq->num_tx_buffers; txq->sw_tx_ring.xdp = kzalloc(size, GFP_KERNEL); if (!txq->sw_tx_ring.xdp) goto err; } else { - size = sizeof(*txq->sw_tx_ring.skbs) * TX_RING_SIZE; + size = sizeof(*txq->sw_tx_ring.skbs) * txq->num_tx_buffers; txq->sw_tx_ring.skbs = kzalloc(size, GFP_KERNEL); if (!txq->sw_tx_ring.skbs) goto err; @@ -1313,7 +1386,7 @@ static int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq) QED_CHAIN_USE_TO_CONSUME_PRODUCE, QED_CHAIN_MODE_PBL, QED_CHAIN_CNT_TYPE_U16, - TX_RING_SIZE, + txq->num_tx_buffers, sizeof(*p_virt), &txq->tx_pbl); if (rc) goto err; @@ -1328,7 +1401,7 @@ err: /* This function frees all memory of a single fp */ static void qede_free_mem_fp(struct qede_dev *edev, struct qede_fastpath *fp) { - qede_free_mem_sb(edev, fp->sb_info); + qede_free_mem_sb(edev, fp->sb_info, fp->id); if (fp->type & QEDE_FASTPATH_RX) qede_free_mem_rxq(edev, fp->rxq); @@ -1725,7 +1798,7 @@ static int qede_start_txq(struct qede_dev *edev, else params.queue_id = txq->index; - params.sb = fp->sb_info->igu_sb_id; + params.p_sb = fp->sb_info; params.sb_idx = sb_idx; rc = edev->ops->q_tx_start(edev->cdev, rss_id, ¶ms, phys_table, @@ -1804,7 +1877,7 @@ static int qede_start_queues(struct qede_dev *edev, bool clear_stats) memset(&q_params, 0, sizeof(q_params)); q_params.queue_id = rxq->rxq_id; q_params.vport_id = 0; - q_params.sb = fp->sb_info->igu_sb_id; + q_params.p_sb = fp->sb_info; q_params.sb_idx = RX_PI; p_phys_table = @@ -1890,9 +1963,10 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode, if (!is_locked) __qede_lock(edev); - qede_roce_dev_event_close(edev); edev->state = QEDE_STATE_CLOSED; + qede_roce_dev_event_close(edev); + /* Close OS Tx */ netif_tx_disable(edev->ndev); netif_carrier_off(edev->ndev); @@ -1988,9 +2062,6 @@ static int qede_load(struct qede_dev *edev, enum qede_load_mode mode, goto err4; DP_INFO(edev, "Start VPORT, RXQ and TXQ succeeded\n"); - /* Add primary mac and set Rx filters */ - ether_addr_copy(edev->primary_mac, edev->ndev->dev_addr); - /* Program un-configured VLANs */ qede_configure_vlan_filters(edev); diff --git a/drivers/net/ethernet/qlogic/qede/qede_ptp.c b/drivers/net/ethernet/qlogic/qede/qede_ptp.c index 24f06e2ef43e..9b2280badaf7 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ptp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ptp.c @@ -244,6 +244,7 @@ static int qede_ptp_cfg_filters(struct qede_dev *edev) break; case HWTSTAMP_FILTER_ALL: case HWTSTAMP_FILTER_SOME: + case HWTSTAMP_FILTER_NTP_ALL: ptp->rx_filter = HWTSTAMP_FILTER_NONE; rx_filter = QED_PTP_FILTER_ALL; break; diff --git a/drivers/net/ethernet/qlogic/qede/qede_roce.c b/drivers/net/ethernet/qlogic/qede/qede_roce.c index f00657ce7c8f..c0030fb8d842 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_roce.c +++ b/drivers/net/ethernet/qlogic/qede/qede_roce.c @@ -221,8 +221,8 @@ static void qede_roce_changeaddr(struct qede_dev *edev) qedr_drv->notify(edev->rdma_info.qedr_dev, QEDE_CHANGE_ADDR); } -struct qede_roce_event_work *qede_roce_get_free_event_node(struct qede_dev - *edev) +static struct qede_roce_event_work * +qede_roce_get_free_event_node(struct qede_dev *edev) { struct qede_roce_event_work *event_node = NULL; struct list_head *list_node = NULL; diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig index d7720bf92d49..877675a27b9f 100644 --- a/drivers/net/ethernet/qualcomm/Kconfig +++ b/drivers/net/ethernet/qualcomm/Kconfig @@ -16,7 +16,13 @@ config NET_VENDOR_QUALCOMM if NET_VENDOR_QUALCOMM config QCA7000 - tristate "Qualcomm Atheros QCA7000 support" + tristate + help + This enables support for the Qualcomm Atheros QCA7000. + +config QCA7000_SPI + tristate "Qualcomm Atheros QCA7000 SPI support" + select QCA7000 depends on SPI_MASTER && OF ---help--- This SPI protocol driver supports the Qualcomm Atheros QCA7000. @@ -24,6 +30,22 @@ config QCA7000 To compile this driver as a module, choose M here. The module will be called qcaspi. +config QCA7000_UART + tristate "Qualcomm Atheros QCA7000 UART support" + select QCA7000 + depends on SERIAL_DEV_BUS && OF + ---help--- + This UART protocol driver supports the Qualcomm Atheros QCA7000. + + Currently the driver assumes these device UART settings: + Data bits: 8 + Parity: None + Stop bits: 1 + Flow control: None + + To compile this driver as a module, choose M here. The module + will be called qcauart. + config QCOM_EMAC tristate "Qualcomm Technologies, Inc. EMAC Gigabit Ethernet support" depends on HAS_DMA && HAS_IOMEM diff --git a/drivers/net/ethernet/qualcomm/Makefile b/drivers/net/ethernet/qualcomm/Makefile index aacb0a585c68..92fa7c4da90a 100644 --- a/drivers/net/ethernet/qualcomm/Makefile +++ b/drivers/net/ethernet/qualcomm/Makefile @@ -2,7 +2,10 @@ # Makefile for the Qualcomm network device drivers. # -obj-$(CONFIG_QCA7000) += qcaspi.o -qcaspi-objs := qca_spi.o qca_framing.o qca_7k.o qca_debug.o +obj-$(CONFIG_QCA7000) += qca_7k_common.o +obj-$(CONFIG_QCA7000_SPI) += qcaspi.o +qcaspi-objs := qca_7k.o qca_debug.o qca_spi.o +obj-$(CONFIG_QCA7000_UART) += qcauart.o +qcauart-objs := qca_uart.o obj-y += emac/ diff --git a/drivers/net/ethernet/qualcomm/qca_7k.c b/drivers/net/ethernet/qualcomm/qca_7k.c index f0066fbb44a6..ffe7a16bdfc8 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k.c +++ b/drivers/net/ethernet/qualcomm/qca_7k.c @@ -23,11 +23,9 @@ * kernel-based SPI device. */ -#include <linux/init.h> -#include <linux/module.h> -#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/netdevice.h> #include <linux/spi/spi.h> -#include <linux/version.h> #include "qca_7k.h" @@ -123,27 +121,3 @@ qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value) return ret; } - -int -qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd) -{ - __be16 tx_data; - struct spi_message *msg = &qca->spi_msg1; - struct spi_transfer *transfer = &qca->spi_xfer1; - int ret; - - tx_data = cpu_to_be16(cmd); - transfer->len = sizeof(tx_data); - transfer->tx_buf = &tx_data; - transfer->rx_buf = NULL; - - ret = spi_sync(qca->spi_dev, msg); - - if (!ret) - ret = msg->status; - - if (ret) - qcaspi_spi_error(qca); - - return ret; -} diff --git a/drivers/net/ethernet/qualcomm/qca_7k.h b/drivers/net/ethernet/qualcomm/qca_7k.h index 1cad851ee507..27124c2bb77a 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k.h +++ b/drivers/net/ethernet/qualcomm/qca_7k.h @@ -54,19 +54,18 @@ #define SPI_REG_ACTION_CTRL 0x1B00 /* SPI_CONFIG register definition; */ -#define QCASPI_SLAVE_RESET_BIT (1 << 6) +#define QCASPI_SLAVE_RESET_BIT BIT(6) /* INTR_CAUSE/ENABLE register definition. */ -#define SPI_INT_WRBUF_BELOW_WM (1 << 10) -#define SPI_INT_CPU_ON (1 << 6) -#define SPI_INT_ADDR_ERR (1 << 3) -#define SPI_INT_WRBUF_ERR (1 << 2) -#define SPI_INT_RDBUF_ERR (1 << 1) -#define SPI_INT_PKT_AVLBL (1 << 0) +#define SPI_INT_WRBUF_BELOW_WM BIT(10) +#define SPI_INT_CPU_ON BIT(6) +#define SPI_INT_ADDR_ERR BIT(3) +#define SPI_INT_WRBUF_ERR BIT(2) +#define SPI_INT_RDBUF_ERR BIT(1) +#define SPI_INT_PKT_AVLBL BIT(0) void qcaspi_spi_error(struct qcaspi *qca); int qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result); int qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value); -int qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd); #endif /* _QCA_7K_H */ diff --git a/drivers/net/ethernet/qualcomm/qca_framing.c b/drivers/net/ethernet/qualcomm/qca_7k_common.c index faa924c85e29..6b511f05df61 100644 --- a/drivers/net/ethernet/qualcomm/qca_framing.c +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.c @@ -21,9 +21,11 @@ * by an atheros frame while transmitted over a serial channel; */ +#include <linux/init.h> #include <linux/kernel.h> +#include <linux/module.h> -#include "qca_framing.h" +#include "qca_7k_common.h" u16 qcafrm_create_header(u8 *buf, u16 length) @@ -46,6 +48,7 @@ qcafrm_create_header(u8 *buf, u16 length) return QCAFRM_HEADER_LEN; } +EXPORT_SYMBOL_GPL(qcafrm_create_header); u16 qcafrm_create_footer(u8 *buf) @@ -57,6 +60,7 @@ qcafrm_create_footer(u8 *buf) buf[1] = 0x55; return QCAFRM_FOOTER_LEN; } +EXPORT_SYMBOL_GPL(qcafrm_create_footer); /* Gather received bytes and try to extract a full ethernet frame by * following a simple state machine. @@ -83,7 +87,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by if (recv_byte != 0x00) { /* first two bytes of length must be 0 */ - handle->state = QCAFRM_HW_LEN0; + handle->state = handle->init; } break; case QCAFRM_HW_LEN2: @@ -97,7 +101,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by case QCAFRM_WAIT_AA4: if (recv_byte != 0xAA) { ret = QCAFRM_NOHEAD; - handle->state = QCAFRM_HW_LEN0; + handle->state = handle->init; } else { handle->state--; } @@ -117,9 +121,9 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by break; case QCAFRM_WAIT_RSVD_BYTE2: len = handle->offset; - if (len > buf_len || len < QCAFRM_ETHMINLEN) { + if (len > buf_len || len < QCAFRM_MIN_LEN) { ret = QCAFRM_INVLEN; - handle->state = QCAFRM_HW_LEN0; + handle->state = handle->init; } else { handle->state = (enum qcafrm_state)(len + 1); /* Remaining number of bytes. */ @@ -135,7 +139,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by case QCAFRM_WAIT_551: if (recv_byte != 0x55) { ret = QCAFRM_NOTAIL; - handle->state = QCAFRM_HW_LEN0; + handle->state = handle->init; } else { handle->state = QCAFRM_WAIT_552; } @@ -143,14 +147,20 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by case QCAFRM_WAIT_552: if (recv_byte != 0x55) { ret = QCAFRM_NOTAIL; - handle->state = QCAFRM_HW_LEN0; + handle->state = handle->init; } else { ret = handle->offset; /* Frame is fully received. */ - handle->state = QCAFRM_HW_LEN0; + handle->state = handle->init; } break; } return ret; } +EXPORT_SYMBOL_GPL(qcafrm_fsm_decode); + +MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 common"); +MODULE_AUTHOR("Qualcomm Atheros Communications"); +MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/ethernet/qualcomm/qca_framing.h b/drivers/net/ethernet/qualcomm/qca_7k_common.h index d5e795dcdf47..928554f11e35 100644 --- a/drivers/net/ethernet/qualcomm/qca_framing.h +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.h @@ -44,12 +44,12 @@ #define QCAFRM_INVFRAME (QCAFRM_ERR_BASE - 4) /* Min/Max Ethernet MTU: 46/1500 */ -#define QCAFRM_ETHMINMTU (ETH_ZLEN - ETH_HLEN) -#define QCAFRM_ETHMAXMTU ETH_DATA_LEN +#define QCAFRM_MIN_MTU (ETH_ZLEN - ETH_HLEN) +#define QCAFRM_MAX_MTU ETH_DATA_LEN /* Min/Max frame lengths */ -#define QCAFRM_ETHMINLEN (QCAFRM_ETHMINMTU + ETH_HLEN) -#define QCAFRM_ETHMAXLEN (QCAFRM_ETHMAXMTU + VLAN_ETH_HLEN) +#define QCAFRM_MIN_LEN (QCAFRM_MIN_MTU + ETH_HLEN) +#define QCAFRM_MAX_LEN (QCAFRM_MAX_MTU + VLAN_ETH_HLEN) /* QCA7K header len */ #define QCAFRM_HEADER_LEN 8 @@ -61,6 +61,7 @@ #define QCAFRM_ERR_BASE -1000 enum qcafrm_state { + /* HW length is only available on SPI */ QCAFRM_HW_LEN0 = 0x8000, QCAFRM_HW_LEN1 = QCAFRM_HW_LEN0 - 1, QCAFRM_HW_LEN2 = QCAFRM_HW_LEN1 - 1, @@ -101,9 +102,11 @@ enum qcafrm_state { struct qcafrm_handle { /* Current decoding state */ enum qcafrm_state state; + /* Initial state depends on connection type */ + enum qcafrm_state init; /* Offset in buffer (borrowed for length too) */ - s16 offset; + u16 offset; /* Frame length as kept by this module */ u16 len; @@ -113,9 +116,16 @@ u16 qcafrm_create_header(u8 *buf, u16 len); u16 qcafrm_create_footer(u8 *buf); -static inline void qcafrm_fsm_init(struct qcafrm_handle *handle) +static inline void qcafrm_fsm_init_spi(struct qcafrm_handle *handle) { - handle->state = QCAFRM_HW_LEN0; + handle->init = QCAFRM_HW_LEN0; + handle->state = handle->init; +} + +static inline void qcafrm_fsm_init_uart(struct qcafrm_handle *handle) +{ + handle->init = QCAFRM_WAIT_AA1; + handle->state = handle->init; } /* Gather received bytes and try to extract a full Ethernet frame diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c index d145df98feff..92b6be9c4429 100644 --- a/drivers/net/ethernet/qualcomm/qca_debug.c +++ b/drivers/net/ethernet/qualcomm/qca_debug.c @@ -275,6 +275,7 @@ qcaspi_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) static int qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) { + const struct net_device_ops *ops = dev->netdev_ops; struct qcaspi *qca = netdev_priv(dev); if ((ring->rx_pending) || @@ -283,13 +284,13 @@ qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) return -EINVAL; if (netif_running(dev)) - qcaspi_netdev_close(dev); + ops->ndo_stop(dev); qca->txr.count = max_t(u32, ring->tx_pending, TX_RING_MIN_LEN); qca->txr.count = min_t(u16, qca->txr.count, TX_RING_MAX_LEN); if (netif_running(dev)) - qcaspi_netdev_open(dev); + ops->ndo_open(dev); return 0; } diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 24ca7df15d07..de78f60309a0 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -43,8 +43,8 @@ #include <linux/types.h> #include "qca_7k.h" +#include "qca_7k_common.h" #include "qca_debug.h" -#include "qca_framing.h" #include "qca_spi.h" #define MAX_DMA_BURST_LEN 5000 @@ -69,7 +69,6 @@ static int qcaspi_pluggable = QCASPI_PLUGGABLE_MIN; module_param(qcaspi_pluggable, int, 0); MODULE_PARM_DESC(qcaspi_pluggable, "Pluggable SPI connection (yes/no)."); -#define QCASPI_MTU QCAFRM_ETHMAXMTU #define QCASPI_TX_TIMEOUT (1 * HZ) #define QCASPI_QCA7K_REBOOT_TIME_MS 1000 @@ -193,6 +192,30 @@ qcaspi_read_legacy(struct qcaspi *qca, u8 *dst, u32 len) } static int +qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd) +{ + __be16 tx_data; + struct spi_message *msg = &qca->spi_msg1; + struct spi_transfer *transfer = &qca->spi_xfer1; + int ret; + + tx_data = cpu_to_be16(cmd); + transfer->len = sizeof(tx_data); + transfer->tx_buf = &tx_data; + transfer->rx_buf = NULL; + + ret = spi_sync(qca->spi_dev, msg); + + if (!ret) + ret = msg->status; + + if (ret) + qcaspi_spi_error(qca); + + return ret; +} + +static int qcaspi_tx_frame(struct qcaspi *qca, struct sk_buff *skb) { u32 count; @@ -403,7 +426,7 @@ qcaspi_tx_ring_has_space(struct tx_ring *txr) if (txr->skb[txr->tail]) return 0; - return (txr->size + QCAFRM_ETHMAXLEN < QCASPI_HW_BUF_LEN) ? 1 : 0; + return (txr->size + QCAFRM_MAX_LEN < QCASPI_HW_BUF_LEN) ? 1 : 0; } /* Flush the tx ring. This function is only safe to @@ -603,7 +626,7 @@ qcaspi_intr_handler(int irq, void *data) return IRQ_HANDLED; } -int +static int qcaspi_netdev_open(struct net_device *dev) { struct qcaspi *qca = netdev_priv(dev); @@ -615,7 +638,7 @@ qcaspi_netdev_open(struct net_device *dev) qca->intr_req = 1; qca->intr_svc = 0; qca->sync = QCASPI_SYNC_UNKNOWN; - qcafrm_fsm_init(&qca->frm_handle); + qcafrm_fsm_init_spi(&qca->frm_handle); qca->spi_thread = kthread_run((void *)qcaspi_spi_thread, qca, "%s", dev->name); @@ -640,7 +663,7 @@ qcaspi_netdev_open(struct net_device *dev) return 0; } -int +static int qcaspi_netdev_close(struct net_device *dev) { struct qcaspi *qca = netdev_priv(dev); @@ -667,8 +690,8 @@ qcaspi_netdev_xmit(struct sk_buff *skb, struct net_device *dev) struct sk_buff *tskb; u8 pad_len = 0; - if (skb->len < QCAFRM_ETHMINLEN) - pad_len = QCAFRM_ETHMINLEN - skb->len; + if (skb->len < QCAFRM_MIN_LEN) + pad_len = QCAFRM_MIN_LEN - skb->len; if (qca->txr.skb[qca->txr.tail]) { netdev_warn(qca->net_dev, "queue was unexpectedly full!\n"); @@ -746,7 +769,7 @@ qcaspi_netdev_init(struct net_device *dev) { struct qcaspi *qca = netdev_priv(dev); - dev->mtu = QCASPI_MTU; + dev->mtu = QCAFRM_MAX_MTU; dev->type = ARPHRD_ETHER; qca->clkspeed = qcaspi_clkspeed; qca->burst_len = qcaspi_burst_len; @@ -805,8 +828,8 @@ qcaspi_netdev_setup(struct net_device *dev) dev->tx_queue_len = 100; /* MTU range: 46 - 1500 */ - dev->min_mtu = QCAFRM_ETHMINMTU; - dev->max_mtu = QCAFRM_ETHMAXMTU; + dev->min_mtu = QCAFRM_MIN_MTU; + dev->max_mtu = QCAFRM_MAX_MTU; qca = netdev_priv(dev); memset(qca, 0, sizeof(struct qcaspi)); @@ -894,6 +917,7 @@ qca_spi_probe(struct spi_device *spi) return -ENOMEM; qcaspi_netdev_setup(qcaspi_devs); + SET_NETDEV_DEV(qcaspi_devs, &spi->dev); qca = netdev_priv(qcaspi_devs); if (!qca) { @@ -975,7 +999,7 @@ static struct spi_driver qca_spi_driver = { }; module_spi_driver(qca_spi_driver); -MODULE_DESCRIPTION("Qualcomm Atheros SPI Driver"); +MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 SPI Driver"); MODULE_AUTHOR("Qualcomm Atheros Communications"); MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h index 6e31a0e744a4..fc4beb1b32d1 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.h +++ b/drivers/net/ethernet/qualcomm/qca_spi.h @@ -32,7 +32,7 @@ #include <linux/spi/spi.h> #include <linux/types.h> -#include "qca_framing.h" +#include "qca_7k_common.h" #define QCASPI_DRV_VERSION "0.2.7-i" #define QCASPI_DRV_NAME "qcaspi" @@ -108,7 +108,4 @@ struct qcaspi { u16 burst_len; }; -int qcaspi_netdev_open(struct net_device *dev); -int qcaspi_netdev_close(struct net_device *dev); - #endif /* _QCA_SPI_H */ diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c new file mode 100644 index 000000000000..db6068cd7a1f --- /dev/null +++ b/drivers/net/ethernet/qualcomm/qca_uart.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. + * Copyright (c) 2017, I2SE GmbH + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear + * in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* This module implements the Qualcomm Atheros UART protocol for + * kernel-based UART device; it is essentially an Ethernet-to-UART + * serial converter; + */ + +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/etherdevice.h> +#include <linux/if_arp.h> +#include <linux/if_ether.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_net.h> +#include <linux/sched.h> +#include <linux/serdev.h> +#include <linux/skbuff.h> +#include <linux/types.h> + +#include "qca_7k_common.h" + +#define QCAUART_DRV_VERSION "0.1.0" +#define QCAUART_DRV_NAME "qcauart" +#define QCAUART_TX_TIMEOUT (1 * HZ) + +struct qcauart { + struct net_device *net_dev; + spinlock_t lock; /* transmit lock */ + struct work_struct tx_work; /* Flushes transmit buffer */ + + struct serdev_device *serdev; + struct qcafrm_handle frm_handle; + struct sk_buff *rx_skb; + + unsigned char *tx_head; /* pointer to next XMIT byte */ + int tx_left; /* bytes left in XMIT queue */ + unsigned char *tx_buffer; +}; + +static int +qca_tty_receive(struct serdev_device *serdev, const unsigned char *data, + size_t count) +{ + struct qcauart *qca = serdev_device_get_drvdata(serdev); + struct net_device *netdev = qca->net_dev; + struct net_device_stats *n_stats = &netdev->stats; + size_t i; + + if (!qca->rx_skb) { + qca->rx_skb = netdev_alloc_skb_ip_align(netdev, + netdev->mtu + + VLAN_ETH_HLEN); + if (!qca->rx_skb) { + n_stats->rx_errors++; + n_stats->rx_dropped++; + return 0; + } + } + + for (i = 0; i < count; i++) { + s32 retcode; + + retcode = qcafrm_fsm_decode(&qca->frm_handle, + qca->rx_skb->data, + skb_tailroom(qca->rx_skb), + data[i]); + + switch (retcode) { + case QCAFRM_GATHER: + case QCAFRM_NOHEAD: + break; + case QCAFRM_NOTAIL: + netdev_dbg(netdev, "recv: no RX tail\n"); + n_stats->rx_errors++; + n_stats->rx_dropped++; + break; + case QCAFRM_INVLEN: + netdev_dbg(netdev, "recv: invalid RX length\n"); + n_stats->rx_errors++; + n_stats->rx_dropped++; + break; + default: + n_stats->rx_packets++; + n_stats->rx_bytes += retcode; + skb_put(qca->rx_skb, retcode); + qca->rx_skb->protocol = eth_type_trans( + qca->rx_skb, qca->rx_skb->dev); + qca->rx_skb->ip_summed = CHECKSUM_UNNECESSARY; + netif_rx_ni(qca->rx_skb); + qca->rx_skb = netdev_alloc_skb_ip_align(netdev, + netdev->mtu + + VLAN_ETH_HLEN); + if (!qca->rx_skb) { + netdev_dbg(netdev, "recv: out of RX resources\n"); + n_stats->rx_errors++; + return i; + } + } + } + + return i; +} + +/* Write out any remaining transmit buffer. Scheduled when tty is writable */ +static void qcauart_transmit(struct work_struct *work) +{ + struct qcauart *qca = container_of(work, struct qcauart, tx_work); + struct net_device_stats *n_stats = &qca->net_dev->stats; + int written; + + spin_lock_bh(&qca->lock); + + /* First make sure we're connected. */ + if (!netif_running(qca->net_dev)) { + spin_unlock_bh(&qca->lock); + return; + } + + if (qca->tx_left <= 0) { + /* Now serial buffer is almost free & we can start + * transmission of another packet + */ + n_stats->tx_packets++; + spin_unlock_bh(&qca->lock); + netif_wake_queue(qca->net_dev); + return; + } + + written = serdev_device_write_buf(qca->serdev, qca->tx_head, + qca->tx_left); + if (written > 0) { + qca->tx_left -= written; + qca->tx_head += written; + } + spin_unlock_bh(&qca->lock); +} + +/* Called by the driver when there's room for more data. + * Schedule the transmit. + */ +static void qca_tty_wakeup(struct serdev_device *serdev) +{ + struct qcauart *qca = serdev_device_get_drvdata(serdev); + + schedule_work(&qca->tx_work); +} + +static struct serdev_device_ops qca_serdev_ops = { + .receive_buf = qca_tty_receive, + .write_wakeup = qca_tty_wakeup, +}; + +static int qcauart_netdev_open(struct net_device *dev) +{ + struct qcauart *qca = netdev_priv(dev); + + netif_start_queue(qca->net_dev); + + return 0; +} + +static int qcauart_netdev_close(struct net_device *dev) +{ + struct qcauart *qca = netdev_priv(dev); + + netif_stop_queue(dev); + flush_work(&qca->tx_work); + + spin_lock_bh(&qca->lock); + qca->tx_left = 0; + spin_unlock_bh(&qca->lock); + + return 0; +} + +static netdev_tx_t +qcauart_netdev_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct net_device_stats *n_stats = &dev->stats; + struct qcauart *qca = netdev_priv(dev); + u8 pad_len = 0; + int written; + u8 *pos; + + spin_lock(&qca->lock); + + WARN_ON(qca->tx_left); + + if (!netif_running(dev)) { + spin_unlock(&qca->lock); + netdev_warn(qca->net_dev, "xmit: iface is down\n"); + goto out; + } + + pos = qca->tx_buffer; + + if (skb->len < QCAFRM_MIN_LEN) + pad_len = QCAFRM_MIN_LEN - skb->len; + + pos += qcafrm_create_header(pos, skb->len + pad_len); + + memcpy(pos, skb->data, skb->len); + pos += skb->len; + + if (pad_len) { + memset(pos, 0, pad_len); + pos += pad_len; + } + + pos += qcafrm_create_footer(pos); + + netif_stop_queue(qca->net_dev); + + written = serdev_device_write_buf(qca->serdev, qca->tx_buffer, + pos - qca->tx_buffer); + if (written > 0) { + qca->tx_left = (pos - qca->tx_buffer) - written; + qca->tx_head = qca->tx_buffer + written; + n_stats->tx_bytes += written; + } + spin_unlock(&qca->lock); + + netif_trans_update(dev); +out: + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + +static void qcauart_netdev_tx_timeout(struct net_device *dev) +{ + struct qcauart *qca = netdev_priv(dev); + + netdev_info(qca->net_dev, "Transmit timeout at %ld, latency %ld\n", + jiffies, dev_trans_start(dev)); + dev->stats.tx_errors++; + dev->stats.tx_dropped++; +} + +static int qcauart_netdev_init(struct net_device *dev) +{ + struct qcauart *qca = netdev_priv(dev); + size_t len; + + /* Finish setting up the device info. */ + dev->mtu = QCAFRM_MAX_MTU; + dev->type = ARPHRD_ETHER; + + len = QCAFRM_HEADER_LEN + QCAFRM_MAX_LEN + QCAFRM_FOOTER_LEN; + qca->tx_buffer = devm_kmalloc(&qca->serdev->dev, len, GFP_KERNEL); + if (!qca->tx_buffer) + return -ENOMEM; + + qca->rx_skb = netdev_alloc_skb_ip_align(qca->net_dev, + qca->net_dev->mtu + + VLAN_ETH_HLEN); + if (!qca->rx_skb) + return -ENOBUFS; + + return 0; +} + +static void qcauart_netdev_uninit(struct net_device *dev) +{ + struct qcauart *qca = netdev_priv(dev); + + if (qca->rx_skb) + dev_kfree_skb(qca->rx_skb); +} + +static const struct net_device_ops qcauart_netdev_ops = { + .ndo_init = qcauart_netdev_init, + .ndo_uninit = qcauart_netdev_uninit, + .ndo_open = qcauart_netdev_open, + .ndo_stop = qcauart_netdev_close, + .ndo_start_xmit = qcauart_netdev_xmit, + .ndo_set_mac_address = eth_mac_addr, + .ndo_tx_timeout = qcauart_netdev_tx_timeout, + .ndo_validate_addr = eth_validate_addr, +}; + +static void qcauart_netdev_setup(struct net_device *dev) +{ + dev->netdev_ops = &qcauart_netdev_ops; + dev->watchdog_timeo = QCAUART_TX_TIMEOUT; + dev->priv_flags &= ~IFF_TX_SKB_SHARING; + dev->tx_queue_len = 100; + + /* MTU range: 46 - 1500 */ + dev->min_mtu = QCAFRM_MIN_MTU; + dev->max_mtu = QCAFRM_MAX_MTU; +} + +static const struct of_device_id qca_uart_of_match[] = { + { + .compatible = "qca,qca7000", + }, + {} +}; +MODULE_DEVICE_TABLE(of, qca_uart_of_match); + +static int qca_uart_probe(struct serdev_device *serdev) +{ + struct net_device *qcauart_dev = alloc_etherdev(sizeof(struct qcauart)); + struct qcauart *qca; + const char *mac; + u32 speed = 115200; + int ret; + + if (!qcauart_dev) + return -ENOMEM; + + qcauart_netdev_setup(qcauart_dev); + SET_NETDEV_DEV(qcauart_dev, &serdev->dev); + + qca = netdev_priv(qcauart_dev); + if (!qca) { + pr_err("qca_uart: Fail to retrieve private structure\n"); + ret = -ENOMEM; + goto free; + } + qca->net_dev = qcauart_dev; + qca->serdev = serdev; + qcafrm_fsm_init_uart(&qca->frm_handle); + + spin_lock_init(&qca->lock); + INIT_WORK(&qca->tx_work, qcauart_transmit); + + of_property_read_u32(serdev->dev.of_node, "current-speed", &speed); + + mac = of_get_mac_address(serdev->dev.of_node); + + if (mac) + ether_addr_copy(qca->net_dev->dev_addr, mac); + + if (!is_valid_ether_addr(qca->net_dev->dev_addr)) { + eth_hw_addr_random(qca->net_dev); + dev_info(&serdev->dev, "Using random MAC address: %pM\n", + qca->net_dev->dev_addr); + } + + netif_carrier_on(qca->net_dev); + serdev_device_set_drvdata(serdev, qca); + serdev_device_set_client_ops(serdev, &qca_serdev_ops); + + ret = serdev_device_open(serdev); + if (ret) { + dev_err(&serdev->dev, "Unable to open device %s\n", + qcauart_dev->name); + goto free; + } + + speed = serdev_device_set_baudrate(serdev, speed); + dev_info(&serdev->dev, "Using baudrate: %u\n", speed); + + serdev_device_set_flow_control(serdev, false); + + ret = register_netdev(qcauart_dev); + if (ret) { + dev_err(&serdev->dev, "Unable to register net device %s\n", + qcauart_dev->name); + serdev_device_close(serdev); + cancel_work_sync(&qca->tx_work); + goto free; + } + + return 0; + +free: + free_netdev(qcauart_dev); + return ret; +} + +static void qca_uart_remove(struct serdev_device *serdev) +{ + struct qcauart *qca = serdev_device_get_drvdata(serdev); + + unregister_netdev(qca->net_dev); + + /* Flush any pending characters in the driver. */ + serdev_device_close(serdev); + cancel_work_sync(&qca->tx_work); + + free_netdev(qca->net_dev); +} + +static struct serdev_device_driver qca_uart_driver = { + .probe = qca_uart_probe, + .remove = qca_uart_remove, + .driver = { + .name = QCAUART_DRV_NAME, + .of_match_table = of_match_ptr(qca_uart_of_match), + }, +}; + +module_serdev_device_driver(qca_uart_driver); + +MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 UART Driver"); +MODULE_AUTHOR("Qualcomm Atheros Communications"); +MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(QCAUART_DRV_VERSION); diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 72233ab9474b..e7ab23e87de2 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -1410,14 +1410,13 @@ static int cp_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct cp_private *cp = netdev_priv(dev); - int rc; unsigned long flags; spin_lock_irqsave(&cp->lock, flags); - rc = mii_ethtool_get_link_ksettings(&cp->mii_if, cmd); + mii_ethtool_get_link_ksettings(&cp->mii_if, cmd); spin_unlock_irqrestore(&cp->lock, flags); - return rc; + return 0; } static int cp_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 0a8f2817ea60..bd07a15d3b7c 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -2148,7 +2148,9 @@ static int rtl8169_get_link_ksettings_xmii(struct net_device *dev, { struct rtl8169_private *tp = netdev_priv(dev); - return mii_ethtool_get_link_ksettings(&tp->mii, cmd); + mii_ethtool_get_link_ksettings(&tp->mii, cmd); + + return 0; } static int rtl8169_get_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index 1e594351a60f..89831adb8eb7 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -1418,8 +1418,7 @@ static netdev_tx_t sxgbe_xmit(struct sk_buff *skb, struct net_device *dev) priv->hw->desc->tx_enable_tstamp(first_desc); } - if (!tqueue->hwts_tx_en) - skb_tx_timestamp(skb); + skb_tx_timestamp(skb); priv->hw->dma->enable_dma_transmission(priv->ioaddr, txq_index); diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 78efb2822b86..ad9c4ded2b90 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -6068,6 +6068,7 @@ static int efx_ef10_ptp_set_ts_config(struct efx_nic *efx, case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: init->rx_filter = HWTSTAMP_FILTER_ALL; rc = efx_ptp_change_mode(efx, true, 0); if (!rc) diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c index 52ead5524de7..b607936e1b3e 100644 --- a/drivers/net/ethernet/sgi/ioc3-eth.c +++ b/drivers/net/ethernet/sgi/ioc3-eth.c @@ -1562,13 +1562,12 @@ static int ioc3_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct ioc3_private *ip = netdev_priv(dev); - int rc; spin_lock_irq(&ip->ioc3_lock); - rc = mii_ethtool_get_link_ksettings(&ip->mii, cmd); + mii_ethtool_get_link_ksettings(&ip->mii, cmd); spin_unlock_irq(&ip->ioc3_lock); - return rc; + return 0; } static int ioc3_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/sis/sis190.c b/drivers/net/ethernet/sis/sis190.c index 02da106c6e04..445109bd6910 100644 --- a/drivers/net/ethernet/sis/sis190.c +++ b/drivers/net/ethernet/sis/sis190.c @@ -1739,7 +1739,9 @@ static int sis190_get_link_ksettings(struct net_device *dev, { struct sis190_private *tp = netdev_priv(dev); - return mii_ethtool_get_link_ksettings(&tp->mii_if, cmd); + mii_ethtool_get_link_ksettings(&tp->mii_if, cmd); + + return 0; } static int sis190_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/smsc/epic100.c b/drivers/net/ethernet/smsc/epic100.c index db6dcb06193d..6a0e1d4b597c 100644 --- a/drivers/net/ethernet/smsc/epic100.c +++ b/drivers/net/ethernet/smsc/epic100.c @@ -1391,13 +1391,12 @@ static int netdev_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct epic_private *np = netdev_priv(dev); - int rc; spin_lock_irq(&np->lock); - rc = mii_ethtool_get_link_ksettings(&np->mii, cmd); + mii_ethtool_get_link_ksettings(&np->mii, cmd); spin_unlock_irq(&np->lock); - return rc; + return 0; } static int netdev_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c index 36307d34f641..05157442a980 100644 --- a/drivers/net/ethernet/smsc/smc911x.c +++ b/drivers/net/ethernet/smsc/smc911x.c @@ -1450,7 +1450,7 @@ smc911x_ethtool_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct smc911x_local *lp = netdev_priv(dev); - int ret, status; + int status; unsigned long flags; u32 supported; @@ -1458,7 +1458,7 @@ smc911x_ethtool_get_link_ksettings(struct net_device *dev, if (lp->phy_type != 0) { spin_lock_irqsave(&lp->lock, flags); - ret = mii_ethtool_get_link_ksettings(&lp->mii, cmd); + mii_ethtool_get_link_ksettings(&lp->mii, cmd); spin_unlock_irqrestore(&lp->lock, flags); } else { supported = SUPPORTED_10baseT_Half | @@ -1480,10 +1480,9 @@ smc911x_ethtool_get_link_ksettings(struct net_device *dev, ethtool_convert_legacy_u32_to_link_mode( cmd->link_modes.supported, supported); - ret = 0; } - return ret; + return 0; } static int diff --git a/drivers/net/ethernet/smsc/smc91c92_cs.c b/drivers/net/ethernet/smsc/smc91c92_cs.c index 976aa876789a..92c927aec66d 100644 --- a/drivers/net/ethernet/smsc/smc91c92_cs.c +++ b/drivers/net/ethernet/smsc/smc91c92_cs.c @@ -1843,8 +1843,8 @@ static int smc_link_ok(struct net_device *dev) } } -static int smc_netdev_get_ecmd(struct net_device *dev, - struct ethtool_link_ksettings *ecmd) +static void smc_netdev_get_ecmd(struct net_device *dev, + struct ethtool_link_ksettings *ecmd) { u16 tmp; unsigned int ioaddr = dev->base_addr; @@ -1865,8 +1865,6 @@ static int smc_netdev_get_ecmd(struct net_device *dev, ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported, supported); - - return 0; } static int smc_netdev_set_ecmd(struct net_device *dev, @@ -1918,18 +1916,17 @@ static int smc_get_link_ksettings(struct net_device *dev, struct smc_private *smc = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; u16 saved_bank = inw(ioaddr + BANK_SELECT); - int ret; unsigned long flags; spin_lock_irqsave(&smc->lock, flags); SMC_SELECT_BANK(3); if (smc->cfg & CFG_MII_SELECT) - ret = mii_ethtool_get_link_ksettings(&smc->mii_if, ecmd); + mii_ethtool_get_link_ksettings(&smc->mii_if, ecmd); else - ret = smc_netdev_get_ecmd(dev, ecmd); + smc_netdev_get_ecmd(dev, ecmd); SMC_SELECT_BANK(saved_bank); spin_unlock_irqrestore(&smc->lock, flags); - return ret; + return 0; } static int smc_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 91e9bd7159ab..0d230b125c6c 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -1539,11 +1539,10 @@ smc_ethtool_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct smc_local *lp = netdev_priv(dev); - int ret; if (lp->phy_type != 0) { spin_lock_irq(&lp->lock); - ret = mii_ethtool_get_link_ksettings(&lp->mii, cmd); + mii_ethtool_get_link_ksettings(&lp->mii, cmd); spin_unlock_irq(&lp->lock); } else { u32 supported = SUPPORTED_10baseT_Half | @@ -1562,11 +1561,9 @@ smc_ethtool_get_link_ksettings(struct net_device *dev, ethtool_convert_legacy_u32_to_link_mode( cmd->link_modes.supported, supported); - - ret = 0; } - return ret; + return 0; } static int diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index cfbe3634dfa1..85c0e41f8021 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -145,6 +145,17 @@ config DWMAC_SUNXI This selects Allwinner SoC glue layer support for the stmmac device driver. This driver is used for A20/A31 GMAC ethernet controller. + +config DWMAC_SUN8I + tristate "Allwinner sun8i GMAC support" + default ARCH_SUNXI + depends on OF && (ARCH_SUNXI || COMPILE_TEST) + ---help--- + Support for Allwinner H3 A83T A64 EMAC ethernet controllers. + + This selects Allwinner SoC glue layer support for the + stmmac device driver. This driver is used for H3/A83T/A64 + EMAC ethernet controller. endif config STMMAC_PCI diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 700c60336674..fd4937a7fcab 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o obj-$(CONFIG_DWMAC_STM32) += dwmac-stm32.o obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o +obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o obj-$(CONFIG_DWMAC_DWC_QOS_ETH) += dwmac-dwc-qos-eth.o obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o stmmac-platform-objs:= stmmac_platform.o diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index b7ce3fbb5375..e82b4b70b7be 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -549,9 +549,11 @@ extern const struct stmmac_hwtimestamp stmmac_ptp; extern const struct stmmac_mode_ops dwmac4_ring_mode_ops; struct mac_link { - int port; - int duplex; - int speed; + u32 speed_mask; + u32 speed10; + u32 speed100; + u32 speed1000; + u32 duplex; }; struct mii_regs { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c new file mode 100644 index 000000000000..54f93ee53ef7 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -0,0 +1,995 @@ +/* + * dwmac-sun8i.c - Allwinner sun8i DWMAC specific glue layer + * + * Copyright (C) 2017 Corentin Labbe <clabbe.montjoie@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of_mdio.h> +#include <linux/of_net.h> +#include <linux/phy.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/regmap.h> +#include <linux/stmmac.h> + +#include "stmmac.h" +#include "stmmac_platform.h" + +/* General notes on dwmac-sun8i: + * Locking: no locking is necessary in this file because all necessary locking + * is done in the "stmmac files" + */ + +/* struct emac_variant - Descrive dwmac-sun8i hardware variant + * @default_syscon_value: The default value of the EMAC register in syscon + * This value is used for disabling properly EMAC + * and used as a good starting value in case of the + * boot process(uboot) leave some stuff. + * @internal_phy: Does the MAC embed an internal PHY + * @support_mii: Does the MAC handle MII + * @support_rmii: Does the MAC handle RMII + * @support_rgmii: Does the MAC handle RGMII + */ +struct emac_variant { + u32 default_syscon_value; + int internal_phy; + bool support_mii; + bool support_rmii; + bool support_rgmii; +}; + +/* struct sunxi_priv_data - hold all sunxi private data + * @tx_clk: reference to MAC TX clock + * @ephy_clk: reference to the optional EPHY clock for the internal PHY + * @regulator: reference to the optional regulator + * @rst_ephy: reference to the optional EPHY reset for the internal PHY + * @variant: reference to the current board variant + * @regmap: regmap for using the syscon + * @use_internal_phy: Does the current PHY choice imply using the internal PHY + */ +struct sunxi_priv_data { + struct clk *tx_clk; + struct clk *ephy_clk; + struct regulator *regulator; + struct reset_control *rst_ephy; + const struct emac_variant *variant; + struct regmap *regmap; + bool use_internal_phy; +}; + +static const struct emac_variant emac_variant_h3 = { + .default_syscon_value = 0x58000, + .internal_phy = PHY_INTERFACE_MODE_MII, + .support_mii = true, + .support_rmii = true, + .support_rgmii = true +}; + +static const struct emac_variant emac_variant_a83t = { + .default_syscon_value = 0, + .internal_phy = 0, + .support_mii = true, + .support_rgmii = true +}; + +static const struct emac_variant emac_variant_a64 = { + .default_syscon_value = 0, + .internal_phy = 0, + .support_mii = true, + .support_rmii = true, + .support_rgmii = true +}; + +#define EMAC_BASIC_CTL0 0x00 +#define EMAC_BASIC_CTL1 0x04 +#define EMAC_INT_STA 0x08 +#define EMAC_INT_EN 0x0C +#define EMAC_TX_CTL0 0x10 +#define EMAC_TX_CTL1 0x14 +#define EMAC_TX_FLOW_CTL 0x1C +#define EMAC_TX_DESC_LIST 0x20 +#define EMAC_RX_CTL0 0x24 +#define EMAC_RX_CTL1 0x28 +#define EMAC_RX_DESC_LIST 0x34 +#define EMAC_RX_FRM_FLT 0x38 +#define EMAC_MDIO_CMD 0x48 +#define EMAC_MDIO_DATA 0x4C +#define EMAC_MACADDR_HI(reg) (0x50 + (reg) * 8) +#define EMAC_MACADDR_LO(reg) (0x54 + (reg) * 8) +#define EMAC_TX_DMA_STA 0xB0 +#define EMAC_TX_CUR_DESC 0xB4 +#define EMAC_TX_CUR_BUF 0xB8 +#define EMAC_RX_DMA_STA 0xC0 +#define EMAC_RX_CUR_DESC 0xC4 +#define EMAC_RX_CUR_BUF 0xC8 + +/* Use in EMAC_BASIC_CTL0 */ +#define EMAC_DUPLEX_FULL BIT(0) +#define EMAC_LOOPBACK BIT(1) +#define EMAC_SPEED_1000 0 +#define EMAC_SPEED_100 (0x03 << 2) +#define EMAC_SPEED_10 (0x02 << 2) + +/* Use in EMAC_BASIC_CTL1 */ +#define EMAC_BURSTLEN_SHIFT 24 + +/* Used in EMAC_RX_FRM_FLT */ +#define EMAC_FRM_FLT_RXALL BIT(0) +#define EMAC_FRM_FLT_CTL BIT(13) +#define EMAC_FRM_FLT_MULTICAST BIT(16) + +/* Used in RX_CTL1*/ +#define EMAC_RX_MD BIT(1) +#define EMAC_RX_TH_MASK GENMASK(4, 5) +#define EMAC_RX_TH_32 0 +#define EMAC_RX_TH_64 (0x1 << 4) +#define EMAC_RX_TH_96 (0x2 << 4) +#define EMAC_RX_TH_128 (0x3 << 4) +#define EMAC_RX_DMA_EN BIT(30) +#define EMAC_RX_DMA_START BIT(31) + +/* Used in TX_CTL1*/ +#define EMAC_TX_MD BIT(1) +#define EMAC_TX_NEXT_FRM BIT(2) +#define EMAC_TX_TH_MASK GENMASK(8, 10) +#define EMAC_TX_TH_64 0 +#define EMAC_TX_TH_128 (0x1 << 8) +#define EMAC_TX_TH_192 (0x2 << 8) +#define EMAC_TX_TH_256 (0x3 << 8) +#define EMAC_TX_DMA_EN BIT(30) +#define EMAC_TX_DMA_START BIT(31) + +/* Used in RX_CTL0 */ +#define EMAC_RX_RECEIVER_EN BIT(31) +#define EMAC_RX_DO_CRC BIT(27) +#define EMAC_RX_FLOW_CTL_EN BIT(16) + +/* Used in TX_CTL0 */ +#define EMAC_TX_TRANSMITTER_EN BIT(31) + +/* Used in EMAC_TX_FLOW_CTL */ +#define EMAC_TX_FLOW_CTL_EN BIT(0) + +/* Used in EMAC_INT_STA */ +#define EMAC_TX_INT BIT(0) +#define EMAC_TX_DMA_STOP_INT BIT(1) +#define EMAC_TX_BUF_UA_INT BIT(2) +#define EMAC_TX_TIMEOUT_INT BIT(3) +#define EMAC_TX_UNDERFLOW_INT BIT(4) +#define EMAC_TX_EARLY_INT BIT(5) +#define EMAC_RX_INT BIT(8) +#define EMAC_RX_BUF_UA_INT BIT(9) +#define EMAC_RX_DMA_STOP_INT BIT(10) +#define EMAC_RX_TIMEOUT_INT BIT(11) +#define EMAC_RX_OVERFLOW_INT BIT(12) +#define EMAC_RX_EARLY_INT BIT(13) +#define EMAC_RGMII_STA_INT BIT(16) + +#define MAC_ADDR_TYPE_DST BIT(31) + +/* H3 specific bits for EPHY */ +#define H3_EPHY_ADDR_SHIFT 20 +#define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */ +#define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */ +#define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */ + +/* H3/A64 specific bits */ +#define SYSCON_RMII_EN BIT(13) /* 1: enable RMII (overrides EPIT) */ + +/* Generic system control EMAC_CLK bits */ +#define SYSCON_ETXDC_MASK GENMASK(2, 0) +#define SYSCON_ETXDC_SHIFT 10 +#define SYSCON_ERXDC_MASK GENMASK(4, 0) +#define SYSCON_ERXDC_SHIFT 5 +/* EMAC PHY Interface Type */ +#define SYSCON_EPIT BIT(2) /* 1: RGMII, 0: MII */ +#define SYSCON_ETCS_MASK GENMASK(1, 0) +#define SYSCON_ETCS_MII 0x0 +#define SYSCON_ETCS_EXT_GMII 0x1 +#define SYSCON_ETCS_INT_GMII 0x2 +#define SYSCON_EMAC_REG 0x30 + +/* sun8i_dwmac_dma_reset() - reset the EMAC + * Called from stmmac via stmmac_dma_ops->reset + */ +static int sun8i_dwmac_dma_reset(void __iomem *ioaddr) +{ + writel(0, ioaddr + EMAC_RX_CTL1); + writel(0, ioaddr + EMAC_TX_CTL1); + writel(0, ioaddr + EMAC_RX_FRM_FLT); + writel(0, ioaddr + EMAC_RX_DESC_LIST); + writel(0, ioaddr + EMAC_TX_DESC_LIST); + writel(0, ioaddr + EMAC_INT_EN); + writel(0x1FFFFFF, ioaddr + EMAC_INT_STA); + return 0; +} + +/* sun8i_dwmac_dma_init() - initialize the EMAC + * Called from stmmac via stmmac_dma_ops->init + */ +static void sun8i_dwmac_dma_init(void __iomem *ioaddr, + struct stmmac_dma_cfg *dma_cfg, + u32 dma_tx, u32 dma_rx, int atds) +{ + /* Write TX and RX descriptors address */ + writel(dma_rx, ioaddr + EMAC_RX_DESC_LIST); + writel(dma_tx, ioaddr + EMAC_TX_DESC_LIST); + + writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN); + writel(0x1FFFFFF, ioaddr + EMAC_INT_STA); +} + +/* sun8i_dwmac_dump_regs() - Dump EMAC address space + * Called from stmmac_dma_ops->dump_regs + * Used for ethtool + */ +static void sun8i_dwmac_dump_regs(void __iomem *ioaddr, u32 *reg_space) +{ + int i; + + for (i = 0; i < 0xC8; i += 4) { + if (i == 0x32 || i == 0x3C) + continue; + reg_space[i / 4] = readl(ioaddr + i); + } +} + +/* sun8i_dwmac_dump_mac_regs() - Dump EMAC address space + * Called from stmmac_ops->dump_regs + * Used for ethtool + */ +static void sun8i_dwmac_dump_mac_regs(struct mac_device_info *hw, + u32 *reg_space) +{ + int i; + void __iomem *ioaddr = hw->pcsr; + + for (i = 0; i < 0xC8; i += 4) { + if (i == 0x32 || i == 0x3C) + continue; + reg_space[i / 4] = readl(ioaddr + i); + } +} + +static void sun8i_dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan) +{ + writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN); +} + +static void sun8i_dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan) +{ + writel(0, ioaddr + EMAC_INT_EN); +} + +static void sun8i_dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan) +{ + u32 v; + + v = readl(ioaddr + EMAC_TX_CTL1); + v |= EMAC_TX_DMA_START; + v |= EMAC_TX_DMA_EN; + writel(v, ioaddr + EMAC_TX_CTL1); +} + +static void sun8i_dwmac_enable_dma_transmission(void __iomem *ioaddr) +{ + u32 v; + + v = readl(ioaddr + EMAC_TX_CTL1); + v |= EMAC_TX_DMA_START; + v |= EMAC_TX_DMA_EN; + writel(v, ioaddr + EMAC_TX_CTL1); +} + +static void sun8i_dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan) +{ + u32 v; + + v = readl(ioaddr + EMAC_TX_CTL1); + v &= ~EMAC_TX_DMA_EN; + writel(v, ioaddr + EMAC_TX_CTL1); +} + +static void sun8i_dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan) +{ + u32 v; + + v = readl(ioaddr + EMAC_RX_CTL1); + v |= EMAC_RX_DMA_START; + v |= EMAC_RX_DMA_EN; + writel(v, ioaddr + EMAC_RX_CTL1); +} + +static void sun8i_dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan) +{ + u32 v; + + v = readl(ioaddr + EMAC_RX_CTL1); + v &= ~EMAC_RX_DMA_EN; + writel(v, ioaddr + EMAC_RX_CTL1); +} + +static int sun8i_dwmac_dma_interrupt(void __iomem *ioaddr, + struct stmmac_extra_stats *x, u32 chan) +{ + u32 v; + int ret = 0; + + v = readl(ioaddr + EMAC_INT_STA); + + if (v & EMAC_TX_INT) { + ret |= handle_tx; + x->tx_normal_irq_n++; + } + + if (v & EMAC_TX_DMA_STOP_INT) + x->tx_process_stopped_irq++; + + if (v & EMAC_TX_BUF_UA_INT) + x->tx_process_stopped_irq++; + + if (v & EMAC_TX_TIMEOUT_INT) + ret |= tx_hard_error; + + if (v & EMAC_TX_UNDERFLOW_INT) { + ret |= tx_hard_error; + x->tx_undeflow_irq++; + } + + if (v & EMAC_TX_EARLY_INT) + x->tx_early_irq++; + + if (v & EMAC_RX_INT) { + ret |= handle_rx; + x->rx_normal_irq_n++; + } + + if (v & EMAC_RX_BUF_UA_INT) + x->rx_buf_unav_irq++; + + if (v & EMAC_RX_DMA_STOP_INT) + x->rx_process_stopped_irq++; + + if (v & EMAC_RX_TIMEOUT_INT) + ret |= tx_hard_error; + + if (v & EMAC_RX_OVERFLOW_INT) { + ret |= tx_hard_error; + x->rx_overflow_irq++; + } + + if (v & EMAC_RX_EARLY_INT) + x->rx_early_irq++; + + if (v & EMAC_RGMII_STA_INT) + x->irq_rgmii_n++; + + writel(v, ioaddr + EMAC_INT_STA); + + return ret; +} + +static void sun8i_dwmac_dma_operation_mode(void __iomem *ioaddr, int txmode, + int rxmode, int rxfifosz) +{ + u32 v; + + v = readl(ioaddr + EMAC_TX_CTL1); + if (txmode == SF_DMA_MODE) { + v |= EMAC_TX_MD; + /* Undocumented bit (called TX_NEXT_FRM in BSP), the original + * comment is + * "Operating on second frame increase the performance + * especially when transmit store-and-forward is used." + */ + v |= EMAC_TX_NEXT_FRM; + } else { + v &= ~EMAC_TX_MD; + v &= ~EMAC_TX_TH_MASK; + if (txmode < 64) + v |= EMAC_TX_TH_64; + else if (txmode < 128) + v |= EMAC_TX_TH_128; + else if (txmode < 192) + v |= EMAC_TX_TH_192; + else if (txmode < 256) + v |= EMAC_TX_TH_256; + } + writel(v, ioaddr + EMAC_TX_CTL1); + + v = readl(ioaddr + EMAC_RX_CTL1); + if (rxmode == SF_DMA_MODE) { + v |= EMAC_RX_MD; + } else { + v &= ~EMAC_RX_MD; + v &= ~EMAC_RX_TH_MASK; + if (rxmode < 32) + v |= EMAC_RX_TH_32; + else if (rxmode < 64) + v |= EMAC_RX_TH_64; + else if (rxmode < 96) + v |= EMAC_RX_TH_96; + else if (rxmode < 128) + v |= EMAC_RX_TH_128; + } + writel(v, ioaddr + EMAC_RX_CTL1); +} + +static const struct stmmac_dma_ops sun8i_dwmac_dma_ops = { + .reset = sun8i_dwmac_dma_reset, + .init = sun8i_dwmac_dma_init, + .dump_regs = sun8i_dwmac_dump_regs, + .dma_mode = sun8i_dwmac_dma_operation_mode, + .enable_dma_transmission = sun8i_dwmac_enable_dma_transmission, + .enable_dma_irq = sun8i_dwmac_enable_dma_irq, + .disable_dma_irq = sun8i_dwmac_disable_dma_irq, + .start_tx = sun8i_dwmac_dma_start_tx, + .stop_tx = sun8i_dwmac_dma_stop_tx, + .start_rx = sun8i_dwmac_dma_start_rx, + .stop_rx = sun8i_dwmac_dma_stop_rx, + .dma_interrupt = sun8i_dwmac_dma_interrupt, +}; + +static int sun8i_dwmac_init(struct platform_device *pdev, void *priv) +{ + struct sunxi_priv_data *gmac = priv; + int ret; + + if (gmac->regulator) { + ret = regulator_enable(gmac->regulator); + if (ret) { + dev_err(&pdev->dev, "Fail to enable regulator\n"); + return ret; + } + } + + ret = clk_prepare_enable(gmac->tx_clk); + if (ret) { + if (gmac->regulator) + regulator_disable(gmac->regulator); + dev_err(&pdev->dev, "Could not enable AHB clock\n"); + return ret; + } + + return 0; +} + +static void sun8i_dwmac_core_init(struct mac_device_info *hw, int mtu) +{ + void __iomem *ioaddr = hw->pcsr; + u32 v; + + v = (8 << EMAC_BURSTLEN_SHIFT); /* burst len */ + writel(v, ioaddr + EMAC_BASIC_CTL1); +} + +static void sun8i_dwmac_set_mac(void __iomem *ioaddr, bool enable) +{ + u32 t, r; + + t = readl(ioaddr + EMAC_TX_CTL0); + r = readl(ioaddr + EMAC_RX_CTL0); + if (enable) { + t |= EMAC_TX_TRANSMITTER_EN; + r |= EMAC_RX_RECEIVER_EN; + } else { + t &= ~EMAC_TX_TRANSMITTER_EN; + r &= ~EMAC_RX_RECEIVER_EN; + } + writel(t, ioaddr + EMAC_TX_CTL0); + writel(r, ioaddr + EMAC_RX_CTL0); +} + +/* Set MAC address at slot reg_n + * All slot > 0 need to be enabled with MAC_ADDR_TYPE_DST + * If addr is NULL, clear the slot + */ +static void sun8i_dwmac_set_umac_addr(struct mac_device_info *hw, + unsigned char *addr, + unsigned int reg_n) +{ + void __iomem *ioaddr = hw->pcsr; + u32 v; + + if (!addr) { + writel(0, ioaddr + EMAC_MACADDR_HI(reg_n)); + return; + } + + stmmac_set_mac_addr(ioaddr, addr, EMAC_MACADDR_HI(reg_n), + EMAC_MACADDR_LO(reg_n)); + if (reg_n > 0) { + v = readl(ioaddr + EMAC_MACADDR_HI(reg_n)); + v |= MAC_ADDR_TYPE_DST; + writel(v, ioaddr + EMAC_MACADDR_HI(reg_n)); + } +} + +static void sun8i_dwmac_get_umac_addr(struct mac_device_info *hw, + unsigned char *addr, + unsigned int reg_n) +{ + void __iomem *ioaddr = hw->pcsr; + + stmmac_get_mac_addr(ioaddr, addr, EMAC_MACADDR_HI(reg_n), + EMAC_MACADDR_LO(reg_n)); +} + +/* caution this function must return non 0 to work */ +static int sun8i_dwmac_rx_ipc_enable(struct mac_device_info *hw) +{ + void __iomem *ioaddr = hw->pcsr; + u32 v; + + v = readl(ioaddr + EMAC_RX_CTL0); + v |= EMAC_RX_DO_CRC; + writel(v, ioaddr + EMAC_RX_CTL0); + + return 1; +} + +static void sun8i_dwmac_set_filter(struct mac_device_info *hw, + struct net_device *dev) +{ + void __iomem *ioaddr = hw->pcsr; + u32 v; + int i = 1; + struct netdev_hw_addr *ha; + int macaddrs = netdev_uc_count(dev) + netdev_mc_count(dev) + 1; + + v = EMAC_FRM_FLT_CTL; + + if (dev->flags & IFF_PROMISC) { + v = EMAC_FRM_FLT_RXALL; + } else if (dev->flags & IFF_ALLMULTI) { + v |= EMAC_FRM_FLT_MULTICAST; + } else if (macaddrs <= hw->unicast_filter_entries) { + if (!netdev_mc_empty(dev)) { + netdev_for_each_mc_addr(ha, dev) { + sun8i_dwmac_set_umac_addr(hw, ha->addr, i); + i++; + } + } + if (!netdev_uc_empty(dev)) { + netdev_for_each_uc_addr(ha, dev) { + sun8i_dwmac_set_umac_addr(hw, ha->addr, i); + i++; + } + } + } else { + netdev_info(dev, "Too many address, switching to promiscuous\n"); + v = EMAC_FRM_FLT_RXALL; + } + + /* Disable unused address filter slots */ + while (i < hw->unicast_filter_entries) + sun8i_dwmac_set_umac_addr(hw, NULL, i++); + + writel(v, ioaddr + EMAC_RX_FRM_FLT); +} + +static void sun8i_dwmac_flow_ctrl(struct mac_device_info *hw, + unsigned int duplex, unsigned int fc, + unsigned int pause_time, u32 tx_cnt) +{ + void __iomem *ioaddr = hw->pcsr; + u32 v; + + v = readl(ioaddr + EMAC_RX_CTL0); + if (fc == FLOW_AUTO) + v |= EMAC_RX_FLOW_CTL_EN; + else + v &= ~EMAC_RX_FLOW_CTL_EN; + writel(v, ioaddr + EMAC_RX_CTL0); + + v = readl(ioaddr + EMAC_TX_FLOW_CTL); + if (fc == FLOW_AUTO) + v |= EMAC_TX_FLOW_CTL_EN; + else + v &= ~EMAC_TX_FLOW_CTL_EN; + writel(v, ioaddr + EMAC_TX_FLOW_CTL); +} + +static int sun8i_dwmac_reset(struct stmmac_priv *priv) +{ + u32 v; + int err; + + v = readl(priv->ioaddr + EMAC_BASIC_CTL1); + writel(v | 0x01, priv->ioaddr + EMAC_BASIC_CTL1); + + /* The timeout was previoulsy set to 10ms, but some board (OrangePI0) + * need more if no cable plugged. 100ms seems OK + */ + err = readl_poll_timeout(priv->ioaddr + EMAC_BASIC_CTL1, v, + !(v & 0x01), 100, 100000); + + if (err) { + dev_err(priv->device, "EMAC reset timeout\n"); + return -EFAULT; + } + return 0; +} + +static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv) +{ + struct sunxi_priv_data *gmac = priv->plat->bsp_priv; + struct device_node *node = priv->device->of_node; + int ret; + u32 reg, val; + + regmap_read(gmac->regmap, SYSCON_EMAC_REG, &val); + reg = gmac->variant->default_syscon_value; + if (reg != val) + dev_warn(priv->device, + "Current syscon value is not the default %x (expect %x)\n", + val, reg); + + if (gmac->variant->internal_phy) { + if (!gmac->use_internal_phy) { + /* switch to external PHY interface */ + reg &= ~H3_EPHY_SELECT; + } else { + reg |= H3_EPHY_SELECT; + reg &= ~H3_EPHY_SHUTDOWN; + dev_dbg(priv->device, "Select internal_phy %x\n", reg); + + if (of_property_read_bool(priv->plat->phy_node, + "allwinner,leds-active-low")) + reg |= H3_EPHY_LED_POL; + else + reg &= ~H3_EPHY_LED_POL; + + ret = of_mdio_parse_addr(priv->device, + priv->plat->phy_node); + if (ret < 0) { + dev_err(priv->device, "Could not parse MDIO addr\n"); + return ret; + } + /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY + * address. No need to mask it again. + */ + reg |= ret << H3_EPHY_ADDR_SHIFT; + } + } + + if (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) { + if (val % 100) { + dev_err(priv->device, "tx-delay must be a multiple of 100\n"); + return -EINVAL; + } + val /= 100; + dev_dbg(priv->device, "set tx-delay to %x\n", val); + if (val <= SYSCON_ETXDC_MASK) { + reg &= ~(SYSCON_ETXDC_MASK << SYSCON_ETXDC_SHIFT); + reg |= (val << SYSCON_ETXDC_SHIFT); + } else { + dev_err(priv->device, "Invalid TX clock delay: %d\n", + val); + return -EINVAL; + } + } + + if (!of_property_read_u32(node, "allwinner,rx-delay-ps", &val)) { + if (val % 100) { + dev_err(priv->device, "rx-delay must be a multiple of 100\n"); + return -EINVAL; + } + val /= 100; + dev_dbg(priv->device, "set rx-delay to %x\n", val); + if (val <= SYSCON_ERXDC_MASK) { + reg &= ~(SYSCON_ERXDC_MASK << SYSCON_ERXDC_SHIFT); + reg |= (val << SYSCON_ERXDC_SHIFT); + } else { + dev_err(priv->device, "Invalid RX clock delay: %d\n", + val); + return -EINVAL; + } + } + + /* Clear interface mode bits */ + reg &= ~(SYSCON_ETCS_MASK | SYSCON_EPIT); + if (gmac->variant->support_rmii) + reg &= ~SYSCON_RMII_EN; + + switch (priv->plat->interface) { + case PHY_INTERFACE_MODE_MII: + /* default */ + break; + case PHY_INTERFACE_MODE_RGMII: + reg |= SYSCON_EPIT | SYSCON_ETCS_INT_GMII; + break; + case PHY_INTERFACE_MODE_RMII: + reg |= SYSCON_RMII_EN | SYSCON_ETCS_EXT_GMII; + break; + default: + dev_err(priv->device, "Unsupported interface mode: %s", + phy_modes(priv->plat->interface)); + return -EINVAL; + } + + regmap_write(gmac->regmap, SYSCON_EMAC_REG, reg); + + return 0; +} + +static void sun8i_dwmac_unset_syscon(struct sunxi_priv_data *gmac) +{ + u32 reg = gmac->variant->default_syscon_value; + + regmap_write(gmac->regmap, SYSCON_EMAC_REG, reg); +} + +static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv) +{ + struct sunxi_priv_data *gmac = priv->plat->bsp_priv; + int ret; + + if (!gmac->use_internal_phy) + return 0; + + ret = clk_prepare_enable(gmac->ephy_clk); + if (ret) { + dev_err(priv->device, "Cannot enable ephy\n"); + return ret; + } + + /* Make sure the EPHY is properly reseted, as U-Boot may leave + * it at deasserted state, and thus it may fail to reset EMAC. + */ + reset_control_assert(gmac->rst_ephy); + + ret = reset_control_deassert(gmac->rst_ephy); + if (ret) { + dev_err(priv->device, "Cannot deassert ephy\n"); + clk_disable_unprepare(gmac->ephy_clk); + return ret; + } + + return 0; +} + +static int sun8i_dwmac_unpower_internal_phy(struct sunxi_priv_data *gmac) +{ + if (!gmac->use_internal_phy) + return 0; + + clk_disable_unprepare(gmac->ephy_clk); + reset_control_assert(gmac->rst_ephy); + return 0; +} + +/* sun8i_power_phy() - Activate the PHY: + * In case of error, no need to call sun8i_unpower_phy(), + * it will be called anyway by sun8i_dwmac_exit() + */ +static int sun8i_power_phy(struct stmmac_priv *priv) +{ + int ret; + + ret = sun8i_dwmac_power_internal_phy(priv); + if (ret) + return ret; + + ret = sun8i_dwmac_set_syscon(priv); + if (ret) + return ret; + + /* After changing syscon value, the MAC need reset or it will use + * the last value (and so the last PHY set. + */ + ret = sun8i_dwmac_reset(priv); + if (ret) + return ret; + return 0; +} + +static void sun8i_unpower_phy(struct sunxi_priv_data *gmac) +{ + sun8i_dwmac_unset_syscon(gmac); + sun8i_dwmac_unpower_internal_phy(gmac); +} + +static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv) +{ + struct sunxi_priv_data *gmac = priv; + + sun8i_unpower_phy(gmac); + + clk_disable_unprepare(gmac->tx_clk); + + if (gmac->regulator) + regulator_disable(gmac->regulator); +} + +static const struct stmmac_ops sun8i_dwmac_ops = { + .core_init = sun8i_dwmac_core_init, + .set_mac = sun8i_dwmac_set_mac, + .dump_regs = sun8i_dwmac_dump_mac_regs, + .rx_ipc = sun8i_dwmac_rx_ipc_enable, + .set_filter = sun8i_dwmac_set_filter, + .flow_ctrl = sun8i_dwmac_flow_ctrl, + .set_umac_addr = sun8i_dwmac_set_umac_addr, + .get_umac_addr = sun8i_dwmac_get_umac_addr, +}; + +static struct mac_device_info *sun8i_dwmac_setup(void *ppriv) +{ + struct mac_device_info *mac; + struct stmmac_priv *priv = ppriv; + int ret; + + mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); + if (!mac) + return NULL; + + ret = sun8i_power_phy(priv); + if (ret) + return NULL; + + mac->pcsr = priv->ioaddr; + mac->mac = &sun8i_dwmac_ops; + mac->dma = &sun8i_dwmac_dma_ops; + + /* The loopback bit seems to be re-set when link change + * Simply mask it each time + * Speed 10/100/1000 are set in BIT(2)/BIT(3) + */ + mac->link.speed_mask = GENMASK(3, 2) | EMAC_LOOPBACK; + mac->link.speed10 = EMAC_SPEED_10; + mac->link.speed100 = EMAC_SPEED_100; + mac->link.speed1000 = EMAC_SPEED_1000; + mac->link.duplex = EMAC_DUPLEX_FULL; + mac->mii.addr = EMAC_MDIO_CMD; + mac->mii.data = EMAC_MDIO_DATA; + mac->mii.reg_shift = 4; + mac->mii.reg_mask = GENMASK(8, 4); + mac->mii.addr_shift = 12; + mac->mii.addr_mask = GENMASK(16, 12); + mac->mii.clk_csr_shift = 20; + mac->mii.clk_csr_mask = GENMASK(22, 20); + mac->unicast_filter_entries = 8; + + /* Synopsys Id is not available */ + priv->synopsys_id = 0; + + return mac; +} + +static int sun8i_dwmac_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + struct sunxi_priv_data *gmac; + struct device *dev = &pdev->dev; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; + + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) + return PTR_ERR(plat_dat); + + gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); + if (!gmac) + return -ENOMEM; + + gmac->variant = of_device_get_match_data(&pdev->dev); + if (!gmac->variant) { + dev_err(&pdev->dev, "Missing dwmac-sun8i variant\n"); + return -EINVAL; + } + + gmac->tx_clk = devm_clk_get(dev, "stmmaceth"); + if (IS_ERR(gmac->tx_clk)) { + dev_err(dev, "Could not get TX clock\n"); + return PTR_ERR(gmac->tx_clk); + } + + /* Optional regulator for PHY */ + gmac->regulator = devm_regulator_get_optional(dev, "phy"); + if (IS_ERR(gmac->regulator)) { + if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_info(dev, "No regulator found\n"); + gmac->regulator = NULL; + } + + gmac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "syscon"); + if (IS_ERR(gmac->regmap)) { + ret = PTR_ERR(gmac->regmap); + dev_err(&pdev->dev, "Unable to map syscon: %d\n", ret); + return ret; + } + + plat_dat->interface = of_get_phy_mode(dev->of_node); + if (plat_dat->interface == gmac->variant->internal_phy) { + dev_info(&pdev->dev, "Will use internal PHY\n"); + gmac->use_internal_phy = true; + gmac->ephy_clk = of_clk_get(plat_dat->phy_node, 0); + if (IS_ERR(gmac->ephy_clk)) { + ret = PTR_ERR(gmac->ephy_clk); + dev_err(&pdev->dev, "Cannot get EPHY clock: %d\n", ret); + return -EINVAL; + } + + gmac->rst_ephy = of_reset_control_get(plat_dat->phy_node, NULL); + if (IS_ERR(gmac->rst_ephy)) { + ret = PTR_ERR(gmac->rst_ephy); + if (ret == -EPROBE_DEFER) + return ret; + dev_err(&pdev->dev, "No EPHY reset control found %d\n", + ret); + return -EINVAL; + } + } else { + dev_info(&pdev->dev, "Will use external PHY\n"); + gmac->use_internal_phy = false; + } + + /* platform data specifying hardware features and callbacks. + * hardware features were copied from Allwinner drivers. + */ + plat_dat->rx_coe = STMMAC_RX_COE_TYPE2; + plat_dat->tx_coe = 1; + plat_dat->has_sun8i = true; + plat_dat->bsp_priv = gmac; + plat_dat->init = sun8i_dwmac_init; + plat_dat->exit = sun8i_dwmac_exit; + plat_dat->setup = sun8i_dwmac_setup; + + ret = sun8i_dwmac_init(pdev, plat_dat->bsp_priv); + if (ret) + return ret; + + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + if (ret) + sun8i_dwmac_exit(pdev, plat_dat->bsp_priv); + + return ret; +} + +static const struct of_device_id sun8i_dwmac_match[] = { + { .compatible = "allwinner,sun8i-h3-emac", + .data = &emac_variant_h3 }, + { .compatible = "allwinner,sun8i-a83t-emac", + .data = &emac_variant_a83t }, + { .compatible = "allwinner,sun50i-a64-emac", + .data = &emac_variant_a64 }, + { } +}; +MODULE_DEVICE_TABLE(of, sun8i_dwmac_match); + +static struct platform_driver sun8i_dwmac_driver = { + .probe = sun8i_dwmac_probe, + .remove = stmmac_pltfr_remove, + .driver = { + .name = "dwmac-sun8i", + .pm = &stmmac_pltfr_pm_ops, + .of_match_table = sun8i_dwmac_match, + }, +}; +module_platform_driver(sun8i_dwmac_driver); + +MODULE_AUTHOR("Corentin Labbe <clabbe.montjoie@gmail.com>"); +MODULE_DESCRIPTION("Allwinner sun8i DWMAC specific glue layer"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index f3d9305e5f70..8a86340ff2d3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -45,15 +45,17 @@ static void dwmac1000_core_init(struct mac_device_info *hw, int mtu) if (hw->ps) { value |= GMAC_CONTROL_TE; - if (hw->ps == SPEED_1000) { - value &= ~GMAC_CONTROL_PS; - } else { - value |= GMAC_CONTROL_PS; - - if (hw->ps == SPEED_10) - value &= ~GMAC_CONTROL_FES; - else - value |= GMAC_CONTROL_FES; + value &= ~hw->link.speed_mask; + switch (hw->ps) { + case SPEED_1000: + value |= hw->link.speed1000; + break; + case SPEED_100: + value |= hw->link.speed100; + break; + case SPEED_10: + value |= hw->link.speed10; + break; } } @@ -531,9 +533,11 @@ struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins, mac->mac = &dwmac1000_ops; mac->dma = &dwmac1000_dma_ops; - mac->link.port = GMAC_CONTROL_PS; mac->link.duplex = GMAC_CONTROL_DM; - mac->link.speed = GMAC_CONTROL_FES; + mac->link.speed10 = GMAC_CONTROL_PS; + mac->link.speed100 = GMAC_CONTROL_PS | GMAC_CONTROL_FES; + mac->link.speed1000 = 0; + mac->link.speed_mask = GMAC_CONTROL_PS | GMAC_CONTROL_FES; mac->mii.addr = GMAC_MII_ADDR; mac->mii.data = GMAC_MII_DATA; mac->mii.addr_shift = 11; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c index 1b3609105484..8ef517356313 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c @@ -175,9 +175,11 @@ struct mac_device_info *dwmac100_setup(void __iomem *ioaddr, int *synopsys_id) mac->mac = &dwmac100_ops; mac->dma = &dwmac100_dma_ops; - mac->link.port = MAC_CONTROL_PS; mac->link.duplex = MAC_CONTROL_F; - mac->link.speed = 0; + mac->link.speed10 = 0; + mac->link.speed100 = 0; + mac->link.speed1000 = 0; + mac->link.speed_mask = MAC_CONTROL_PS; mac->mii.addr = MAC_MII_ADDR; mac->mii.data = MAC_MII_DATA; mac->mii.addr_shift = 11; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 48793f2e9307..f233bf8b4ebb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -35,15 +35,17 @@ static void dwmac4_core_init(struct mac_device_info *hw, int mtu) if (hw->ps) { value |= GMAC_CONFIG_TE; - if (hw->ps == SPEED_1000) { - value &= ~GMAC_CONFIG_PS; - } else { - value |= GMAC_CONFIG_PS; - - if (hw->ps == SPEED_10) - value &= ~GMAC_CONFIG_FES; - else - value |= GMAC_CONFIG_FES; + value &= hw->link.speed_mask; + switch (hw->ps) { + case SPEED_1000: + value |= hw->link.speed1000; + break; + case SPEED_100: + value |= hw->link.speed100; + break; + case SPEED_10: + value |= hw->link.speed10; + break; } } @@ -747,9 +749,11 @@ struct mac_device_info *dwmac4_setup(void __iomem *ioaddr, int mcbins, if (mac->multicast_filter_bins) mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins); - mac->link.port = GMAC_CONFIG_PS; mac->link.duplex = GMAC_CONFIG_DM; - mac->link.speed = GMAC_CONFIG_FES; + mac->link.speed10 = GMAC_CONFIG_PS; + mac->link.speed100 = GMAC_CONFIG_FES | GMAC_CONFIG_PS; + mac->link.speed1000 = 0; + mac->link.speed_mask = GMAC_CONFIG_FES | GMAC_CONFIG_PS; mac->mii.addr = GMAC_MDIO_ADDR; mac->mii.data = GMAC_MDIO_DATA; mac->mii.addr_shift = 21; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c index 38f94305aab5..67af0bdd7f10 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c @@ -248,6 +248,7 @@ void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; writel(data, ioaddr + low); } +EXPORT_SYMBOL_GPL(stmmac_set_mac_addr); /* Enable disable MAC RX/TX */ void stmmac_set_mac(void __iomem *ioaddr, bool enable) @@ -279,4 +280,4 @@ void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, addr[4] = hi_addr & 0xff; addr[5] = (hi_addr >> 8) & 0xff; } - +EXPORT_SYMBOL_GPL(stmmac_get_mac_addr); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 33efe7038cab..a916e13624eb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -104,7 +104,7 @@ struct stmmac_priv { /* TX Queue */ struct stmmac_tx_queue tx_queue[MTL_MAX_TX_QUEUES]; - int oldlink; + bool oldlink; int speed; int oldduplex; unsigned int flow_ctrl; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 12236daf7bb6..f446f368dd20 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -235,6 +235,17 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv) else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M)) priv->clk_csr = STMMAC_CSR_250_300M; } + + if (priv->plat->has_sun8i) { + if (clk_rate > 160000000) + priv->clk_csr = 0x03; + else if (clk_rate > 80000000) + priv->clk_csr = 0x02; + else if (clk_rate > 40000000) + priv->clk_csr = 0x01; + else + priv->clk_csr = 0; + } } static void print_pkt(unsigned char *buf, int len) @@ -644,6 +655,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) ptp_over_ethernet = PTP_TCR_TSIPENA; break; + case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: /* time stamp any incoming packet */ config.rx_filter = HWTSTAMP_FILTER_ALL; @@ -774,7 +786,7 @@ static void stmmac_adjust_link(struct net_device *dev) struct stmmac_priv *priv = netdev_priv(dev); struct phy_device *phydev = dev->phydev; unsigned long flags; - int new_state = 0; + bool new_state = false; if (!phydev) return; @@ -787,8 +799,8 @@ static void stmmac_adjust_link(struct net_device *dev) /* Now we make sure that we can be in full duplex mode. * If not, we operate in half-duplex mode. */ if (phydev->duplex != priv->oldduplex) { - new_state = 1; - if (!(phydev->duplex)) + new_state = true; + if (!phydev->duplex) ctrl &= ~priv->hw->link.duplex; else ctrl |= priv->hw->link.duplex; @@ -799,30 +811,17 @@ static void stmmac_adjust_link(struct net_device *dev) stmmac_mac_flow_ctrl(priv, phydev->duplex); if (phydev->speed != priv->speed) { - new_state = 1; + new_state = true; + ctrl &= ~priv->hw->link.speed_mask; switch (phydev->speed) { - case 1000: - if (priv->plat->has_gmac || - priv->plat->has_gmac4) - ctrl &= ~priv->hw->link.port; + case SPEED_1000: + ctrl |= priv->hw->link.speed1000; break; - case 100: - if (priv->plat->has_gmac || - priv->plat->has_gmac4) { - ctrl |= priv->hw->link.port; - ctrl |= priv->hw->link.speed; - } else { - ctrl &= ~priv->hw->link.port; - } + case SPEED_100: + ctrl |= priv->hw->link.speed100; break; - case 10: - if (priv->plat->has_gmac || - priv->plat->has_gmac4) { - ctrl |= priv->hw->link.port; - ctrl &= ~(priv->hw->link.speed); - } else { - ctrl &= ~priv->hw->link.port; - } + case SPEED_10: + ctrl |= priv->hw->link.speed10; break; default: netif_warn(priv, link, priv->dev, @@ -838,12 +837,12 @@ static void stmmac_adjust_link(struct net_device *dev) writel(ctrl, priv->ioaddr + MAC_CTRL_REG); if (!priv->oldlink) { - new_state = 1; - priv->oldlink = 1; + new_state = true; + priv->oldlink = true; } } else if (priv->oldlink) { - new_state = 1; - priv->oldlink = 0; + new_state = true; + priv->oldlink = false; priv->speed = SPEED_UNKNOWN; priv->oldduplex = DUPLEX_UNKNOWN; } @@ -906,7 +905,7 @@ static int stmmac_init_phy(struct net_device *dev) char bus_id[MII_BUS_ID_SIZE]; int interface = priv->plat->interface; int max_speed = priv->plat->max_speed; - priv->oldlink = 0; + priv->oldlink = false; priv->speed = SPEED_UNKNOWN; priv->oldduplex = DUPLEX_UNKNOWN; @@ -2879,8 +2878,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) priv->xstats.tx_set_ic_bit++; } - if (!priv->hwts_tx_en) - skb_tx_timestamp(skb); + skb_tx_timestamp(skb); if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en)) { @@ -3084,8 +3082,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) priv->xstats.tx_set_ic_bit++; } - if (!priv->hwts_tx_en) - skb_tx_timestamp(skb); + skb_tx_timestamp(skb); /* Ready to fill the first descriptor and set the OWN bit w/o any * problems because all the descriptors are actually ready to be @@ -3948,7 +3945,9 @@ static int stmmac_hw_init(struct stmmac_priv *priv) struct mac_device_info *mac; /* Identify the MAC HW device */ - if (priv->plat->has_gmac) { + if (priv->plat->setup) { + mac = priv->plat->setup(priv); + } else if (priv->plat->has_gmac) { priv->dev->priv_flags |= IFF_UNICAST_FLT; mac = dwmac1000_setup(priv->ioaddr, priv->plat->multicast_filter_bins, @@ -3968,6 +3967,10 @@ static int stmmac_hw_init(struct stmmac_priv *priv) priv->hw = mac; + /* dwmac-sun8i only work in chain mode */ + if (priv->plat->has_sun8i) + chain_mode = 1; + /* To use the chained or ring mode */ if (priv->synopsys_id >= DWMAC_CORE_4_00) { priv->hw->mode = &dwmac4_ring_mode_ops; @@ -4293,7 +4296,7 @@ int stmmac_suspend(struct device *dev) } spin_unlock_irqrestore(&priv->lock, flags); - priv->oldlink = 0; + priv->oldlink = false; priv->speed = SPEED_UNKNOWN; priv->oldduplex = DUPLEX_UNKNOWN; return 0; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 7fc3a1ef395a..3840529344ed 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -309,6 +309,12 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat, struct device_node *np, struct device *dev) { bool mdio = true; + static const struct of_device_id need_mdio_ids[] = { + { .compatible = "snps,dwc-qos-ethernet-4.10" }, + { .compatible = "allwinner,sun8i-a83t-emac" }, + { .compatible = "allwinner,sun8i-h3-emac" }, + { .compatible = "allwinner,sun50i-a64-emac" }, + }; /* If phy-handle property is passed from DT, use it as the PHY */ plat->phy_node = of_parse_phandle(np, "phy-handle", 0); @@ -325,8 +331,7 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat, mdio = false; } - /* exception for dwmac-dwc-qos-eth glue logic */ - if (of_device_is_compatible(np, "snps,dwc-qos-ethernet-4.10")) { + if (of_match_node(need_mdio_ids, np)) { plat->mdio_node = of_get_child_by_name(np, "mdio"); } else { /** diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index f4d7aec50479..37fc16521143 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1734,6 +1734,7 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: return -ERANGE; case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index 7c634bc75615..aec95382ea5c 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -512,6 +512,7 @@ static int tile_hwtstamp_set(struct net_device *dev, struct ifreq *rq) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: config.rx_filter = HWTSTAMP_FILTER_ALL; break; default: diff --git a/drivers/net/ethernet/tundra/tsi108_eth.c b/drivers/net/ethernet/tundra/tsi108_eth.c index 5ac6eaa9e785..c2d15d9c0c33 100644 --- a/drivers/net/ethernet/tundra/tsi108_eth.c +++ b/drivers/net/ethernet/tundra/tsi108_eth.c @@ -1504,13 +1504,12 @@ static int tsi108_get_link_ksettings(struct net_device *dev, { struct tsi108_prv_data *data = netdev_priv(dev); unsigned long flags; - int rc; spin_lock_irqsave(&data->txlock, flags); - rc = mii_ethtool_get_link_ksettings(&data->mii_if, cmd); + mii_ethtool_get_link_ksettings(&data->mii_if, cmd); spin_unlock_irqrestore(&data->txlock, flags); - return rc; + return 0; } static int tsi108_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index 4cf41f779d0e..acd29d60174a 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -2307,13 +2307,12 @@ static int netdev_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct rhine_private *rp = netdev_priv(dev); - int rc; mutex_lock(&rp->task_lock); - rc = mii_ethtool_get_link_ksettings(&rp->mii_if, cmd); + mii_ethtool_get_link_ksettings(&rp->mii_if, cmd); mutex_unlock(&rp->task_lock); - return rc; + return 0; } static int netdev_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 4421a6d00375..2564ac83eb64 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -37,6 +37,8 @@ #include <net/route.h> #include <net/sock.h> #include <net/pkt_sched.h> +#include <net/checksum.h> +#include <net/ip6_checksum.h> #include "hyperv_net.h" diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c index 25fd3b04b3c0..7a218549c80a 100644 --- a/drivers/net/ieee802154/ca8210.c +++ b/drivers/net/ieee802154/ca8210.c @@ -912,7 +912,7 @@ static int ca8210_spi_transfer( ) { int i, status = 0; - struct ca8210_priv *priv = spi_get_drvdata(spi); + struct ca8210_priv *priv; struct cas_control *cas_ctl; if (!spi) { @@ -923,6 +923,7 @@ static int ca8210_spi_transfer( return -ENODEV; } + priv = spi_get_drvdata(spi); reinit_completion(&priv->spi_transfer_complete); dev_dbg(&spi->dev, "ca8210_spi_transfer called\n"); @@ -1808,10 +1809,9 @@ static int ca8210_skb_rx( /* Allocate mtu size buffer for every rx packet */ skb = dev_alloc_skb(IEEE802154_MTU + sizeof(hdr)); - if (!skb) { - dev_crit(&priv->spi->dev, "dev_alloc_skb failed\n"); + if (!skb) return -ENOMEM; - } + skb_reserve(skb, sizeof(hdr)); msdulen = data_ind[22]; /* msdu_length */ @@ -3143,10 +3143,6 @@ static int ca8210_probe(struct spi_device *spi_device) pdata = kmalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) { - dev_crit( - &spi_device->dev, - "Could not allocate platform data\n" - ); ret = -ENOMEM; goto error; } diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index cdc347be68f2..b79513b8322f 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -588,8 +588,6 @@ static void count_tx(struct net_device *dev, int ret, int len) stats->tx_packets++; stats->tx_bytes += len; u64_stats_update_end(&stats->syncp); - } else { - dev->stats.tx_dropped++; } } @@ -742,7 +740,12 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb, macsec_fill_iv(iv, secy->sci, pn); sg_init_table(sg, ret); - skb_to_sgvec(skb, sg, 0, skb->len); + ret = skb_to_sgvec(skb, sg, 0, skb->len); + if (unlikely(ret < 0)) { + macsec_txsa_put(tx_sa); + kfree_skb(skb); + return ERR_PTR(ret); + } if (tx_sc->encrypt) { int len = skb->len - macsec_hdr_len(sci_present) - @@ -883,7 +886,7 @@ static void macsec_decrypt_done(struct crypto_async_request *base, int err) struct macsec_dev *macsec = macsec_priv(dev); struct macsec_rx_sa *rx_sa = macsec_skb_cb(skb)->rx_sa; struct macsec_rx_sc *rx_sc = rx_sa->sc; - int len, ret; + int len; u32 pn; aead_request_free(macsec_skb_cb(skb)->req); @@ -904,11 +907,8 @@ static void macsec_decrypt_done(struct crypto_async_request *base, int err) macsec_reset_skb(skb, macsec->secy.netdev); len = skb->len; - ret = gro_cells_receive(&macsec->gro_cells, skb); - if (ret == NET_RX_SUCCESS) + if (gro_cells_receive(&macsec->gro_cells, skb) == NET_RX_SUCCESS) count_rx(dev, len); - else - macsec->secy.netdev->stats.rx_dropped++; rcu_read_unlock_bh(); @@ -952,7 +952,11 @@ static struct sk_buff *macsec_decrypt(struct sk_buff *skb, macsec_fill_iv(iv, sci, ntohl(hdr->packet_number)); sg_init_table(sg, ret); - skb_to_sgvec(skb, sg, 0, skb->len); + ret = skb_to_sgvec(skb, sg, 0, skb->len); + if (unlikely(ret < 0)) { + kfree_skb(skb); + return ERR_PTR(ret); + } if (hdr->tci_an & MACSEC_TCI_E) { /* confidentiality: ethernet + macsec header @@ -1037,7 +1041,6 @@ static void handle_not_macsec(struct sk_buff *skb) */ list_for_each_entry_rcu(macsec, &rxd->secys, secys) { struct sk_buff *nskb; - int ret; struct pcpu_secy_stats *secy_stats = this_cpu_ptr(macsec->stats); if (macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) { @@ -1054,13 +1057,10 @@ static void handle_not_macsec(struct sk_buff *skb) nskb->dev = macsec->secy.netdev; - ret = netif_rx(nskb); - if (ret == NET_RX_SUCCESS) { + if (netif_rx(nskb) == NET_RX_SUCCESS) { u64_stats_update_begin(&secy_stats->syncp); secy_stats->stats.InPktsUntagged++; u64_stats_update_end(&secy_stats->syncp); - } else { - macsec->secy.netdev->stats.rx_dropped++; } } diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 6d953c53eed6..44612122338b 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -141,11 +141,9 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) * * The @cmd parameter is expected to have been cleared before calling * mii_ethtool_get_link_ksettings(). - * - * Returns 0 for success, negative on error. */ -int mii_ethtool_get_link_ksettings(struct mii_if_info *mii, - struct ethtool_link_ksettings *cmd) +void mii_ethtool_get_link_ksettings(struct mii_if_info *mii, + struct ethtool_link_ksettings *cmd) { struct net_device *dev = mii->dev; u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0; @@ -227,8 +225,6 @@ int mii_ethtool_get_link_ksettings(struct mii_if_info *mii, lp_advertising); /* ignore maxtxpkt, maxrxpkt for now */ - - return 0; } /** diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index c360dd6ead22..65af31f24f01 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -234,6 +234,11 @@ config CICADA_PHY ---help--- Currently supports the cis8204 +config CORTINA_PHY + tristate "Cortina EDC CDR 10G Ethernet PHY" + ---help--- + Currently supports the CS4340 phy. + config DAVICOM_PHY tristate "Davicom PHYs" ---help--- @@ -287,6 +292,11 @@ config MARVELL_PHY ---help--- Currently has a driver for the 88E1011S +config MARVELL_10G_PHY + tristate "Marvell Alaska 10Gbit PHYs" + ---help--- + Support for the Marvell Alaska MV88X3310 and compatible PHYs. + config MESON_GXL_PHY tristate "Amlogic Meson GXL Internal PHY" depends on ARCH_MESON || COMPILE_TEST diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index e36db9a2ba38..8e9b9f349384 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -1,6 +1,6 @@ # Makefile for Linux PHY drivers and MDIO bus drivers -libphy-y := phy.o phy-core.o phy_device.o +libphy-y := phy.o phy-c45.o phy-core.o phy_device.o mdio-bus-y += mdio_bus.o mdio_device.o ifdef CONFIG_MDIO_DEVICE @@ -46,6 +46,7 @@ obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o obj-$(CONFIG_CICADA_PHY) += cicada.o +obj-$(CONFIG_CORTINA_PHY) += cortina.o obj-$(CONFIG_DAVICOM_PHY) += davicom.o obj-$(CONFIG_DP83640_PHY) += dp83640.o obj-$(CONFIG_DP83848_PHY) += dp83848.o @@ -56,6 +57,7 @@ obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o obj-$(CONFIG_LXT_PHY) += lxt.o obj-$(CONFIG_MARVELL_PHY) += marvell.o +obj-$(CONFIG_MARVELL_10G_PHY) += marvell10g.o obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o obj-$(CONFIG_MICREL_PHY) += micrel.o diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index a32dc5d11e89..1e9ad30a35c8 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -540,7 +540,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5411", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -551,7 +551,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5421", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -562,7 +562,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM54210E", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -573,7 +573,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5461", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -584,7 +584,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM54612E", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -595,7 +595,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM54616S", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -606,7 +606,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5464", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -617,7 +617,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5481", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = bcm5481_config_aneg, .read_status = genphy_read_status, @@ -628,7 +628,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM54810", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = bcm5481_config_aneg, .read_status = genphy_read_status, @@ -639,7 +639,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5482", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm5482_config_init, .config_aneg = genphy_config_aneg, .read_status = bcm5482_read_status, @@ -650,7 +650,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM50610", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -661,7 +661,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM50610M", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -672,7 +672,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM57780", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -683,7 +683,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCMAC131", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = brcm_fet_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -694,7 +694,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5241", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = brcm_fet_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c new file mode 100644 index 000000000000..72f4228a63bb --- /dev/null +++ b/drivers/net/phy/cortina.c @@ -0,0 +1,118 @@ +/* + * Copyright 2017 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * CORTINA is a registered trademark of Cortina Systems, Inc. + * + */ +#include <linux/module.h> +#include <linux/phy.h> + +#define PHY_ID_CS4340 0x13e51002 + +#define VILLA_GLOBAL_CHIP_ID_LSB 0x0 +#define VILLA_GLOBAL_CHIP_ID_MSB 0x1 + +#define VILLA_GLOBAL_GPIO_1_INTS 0x017 + +static int cortina_read_reg(struct phy_device *phydev, u16 regnum) +{ + return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, + MII_ADDR_C45 | regnum); +} + +static int cortina_config_aneg(struct phy_device *phydev) +{ + phydev->supported = SUPPORTED_10000baseT_Full; + phydev->advertising = SUPPORTED_10000baseT_Full; + + return 0; +} + +static int cortina_read_status(struct phy_device *phydev) +{ + int gpio_int_status, ret = 0; + + gpio_int_status = cortina_read_reg(phydev, VILLA_GLOBAL_GPIO_1_INTS); + if (gpio_int_status < 0) { + ret = gpio_int_status; + goto err; + } + + if (gpio_int_status & 0x8) { + /* up when edc_convergedS set */ + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + phydev->link = 1; + } else { + phydev->link = 0; + } + +err: + return ret; +} + +static int cortina_soft_reset(struct phy_device *phydev) +{ + return 0; +} + +static int cortina_probe(struct phy_device *phydev) +{ + u32 phy_id = 0; + int id_lsb = 0, id_msb = 0; + + /* Read device id from phy registers. */ + id_lsb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_LSB); + if (id_lsb < 0) + return -ENXIO; + + phy_id = id_lsb << 16; + + id_msb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_MSB); + if (id_msb < 0) + return -ENXIO; + + phy_id |= id_msb; + + /* Make sure the device tree binding matched the driver with the + * right device. + */ + if (phy_id != phydev->drv->phy_id) { + phydev_err(phydev, "Error matching phy with %s driver\n", + phydev->drv->name); + return -ENODEV; + } + + return 0; +} + +static struct phy_driver cortina_driver[] = { +{ + .phy_id = PHY_ID_CS4340, + .phy_id_mask = 0xffffffff, + .name = "Cortina CS4340", + .config_aneg = cortina_config_aneg, + .read_status = cortina_read_status, + .soft_reset = cortina_soft_reset, + .probe = cortina_probe, +}, +}; + +module_phy_driver(cortina_driver); + +static struct mdio_device_id __maybe_unused cortina_tbl[] = { + { PHY_ID_CS4340, 0xffffffff}, + {}, +}; + +MODULE_DEVICE_TABLE(mdio, cortina_tbl); diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 57297ba23987..4c5246fed69b 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -41,6 +41,12 @@ #include <linux/uaccess.h> #define MII_MARVELL_PHY_PAGE 22 +#define MII_MARVELL_COPPER_PAGE 0x00 +#define MII_MARVELL_FIBER_PAGE 0x01 +#define MII_MARVELL_MSCR_PAGE 0x02 +#define MII_MARVELL_LED_PAGE 0x03 +#define MII_MARVELL_MISC_TEST_PAGE 0x06 +#define MII_MARVELL_WOL_PAGE 0x11 #define MII_M1011_IEVENT 0x13 #define MII_M1011_IEVENT_CLEAR 0x0000 @@ -54,7 +60,6 @@ #define MII_M1011_PHY_SCR_MDI_X 0x0020 #define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060 -#define MII_M1145_PHY_EXT_ADDR_PAGE 0x16 #define MII_M1145_PHY_EXT_SR 0x1b #define MII_M1145_PHY_EXT_CR 0x14 #define MII_M1145_RGMII_RX_DELAY 0x0080 @@ -83,10 +88,6 @@ #define MII_M1111_HWCFG_FIBER_COPPER_AUTO 0x8000 #define MII_M1111_HWCFG_FIBER_COPPER_RES 0x2000 -#define MII_M1111_COPPER 0 -#define MII_M1111_FIBER 1 - -#define MII_88E1121_PHY_MSCR_PAGE 2 #define MII_88E1121_PHY_MSCR_REG 21 #define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5) #define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4) @@ -112,7 +113,6 @@ #define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7) /* LED Timer Control Register */ -#define MII_88E1318S_PHY_LED_PAGE 0x03 #define MII_88E1318S_PHY_LED_TCR 0x12 #define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) #define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) @@ -123,13 +123,11 @@ #define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18 #define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19 -#define MII_88E1318S_PHY_WOL_PAGE 0x11 #define MII_88E1318S_PHY_WOL_CTRL 0x10 #define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12) #define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14) #define MII_88E1121_PHY_LED_CTRL 16 -#define MII_88E1121_PHY_LED_PAGE 3 #define MII_88E1121_PHY_LED_DEF 0x0030 #define MII_M1011_PHY_STATUS 0x11 @@ -189,6 +187,29 @@ struct marvell_priv { struct device *hwmon_dev; }; +static int marvell_get_page(struct phy_device *phydev) +{ + return phy_read(phydev, MII_MARVELL_PHY_PAGE); +} + +static int marvell_set_page(struct phy_device *phydev, int page) +{ + return phy_write(phydev, MII_MARVELL_PHY_PAGE, page); +} + +static int marvell_get_set_page(struct phy_device *phydev, int page) +{ + int oldpage = marvell_get_page(phydev); + + if (oldpage < 0) + return oldpage; + + if (page != oldpage) + return marvell_set_page(phydev, page); + + return 0; +} + static int marvell_ack_interrupt(struct phy_device *phydev) { int err; @@ -207,9 +228,11 @@ static int marvell_config_intr(struct phy_device *phydev) int err; if (phydev->interrupts == PHY_INTERRUPT_ENABLED) - err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT); + err = phy_write(phydev, MII_M1011_IMASK, + MII_M1011_IMASK_INIT); else - err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); + err = phy_write(phydev, MII_M1011_IMASK, + MII_M1011_IMASK_CLEAR); return err; } @@ -271,8 +294,7 @@ static int marvell_config_aneg(struct phy_device *phydev) if (phydev->autoneg != AUTONEG_ENABLE) { int bmcr; - /* - * A write to speed/duplex bits (that is performed by + /* A write to speed/duplex bits (that is performed by * genphy_config_aneg() call above) must be followed by * a software reset. Otherwise, the write has no effect. */ @@ -367,8 +389,7 @@ static int m88e1111_config_aneg(struct phy_device *phydev) } #ifdef CONFIG_OF_MDIO -/* - * Set and/or override some configuration registers based on the +/* Set and/or override some configuration registers based on the * marvell,reg-init property stored in the of_node for the phydev. * * marvell,reg-init = <reg-page reg mask value>,...; @@ -394,7 +415,7 @@ static int marvell_of_reg_init(struct phy_device *phydev) if (!paddr || len < (4 * sizeof(*paddr))) return 0; - saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE); + saved_page = marvell_get_page(phydev); if (saved_page < 0) return saved_page; current_page = saved_page; @@ -402,15 +423,15 @@ static int marvell_of_reg_init(struct phy_device *phydev) ret = 0; len /= sizeof(*paddr); for (i = 0; i < len - 3; i += 4) { - u16 reg_page = be32_to_cpup(paddr + i); + u16 page = be32_to_cpup(paddr + i); u16 reg = be32_to_cpup(paddr + i + 1); u16 mask = be32_to_cpup(paddr + i + 2); u16 val_bits = be32_to_cpup(paddr + i + 3); int val; - if (reg_page != current_page) { - current_page = reg_page; - ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page); + if (page != current_page) { + current_page = page; + ret = marvell_set_page(phydev, page); if (ret < 0) goto err; } @@ -429,11 +450,10 @@ static int marvell_of_reg_init(struct phy_device *phydev) ret = phy_write(phydev, reg, val); if (ret < 0) goto err; - } err: if (current_page != saved_page) { - i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page); + i = marvell_set_page(phydev, saved_page); if (ret == 0) ret = i; } @@ -450,15 +470,11 @@ static int m88e1121_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1121_PHY_MSCR_PAGE); - if (err < 0) - return err; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MSCR_PAGE); + if (oldpage < 0) + return oldpage; if (phy_interface_is_rgmii(phydev)) { - mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) & MII_88E1121_PHY_MSCR_DELAY_MASK; @@ -475,7 +491,7 @@ static int m88e1121_config_aneg(struct phy_device *phydev) return err; } - phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + marvell_set_page(phydev, oldpage); err = phy_write(phydev, MII_BMCR, BMCR_RESET); if (err < 0) @@ -493,12 +509,9 @@ static int m88e1318_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1121_PHY_MSCR_PAGE); - if (err < 0) - return err; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MSCR_PAGE); + if (oldpage < 0) + return oldpage; mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG); mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD; @@ -507,7 +520,7 @@ static int m88e1318_config_aneg(struct phy_device *phydev) if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + err = marvell_set_page(phydev, oldpage); if (err < 0) return err; @@ -607,7 +620,7 @@ static int m88e1510_config_aneg(struct phy_device *phydev) { int err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) goto error; @@ -617,7 +630,7 @@ static int m88e1510_config_aneg(struct phy_device *phydev) goto error; /* Then the fiber link */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; @@ -625,10 +638,10 @@ static int m88e1510_config_aneg(struct phy_device *phydev) if (err < 0) goto error; - return phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); error: - phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); return err; } @@ -651,7 +664,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) mdelay(500); - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; @@ -663,7 +676,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 2); + err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); if (err < 0) return err; temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC); @@ -672,7 +685,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp); if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; @@ -706,103 +719,129 @@ static int m88e3016_config_init(struct phy_device *phydev) return marvell_config_init(phydev); } -static int m88e1111_config_init(struct phy_device *phydev) +static int m88e1111_config_init_rgmii(struct phy_device *phydev) { int err; int temp; - if (phy_interface_is_rgmii(phydev)) { + temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); + if (temp < 0) + return temp; - temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); - if (temp < 0) - return temp; + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { + temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); + } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { + temp &= ~MII_M1111_TX_DELAY; + temp |= MII_M1111_RX_DELAY; + } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { + temp &= ~MII_M1111_RX_DELAY; + temp |= MII_M1111_TX_DELAY; + } - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { - temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); - } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { - temp &= ~MII_M1111_TX_DELAY; - temp |= MII_M1111_RX_DELAY; - } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { - temp &= ~MII_M1111_RX_DELAY; - temp |= MII_M1111_TX_DELAY; - } + err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); + if (err < 0) + return err; - err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); - if (err < 0) - return err; + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + if (temp < 0) + return temp; - temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); - if (temp < 0) - return temp; + temp &= ~(MII_M1111_HWCFG_MODE_MASK); - temp &= ~(MII_M1111_HWCFG_MODE_MASK); + if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) + temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; + else + temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; - if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) - temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; - else - temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; + return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); +} - err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); - if (err < 0) - return err; - } +static int m88e1111_config_init_sgmii(struct phy_device *phydev) +{ + int err; + int temp; - if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { - temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); - if (temp < 0) - return temp; + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + if (temp < 0) + return temp; - temp &= ~(MII_M1111_HWCFG_MODE_MASK); - temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK; - temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; + temp &= ~(MII_M1111_HWCFG_MODE_MASK); + temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK; + temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; - err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); - if (err < 0) - return err; + err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); + if (err < 0) + return err; - /* make sure copper is selected */ - err = phy_read(phydev, MII_M1145_PHY_EXT_ADDR_PAGE); - if (err < 0) - return err; + /* make sure copper is selected */ + return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); +} - err = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, - err & (~0xff)); - if (err < 0) - return err; - } +static int m88e1111_config_init_rtbi(struct phy_device *phydev) +{ + int err; + int temp; - if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { - temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); - if (temp < 0) - return temp; - temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); - err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); - if (err < 0) - return err; + temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); + if (temp < 0) + return temp; - temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); - if (temp < 0) - return temp; - temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES); - temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO; - err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); - if (err < 0) + temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); + err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); + if (err < 0) + return err; + + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + if (temp < 0) + return temp; + + temp &= ~(MII_M1111_HWCFG_MODE_MASK | + MII_M1111_HWCFG_FIBER_COPPER_RES); + temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO; + + err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); + if (err < 0) + return err; + + /* soft reset */ + err = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (err < 0) + return err; + + do + temp = phy_read(phydev, MII_BMCR); + while (temp & BMCR_RESET); + + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + if (temp < 0) + return temp; + + temp &= ~(MII_M1111_HWCFG_MODE_MASK | + MII_M1111_HWCFG_FIBER_COPPER_RES); + temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | + MII_M1111_HWCFG_FIBER_COPPER_AUTO; + + return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); +} + +static int m88e1111_config_init(struct phy_device *phydev) +{ + int err; + + if (phy_interface_is_rgmii(phydev)) { + err = m88e1111_config_init_rgmii(phydev); + if (err) return err; + } - /* soft reset */ - err = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { + err = m88e1111_config_init_sgmii(phydev); if (err < 0) return err; - do - temp = phy_read(phydev, MII_BMCR); - while (temp & BMCR_RESET); + } - temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); - if (temp < 0) - return temp; - temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES); - temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO; - err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); + if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { + err = m88e1111_config_init_rtbi(phydev); if (err < 0) return err; } @@ -818,11 +857,9 @@ static int m88e1121_config_init(struct phy_device *phydev) { int err, oldpage; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE); - if (err < 0) - return err; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_LED_PAGE); + if (oldpage < 0) + return oldpage; /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */ err = phy_write(phydev, MII_88E1121_PHY_LED_CTRL, @@ -830,7 +867,7 @@ static int m88e1121_config_init(struct phy_device *phydev) if (err < 0) return err; - phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + marvell_set_page(phydev, oldpage); /* Set marvell,reg-init configuration from device tree */ return marvell_config_init(phydev); @@ -844,7 +881,7 @@ static int m88e1510_config_init(struct phy_device *phydev) /* SGMII-to-Copper mode initialization */ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { /* Select page 18 */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 18); + err = marvell_set_page(phydev, 18); if (err < 0) return err; @@ -863,7 +900,7 @@ static int m88e1510_config_init(struct phy_device *phydev) return err; /* Reset page selection */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; } @@ -893,7 +930,7 @@ static int m88e1118_config_init(struct phy_device *phydev) int err; /* Change address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); + err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); if (err < 0) return err; @@ -903,7 +940,7 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Change address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003); + err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); if (err < 0) return err; @@ -920,7 +957,7 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Reset address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; @@ -932,7 +969,7 @@ static int m88e1149_config_init(struct phy_device *phydev) int err; /* Change address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); + err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); if (err < 0) return err; @@ -946,17 +983,70 @@ static int m88e1149_config_init(struct phy_device *phydev) return err; /* Reset address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; return phy_write(phydev, MII_BMCR, BMCR_RESET); } +static int m88e1145_config_init_rgmii(struct phy_device *phydev) +{ + int err; + int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR); + + if (temp < 0) + return temp; + + temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY); + + err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp); + if (err < 0) + return err; + + if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { + err = phy_write(phydev, 0x1d, 0x0012); + if (err < 0) + return err; + + temp = phy_read(phydev, 0x1e); + if (temp < 0) + return temp; + + temp &= 0xf03f; + temp |= 2 << 9; /* 36 ohm */ + temp |= 2 << 6; /* 39 ohm */ + + err = phy_write(phydev, 0x1e, temp); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1d, 0x3); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0x8000); + } + return err; +} + +static int m88e1145_config_init_sgmii(struct phy_device *phydev) +{ + int temp = phy_read(phydev, MII_M1145_PHY_EXT_SR); + + if (temp < 0) + return temp; + + temp &= ~MII_M1145_HWCFG_MODE_MASK; + temp |= MII_M1145_HWCFG_MODE_SGMII_NO_CLK; + temp |= MII_M1145_HWCFG_FIBER_COPPER_AUTO; + + return phy_write(phydev, MII_M1145_PHY_EXT_SR, temp); +} + static int m88e1145_config_init(struct phy_device *phydev) { int err; - int temp; /* Take care of errata E0 & E1 */ err = phy_write(phydev, 0x1d, 0x001b); @@ -976,53 +1066,13 @@ static int m88e1145_config_init(struct phy_device *phydev) return err; if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { - int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR); - if (temp < 0) - return temp; - - temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY); - - err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp); + err = m88e1145_config_init_rgmii(phydev); if (err < 0) return err; - - if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { - err = phy_write(phydev, 0x1d, 0x0012); - if (err < 0) - return err; - - temp = phy_read(phydev, 0x1e); - if (temp < 0) - return temp; - - temp &= 0xf03f; - temp |= 2 << 9; /* 36 ohm */ - temp |= 2 << 6; /* 39 ohm */ - - err = phy_write(phydev, 0x1e, temp); - if (err < 0) - return err; - - err = phy_write(phydev, 0x1d, 0x3); - if (err < 0) - return err; - - err = phy_write(phydev, 0x1e, 0x8000); - if (err < 0) - return err; - } } if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { - temp = phy_read(phydev, MII_M1145_PHY_EXT_SR); - if (temp < 0) - return temp; - - temp &= ~MII_M1145_HWCFG_MODE_MASK; - temp |= MII_M1145_HWCFG_MODE_SGMII_NO_CLK; - temp |= MII_M1145_HWCFG_FIBER_COPPER_AUTO; - - err = phy_write(phydev, MII_M1145_PHY_EXT_SR, temp); + err = m88e1145_config_init_sgmii(phydev); if (err < 0) return err; } @@ -1065,7 +1115,8 @@ static int marvell_update_link(struct phy_device *phydev, int fiber) int status; /* Use the generic register for copper link, or specific - * register for fiber case */ + * register for fiber case + */ if (fiber) { status = phy_read(phydev, MII_M1011_PHY_STATUS); if (status < 0) @@ -1082,123 +1133,143 @@ static int marvell_update_link(struct phy_device *phydev, int fiber) return 0; } -/* marvell_read_status_page - * - * Description: - * Check the link, then figure out the current state - * by comparing what we advertise with what the link partner - * advertises. Start by checking the gigabit possibilities, - * then move on to 10/100. - */ -static int marvell_read_status_page(struct phy_device *phydev, int page) +static int marvell_read_status_page_an(struct phy_device *phydev, + int fiber) { - int adv; - int err; + int status; int lpa; int lpagb; - int status = 0; - int fiber; + int adv; - /* Detect and update the link, but return if there - * was an error */ - if (page == MII_M1111_FIBER) - fiber = 1; - else - fiber = 0; + status = phy_read(phydev, MII_M1011_PHY_STATUS); + if (status < 0) + return status; - err = marvell_update_link(phydev, fiber); - if (err) - return err; + lpa = phy_read(phydev, MII_LPA); + if (lpa < 0) + return lpa; - if (AUTONEG_ENABLE == phydev->autoneg) { - status = phy_read(phydev, MII_M1011_PHY_STATUS); - if (status < 0) - return status; - - lpa = phy_read(phydev, MII_LPA); - if (lpa < 0) - return lpa; + lpagb = phy_read(phydev, MII_STAT1000); + if (lpagb < 0) + return lpagb; - lpagb = phy_read(phydev, MII_STAT1000); - if (lpagb < 0) - return lpagb; + adv = phy_read(phydev, MII_ADVERTISE); + if (adv < 0) + return adv; - adv = phy_read(phydev, MII_ADVERTISE); - if (adv < 0) - return adv; + lpa &= adv; - if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) - phydev->duplex = DUPLEX_FULL; - else - phydev->duplex = DUPLEX_HALF; + if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; - status = status & MII_M1011_PHY_STATUS_SPD_MASK; - phydev->pause = phydev->asym_pause = 0; + status = status & MII_M1011_PHY_STATUS_SPD_MASK; + phydev->pause = 0; + phydev->asym_pause = 0; - switch (status) { - case MII_M1011_PHY_STATUS_1000: - phydev->speed = SPEED_1000; - break; + switch (status) { + case MII_M1011_PHY_STATUS_1000: + phydev->speed = SPEED_1000; + break; - case MII_M1011_PHY_STATUS_100: - phydev->speed = SPEED_100; - break; + case MII_M1011_PHY_STATUS_100: + phydev->speed = SPEED_100; + break; - default: - phydev->speed = SPEED_10; - break; - } + default: + phydev->speed = SPEED_10; + break; + } - if (!fiber) { - phydev->lp_advertising = mii_stat1000_to_ethtool_lpa_t(lpagb) | - mii_lpa_to_ethtool_lpa_t(lpa); + if (!fiber) { + phydev->lp_advertising = + mii_stat1000_to_ethtool_lpa_t(lpagb) | + mii_lpa_to_ethtool_lpa_t(lpa); - if (phydev->duplex == DUPLEX_FULL) { - phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; - phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; - } - } else { - /* The fiber link is only 1000M capable */ - phydev->lp_advertising = fiber_lpa_to_ethtool_lpa_t(lpa); - - if (phydev->duplex == DUPLEX_FULL) { - if (!(lpa & LPA_PAUSE_FIBER)) { - phydev->pause = 0; - phydev->asym_pause = 0; - } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { - phydev->pause = 1; - phydev->asym_pause = 1; - } else { - phydev->pause = 1; - phydev->asym_pause = 0; - } - } + if (phydev->duplex == DUPLEX_FULL) { + phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; + phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; } } else { - int bmcr = phy_read(phydev, MII_BMCR); + /* The fiber link is only 1000M capable */ + phydev->lp_advertising = fiber_lpa_to_ethtool_lpa_t(lpa); + + if (phydev->duplex == DUPLEX_FULL) { + if (!(lpa & LPA_PAUSE_FIBER)) { + phydev->pause = 0; + phydev->asym_pause = 0; + } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { + phydev->pause = 1; + phydev->asym_pause = 1; + } else { + phydev->pause = 1; + phydev->asym_pause = 0; + } + } + } + return 0; +} - if (bmcr < 0) - return bmcr; +static int marvell_read_status_page_fixed(struct phy_device *phydev) +{ + int bmcr = phy_read(phydev, MII_BMCR); - if (bmcr & BMCR_FULLDPLX) - phydev->duplex = DUPLEX_FULL; - else - phydev->duplex = DUPLEX_HALF; + if (bmcr < 0) + return bmcr; - if (bmcr & BMCR_SPEED1000) - phydev->speed = SPEED_1000; - else if (bmcr & BMCR_SPEED100) - phydev->speed = SPEED_100; - else - phydev->speed = SPEED_10; + if (bmcr & BMCR_FULLDPLX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; - phydev->pause = phydev->asym_pause = 0; - phydev->lp_advertising = 0; - } + if (bmcr & BMCR_SPEED1000) + phydev->speed = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + phydev->speed = SPEED_100; + else + phydev->speed = SPEED_10; + + phydev->pause = 0; + phydev->asym_pause = 0; + phydev->lp_advertising = 0; return 0; } +/* marvell_read_status_page + * + * Description: + * Check the link, then figure out the current state + * by comparing what we advertise with what the link partner + * advertises. Start by checking the gigabit possibilities, + * then move on to 10/100. + */ +static int marvell_read_status_page(struct phy_device *phydev, int page) +{ + int fiber; + int err; + + /* Detect and update the link, but return if there + * was an error + */ + if (page == MII_MARVELL_FIBER_PAGE) + fiber = 1; + else + fiber = 0; + + err = marvell_update_link(phydev, fiber); + if (err) + return err; + + if (phydev->autoneg == AUTONEG_ENABLE) + err = marvell_read_status_page_an(phydev, fiber); + else + err = marvell_read_status_page_fixed(phydev); + + return err; +} + /* marvell_read_status * * Some Marvell's phys have two modes: fiber and copper. @@ -1215,33 +1286,34 @@ static int marvell_read_status(struct phy_device *phydev) /* Check the fiber mode first */ if (phydev->supported & SUPPORTED_FIBRE && phydev->interface != PHY_INTERFACE_MODE_SGMII) { - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; - err = marvell_read_status_page(phydev, MII_M1111_FIBER); + err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; - /* If the fiber link is up, it is the selected and used link. - * In this case, we need to stay in the fiber page. - * Please to be careful about that, avoid to restore Copper page - * in other functions which could break the behaviour - * for some fiber phy like 88E1512. - * */ + /* If the fiber link is up, it is the selected and + * used link. In this case, we need to stay in the + * fiber page. Please to be careful about that, avoid + * to restore Copper page in other functions which + * could break the behaviour for some fiber phy like + * 88E1512. + */ if (phydev->link) return 0; /* If fiber link is down, check and save copper mode state */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) goto error; } - return marvell_read_status_page(phydev, MII_M1111_COPPER); + return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE); error: - phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); return err; } @@ -1256,7 +1328,7 @@ static int marvell_suspend(struct phy_device *phydev) /* Suspend the fiber mode first */ if (!(phydev->supported & SUPPORTED_FIBRE)) { - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; @@ -1266,7 +1338,7 @@ static int marvell_suspend(struct phy_device *phydev) goto error; /* Then, the copper link */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) goto error; } @@ -1275,7 +1347,7 @@ static int marvell_suspend(struct phy_device *phydev) return genphy_suspend(phydev); error: - phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); return err; } @@ -1290,7 +1362,7 @@ static int marvell_resume(struct phy_device *phydev) /* Resume the fiber mode first */ if (!(phydev->supported & SUPPORTED_FIBRE)) { - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; @@ -1300,7 +1372,7 @@ static int marvell_resume(struct phy_device *phydev) goto error; /* Then, the copper link */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) goto error; } @@ -1309,13 +1381,14 @@ static int marvell_resume(struct phy_device *phydev) return genphy_resume(phydev); error: - phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); return err; } static int marvell_aneg_done(struct phy_device *phydev) { int retval = phy_read(phydev, MII_M1011_PHY_STATUS); + return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED); } @@ -1331,32 +1404,33 @@ static int m88e1121_did_interrupt(struct phy_device *phydev) return 0; } -static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) +static void m88e1318_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) { wol->supported = WAKE_MAGIC; wol->wolopts = 0; - if (phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1318S_PHY_WOL_PAGE) < 0) + if (marvell_set_page(phydev, MII_MARVELL_WOL_PAGE) < 0) return; if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) wol->wolopts |= WAKE_MAGIC; - if (phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00) < 0) + if (marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE) < 0) return; } -static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) +static int m88e1318_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) { int err, oldpage, temp; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); + oldpage = marvell_get_page(phydev); if (wol->wolopts & WAKE_MAGIC) { /* Explicitly switch to page 0x00, just to be sure */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; @@ -1367,8 +1441,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1318S_PHY_LED_PAGE); + err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); if (err < 0) return err; @@ -1381,8 +1454,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1318S_PHY_WOL_PAGE); + err = marvell_set_page(phydev, MII_MARVELL_WOL_PAGE); if (err < 0) return err; @@ -1411,8 +1483,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w if (err < 0) return err; } else { - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1318S_PHY_WOL_PAGE); + err = marvell_set_page(phydev, MII_MARVELL_WOL_PAGE); if (err < 0) return err; @@ -1425,7 +1496,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w return err; } - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + err = marvell_set_page(phydev, oldpage); if (err < 0) return err; @@ -1457,13 +1528,11 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i) { struct marvell_hw_stat stat = marvell_hw_stats[i]; struct marvell_priv *priv = phydev->priv; - int err, oldpage, val; + int oldpage, val; u64 ret; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - stat.page); - if (err < 0) + oldpage = marvell_get_set_page(phydev, stat.page); + if (oldpage < 0) return UINT64_MAX; val = phy_read(phydev, stat.reg); @@ -1475,7 +1544,7 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i) ret = priv->stats[i]; } - phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + marvell_set_page(phydev, oldpage); return ret; } @@ -1492,6 +1561,7 @@ static void marvell_get_stats(struct phy_device *phydev, #ifdef CONFIG_HWMON static int m88e1121_get_temp(struct phy_device *phydev, long *temp) { + int oldpage; int ret; int val; @@ -1499,9 +1569,11 @@ static int m88e1121_get_temp(struct phy_device *phydev, long *temp) mutex_lock(&phydev->lock); - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); - if (ret < 0) - goto error; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } /* Enable temperature sensor */ ret = phy_read(phydev, MII_88E1121_MISC_TEST); @@ -1531,7 +1603,7 @@ static int m88e1121_get_temp(struct phy_device *phydev, long *temp) *temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000; error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; @@ -1608,15 +1680,18 @@ static const struct hwmon_chip_info m88e1121_hwmon_chip_info = { static int m88e1510_get_temp(struct phy_device *phydev, long *temp) { + int oldpage; int ret; *temp = 0; mutex_lock(&phydev->lock); - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); - if (ret < 0) - goto error; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } ret = phy_read(phydev, MII_88E1510_TEMP_SENSOR); if (ret < 0) @@ -1625,23 +1700,26 @@ static int m88e1510_get_temp(struct phy_device *phydev, long *temp) *temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000; error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; } -int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) +static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) { + int oldpage; int ret; *temp = 0; mutex_lock(&phydev->lock); - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); - if (ret < 0) - goto error; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } ret = phy_read(phydev, MII_88E1121_MISC_TEST); if (ret < 0) @@ -1653,21 +1731,24 @@ int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) *temp *= 1000; error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; } -int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) +static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) { + int oldpage; int ret; mutex_lock(&phydev->lock); - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); - if (ret < 0) - goto error; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } ret = phy_read(phydev, MII_88E1121_MISC_TEST); if (ret < 0) @@ -1680,23 +1761,26 @@ int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) (temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT)); error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; } -int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) +static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) { + int oldpage; int ret; *alarm = false; mutex_lock(&phydev->lock); - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); - if (ret < 0) - goto error; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } ret = phy_read(phydev, MII_88E1121_MISC_TEST); if (ret < 0) @@ -1704,7 +1788,7 @@ int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ); error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c new file mode 100644 index 000000000000..aebc08beceba --- /dev/null +++ b/drivers/net/phy/marvell10g.c @@ -0,0 +1,368 @@ +/* + * Marvell 10G 88x3310 PHY driver + * + * Based upon the ID registers, this PHY appears to be a mixture of IPs + * from two different companies. + * + * There appears to be several different data paths through the PHY which + * are automatically managed by the PHY. The following has been determined + * via observation and experimentation: + * + * SGMII PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for <= 1G) + * 10GBASE-KR PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for 10G) + * 10GBASE-KR PHYXS -- BASE-R PCS -- Fiber + * + * If both the fiber and copper ports are connected, the first to gain + * link takes priority and the other port is completely locked out. + */ +#include <linux/phy.h> + +enum { + MV_PCS_BASE_T = 0x0000, + MV_PCS_BASE_R = 0x1000, + MV_PCS_1000BASEX = 0x2000, + + /* These registers appear at 0x800X and 0xa00X - the 0xa00X control + * registers appear to set themselves to the 0x800X when AN is + * restarted, but status registers appear readable from either. + */ + MV_AN_CTRL1000 = 0x8000, /* 1000base-T control register */ + MV_AN_STAT1000 = 0x8001, /* 1000base-T status register */ + + /* This register appears to reflect the copper status */ + MV_AN_RESULT = 0xa016, + MV_AN_RESULT_SPD_10 = BIT(12), + MV_AN_RESULT_SPD_100 = BIT(13), + MV_AN_RESULT_SPD_1000 = BIT(14), + MV_AN_RESULT_SPD_10000 = BIT(15), +}; + +static int mv3310_modify(struct phy_device *phydev, int devad, u16 reg, + u16 mask, u16 bits) +{ + int old, val, ret; + + old = phy_read_mmd(phydev, devad, reg); + if (old < 0) + return old; + + val = (old & ~mask) | (bits & mask); + if (val == old) + return 0; + + ret = phy_write_mmd(phydev, devad, reg, val); + + return ret < 0 ? ret : 1; +} + +static int mv3310_probe(struct phy_device *phydev) +{ + u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN; + + if (!phydev->is_c45 || + (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask) + return -ENODEV; + + return 0; +} + +/* + * Resetting the MV88X3310 causes it to become non-responsive. Avoid + * setting the reset bit(s). + */ +static int mv3310_soft_reset(struct phy_device *phydev) +{ + return 0; +} + +static int mv3310_config_init(struct phy_device *phydev) +{ + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, }; + u32 mask; + int val; + + /* Check that the PHY interface type is compatible */ + if (phydev->interface != PHY_INTERFACE_MODE_SGMII && + phydev->interface != PHY_INTERFACE_MODE_XGMII && + phydev->interface != PHY_INTERFACE_MODE_XAUI && + phydev->interface != PHY_INTERFACE_MODE_RXAUI && + phydev->interface != PHY_INTERFACE_MODE_10GKR) + return -ENODEV; + + __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, supported); + __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, supported); + + if (phydev->c45_ids.devices_in_package & MDIO_DEVS_AN) { + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + if (val < 0) + return val; + + if (val & MDIO_AN_STAT1_ABLE) + __set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, supported); + } + + val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT2); + if (val < 0) + return val; + + /* Ethtool does not support the WAN mode bits */ + if (val & (MDIO_PMA_STAT2_10GBSR | MDIO_PMA_STAT2_10GBLR | + MDIO_PMA_STAT2_10GBER | MDIO_PMA_STAT2_10GBLX4 | + MDIO_PMA_STAT2_10GBSW | MDIO_PMA_STAT2_10GBLW | + MDIO_PMA_STAT2_10GBEW)) + __set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported); + if (val & MDIO_PMA_STAT2_10GBSR) + __set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, supported); + if (val & MDIO_PMA_STAT2_10GBLR) + __set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, supported); + if (val & MDIO_PMA_STAT2_10GBER) + __set_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT, supported); + + if (val & MDIO_PMA_STAT2_EXTABLE) { + val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE); + if (val < 0) + return val; + + if (val & (MDIO_PMA_EXTABLE_10GBT | MDIO_PMA_EXTABLE_1000BT | + MDIO_PMA_EXTABLE_100BTX | MDIO_PMA_EXTABLE_10BT)) + __set_bit(ETHTOOL_LINK_MODE_TP_BIT, supported); + if (val & MDIO_PMA_EXTABLE_10GBLRM) + __set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported); + if (val & (MDIO_PMA_EXTABLE_10GBKX4 | MDIO_PMA_EXTABLE_10GBKR | + MDIO_PMA_EXTABLE_1000BKX)) + __set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, supported); + if (val & MDIO_PMA_EXTABLE_10GBLRM) + __set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, + supported); + if (val & MDIO_PMA_EXTABLE_10GBT) + __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, + supported); + if (val & MDIO_PMA_EXTABLE_10GBKX4) + __set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, + supported); + if (val & MDIO_PMA_EXTABLE_10GBKR) + __set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, + supported); + if (val & MDIO_PMA_EXTABLE_1000BT) + __set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + supported); + if (val & MDIO_PMA_EXTABLE_1000BKX) + __set_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, + supported); + if (val & MDIO_PMA_EXTABLE_100BTX) + __set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, + supported); + if (val & MDIO_PMA_EXTABLE_10BT) + __set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, + supported); + } + + if (!ethtool_convert_link_mode_to_legacy_u32(&mask, supported)) + dev_warn(&phydev->mdio.dev, + "PHY supports (%*pb) more modes than phylib supports, some modes not supported.\n", + __ETHTOOL_LINK_MODE_MASK_NBITS, supported); + + phydev->supported &= mask; + phydev->advertising &= phydev->supported; + + return 0; +} + +static int mv3310_config_aneg(struct phy_device *phydev) +{ + bool changed = false; + u32 advertising; + int ret; + + if (phydev->autoneg == AUTONEG_DISABLE) { + ret = genphy_c45_pma_setup_forced(phydev); + if (ret < 0) + return ret; + + return genphy_c45_an_disable_aneg(phydev); + } + + phydev->advertising &= phydev->supported; + advertising = phydev->advertising; + + ret = mv3310_modify(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_100BASE4 | + ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM, + ethtool_adv_to_mii_adv_t(advertising)); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + ret = mv3310_modify(phydev, MDIO_MMD_AN, MV_AN_CTRL1000, + ADVERTISE_1000FULL | ADVERTISE_1000HALF, + ethtool_adv_to_mii_ctrl1000_t(advertising)); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + /* 10G control register */ + ret = mv3310_modify(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV10G, + advertising & ADVERTISED_10000baseT_Full ? + MDIO_AN_10GBT_CTRL_ADV10G : 0); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + if (changed) + ret = genphy_c45_restart_aneg(phydev); + + return ret; +} + +static int mv3310_aneg_done(struct phy_device *phydev) +{ + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1); + if (val < 0) + return val; + + if (val & MDIO_STAT1_LSTATUS) + return 1; + + return genphy_c45_aneg_done(phydev); +} + +/* 10GBASE-ER,LR,LRM,SR do not support autonegotiation. */ +static int mv3310_read_10gbr_status(struct phy_device *phydev) +{ + phydev->link = 1; + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + + if (phydev->interface == PHY_INTERFACE_MODE_SGMII) + phydev->interface = PHY_INTERFACE_MODE_10GKR; + + return 0; +} + +static int mv3310_read_status(struct phy_device *phydev) +{ + u32 mmd_mask = phydev->c45_ids.devices_in_package; + int val; + + /* The vendor devads do not report link status. Avoid the PHYXS + * instance as there are three, and its status depends on the MAC + * being appropriately configured for the negotiated speed. + */ + mmd_mask &= ~(BIT(MDIO_MMD_VEND1) | BIT(MDIO_MMD_VEND2) | + BIT(MDIO_MMD_PHYXS)); + + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->lp_advertising = 0; + phydev->link = 0; + phydev->pause = 0; + phydev->asym_pause = 0; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1); + if (val < 0) + return val; + + if (val & MDIO_STAT1_LSTATUS) + return mv3310_read_10gbr_status(phydev); + + val = genphy_c45_read_link(phydev, mmd_mask); + if (val < 0) + return val; + + phydev->link = val > 0 ? 1 : 0; + + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + if (val < 0) + return val; + + if (val & MDIO_AN_STAT1_COMPLETE) { + val = genphy_c45_read_lpa(phydev); + if (val < 0) + return val; + + /* Read the link partner's 1G advertisment */ + val = phy_read_mmd(phydev, MDIO_MMD_AN, MV_AN_STAT1000); + if (val < 0) + return val; + + phydev->lp_advertising |= mii_stat1000_to_ethtool_lpa_t(val); + + if (phydev->autoneg == AUTONEG_ENABLE) { + val = phy_read_mmd(phydev, MDIO_MMD_AN, MV_AN_RESULT); + if (val < 0) + return val; + + if (val & MV_AN_RESULT_SPD_10000) + phydev->speed = SPEED_10000; + else if (val & MV_AN_RESULT_SPD_1000) + phydev->speed = SPEED_1000; + else if (val & MV_AN_RESULT_SPD_100) + phydev->speed = SPEED_100; + else if (val & MV_AN_RESULT_SPD_10) + phydev->speed = SPEED_10; + + phydev->duplex = DUPLEX_FULL; + } + } + + if (phydev->autoneg != AUTONEG_ENABLE) { + val = genphy_c45_read_pma(phydev); + if (val < 0) + return val; + } + + if ((phydev->interface == PHY_INTERFACE_MODE_SGMII || + phydev->interface == PHY_INTERFACE_MODE_10GKR) && phydev->link) { + /* The PHY automatically switches its serdes interface (and + * active PHYXS instance) between Cisco SGMII and 10GBase-KR + * modes according to the speed. Florian suggests setting + * phydev->interface to communicate this to the MAC. Only do + * this if we are already in either SGMII or 10GBase-KR mode. + */ + if (phydev->speed == SPEED_10000) + phydev->interface = PHY_INTERFACE_MODE_10GKR; + else if (phydev->speed >= SPEED_10 && + phydev->speed < SPEED_10000) + phydev->interface = PHY_INTERFACE_MODE_SGMII; + } + + return 0; +} + +static struct phy_driver mv3310_drivers[] = { + { + .phy_id = 0x002b09aa, + .phy_id_mask = 0xffffffff, + .name = "mv88x3310", + .features = SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_TP | + SUPPORTED_FIBRE | + SUPPORTED_10000baseT_Full | + SUPPORTED_Backplane, + .probe = mv3310_probe, + .soft_reset = mv3310_soft_reset, + .config_init = mv3310_config_init, + .config_aneg = mv3310_config_aneg, + .aneg_done = mv3310_aneg_done, + .read_status = mv3310_read_status, + }, +}; + +module_phy_driver(mv3310_drivers); + +static struct mdio_device_id __maybe_unused mv3310_tbl[] = { + { 0x002b09aa, 0xffffffff }, + { }, +}; +MODULE_DEVICE_TABLE(mdio, mv3310_tbl); +MODULE_DESCRIPTION("Marvell Alaska X 10Gigabit Ethernet PHY driver (MV88X3310)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c index 599ce24c514f..00755b6a42cf 100644 --- a/drivers/net/phy/mdio-mux.c +++ b/drivers/net/phy/mdio-mux.c @@ -133,29 +133,35 @@ int mdio_mux_init(struct device *dev, ret_val = -ENODEV; for_each_available_child_of_node(dev->of_node, child_bus_node) { - u32 v; + int v; - r = of_property_read_u32(child_bus_node, "reg", &v); - if (r) + v = of_mdio_parse_addr(dev, child_bus_node); + if (v < 0) { + dev_err(dev, + "Error: Failed to find reg for child %s\n", + of_node_full_name(child_bus_node)); continue; + } cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL); if (cb == NULL) { dev_err(dev, - "Error: Failed to allocate memory for child\n"); + "Error: Failed to allocate memory for child %s\n", + of_node_full_name(child_bus_node)); ret_val = -ENOMEM; - of_node_put(child_bus_node); - break; + continue; } cb->bus_number = v; cb->parent = pb; cb->mii_bus = mdiobus_alloc(); if (!cb->mii_bus) { + dev_err(dev, + "Error: Failed to allocate MDIO bus for child %s\n", + of_node_full_name(child_bus_node)); ret_val = -ENOMEM; devm_kfree(dev, cb); - of_node_put(child_bus_node); - break; + continue; } cb->mii_bus->priv = cb; @@ -167,6 +173,9 @@ int mdio_mux_init(struct device *dev, cb->mii_bus->write = mdio_mux_write; r = of_mdiobus_register(cb->mii_bus, child_bus_node); if (r) { + dev_err(dev, + "Error: Failed to register MDIO bus for child %s\n", + of_node_full_name(child_bus_node)); mdiobus_free(cb->mii_bus); devm_kfree(dev, cb); } else { @@ -180,6 +189,7 @@ int mdio_mux_init(struct device *dev, return 0; } + dev_err(dev, "Error: No acceptable child buses found\n"); devm_kfree(dev, pb); err_pb_kz: /* balance the reference of_mdio_find_bus() took */ diff --git a/drivers/net/phy/mdio-xgene.c b/drivers/net/phy/mdio-xgene.c index 3e2ac07b6e37..bfd3090fb055 100644 --- a/drivers/net/phy/mdio-xgene.c +++ b/drivers/net/phy/mdio-xgene.c @@ -34,76 +34,73 @@ static bool xgene_mdio_status; -static u32 xgene_enet_rd_mac(void __iomem *base_addr, u32 rd_addr) +u32 xgene_mdio_rd_mac(struct xgene_mdio_pdata *pdata, u32 rd_addr) { void __iomem *addr, *rd, *cmd, *cmd_done; u32 done, rd_data = BUSY_MASK; u8 wait = 10; - addr = base_addr + MAC_ADDR_REG_OFFSET; - rd = base_addr + MAC_READ_REG_OFFSET; - cmd = base_addr + MAC_COMMAND_REG_OFFSET; - cmd_done = base_addr + MAC_COMMAND_DONE_REG_OFFSET; + addr = pdata->mac_csr_addr + MAC_ADDR_REG_OFFSET; + rd = pdata->mac_csr_addr + MAC_READ_REG_OFFSET; + cmd = pdata->mac_csr_addr + MAC_COMMAND_REG_OFFSET; + cmd_done = pdata->mac_csr_addr + MAC_COMMAND_DONE_REG_OFFSET; + spin_lock(&pdata->mac_lock); iowrite32(rd_addr, addr); iowrite32(XGENE_ENET_RD_CMD, cmd); - while (wait--) { - done = ioread32(cmd_done); - if (done) - break; + while (!(done = ioread32(cmd_done)) && wait--) udelay(1); - } - if (!done) - return rd_data; + if (done) + rd_data = ioread32(rd); - rd_data = ioread32(rd); iowrite32(0, cmd); + spin_unlock(&pdata->mac_lock); return rd_data; } +EXPORT_SYMBOL(xgene_mdio_rd_mac); -static void xgene_enet_wr_mac(void __iomem *base_addr, u32 wr_addr, u32 wr_data) +void xgene_mdio_wr_mac(struct xgene_mdio_pdata *pdata, u32 wr_addr, u32 data) { void __iomem *addr, *wr, *cmd, *cmd_done; u8 wait = 10; u32 done; - addr = base_addr + MAC_ADDR_REG_OFFSET; - wr = base_addr + MAC_WRITE_REG_OFFSET; - cmd = base_addr + MAC_COMMAND_REG_OFFSET; - cmd_done = base_addr + MAC_COMMAND_DONE_REG_OFFSET; + addr = pdata->mac_csr_addr + MAC_ADDR_REG_OFFSET; + wr = pdata->mac_csr_addr + MAC_WRITE_REG_OFFSET; + cmd = pdata->mac_csr_addr + MAC_COMMAND_REG_OFFSET; + cmd_done = pdata->mac_csr_addr + MAC_COMMAND_DONE_REG_OFFSET; + spin_lock(&pdata->mac_lock); iowrite32(wr_addr, addr); - iowrite32(wr_data, wr); + iowrite32(data, wr); iowrite32(XGENE_ENET_WR_CMD, cmd); - while (wait--) { - done = ioread32(cmd_done); - if (done) - break; + while (!(done = ioread32(cmd_done)) && wait--) udelay(1); - } if (!done) pr_err("MCX mac write failed, addr: 0x%04x\n", wr_addr); iowrite32(0, cmd); + spin_unlock(&pdata->mac_lock); } +EXPORT_SYMBOL(xgene_mdio_wr_mac); int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg) { - void __iomem *addr = (void __iomem *)bus->priv; + struct xgene_mdio_pdata *pdata = (struct xgene_mdio_pdata *)bus->priv; u32 data, done; u8 wait = 10; data = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg); - xgene_enet_wr_mac(addr, MII_MGMT_ADDRESS_ADDR, data); - xgene_enet_wr_mac(addr, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); + xgene_mdio_wr_mac(pdata, MII_MGMT_ADDRESS_ADDR, data); + xgene_mdio_wr_mac(pdata, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); do { usleep_range(5, 10); - done = xgene_enet_rd_mac(addr, MII_MGMT_INDICATORS_ADDR); + done = xgene_mdio_rd_mac(pdata, MII_MGMT_INDICATORS_ADDR); } while ((done & BUSY_MASK) && wait--); if (done & BUSY_MASK) { @@ -111,8 +108,8 @@ int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg) return -EBUSY; } - data = xgene_enet_rd_mac(addr, MII_MGMT_STATUS_ADDR); - xgene_enet_wr_mac(addr, MII_MGMT_COMMAND_ADDR, 0); + data = xgene_mdio_rd_mac(pdata, MII_MGMT_STATUS_ADDR); + xgene_mdio_wr_mac(pdata, MII_MGMT_COMMAND_ADDR, 0); return data; } @@ -120,17 +117,17 @@ EXPORT_SYMBOL(xgene_mdio_rgmii_read); int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data) { - void __iomem *addr = (void __iomem *)bus->priv; + struct xgene_mdio_pdata *pdata = (struct xgene_mdio_pdata *)bus->priv; u32 val, done; u8 wait = 10; val = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg); - xgene_enet_wr_mac(addr, MII_MGMT_ADDRESS_ADDR, val); + xgene_mdio_wr_mac(pdata, MII_MGMT_ADDRESS_ADDR, val); - xgene_enet_wr_mac(addr, MII_MGMT_CONTROL_ADDR, data); + xgene_mdio_wr_mac(pdata, MII_MGMT_CONTROL_ADDR, data); do { usleep_range(5, 10); - done = xgene_enet_rd_mac(addr, MII_MGMT_INDICATORS_ADDR); + done = xgene_mdio_rd_mac(pdata, MII_MGMT_INDICATORS_ADDR); } while ((done & BUSY_MASK) && wait--); if (done & BUSY_MASK) { @@ -174,8 +171,8 @@ static int xgene_enet_ecc_init(struct xgene_mdio_pdata *pdata) static void xgene_gmac_reset(struct xgene_mdio_pdata *pdata) { - xgene_enet_wr_mac(pdata->mac_csr_addr, MAC_CONFIG_1_ADDR, SOFT_RESET); - xgene_enet_wr_mac(pdata->mac_csr_addr, MAC_CONFIG_1_ADDR, 0); + xgene_mdio_wr_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET); + xgene_mdio_wr_mac(pdata, MAC_CONFIG_1_ADDR, 0); } static int xgene_mdio_reset(struct xgene_mdio_pdata *pdata) @@ -375,6 +372,9 @@ static int xgene_mdio_probe(struct platform_device *pdev) pdata->mdio_csr_addr = csr_base + BLOCK_XG_MDIO_CSR_OFFSET; pdata->diag_csr_addr = csr_base + BLOCK_DIAG_CSR_OFFSET; + if (mdio_id == XGENE_MDIO_RGMII) + spin_lock_init(&pdata->mac_lock); + if (dev->of_node) { pdata->clk = devm_clk_get(dev, NULL); if (IS_ERR(pdata->clk)) { @@ -396,7 +396,7 @@ static int xgene_mdio_probe(struct platform_device *pdev) if (mdio_id == XGENE_MDIO_RGMII) { mdio_bus->read = xgene_mdio_rgmii_read; mdio_bus->write = xgene_mdio_rgmii_write; - mdio_bus->priv = (void __force *)pdata->mac_csr_addr; + mdio_bus->priv = (void __force *)pdata; snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s", "xgene-mii-rgmii"); } else { diff --git a/drivers/net/phy/mdio-xgene.h b/drivers/net/phy/mdio-xgene.h index 594a11d42401..3c85f3e30baa 100644 --- a/drivers/net/phy/mdio-xgene.h +++ b/drivers/net/phy/mdio-xgene.h @@ -102,6 +102,7 @@ struct xgene_mdio_pdata { void __iomem *mdio_csr_addr; struct mii_bus *mdio_bus; int mdio_id; + spinlock_t mac_lock; /* mac lock */ }; /* Set the specified value into a bit-field defined by its starting position @@ -132,6 +133,8 @@ static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src) #define GET_BIT(field, src) \ xgene_enet_get_field_value(field ## _POS, 1, src) +u32 xgene_mdio_rd_mac(struct xgene_mdio_pdata *pdata, u32 rd_addr); +void xgene_mdio_wr_mac(struct xgene_mdio_pdata *pdata, u32 wr_addr, u32 data); int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg); int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data); struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr); diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index f99c21f78b63..4c169dbf9138 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -263,21 +263,10 @@ static void of_mdiobus_link_mdiodev(struct mii_bus *bus, for_each_available_child_of_node(bus->dev.of_node, child) { int addr; - int ret; - ret = of_property_read_u32(child, "reg", &addr); - if (ret < 0) { - dev_err(dev, "%s has invalid MDIO address\n", - child->full_name); + addr = of_mdio_parse_addr(dev, child); + if (addr < 0) continue; - } - - /* A MDIO device must have a reg property in the range [0-31] */ - if (addr >= PHY_MAX_ADDR) { - dev_err(dev, "%s MDIO address %i is too large\n", - child->full_name, addr); - continue; - } if (addr == mdiodev->addr) { dev->of_node = child; diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index b9252b8d81ff..9365b0792309 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -20,6 +20,7 @@ * ksz8081, ksz8091, * ksz8061, * Switch : ksz8873, ksz886x + * ksz9477 */ #include <linux/kernel.h> @@ -793,7 +794,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KS8737", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ks8737_type, .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, @@ -807,7 +808,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = 0x00ffffff, .name = "Micrel KSZ8021 or KSZ8031", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz8021_type, .probe = kszphy_probe, .config_init = kszphy_config_init, @@ -825,7 +826,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = 0x00ffffff, .name = "Micrel KSZ8031", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz8021_type, .probe = kszphy_probe, .config_init = kszphy_config_init, @@ -843,7 +844,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8041", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz8041_type, .probe = kszphy_probe, .config_init = ksz8041_config_init, @@ -861,7 +862,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8041RNLI", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz8041_type, .probe = kszphy_probe, .config_init = kszphy_config_init, @@ -879,7 +880,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8051", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz8051_type, .probe = kszphy_probe, .config_init = kszphy_config_init, @@ -897,7 +898,7 @@ static struct phy_driver ksphy_driver[] = { .name = "Micrel KSZ8001 or KS8721", .phy_id_mask = 0x00fffffc, .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz8041_type, .probe = kszphy_probe, .config_init = kszphy_config_init, @@ -915,7 +916,7 @@ static struct phy_driver ksphy_driver[] = { .name = "Micrel KSZ8081 or KSZ8091", .phy_id_mask = MICREL_PHY_ID_MASK, .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz8081_type, .probe = kszphy_probe, .config_init = kszphy_config_init, @@ -933,7 +934,7 @@ static struct phy_driver ksphy_driver[] = { .name = "Micrel KSZ8061", .phy_id_mask = MICREL_PHY_ID_MASK, .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -946,7 +947,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = 0x000ffffe, .name = "Micrel KSZ9021 Gigabit PHY", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz9021_type, .probe = kszphy_probe, .config_init = ksz9021_config_init, @@ -966,7 +967,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ9031 Gigabit PHY", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz9021_type, .probe = kszphy_probe, .config_init = ksz9031_config_init, @@ -983,7 +984,6 @@ static struct phy_driver ksphy_driver[] = { .phy_id = PHY_ID_KSZ8873MLL, .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8873MLL Switch", - .flags = PHY_HAS_MAGICANEG, .config_init = kszphy_config_init, .config_aneg = ksz8873mll_config_aneg, .read_status = ksz8873mll_read_status, @@ -994,7 +994,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ886X Switch", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -1005,12 +1005,22 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8795", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = kszphy_config_init, .config_aneg = ksz8873mll_config_aneg, .read_status = ksz8873mll_read_status, .suspend = genphy_suspend, .resume = genphy_resume, +}, { + .phy_id = PHY_ID_KSZ9477, + .phy_id_mask = MICREL_PHY_ID_MASK, + .name = "Microchip KSZ9477", + .features = PHY_GBIT_FEATURES, + .config_init = kszphy_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, } }; module_phy_driver(ksphy_driver); diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c index 2b2f543cf9f0..37ee856c7680 100644 --- a/drivers/net/phy/microchip.c +++ b/drivers/net/phy/microchip.c @@ -146,7 +146,7 @@ static struct phy_driver microchip_phy_driver[] = { .name = "Microchip LAN88xx", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + .flags = PHY_HAS_INTERRUPT, .probe = lan88xx_probe, .remove = lan88xx_remove, diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c new file mode 100644 index 000000000000..dada819c6b78 --- /dev/null +++ b/drivers/net/phy/phy-c45.c @@ -0,0 +1,298 @@ +/* + * Clause 45 PHY support + */ +#include <linux/ethtool.h> +#include <linux/export.h> +#include <linux/mdio.h> +#include <linux/mii.h> +#include <linux/phy.h> + +/** + * genphy_c45_setup_forced - configures a forced speed + * @phydev: target phy_device struct + */ +int genphy_c45_pma_setup_forced(struct phy_device *phydev) +{ + int ctrl1, ctrl2, ret; + + /* Half duplex is not supported */ + if (phydev->duplex != DUPLEX_FULL) + return -EINVAL; + + ctrl1 = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1); + if (ctrl1 < 0) + return ctrl1; + + ctrl2 = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL2); + if (ctrl2 < 0) + return ctrl2; + + ctrl1 &= ~MDIO_CTRL1_SPEEDSEL; + /* + * PMA/PMD type selection is 1.7.5:0 not 1.7.3:0. See 45.2.1.6.1 + * in 802.3-2012 and 802.3-2015. + */ + ctrl2 &= ~(MDIO_PMA_CTRL2_TYPE | 0x30); + + switch (phydev->speed) { + case SPEED_10: + ctrl2 |= MDIO_PMA_CTRL2_10BT; + break; + case SPEED_100: + ctrl1 |= MDIO_PMA_CTRL1_SPEED100; + ctrl2 |= MDIO_PMA_CTRL2_100BTX; + break; + case SPEED_1000: + ctrl1 |= MDIO_PMA_CTRL1_SPEED1000; + /* Assume 1000base-T */ + ctrl2 |= MDIO_PMA_CTRL2_1000BT; + break; + case SPEED_10000: + ctrl1 |= MDIO_CTRL1_SPEED10G; + /* Assume 10Gbase-T */ + ctrl2 |= MDIO_PMA_CTRL2_10GBT; + break; + default: + return -EINVAL; + } + + ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, ctrl1); + if (ret < 0) + return ret; + + return phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL2, ctrl2); +} +EXPORT_SYMBOL_GPL(genphy_c45_pma_setup_forced); + +/** + * genphy_c45_an_disable_aneg - disable auto-negotiation + * @phydev: target phy_device struct + * + * Disable auto-negotiation in the Clause 45 PHY. The link parameters + * parameters are controlled through the PMA/PMD MMD registers. + * + * Returns zero on success, negative errno code on failure. + */ +int genphy_c45_an_disable_aneg(struct phy_device *phydev) +{ + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); + if (val < 0) + return val; + + val &= ~(MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART); + + return phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, val); +} +EXPORT_SYMBOL_GPL(genphy_c45_an_disable_aneg); + +/** + * genphy_c45_restart_aneg - Enable and restart auto-negotiation + * @phydev: target phy_device struct + * + * This assumes that the auto-negotiation MMD is present. + * + * Enable and restart auto-negotiation. + */ +int genphy_c45_restart_aneg(struct phy_device *phydev) +{ + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); + if (val < 0) + return val; + + val |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART; + + return phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, val); +} +EXPORT_SYMBOL_GPL(genphy_c45_restart_aneg); + +/** + * genphy_c45_aneg_done - return auto-negotiation complete status + * @phydev: target phy_device struct + * + * This assumes that the auto-negotiation MMD is present. + * + * Reads the status register from the auto-negotiation MMD, returning: + * - positive if auto-negotiation is complete + * - negative errno code on error + * - zero otherwise + */ +int genphy_c45_aneg_done(struct phy_device *phydev) +{ + int val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + + return val < 0 ? val : val & MDIO_AN_STAT1_COMPLETE ? 1 : 0; +} +EXPORT_SYMBOL_GPL(genphy_c45_aneg_done); + +/** + * genphy_c45_read_link - read the overall link status from the MMDs + * @phydev: target phy_device struct + * @mmd_mask: MMDs to read status from + * + * Read the link status from the specified MMDs, and if they all indicate + * that the link is up, return positive. If an error is encountered, + * a negative errno will be returned, otherwise zero. + */ +int genphy_c45_read_link(struct phy_device *phydev, u32 mmd_mask) +{ + int val, devad; + bool link = true; + + while (mmd_mask) { + devad = __ffs(mmd_mask); + mmd_mask &= ~BIT(devad); + + /* The link state is latched low so that momentary link + * drops can be detected. Do not double-read the status + * register if the link is down. + */ + val = phy_read_mmd(phydev, devad, MDIO_STAT1); + if (val < 0) + return val; + + if (!(val & MDIO_STAT1_LSTATUS)) + link = false; + } + + return link; +} +EXPORT_SYMBOL_GPL(genphy_c45_read_link); + +/** + * genphy_c45_read_lpa - read the link partner advertisment and pause + * @phydev: target phy_device struct + * + * Read the Clause 45 defined base (7.19) and 10G (7.33) status registers, + * filling in the link partner advertisment, pause and asym_pause members + * in @phydev. This assumes that the auto-negotiation MMD is present, and + * the backplane bit (7.48.0) is clear. Clause 45 PHY drivers are expected + * to fill in the remainder of the link partner advert from vendor registers. + */ +int genphy_c45_read_lpa(struct phy_device *phydev) +{ + int val; + + /* Read the link partner's base page advertisment */ + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA); + if (val < 0) + return val; + + phydev->lp_advertising = mii_lpa_to_ethtool_lpa_t(val); + phydev->pause = val & LPA_PAUSE_CAP ? 1 : 0; + phydev->asym_pause = val & LPA_PAUSE_ASYM ? 1 : 0; + + /* Read the link partner's 10G advertisment */ + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); + if (val < 0) + return val; + + if (val & MDIO_AN_10GBT_STAT_LP10G) + phydev->lp_advertising |= ADVERTISED_10000baseT_Full; + + return 0; +} +EXPORT_SYMBOL_GPL(genphy_c45_read_lpa); + +/** + * genphy_c45_read_pma - read link speed etc from PMA + * @phydev: target phy_device struct + */ +int genphy_c45_read_pma(struct phy_device *phydev) +{ + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1); + if (val < 0) + return val; + + switch (val & MDIO_CTRL1_SPEEDSEL) { + case 0: + phydev->speed = SPEED_10; + break; + case MDIO_PMA_CTRL1_SPEED100: + phydev->speed = SPEED_100; + break; + case MDIO_PMA_CTRL1_SPEED1000: + phydev->speed = SPEED_1000; + break; + case MDIO_CTRL1_SPEED10G: + phydev->speed = SPEED_10000; + break; + default: + phydev->speed = SPEED_UNKNOWN; + break; + } + + phydev->duplex = DUPLEX_FULL; + + return 0; +} +EXPORT_SYMBOL_GPL(genphy_c45_read_pma); + +/* The gen10g_* functions are the old Clause 45 stub */ + +static int gen10g_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int gen10g_read_status(struct phy_device *phydev) +{ + u32 mmd_mask = phydev->c45_ids.devices_in_package; + int ret; + + /* For now just lie and say it's 10G all the time */ + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + + /* Avoid reading the vendor MMDs */ + mmd_mask &= ~(BIT(MDIO_MMD_VEND1) | BIT(MDIO_MMD_VEND2)); + + ret = genphy_c45_read_link(phydev, mmd_mask); + + phydev->link = ret > 0 ? 1 : 0; + + return 0; +} + +static int gen10g_soft_reset(struct phy_device *phydev) +{ + /* Do nothing for now */ + return 0; +} + +static int gen10g_config_init(struct phy_device *phydev) +{ + /* Temporarily just say we support everything */ + phydev->supported = SUPPORTED_10000baseT_Full; + phydev->advertising = SUPPORTED_10000baseT_Full; + + return 0; +} + +static int gen10g_suspend(struct phy_device *phydev) +{ + return 0; +} + +static int gen10g_resume(struct phy_device *phydev) +{ + return 0; +} + +struct phy_driver genphy_10g_driver = { + .phy_id = 0xffffffff, + .phy_id_mask = 0xffffffff, + .name = "Generic 10G PHY", + .soft_reset = gen10g_soft_reset, + .config_init = gen10g_config_init, + .features = 0, + .config_aneg = gen10g_config_aneg, + .read_status = gen10g_read_status, + .suspend = gen10g_suspend, + .resume = gen10g_resume, +}; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 7524caa0f29d..14fc5bc75cd1 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -149,6 +149,25 @@ static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) return 0; } +/** + * phy_restart_aneg - restart auto-negotiation + * @phydev: target phy_device struct + * + * Restart the autonegotiation on @phydev. Returns >= 0 on success or + * negative errno on error. + */ +int phy_restart_aneg(struct phy_device *phydev) +{ + int ret; + + if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0))) + ret = genphy_c45_restart_aneg(phydev); + else + ret = genphy_restart_aneg(phydev); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_restart_aneg); /** * phy_aneg_done - return auto-negotiation status @@ -163,6 +182,12 @@ int phy_aneg_done(struct phy_device *phydev) if (phydev->drv && phydev->drv->aneg_done) return phydev->drv->aneg_done(phydev); + /* Avoid genphy_aneg_done() if the Clause 45 PHY does not + * implement Clause 22 registers + */ + if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0))) + return -EINVAL; + return genphy_aneg_done(phydev); } EXPORT_SYMBOL(phy_aneg_done); @@ -484,30 +509,6 @@ int phy_ethtool_ksettings_set(struct phy_device *phydev, } EXPORT_SYMBOL(phy_ethtool_ksettings_set); -int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) -{ - cmd->supported = phydev->supported; - - cmd->advertising = phydev->advertising; - cmd->lp_advertising = phydev->lp_advertising; - - ethtool_cmd_speed_set(cmd, phydev->speed); - cmd->duplex = phydev->duplex; - if (phydev->interface == PHY_INTERFACE_MODE_MOCA) - cmd->port = PORT_BNC; - else - cmd->port = PORT_MII; - cmd->phy_address = phydev->mdio.addr; - cmd->transceiver = phy_is_internal(phydev) ? - XCVR_INTERNAL : XCVR_EXTERNAL; - cmd->autoneg = phydev->autoneg; - cmd->eth_tp_mdix_ctrl = phydev->mdix_ctrl; - cmd->eth_tp_mdix = phydev->mdix; - - return 0; -} -EXPORT_SYMBOL(phy_ethtool_gset); - int phy_ethtool_ksettings_get(struct phy_device *phydev, struct ethtool_link_ksettings *cmd) { @@ -1415,7 +1416,7 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data) /* Restart autonegotiation so the new modes get sent to the * link partner. */ - ret = genphy_restart_aneg(phydev); + ret = phy_restart_aneg(phydev); if (ret < 0) return ret; } @@ -1474,6 +1475,6 @@ int phy_ethtool_nway_reset(struct net_device *ndev) if (!phydev->drv) return -EIO; - return genphy_restart_aneg(phydev); + return phy_restart_aneg(phydev); } EXPORT_SYMBOL(phy_ethtool_nway_reset); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 1219eeab69d1..acf00f071c9a 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -69,13 +69,8 @@ static void phy_mdio_device_remove(struct mdio_device *mdiodev) phy_device_remove(phydev); } -enum genphy_driver { - GENPHY_DRV_1G, - GENPHY_DRV_10G, - GENPHY_DRV_MAX -}; - -static struct phy_driver genphy_driver[GENPHY_DRV_MAX]; +static struct phy_driver genphy_driver; +extern struct phy_driver genphy_10g_driver; static LIST_HEAD(phy_fixup_list); static DEFINE_MUTEX(phy_fixup_lock); @@ -928,11 +923,9 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, */ if (!d->driver) { if (phydev->is_c45) - d->driver = - &genphy_driver[GENPHY_DRV_10G].mdiodrv.driver; + d->driver = &genphy_10g_driver.mdiodrv.driver; else - d->driver = - &genphy_driver[GENPHY_DRV_1G].mdiodrv.driver; + d->driver = &genphy_driver.mdiodrv.driver; using_genphy = true; } @@ -961,6 +954,27 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, phydev->attached_dev = dev; dev->phydev = phydev; + /* Some Ethernet drivers try to connect to a PHY device before + * calling register_netdevice() -> netdev_register_kobject() and + * does the dev->dev.kobj initialization. Here we only check for + * success which indicates that the network device kobject is + * ready. Once we do that we still need to keep track of whether + * links were successfully set up or not for phy_detach() to + * remove them accordingly. + */ + phydev->sysfs_links = false; + + err = sysfs_create_link(&phydev->mdio.dev.kobj, &dev->dev.kobj, + "attached_dev"); + if (!err) { + err = sysfs_create_link(&dev->dev.kobj, &phydev->mdio.dev.kobj, + "phydev"); + if (err) + goto error; + + phydev->sysfs_links = true; + } + phydev->dev_flags = flags; phydev->interface = interface; @@ -1048,8 +1062,11 @@ void phy_detach(struct phy_device *phydev) struct net_device *dev = phydev->attached_dev; struct module *ndev_owner = dev->dev.parent->driver->owner; struct mii_bus *bus; - int i; + if (phydev->sysfs_links) { + sysfs_remove_link(&dev->dev.kobj, "phydev"); + sysfs_remove_link(&phydev->mdio.dev.kobj, "attached_dev"); + } phydev->attached_dev->phydev = NULL; phydev->attached_dev = NULL; phy_suspend(phydev); @@ -1063,13 +1080,9 @@ void phy_detach(struct phy_device *phydev) * from the generic driver so that there's a chance a * real driver could be loaded */ - for (i = 0; i < ARRAY_SIZE(genphy_driver); i++) { - if (phydev->mdio.dev.driver == - &genphy_driver[i].mdiodrv.driver) { - device_release_driver(&phydev->mdio.dev); - break; - } - } + if (phydev->mdio.dev.driver == &genphy_10g_driver.mdiodrv.driver || + phydev->mdio.dev.driver == &genphy_driver.mdiodrv.driver) + device_release_driver(&phydev->mdio.dev); /* * The phydev might go away on the put_device() below, so avoid @@ -1343,11 +1356,6 @@ int genphy_aneg_done(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_aneg_done); -static int gen10g_config_aneg(struct phy_device *phydev) -{ - return 0; -} - /** * genphy_update_link - update link status in @phydev * @phydev: target phy_device struct @@ -1481,33 +1489,6 @@ int genphy_read_status(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_read_status); -static int gen10g_read_status(struct phy_device *phydev) -{ - int devad, reg; - u32 mmd_mask = phydev->c45_ids.devices_in_package; - - phydev->link = 1; - - /* For now just lie and say it's 10G all the time */ - phydev->speed = SPEED_10000; - phydev->duplex = DUPLEX_FULL; - - for (devad = 0; mmd_mask; devad++, mmd_mask = mmd_mask >> 1) { - if (!(mmd_mask & 1)) - continue; - - /* Read twice because link state is latched and a - * read moves the current state into the register - */ - phy_read_mmd(phydev, devad, MDIO_STAT1); - reg = phy_read_mmd(phydev, devad, MDIO_STAT1); - if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) - phydev->link = 0; - } - - return 0; -} - /** * genphy_soft_reset - software reset the PHY via BMCR_RESET bit * @phydev: target phy_device struct @@ -1571,23 +1552,8 @@ int genphy_config_init(struct phy_device *phydev) return 0; } - -static int gen10g_soft_reset(struct phy_device *phydev) -{ - /* Do nothing for now */ - return 0; -} EXPORT_SYMBOL(genphy_config_init); -static int gen10g_config_init(struct phy_device *phydev) -{ - /* Temporarily just say we support everything */ - phydev->supported = SUPPORTED_10000baseT_Full; - phydev->advertising = SUPPORTED_10000baseT_Full; - - return 0; -} - int genphy_suspend(struct phy_device *phydev) { int value; @@ -1603,11 +1569,6 @@ int genphy_suspend(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_suspend); -static int gen10g_suspend(struct phy_device *phydev) -{ - return 0; -} - int genphy_resume(struct phy_device *phydev) { int value; @@ -1623,11 +1584,6 @@ int genphy_resume(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_resume); -static int gen10g_resume(struct phy_device *phydev) -{ - return 0; -} - static int __set_phy_supported(struct phy_device *phydev, u32 max_speed) { /* The default values for phydev->supported are provided by the PHY @@ -1859,8 +1815,7 @@ void phy_drivers_unregister(struct phy_driver *drv, int n) } EXPORT_SYMBOL(phy_drivers_unregister); -static struct phy_driver genphy_driver[] = { -{ +static struct phy_driver genphy_driver = { .phy_id = 0xffffffff, .phy_id_mask = 0xffffffff, .name = "Generic PHY", @@ -1874,18 +1829,7 @@ static struct phy_driver genphy_driver[] = { .read_status = genphy_read_status, .suspend = genphy_suspend, .resume = genphy_resume, -}, { - .phy_id = 0xffffffff, - .phy_id_mask = 0xffffffff, - .name = "Generic 10G PHY", - .soft_reset = gen10g_soft_reset, - .config_init = gen10g_config_init, - .features = 0, - .config_aneg = gen10g_config_aneg, - .read_status = gen10g_read_status, - .suspend = gen10g_suspend, - .resume = gen10g_resume, -} }; +}; static int __init phy_init(void) { @@ -1895,18 +1839,24 @@ static int __init phy_init(void) if (rc) return rc; - rc = phy_drivers_register(genphy_driver, - ARRAY_SIZE(genphy_driver), THIS_MODULE); + rc = phy_driver_register(&genphy_10g_driver, THIS_MODULE); if (rc) + goto err_10g; + + rc = phy_driver_register(&genphy_driver, THIS_MODULE); + if (rc) { + phy_driver_unregister(&genphy_10g_driver); +err_10g: mdio_bus_exit(); + } return rc; } static void __exit phy_exit(void) { - phy_drivers_unregister(genphy_driver, - ARRAY_SIZE(genphy_driver)); + phy_driver_unregister(&genphy_10g_driver); + phy_driver_unregister(&genphy_driver); mdio_bus_exit(); } diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index cef6967b0396..1b8204be064c 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -25,6 +25,16 @@ #include <linux/netdevice.h> #include <linux/smscphy.h> +struct smsc_hw_stat { + const char *string; + u8 reg; + u8 bits; +}; + +static struct smsc_hw_stat smsc_hw_stats[] = { + { "phy_symbol_errors", 26, 16}, +}; + struct smsc_phy_priv { bool energy_enable; }; @@ -143,6 +153,48 @@ static int lan87xx_read_status(struct phy_device *phydev) return err; } +static int smsc_get_sset_count(struct phy_device *phydev) +{ + return ARRAY_SIZE(smsc_hw_stats); +} + +static void smsc_get_strings(struct phy_device *phydev, u8 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++) { + memcpy(data + i * ETH_GSTRING_LEN, + smsc_hw_stats[i].string, ETH_GSTRING_LEN); + } +} + +#ifndef UINT64_MAX +#define UINT64_MAX (u64)(~((u64)0)) +#endif +static u64 smsc_get_stat(struct phy_device *phydev, int i) +{ + struct smsc_hw_stat stat = smsc_hw_stats[i]; + int val; + u64 ret; + + val = phy_read(phydev, stat.reg); + if (val < 0) + ret = UINT64_MAX; + else + ret = val; + + return ret; +} + +static void smsc_get_stats(struct phy_device *phydev, + struct ethtool_stats *stats, u64 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++) + data[i] = smsc_get_stat(phydev, i); +} + static int smsc_phy_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; @@ -170,7 +222,7 @@ static struct phy_driver smsc_phy_driver[] = { .name = "SMSC LAN83C185", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + .flags = PHY_HAS_INTERRUPT, .probe = smsc_phy_probe, @@ -192,7 +244,7 @@ static struct phy_driver smsc_phy_driver[] = { .name = "SMSC LAN8187", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + .flags = PHY_HAS_INTERRUPT, .probe = smsc_phy_probe, @@ -206,6 +258,11 @@ static struct phy_driver smsc_phy_driver[] = { .ack_interrupt = smsc_phy_ack_interrupt, .config_intr = smsc_phy_config_intr, + /* Statistics */ + .get_sset_count = smsc_get_sset_count, + .get_strings = smsc_get_strings, + .get_stats = smsc_get_stats, + .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -214,7 +271,7 @@ static struct phy_driver smsc_phy_driver[] = { .name = "SMSC LAN8700", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + .flags = PHY_HAS_INTERRUPT, .probe = smsc_phy_probe, @@ -228,6 +285,11 @@ static struct phy_driver smsc_phy_driver[] = { .ack_interrupt = smsc_phy_ack_interrupt, .config_intr = smsc_phy_config_intr, + /* Statistics */ + .get_sset_count = smsc_get_sset_count, + .get_strings = smsc_get_strings, + .get_stats = smsc_get_stats, + .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -236,7 +298,7 @@ static struct phy_driver smsc_phy_driver[] = { .name = "SMSC LAN911x Internal PHY", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + .flags = PHY_HAS_INTERRUPT, .probe = smsc_phy_probe, @@ -257,7 +319,7 @@ static struct phy_driver smsc_phy_driver[] = { .name = "SMSC LAN8710/LAN8720", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + .flags = PHY_HAS_INTERRUPT, .probe = smsc_phy_probe, @@ -271,6 +333,11 @@ static struct phy_driver smsc_phy_driver[] = { .ack_interrupt = smsc_phy_ack_interrupt, .config_intr = smsc_phy_config_intr, + /* Statistics */ + .get_sset_count = smsc_get_sset_count, + .get_strings = smsc_get_strings, + .get_stats = smsc_get_stats, + .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -279,7 +346,7 @@ static struct phy_driver smsc_phy_driver[] = { .name = "SMSC LAN8740", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + .flags = PHY_HAS_INTERRUPT, .probe = smsc_phy_probe, @@ -293,6 +360,11 @@ static struct phy_driver smsc_phy_driver[] = { .ack_interrupt = smsc_phy_ack_interrupt, .config_intr = smsc_phy_config_intr, + /* Statistics */ + .get_sset_count = smsc_get_sset_count, + .get_strings = smsc_get_strings, + .get_stats = smsc_get_stats, + .suspend = genphy_suspend, .resume = genphy_resume, } }; diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index f9c0e62716ea..bbded33120fe 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -1618,7 +1618,7 @@ ppp_push(struct ppp *ppp) list = list->next; pch = list_entry(list, struct channel, clist); - spin_lock_bh(&pch->downl); + spin_lock(&pch->downl); if (pch->chan) { if (pch->chan->ops->start_xmit(pch->chan, skb)) ppp->xmit_pending = NULL; @@ -1627,7 +1627,7 @@ ppp_push(struct ppp *ppp) kfree_skb(skb); ppp->xmit_pending = NULL; } - spin_unlock_bh(&pch->downl); + spin_unlock(&pch->downl); return; } @@ -1757,7 +1757,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) } /* check the channel's mtu and whether it is still attached. */ - spin_lock_bh(&pch->downl); + spin_lock(&pch->downl); if (pch->chan == NULL) { /* can't use this channel, it's being deregistered */ if (pch->speed == 0) @@ -1765,7 +1765,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) else totspeed -= pch->speed; - spin_unlock_bh(&pch->downl); + spin_unlock(&pch->downl); pch->avail = 0; totlen = len; totfree--; @@ -1816,7 +1816,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) */ if (flen <= 0) { pch->avail = 2; - spin_unlock_bh(&pch->downl); + spin_unlock(&pch->downl); continue; } @@ -1861,14 +1861,14 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) len -= flen; ++ppp->nxseq; bits = 0; - spin_unlock_bh(&pch->downl); + spin_unlock(&pch->downl); } ppp->nxchan = i; return 1; noskb: - spin_unlock_bh(&pch->downl); + spin_unlock(&pch->downl); if (ppp->debug & 1) netdev_err(ppp->dev, "PPP: no memory (fragment)\n"); ++ppp->dev->stats.tx_errors; @@ -1883,7 +1883,7 @@ static void __ppp_channel_push(struct channel *pch) struct sk_buff *skb; struct ppp *ppp; - spin_lock_bh(&pch->downl); + spin_lock(&pch->downl); if (pch->chan) { while (!skb_queue_empty(&pch->file.xq)) { skb = skb_dequeue(&pch->file.xq); @@ -1897,14 +1897,14 @@ static void __ppp_channel_push(struct channel *pch) /* channel got deregistered */ skb_queue_purge(&pch->file.xq); } - spin_unlock_bh(&pch->downl); + spin_unlock(&pch->downl); /* see if there is anything from the attached unit to be sent */ if (skb_queue_empty(&pch->file.xq)) { - read_lock_bh(&pch->upl); + read_lock(&pch->upl); ppp = pch->ppp; if (ppp) __ppp_xmit_process(ppp); - read_unlock_bh(&pch->upl); + read_unlock(&pch->upl); } } diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c index f60f7660b451..6c7fd98cb00a 100644 --- a/drivers/net/ppp/ppp_mppe.c +++ b/drivers/net/ppp/ppp_mppe.c @@ -298,21 +298,14 @@ mppe_init(void *arg, unsigned char *options, int optlen, int unit, int debug, mppe_rekey(state, 1); if (debug) { - int i; - char mkey[sizeof(state->master_key) * 2 + 1]; - char skey[sizeof(state->session_key) * 2 + 1]; - printk(KERN_DEBUG "%s[%d]: initialized with %d-bit %s mode\n", debugstr, unit, (state->keylen == 16) ? 128 : 40, (state->stateful) ? "stateful" : "stateless"); - - for (i = 0; i < sizeof(state->master_key); i++) - sprintf(mkey + i * 2, "%02x", state->master_key[i]); - for (i = 0; i < sizeof(state->session_key); i++) - sprintf(skey + i * 2, "%02x", state->session_key[i]); printk(KERN_DEBUG - "%s[%d]: keys: master: %s initial session: %s\n", - debugstr, unit, mkey, skey); + "%s[%d]: keys: master: %*phN initial session: %*phN\n", + debugstr, unit, + (int)sizeof(state->master_key), state->master_key, + (int)sizeof(state->session_key), state->session_key); } /* diff --git a/drivers/net/tap.c b/drivers/net/tap.c index 4d4173d25dd0..9af3239d6ad5 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -824,15 +824,17 @@ done: static ssize_t tap_do_read(struct tap_queue *q, struct iov_iter *to, - int noblock) + int noblock, struct sk_buff *skb) { DEFINE_WAIT(wait); - struct sk_buff *skb; ssize_t ret = 0; if (!iov_iter_count(to)) return 0; + if (skb) + goto put; + while (1) { if (!noblock) prepare_to_wait(sk_sleep(&q->sk), &wait, @@ -856,6 +858,7 @@ static ssize_t tap_do_read(struct tap_queue *q, if (!noblock) finish_wait(sk_sleep(&q->sk), &wait); +put: if (skb) { ret = tap_put_user(q, skb, to); if (unlikely(ret < 0)) @@ -872,7 +875,7 @@ static ssize_t tap_read_iter(struct kiocb *iocb, struct iov_iter *to) struct tap_queue *q = file->private_data; ssize_t len = iov_iter_count(to), ret; - ret = tap_do_read(q, to, file->f_flags & O_NONBLOCK); + ret = tap_do_read(q, to, file->f_flags & O_NONBLOCK, NULL); ret = min_t(ssize_t, ret, len); if (ret > 0) iocb->ki_pos = ret; @@ -1155,7 +1158,8 @@ static int tap_recvmsg(struct socket *sock, struct msghdr *m, int ret; if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) return -EINVAL; - ret = tap_do_read(q, &m->msg_iter, flags & MSG_DONTWAIT); + ret = tap_do_read(q, &m->msg_iter, flags & MSG_DONTWAIT, + m->msg_control); if (ret > total_len) { m->msg_flags |= MSG_TRUNC; ret = flags & MSG_TRUNC ? ret : total_len; @@ -1193,6 +1197,19 @@ struct socket *tap_get_socket(struct file *file) } EXPORT_SYMBOL_GPL(tap_get_socket); +struct skb_array *tap_get_skb_array(struct file *file) +{ + struct tap_queue *q; + + if (file->f_op != &tap_fops) + return ERR_PTR(-EINVAL); + q = file->private_data; + if (!q) + return ERR_PTR(-EBADFD); + return &q->skb_array; +} +EXPORT_SYMBOL_GPL(tap_get_skb_array); + int tap_queue_resize(struct tap_dev *tap) { struct net_device *dev = tap->dev; diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c index 3f189823ba3b..ddd16a0c1fc1 100644 --- a/drivers/net/team/team_mode_activebackup.c +++ b/drivers/net/team/team_mode_activebackup.c @@ -146,4 +146,4 @@ module_exit(ab_cleanup_module); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>"); MODULE_DESCRIPTION("Active-backup mode for team"); -MODULE_ALIAS("team-mode-activebackup"); +MODULE_ALIAS_TEAM_MODE("activebackup"); diff --git a/drivers/net/team/team_mode_broadcast.c b/drivers/net/team/team_mode_broadcast.c index 302ff35b0cbc..e4eac3de1862 100644 --- a/drivers/net/team/team_mode_broadcast.c +++ b/drivers/net/team/team_mode_broadcast.c @@ -75,4 +75,4 @@ module_exit(bc_cleanup_module); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>"); MODULE_DESCRIPTION("Broadcast mode for team"); -MODULE_ALIAS("team-mode-broadcast"); +MODULE_ALIAS_TEAM_MODE("broadcast"); diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c index b228bea7931f..1468ddf424cc 100644 --- a/drivers/net/team/team_mode_loadbalance.c +++ b/drivers/net/team/team_mode_loadbalance.c @@ -695,4 +695,4 @@ module_exit(lb_cleanup_module); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>"); MODULE_DESCRIPTION("Load-balancing mode for team"); -MODULE_ALIAS("team-mode-loadbalance"); +MODULE_ALIAS_TEAM_MODE("loadbalance"); diff --git a/drivers/net/team/team_mode_random.c b/drivers/net/team/team_mode_random.c index 215f845782db..c20b9446e2e4 100644 --- a/drivers/net/team/team_mode_random.c +++ b/drivers/net/team/team_mode_random.c @@ -65,4 +65,4 @@ module_exit(rnd_cleanup_module); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>"); MODULE_DESCRIPTION("Random mode for team"); -MODULE_ALIAS("team-mode-random"); +MODULE_ALIAS_TEAM_MODE("random"); diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c index 0aa234118c03..66c3209dc4a6 100644 --- a/drivers/net/team/team_mode_roundrobin.c +++ b/drivers/net/team/team_mode_roundrobin.c @@ -77,4 +77,4 @@ module_exit(rr_cleanup_module); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>"); MODULE_DESCRIPTION("Round-robin mode for team"); -MODULE_ALIAS("team-mode-roundrobin"); +MODULE_ALIAS_TEAM_MODE("roundrobin"); diff --git a/drivers/net/tun.c b/drivers/net/tun.c index bbd707b9ef7a..fe660e524af9 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -465,7 +465,7 @@ static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb, rcu_read_lock(); numqueues = ACCESS_ONCE(tun->numqueues); - txq = skb_get_hash(skb); + txq = __skb_get_hash_symmetric(skb); if (txq) { e = tun_flow_find(&tun->flows[tun_hashfn(txq)], txq); if (e) { @@ -867,7 +867,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) */ __u32 rxhash; - rxhash = skb_get_hash(skb); + rxhash = __skb_get_hash_symmetric(skb); if (rxhash) { struct tun_flow_entry *e; e = tun_flow_find(&tun->flows[tun_hashfn(rxhash)], @@ -1334,7 +1334,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, skb_reset_network_header(skb); skb_probe_transport_header(skb, 0); - rxhash = skb_get_hash(skb); + rxhash = __skb_get_hash_symmetric(skb); #ifndef CONFIG_4KSTACKS tun_rx_batched(tun, tfile, skb, more); #else @@ -1510,9 +1510,8 @@ out: static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, struct iov_iter *to, - int noblock) + int noblock, struct sk_buff *skb) { - struct sk_buff *skb; ssize_t ret; int err; @@ -1521,10 +1520,12 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, if (!iov_iter_count(to)) return 0; - /* Read frames from ring */ - skb = tun_ring_recv(tfile, noblock, &err); - if (!skb) - return err; + if (!skb) { + /* Read frames from ring */ + skb = tun_ring_recv(tfile, noblock, &err); + if (!skb) + return err; + } ret = tun_put_user(tun, tfile, skb, to); if (unlikely(ret < 0)) @@ -1544,7 +1545,7 @@ static ssize_t tun_chr_read_iter(struct kiocb *iocb, struct iov_iter *to) if (!tun) return -EBADFD; - ret = tun_do_read(tun, tfile, to, file->f_flags & O_NONBLOCK); + ret = tun_do_read(tun, tfile, to, file->f_flags & O_NONBLOCK, NULL); ret = min_t(ssize_t, ret, len); if (ret > 0) iocb->ki_pos = ret; @@ -1646,7 +1647,8 @@ static int tun_recvmsg(struct socket *sock, struct msghdr *m, size_t total_len, SOL_PACKET, TUN_TX_TIMESTAMP); goto out; } - ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT); + ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT, + m->msg_control); if (ret > (ssize_t)total_len) { m->msg_flags |= MSG_TRUNC; ret = flags & MSG_TRUNC ? ret : total_len; @@ -2626,6 +2628,19 @@ struct socket *tun_get_socket(struct file *file) } EXPORT_SYMBOL_GPL(tun_get_socket); +struct skb_array *tun_get_skb_array(struct file *file) +{ + struct tun_file *tfile; + + if (file->f_op != &tun_fops) + return ERR_PTR(-EINVAL); + tfile = file->private_data; + if (!tfile) + return ERR_PTR(-EBADFD); + return &tfile->tx_array; +} +EXPORT_SYMBOL_GPL(tun_get_skb_array); + module_init(tun_init); module_exit(tun_cleanup); MODULE_DESCRIPTION(DRV_DESCRIPTION); diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 51cf60092a18..793ce900dffa 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -624,7 +624,10 @@ static int ax88179_get_link_ksettings(struct net_device *net, struct ethtool_link_ksettings *cmd) { struct usbnet *dev = netdev_priv(net); - return mii_ethtool_get_link_ksettings(&dev->mii, cmd); + + mii_ethtool_get_link_ksettings(&dev->mii, cmd); + + return 0; } static int ax88179_set_link_ksettings(struct net_device *net, diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c index 4cbdb1307f3e..3202c19df83d 100644 --- a/drivers/net/usb/net1080.c +++ b/drivers/net/usb/net1080.c @@ -264,17 +264,9 @@ static inline void nc_dump_status(struct usbnet *dev, u16 status) * TTL register */ -#define TTL_THIS(ttl) (0x00ff & ttl) #define TTL_OTHER(ttl) (0x00ff & (ttl >> 8)) #define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this)))) -static inline void nc_dump_ttl(struct usbnet *dev, u16 ttl) -{ - netif_dbg(dev, link, dev->net, "net1080 %s-%s ttl 0x%x this = %d, other = %d\n", - dev->udev->bus->bus_name, dev->udev->devpath, - ttl, TTL_THIS(ttl), TTL_OTHER(ttl)); -} - /*-------------------------------------------------------------------------*/ static int net1080_reset(struct usbnet *dev) @@ -308,7 +300,6 @@ static int net1080_reset(struct usbnet *dev) goto done; } ttl = vp; - // nc_dump_ttl(dev, ttl); nc_register_write(dev, REG_TTL, MK_TTL(NC_READ_TTL_MS, TTL_OTHER(ttl)) ); diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index ddc62cb69be8..fd31fab2a9da 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -841,12 +841,6 @@ int pla_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data) } static inline -int usb_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data) -{ - return generic_ocp_read(tp, index, size, data, MCU_TYPE_USB); -} - -static inline int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data) { return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_USB); @@ -3841,7 +3835,7 @@ int rtl8152_get_link_ksettings(struct net_device *netdev, mutex_lock(&tp->control); - ret = mii_ethtool_get_link_ksettings(&tp->mii, cmd); + mii_ethtool_get_link_ksettings(&tp->mii, cmd); mutex_unlock(&tp->control); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 79048e72c1bd..6510e5cc1817 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -956,7 +956,9 @@ int usbnet_get_link_ksettings(struct net_device *net, if (!dev->mii.mdio_read) return -EOPNOTSUPP; - return mii_ethtool_get_link_ksettings(&dev->mii, cmd); + mii_ethtool_get_link_ksettings(&dev->mii, cmd); + + return 0; } EXPORT_SYMBOL_GPL(usbnet_get_link_ksettings); diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index a871f45ecc79..1f8c15cb63b0 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1150,7 +1150,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) struct virtio_net_hdr_mrg_rxbuf *hdr; const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; struct virtnet_info *vi = sq->vq->vdev->priv; - unsigned num_sg; + int num_sg; unsigned hdr_len = vi->hdr_len; bool can_push; @@ -1177,11 +1177,16 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) if (can_push) { __skb_push(skb, hdr_len); num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len); + if (unlikely(num_sg < 0)) + return num_sg; /* Pull header back to avoid skew in tx bytes calculations. */ __skb_pull(skb, hdr_len); } else { sg_set_buf(sq->sg, hdr, hdr_len); - num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1; + num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len); + if (unlikely(num_sg < 0)) + return num_sg; + num_sg++; } return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, skb, GFP_ATOMIC); } diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 6742ae605660..33df76405b86 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -36,7 +36,6 @@ #define DRV_NAME "ucc_hdlc" #define TDM_PPPOHT_SLIC_MAXIN -#define BROKEN_FRAME_INFO static struct ucc_tdm_info utdm_primary_info = { .uf_info = { @@ -99,6 +98,13 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) uf_info->tsa = 1; uf_info->ctsp = 1; } + + /* This sets HPM register in CMXUCR register which configures a + * open drain connected HDLC bus + */ + if (priv->hdlc_bus) + uf_info->brkpt_support = 1; + uf_info->uccm_mask = ((UCC_HDLC_UCCE_RXB | UCC_HDLC_UCCE_RXF | UCC_HDLC_UCCE_TXB) << 16); @@ -114,6 +120,9 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) /* Loopback mode */ if (priv->loopback) { dev_info(priv->dev, "Loopback Mode\n"); + /* use the same clock when work in loopback */ + qe_setbrg(ut_info->uf_info.rx_clock, 20000000, 1); + gumr = ioread32be(&priv->uf_regs->gumr); gumr |= (UCC_FAST_GUMR_LOOPBACK | UCC_FAST_GUMR_CDS | UCC_FAST_GUMR_TCI); @@ -133,11 +142,33 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) /* Set UPSMR normal mode (need fixed)*/ iowrite32be(0, &priv->uf_regs->upsmr); + /* hdlc_bus mode */ + if (priv->hdlc_bus) { + u32 upsmr; + + dev_info(priv->dev, "HDLC bus Mode\n"); + upsmr = ioread32be(&priv->uf_regs->upsmr); + + /* bus mode and retransmit enable, with collision window + * set to 8 bytes + */ + upsmr |= UCC_HDLC_UPSMR_RTE | UCC_HDLC_UPSMR_BUS | + UCC_HDLC_UPSMR_CW8; + iowrite32be(upsmr, &priv->uf_regs->upsmr); + + /* explicitly disable CDS & CTSP */ + gumr = ioread32be(&priv->uf_regs->gumr); + gumr &= ~(UCC_FAST_GUMR_CDS | UCC_FAST_GUMR_CTSP); + /* set automatic sync to explicitly ignore CD signal */ + gumr |= UCC_FAST_GUMR_SYNL_AUTO; + iowrite32be(gumr, &priv->uf_regs->gumr); + } + priv->rx_ring_size = RX_BD_RING_LEN; priv->tx_ring_size = TX_BD_RING_LEN; /* Alloc Rx BD */ priv->rx_bd_base = dma_alloc_coherent(priv->dev, - RX_BD_RING_LEN * sizeof(struct qe_bd *), + RX_BD_RING_LEN * sizeof(struct qe_bd), &priv->dma_rx_bd, GFP_KERNEL); if (!priv->rx_bd_base) { @@ -148,7 +179,7 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) /* Alloc Tx BD */ priv->tx_bd_base = dma_alloc_coherent(priv->dev, - TX_BD_RING_LEN * sizeof(struct qe_bd *), + TX_BD_RING_LEN * sizeof(struct qe_bd), &priv->dma_tx_bd, GFP_KERNEL); if (!priv->tx_bd_base) { @@ -158,7 +189,7 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) } /* Alloc parameter ram for ucc hdlc */ - priv->ucc_pram_offset = qe_muram_alloc(sizeof(priv->ucc_pram), + priv->ucc_pram_offset = qe_muram_alloc(sizeof(struct ucc_hdlc_param), ALIGNMENT_OF_UCC_HDLC_PRAM); if (priv->ucc_pram_offset < 0) { @@ -295,11 +326,11 @@ free_ucc_pram: qe_muram_free(priv->ucc_pram_offset); free_tx_bd: dma_free_coherent(priv->dev, - TX_BD_RING_LEN * sizeof(struct qe_bd *), + TX_BD_RING_LEN * sizeof(struct qe_bd), priv->tx_bd_base, priv->dma_tx_bd); free_rx_bd: dma_free_coherent(priv->dev, - RX_BD_RING_LEN * sizeof(struct qe_bd *), + RX_BD_RING_LEN * sizeof(struct qe_bd), priv->rx_bd_base, priv->dma_rx_bd); free_uccf: ucc_fast_free(priv->uccf); @@ -314,8 +345,6 @@ static netdev_tx_t ucc_hdlc_tx(struct sk_buff *skb, struct net_device *dev) struct qe_bd __iomem *bd; u16 bd_status; unsigned long flags; - u8 *send_buf; - int i; u16 *proto_head; switch (dev->type) { @@ -352,16 +381,6 @@ static netdev_tx_t ucc_hdlc_tx(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); return -ENOMEM; } - - pr_info("Tx data skb->len:%d ", skb->len); - send_buf = (u8 *)skb->data; - pr_info("\nTransmitted data:\n"); - for (i = 0; i < 16; i++) { - if (i == skb->len) - pr_info("++++"); - else - pr_info("%02x\n", send_buf[i]); - } spin_lock_irqsave(&priv->lock, flags); /* Start from the next BD that should be filled */ @@ -423,7 +442,6 @@ static int hdlc_tx_done(struct ucc_hdlc_private *priv) skb = priv->tx_skbuff[priv->skb_dirtytx]; if (!skb) break; - pr_info("TxBD: %x\n", bd_status); dev->stats.tx_packets++; memset(priv->tx_buffer + (be32_to_cpu(bd->buf) - priv->dma_tx_addr), @@ -454,14 +472,12 @@ static int hdlc_tx_done(struct ucc_hdlc_private *priv) static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit) { struct net_device *dev = priv->ndev; - struct sk_buff *skb; + struct sk_buff *skb = NULL; hdlc_device *hdlc = dev_to_hdlc(dev); struct qe_bd *bd; u16 bd_status; u16 length, howmany = 0; u8 *bdbuffer; - int i; - static int entry; bd = priv->currx_bd; bd_status = ioread16be(&bd->status); @@ -471,9 +487,6 @@ static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit) if (bd_status & R_OV_S) dev->stats.rx_over_errors++; if (bd_status & R_CR_S) { -#ifdef BROKEN_FRAME_INFO - pr_info("Broken Frame with RxBD: %x\n", bd_status); -#endif dev->stats.rx_crc_errors++; dev->stats.rx_dropped++; goto recycle; @@ -482,17 +495,6 @@ static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit) (priv->currx_bdnum * MAX_RX_BUF_LENGTH); length = ioread16be(&bd->length); - pr_info("Received data length:%d", length); - pr_info("while entry times:%d", entry++); - - pr_info("\nReceived data:\n"); - for (i = 0; (i < 16); i++) { - if (i == length) - pr_info("++++"); - else - pr_info("%02x\n", bdbuffer[i]); - } - switch (dev->type) { case ARPHRD_RAWHDLC: bdbuffer += HDLC_HEAD_LEN; @@ -531,7 +533,6 @@ static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit) howmany++; if (hdlc->proto) skb->protocol = hdlc_type_trans(skb, dev); - pr_info("skb->protocol:%x\n", skb->protocol); netif_receive_skb(skb); recycle: @@ -566,7 +567,7 @@ static int ucc_hdlc_poll(struct napi_struct *napi, int budget) /* Tx event processing */ spin_lock(&priv->lock); - hdlc_tx_done(priv); + hdlc_tx_done(priv); spin_unlock(&priv->lock); howmany = 0; @@ -597,7 +598,6 @@ static irqreturn_t ucc_hdlc_irq_handler(int irq, void *dev_id) uccm = ioread32be(uccf->p_uccm); ucce &= uccm; iowrite32be(ucce, uccf->p_ucce); - pr_info("irq ucce:%x\n", ucce); if (!ucce) return IRQ_NONE; @@ -688,7 +688,7 @@ static void uhdlc_memclean(struct ucc_hdlc_private *priv) if (priv->rx_bd_base) { dma_free_coherent(priv->dev, - RX_BD_RING_LEN * sizeof(struct qe_bd *), + RX_BD_RING_LEN * sizeof(struct qe_bd), priv->rx_bd_base, priv->dma_rx_bd); priv->rx_bd_base = NULL; @@ -697,7 +697,7 @@ static void uhdlc_memclean(struct ucc_hdlc_private *priv) if (priv->tx_bd_base) { dma_free_coherent(priv->dev, - TX_BD_RING_LEN * sizeof(struct qe_bd *), + TX_BD_RING_LEN * sizeof(struct qe_bd), priv->tx_bd_base, priv->dma_tx_bd); priv->tx_bd_base = NULL; @@ -855,7 +855,6 @@ static int uhdlc_suspend(struct device *dev) /* save power */ ucc_fast_disable(priv->uccf, COMM_DIR_RX | COMM_DIR_TX); - dev_dbg(dev, "ucc hdlc suspend\n"); return 0; } @@ -1001,7 +1000,7 @@ static int ucc_hdlc_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct ucc_hdlc_private *uhdlc_priv = NULL; struct ucc_tdm_info *ut_info; - struct ucc_tdm *utdm; + struct ucc_tdm *utdm = NULL; struct resource res; struct net_device *dev; hdlc_device *hdlc; @@ -1054,10 +1053,6 @@ static int ucc_hdlc_probe(struct platform_device *pdev) return -EINVAL; } - /* use the same clock when work in loopback */ - if (ut_info->uf_info.rx_clock == ut_info->uf_info.tx_clock) - qe_setbrg(ut_info->uf_info.rx_clock, 20000000, 1); - ret = of_address_to_resource(np, 0, &res); if (ret) return -EINVAL; @@ -1080,6 +1075,9 @@ static int ucc_hdlc_probe(struct platform_device *pdev) if (of_get_property(np, "fsl,ucc-internal-loopback", NULL)) uhdlc_priv->loopback = 1; + if (of_get_property(np, "fsl,hdlc-bus", NULL)) + uhdlc_priv->hdlc_bus = 1; + if (uhdlc_priv->tsa == 1) { utdm = kzalloc(sizeof(*utdm), GFP_KERNEL); if (!utdm) { diff --git a/drivers/net/wan/fsl_ucc_hdlc.h b/drivers/net/wan/fsl_ucc_hdlc.h index 881ecdeef076..c21134c1f180 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.h +++ b/drivers/net/wan/fsl_ucc_hdlc.h @@ -78,6 +78,7 @@ struct ucc_hdlc_private { u16 tsa; bool hdlc_busy; bool loopback; + bool hdlc_bus; u8 *tx_buffer; u8 *rx_buffer; diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c index 2f11836078ab..8bd3ed905813 100644 --- a/drivers/net/wan/hdlc_raw_eth.c +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -57,7 +57,8 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) const size_t size = sizeof(raw_hdlc_proto); raw_hdlc_proto new_settings; hdlc_device *hdlc = dev_to_hdlc(dev); - int result, old_qlen; + unsigned int old_qlen; + int result; switch (ifr->ifr_settings.type) { case IF_GET_PROTO: diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 30bc6105aac3..0efc54a4d82f 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -659,6 +659,7 @@ struct qeth_card_info { int max_mtu; int broadcast_capable; int unique_id; + bool layer_enforced; struct qeth_card_blkt blkt; enum qeth_ipa_promisc_modes promisc_mode; __u32 diagass_support; @@ -696,6 +697,7 @@ struct qeth_osn_info { }; enum qeth_discipline_id { + QETH_DISCIPLINE_UNDETERMINED = -1, QETH_DISCIPLINE_LAYER3 = 0, QETH_DISCIPLINE_LAYER2 = 1, }; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index fc6d85f2b38d..1fb92e870040 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1723,6 +1723,25 @@ static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd) (prcd[0x11] == _ascebc['M'])); } +/* Determine whether the device requires a specific layer discipline */ +static enum qeth_discipline_id qeth_enforce_discipline(struct qeth_card *card) +{ + if (card->info.type == QETH_CARD_TYPE_OSM || + card->info.type == QETH_CARD_TYPE_OSN) { + QETH_DBF_TEXT(SETUP, 3, "force l2"); + return QETH_DISCIPLINE_LAYER2; + } + + /* virtual HiperSocket is L3 only: */ + if (card->info.guestlan && card->info.type == QETH_CARD_TYPE_IQD) { + QETH_DBF_TEXT(SETUP, 3, "force l3"); + return QETH_DISCIPLINE_LAYER3; + } + + QETH_DBF_TEXT(SETUP, 3, "force no"); + return QETH_DISCIPLINE_UNDETERMINED; +} + static void qeth_configure_blkt_default(struct qeth_card *card, char *prcd) { QETH_DBF_TEXT(SETUP, 2, "cfgblkt"); @@ -3347,6 +3366,28 @@ static void qeth_handle_send_error(struct qeth_card *card, (u16)qdio_err, (u8)sbalf15); } +/** + * qeth_prep_flush_pack_buffer - Prepares flushing of a packing buffer. + * @queue: queue to check for packing buffer + * + * Returns number of buffers that were prepared for flush. + */ +static int qeth_prep_flush_pack_buffer(struct qeth_qdio_out_q *queue) +{ + struct qeth_qdio_out_buffer *buffer; + + buffer = queue->bufs[queue->next_buf_to_fill]; + if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) && + (buffer->next_element_to_fill > 0)) { + /* it's a packing buffer */ + atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED); + queue->next_buf_to_fill = + (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; + return 1; + } + return 0; +} + /* * Switched to packing state if the number of used buffers on a queue * reaches a certain limit. @@ -3373,9 +3414,6 @@ static void qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue) */ static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue) { - struct qeth_qdio_out_buffer *buffer; - int flush_count = 0; - if (queue->do_pack) { if (atomic_read(&queue->used_buffers) <= QETH_LOW_WATERMARK_PACK) { @@ -3384,42 +3422,9 @@ static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue) if (queue->card->options.performance_stats) queue->card->perf_stats.sc_p_dp++; queue->do_pack = 0; - /* flush packing buffers */ - buffer = queue->bufs[queue->next_buf_to_fill]; - if ((atomic_read(&buffer->state) == - QETH_QDIO_BUF_EMPTY) && - (buffer->next_element_to_fill > 0)) { - atomic_set(&buffer->state, - QETH_QDIO_BUF_PRIMED); - flush_count++; - queue->next_buf_to_fill = - (queue->next_buf_to_fill + 1) % - QDIO_MAX_BUFFERS_PER_Q; - } + return qeth_prep_flush_pack_buffer(queue); } } - return flush_count; -} - - -/* - * Called to flush a packing buffer if no more pci flags are on the queue. - * Checks if there is a packing buffer and prepares it to be flushed. - * In that case returns 1, otherwise zero. - */ -static int qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue) -{ - struct qeth_qdio_out_buffer *buffer; - - buffer = queue->bufs[queue->next_buf_to_fill]; - if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) && - (buffer->next_element_to_fill > 0)) { - /* it's a packing buffer */ - atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED); - queue->next_buf_to_fill = - (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; - return 1; - } return 0; } @@ -3532,8 +3537,7 @@ static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) flush_cnt += qeth_switch_to_nonpacking_if_needed(queue); if (!flush_cnt && !atomic_read(&queue->set_pci_flags_count)) - flush_cnt += - qeth_flush_buffers_on_no_pci(queue); + flush_cnt += qeth_prep_flush_pack_buffer(queue); if (queue->card->options.performance_stats && q_was_packing) queue->card->perf_stats.bufs_sent_pack += @@ -4127,7 +4131,7 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, * flag out on the queue */ if (!flush_count && !atomic_read(&queue->set_pci_flags_count)) - flush_count += qeth_flush_buffers_on_no_pci(queue); + flush_count += qeth_prep_flush_pack_buffer(queue); if (flush_count) qeth_flush_buffers(queue, start_index, flush_count); } @@ -4199,8 +4203,7 @@ int qeth_change_mtu(struct net_device *dev, int new_mtu) sprintf(dbf_text, "%8x", new_mtu); QETH_CARD_TEXT(card, 4, dbf_text); - if ((!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) && - (!qeth_mtu_is_valid(card, new_mtu))) + if (!qeth_mtu_is_valid(card, new_mtu)) return -EINVAL; dev->mtu = new_mtu; return 0; @@ -5501,6 +5504,7 @@ int qeth_core_load_discipline(struct qeth_card *card, enum qeth_discipline_id discipline) { int rc = 0; + mutex_lock(&qeth_mod_mutex); switch (discipline) { case QETH_DISCIPLINE_LAYER3: @@ -5511,7 +5515,10 @@ int qeth_core_load_discipline(struct qeth_card *card, card->discipline = try_then_request_module( symbol_get(qeth_l2_discipline), "qeth_l2"); break; + default: + break; } + if (!card->discipline) { dev_err(&card->gdev->dev, "There is no kernel module to " "support discipline %d\n", discipline); @@ -5614,6 +5621,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) struct qeth_card *card; struct device *dev; int rc; + enum qeth_discipline_id enforced_disc; unsigned long flags; char dbf_name[DBF_NAME_LEN]; @@ -5661,10 +5669,15 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) goto err_card; } - switch (card->info.type) { - case QETH_CARD_TYPE_OSN: - case QETH_CARD_TYPE_OSM: - rc = qeth_core_load_discipline(card, QETH_DISCIPLINE_LAYER2); + qeth_determine_capabilities(card); + enforced_disc = qeth_enforce_discipline(card); + switch (enforced_disc) { + case QETH_DISCIPLINE_UNDETERMINED: + gdev->dev.type = &qeth_generic_devtype; + break; + default: + card->info.layer_enforced = true; + rc = qeth_core_load_discipline(card, enforced_disc); if (rc) goto err_card; @@ -5675,16 +5688,11 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) if (rc) goto err_disc; break; - default: - gdev->dev.type = &qeth_generic_devtype; - break; } write_lock_irqsave(&qeth_core_card_list.rwlock, flags); list_add_tail(&card->list, &qeth_core_card_list.list); write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags); - - qeth_determine_capabilities(card); return 0; err_disc: @@ -5721,7 +5729,7 @@ static int qeth_core_set_online(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); int rc = 0; - int def_discipline; + enum qeth_discipline_id def_discipline; if (!card->discipline) { if (card->info.type == QETH_CARD_TYPE_IQD) @@ -6406,11 +6414,8 @@ netdev_features_t qeth_fix_features(struct net_device *dev, features &= ~NETIF_F_IP_CSUM; if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) features &= ~NETIF_F_RXCSUM; - if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) { + if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) features &= ~NETIF_F_TSO; - dev_info(&card->gdev->dev, "Outbound TSO not supported on %s\n", - QETH_CARD_IFNAME(card)); - } /* if the card isn't up, remove features that require hw changes */ if (card->state == CARD_STATE_DOWN || card->state == CARD_STATE_RECOVER) diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c index beb4bdc26de5..ab9b1376467f 100644 --- a/drivers/s390/net/qeth_core_mpc.c +++ b/drivers/s390/net/qeth_core_mpc.c @@ -167,6 +167,8 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = { {IPA_RC_IP_TABLE_FULL, "Add Addr IP Table Full - ipv6"}, {IPA_RC_UNKNOWN_ERROR, "IPA command failed - reason unknown"}, {IPA_RC_UNSUPPORTED_COMMAND, "Command not supported"}, + {IPA_RC_TRACE_ALREADY_ACTIVE, "trace already active"}, + {IPA_RC_INVALID_FORMAT, "invalid format or length"}, {IPA_RC_DUP_IPV6_REMOTE, "ipv6 address already registered remote"}, {IPA_RC_DUP_IPV6_HOME, "ipv6 address already registered"}, {IPA_RC_UNREGISTERED_ADDR, "Address not registered"}, diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 4accb0a61ce0..45bbea2843bf 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -192,7 +192,7 @@ enum qeth_ipa_funcs { IPA_ARP_PROCESSING = 0x00000001L, IPA_INBOUND_CHECKSUM = 0x00000002L, IPA_OUTBOUND_CHECKSUM = 0x00000004L, - IPA_IP_FRAGMENTATION = 0x00000008L, + /* RESERVED = 0x00000008L,*/ IPA_FILTERING = 0x00000010L, IPA_IPV6 = 0x00000020L, IPA_MULTICASTING = 0x00000040L, diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index db6a285d41e0..6d255c22656d 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -413,7 +413,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, if (card->options.layer2 == newdis) goto out; - if (card->info.type == QETH_CARD_TYPE_OSM) { + if (card->info.layer_enforced) { /* fixed layer, can't switch */ rc = -EOPNOTSUPP; goto out; diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index bd2df62a5cdf..70b633f951ea 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -1017,6 +1017,13 @@ static int qeth_l2_start_ipassists(struct qeth_card *card) return 0; } +static void qeth_l2_trace_features(struct qeth_card *card) +{ + QETH_CARD_TEXT(card, 2, "l2featur"); + QETH_CARD_HEX(card, 2, &card->options.sbp.supported_funcs, + sizeof(card->options.sbp.supported_funcs)); +} + static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); @@ -1040,6 +1047,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) dev_info(&card->gdev->dev, "The device represents a Bridge Capable Port\n"); qeth_trace_features(card); + qeth_l2_trace_features(card); if (!card->dev && qeth_l2_setup_netdev(card)) { rc = -ENODEV; diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index 26f79533e62e..9b5e439f18cf 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h @@ -65,6 +65,7 @@ struct qeth_ipato_entry { int mask_bits; }; +extern const struct attribute_group *qeth_l3_attr_groups[]; void qeth_l3_ipaddr_to_string(enum qeth_prot_versions, const __u8 *, char *); int qeth_l3_string_to_ipaddr(const char *, enum qeth_prot_versions, __u8 *); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index d8df1e635163..37b594231b76 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -956,31 +956,6 @@ static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card) return rc; } -static int qeth_l3_start_ipa_ip_fragmentation(struct qeth_card *card) -{ - int rc; - - QETH_CARD_TEXT(card, 3, "ipaipfrg"); - - if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) { - dev_info(&card->gdev->dev, - "Hardware IP fragmentation not supported on %s\n", - QETH_CARD_IFNAME(card)); - return -EOPNOTSUPP; - } - - rc = qeth_send_simple_setassparms(card, IPA_IP_FRAGMENTATION, - IPA_CMD_ASS_START, 0); - if (rc) { - dev_warn(&card->gdev->dev, - "Starting IP fragmentation support for %s failed\n", - QETH_CARD_IFNAME(card)); - } else - dev_info(&card->gdev->dev, - "Hardware IP fragmentation enabled \n"); - return rc; -} - static int qeth_l3_start_ipa_source_mac(struct qeth_card *card) { int rc; @@ -1060,9 +1035,6 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card) QETH_CARD_TEXT(card, 3, "softipv6"); - if (card->info.type == QETH_CARD_TYPE_IQD) - goto out; - rc = qeth_query_ipassists(card, QETH_PROT_IPV6); if (rc) { dev_err(&card->gdev->dev, @@ -1070,6 +1042,10 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card) QETH_CARD_IFNAME(card)); return rc; } + + if (card->info.type == QETH_CARD_TYPE_IQD) + goto out; + rc = qeth_send_simple_setassparms(card, IPA_IPV6, IPA_CMD_ASS_START, 3); if (rc) { @@ -1171,7 +1147,6 @@ static int qeth_l3_start_ipassists(struct qeth_card *card) if (qeth_set_access_ctrl_online(card, 0)) return -EIO; qeth_l3_start_ipa_arp_processing(card); /* go on*/ - qeth_l3_start_ipa_ip_fragmentation(card); /* go on*/ qeth_l3_start_ipa_source_mac(card); /* go on*/ qeth_l3_start_ipa_vlan(card); /* go on*/ qeth_l3_start_ipa_multicast(card); /* go on*/ @@ -2702,8 +2677,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, use_tso = skb_is_gso(skb) && (qeth_get_ip_protocol(skb) == IPPROTO_TCP) && (ipv == 4); - if ((card->info.type == QETH_CARD_TYPE_IQD) && - !skb_is_nonlinear(skb)) { + if (card->info.type == QETH_CARD_TYPE_IQD) { new_skb = skb; data_offset = ETH_HLEN; hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); @@ -2716,12 +2690,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, + VLAN_HLEN); if (!new_skb) goto tx_drop; - } - if (card->info.type == QETH_CARD_TYPE_IQD) { - if (data_offset < 0) - skb_pull(new_skb, ETH_HLEN); - } else { if (ipv == 4) { skb_pull(new_skb, ETH_HLEN); } @@ -3036,14 +3005,21 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) return register_netdev(card->dev); } +static const struct device_type qeth_l3_devtype = { + .name = "qeth_layer3", + .groups = qeth_l3_attr_groups, +}; + static int qeth_l3_probe_device(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); int rc; - rc = qeth_l3_create_device_attributes(&gdev->dev); - if (rc) - return rc; + if (gdev->dev.type == &qeth_generic_devtype) { + rc = qeth_l3_create_device_attributes(&gdev->dev); + if (rc) + return rc; + } hash_init(card->ip_htable); hash_init(card->ip_mc_htable); card->options.layer2 = 0; @@ -3055,7 +3031,8 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) { struct qeth_card *card = dev_get_drvdata(&cgdev->dev); - qeth_l3_remove_device_attributes(&cgdev->dev); + if (cgdev->dev.type == &qeth_generic_devtype) + qeth_l3_remove_device_attributes(&cgdev->dev); qeth_set_allowed_threads(card, 0, 1); wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); @@ -3311,7 +3288,7 @@ static int qeth_l3_control_event(struct qeth_card *card, } struct qeth_discipline qeth_l3_discipline = { - .devtype = &qeth_generic_devtype, + .devtype = &qeth_l3_devtype, .start_poll = qeth_qdio_start_poll, .input_handler = (qdio_handler_t *) qeth_qdio_input_handler, .output_handler = (qdio_handler_t *) qeth_qdio_output_handler, diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index ff29a4b416b4..f2f94f59e0fa 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -1049,3 +1049,14 @@ void qeth_l3_remove_device_attributes(struct device *dev) sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group); sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group); } + +const struct attribute_group *qeth_l3_attr_groups[] = { + &qeth_device_attr_group, + &qeth_device_blkt_group, + /* l3 specific, see l3_{create,remove}_device_attributes(): */ + &qeth_l3_device_attr_group, + &qeth_device_ipato_group, + &qeth_device_vipa_group, + &qeth_device_rxip_group, +NULL, +}; diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index a5c97342fd5d..b97405ed6cae 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -2954,7 +2954,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) "WWPN=%016llx.\n", qedf->wwnn, qedf->wwpn); sprintf(host_buf, "host_%d", host->host_no); - qed_ops->common->set_id(qedf->cdev, host_buf, QEDF_VERSION); + qed_ops->common->set_name(qedf->cdev, host_buf); /* Set xid max values */ diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c index 8bc7ee1a8ca8..2ee92aa90fe9 100644 --- a/drivers/scsi/qedi/qedi_fw.c +++ b/drivers/scsi/qedi/qedi_fw.c @@ -2101,14 +2101,16 @@ int qedi_iscsi_send_ioreq(struct iscsi_task *task) /* Update header info */ SET_FIELD(cmd_pdu_header.flags_attr, ISCSI_CMD_HDR_ATTR, ISCSI_ATTR_SIMPLE); - if (sc->sc_data_direction == DMA_TO_DEVICE) { - SET_FIELD(cmd_pdu_header.flags_attr, - ISCSI_CMD_HDR_WRITE, 1); - task_type = ISCSI_TASK_TYPE_INITIATOR_WRITE; - } else { - SET_FIELD(cmd_pdu_header.flags_attr, - ISCSI_CMD_HDR_READ, 1); - task_type = ISCSI_TASK_TYPE_INITIATOR_READ; + if (hdr->cdb[0] != TEST_UNIT_READY) { + if (sc->sc_data_direction == DMA_TO_DEVICE) { + SET_FIELD(cmd_pdu_header.flags_attr, + ISCSI_CMD_HDR_WRITE, 1); + task_type = ISCSI_TASK_TYPE_INITIATOR_WRITE; + } else { + SET_FIELD(cmd_pdu_header.flags_attr, + ISCSI_CMD_HDR_READ, 1); + task_type = ISCSI_TASK_TYPE_INITIATOR_READ; + } } cmd_pdu_header.lun.lo = be32_to_cpu(scsi_lun[0]); @@ -2119,7 +2121,7 @@ int qedi_iscsi_send_ioreq(struct iscsi_task *task) cmd_pdu_header.expected_transfer_length = cpu_to_be32(hdr->data_length); cmd_pdu_header.hdr_second_dword = ntoh24(hdr->dlength); cmd_pdu_header.cmd_sn = be32_to_cpu(hdr->cmdsn); - cmd_pdu_header.opcode = hdr->opcode; + cmd_pdu_header.hdr_first_byte = hdr->opcode; qedi_cpy_scsi_cdb(sc, (u32 *)cmd_pdu_header.cdb); /* Fill tx AHS and rx buffer */ diff --git a/drivers/scsi/qedi/qedi_fw_api.c b/drivers/scsi/qedi/qedi_fw_api.c index fd354d4e03eb..7df32a68bd54 100644 --- a/drivers/scsi/qedi/qedi_fw_api.c +++ b/drivers/scsi/qedi/qedi_fw_api.c @@ -578,7 +578,8 @@ int init_initiator_rw_iscsi_task(struct iscsi_task_params *task_params, (struct iscsi_common_hdr *)cmd_header, tx_sgl_params, cmd_params, dif_task_params); - else if (GET_FIELD(cmd_header->flags_attr, ISCSI_CMD_HDR_READ)) + else if (GET_FIELD(cmd_header->flags_attr, ISCSI_CMD_HDR_READ) || + (task_params->rx_io_size == 0 && task_params->tx_io_size == 0)) return init_rw_iscsi_task(task_params, ISCSI_TASK_TYPE_INITIATOR_READ, conn_params, diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c index 87f0af358b33..80edd28b635f 100644 --- a/drivers/scsi/qedi/qedi_iscsi.c +++ b/drivers/scsi/qedi/qedi_iscsi.c @@ -1466,9 +1466,6 @@ static const struct { { ISCSI_CONN_ERROR_OUT_OF_SGES_ERROR, "out of sge error" }, - { ISCSI_CONN_ERROR_TCP_SEG_PROC_IP_OPTIONS_ERROR, - "tcp seg ip options error" - }, { ISCSI_CONN_ERROR_TCP_IP_FRAGMENT_ERROR, "tcp ip fragment error" }, diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index 09a294634bc7..f46880315ba8 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -1844,7 +1844,7 @@ static int __qedi_probe(struct pci_dev *pdev, int mode) qedi->mac); sprintf(host_buf, "host_%d", qedi->shost->host_no); - qedi_ops->common->set_id(qedi->cdev, host_buf, QEDI_MODULE_VERSION); + qedi_ops->common->set_name(qedi->cdev, host_buf); qedi_ops->register_ops(qedi->cdev, &qedi_cb_ops, qedi); diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index f61f852d6cfd..e3d7ea1288c6 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -28,6 +28,8 @@ #include <linux/if_macvlan.h> #include <linux/if_tap.h> #include <linux/if_vlan.h> +#include <linux/skb_array.h> +#include <linux/skbuff.h> #include <net/sock.h> @@ -85,6 +87,13 @@ struct vhost_net_ubuf_ref { struct vhost_virtqueue *vq; }; +#define VHOST_RX_BATCH 64 +struct vhost_net_buf { + struct sk_buff **queue; + int tail; + int head; +}; + struct vhost_net_virtqueue { struct vhost_virtqueue vq; size_t vhost_hlen; @@ -99,6 +108,8 @@ struct vhost_net_virtqueue { /* Reference counting for outstanding ubufs. * Protected by vq mutex. Writers must also take device mutex. */ struct vhost_net_ubuf_ref *ubufs; + struct skb_array *rx_array; + struct vhost_net_buf rxq; }; struct vhost_net { @@ -117,6 +128,71 @@ struct vhost_net { static unsigned vhost_net_zcopy_mask __read_mostly; +static void *vhost_net_buf_get_ptr(struct vhost_net_buf *rxq) +{ + if (rxq->tail != rxq->head) + return rxq->queue[rxq->head]; + else + return NULL; +} + +static int vhost_net_buf_get_size(struct vhost_net_buf *rxq) +{ + return rxq->tail - rxq->head; +} + +static int vhost_net_buf_is_empty(struct vhost_net_buf *rxq) +{ + return rxq->tail == rxq->head; +} + +static void *vhost_net_buf_consume(struct vhost_net_buf *rxq) +{ + void *ret = vhost_net_buf_get_ptr(rxq); + ++rxq->head; + return ret; +} + +static int vhost_net_buf_produce(struct vhost_net_virtqueue *nvq) +{ + struct vhost_net_buf *rxq = &nvq->rxq; + + rxq->head = 0; + rxq->tail = skb_array_consume_batched(nvq->rx_array, rxq->queue, + VHOST_RX_BATCH); + return rxq->tail; +} + +static void vhost_net_buf_unproduce(struct vhost_net_virtqueue *nvq) +{ + struct vhost_net_buf *rxq = &nvq->rxq; + + if (nvq->rx_array && !vhost_net_buf_is_empty(rxq)) { + skb_array_unconsume(nvq->rx_array, rxq->queue + rxq->head, + vhost_net_buf_get_size(rxq)); + rxq->head = rxq->tail = 0; + } +} + +static int vhost_net_buf_peek(struct vhost_net_virtqueue *nvq) +{ + struct vhost_net_buf *rxq = &nvq->rxq; + + if (!vhost_net_buf_is_empty(rxq)) + goto out; + + if (!vhost_net_buf_produce(nvq)) + return 0; + +out: + return __skb_array_len_with_tag(vhost_net_buf_get_ptr(rxq)); +} + +static void vhost_net_buf_init(struct vhost_net_buf *rxq) +{ + rxq->head = rxq->tail = 0; +} + static void vhost_net_enable_zcopy(int vq) { vhost_net_zcopy_mask |= 0x1 << vq; @@ -201,6 +277,7 @@ static void vhost_net_vq_reset(struct vhost_net *n) n->vqs[i].ubufs = NULL; n->vqs[i].vhost_hlen = 0; n->vqs[i].sock_hlen = 0; + vhost_net_buf_init(&n->vqs[i].rxq); } } @@ -503,15 +580,14 @@ out: mutex_unlock(&vq->mutex); } -static int peek_head_len(struct sock *sk) +static int peek_head_len(struct vhost_net_virtqueue *rvq, struct sock *sk) { - struct socket *sock = sk->sk_socket; struct sk_buff *head; int len = 0; unsigned long flags; - if (sock->ops->peek_len) - return sock->ops->peek_len(sock); + if (rvq->rx_array) + return vhost_net_buf_peek(rvq); spin_lock_irqsave(&sk->sk_receive_queue.lock, flags); head = skb_peek(&sk->sk_receive_queue); @@ -537,10 +613,11 @@ static int sk_has_rx_data(struct sock *sk) static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) { + struct vhost_net_virtqueue *rvq = &net->vqs[VHOST_NET_VQ_RX]; struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX]; struct vhost_virtqueue *vq = &nvq->vq; unsigned long uninitialized_var(endtime); - int len = peek_head_len(sk); + int len = peek_head_len(rvq, sk); if (!len && vq->busyloop_timeout) { /* Both tx vq and rx socket were polled here */ @@ -561,7 +638,7 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) vhost_poll_queue(&vq->poll); mutex_unlock(&vq->mutex); - len = peek_head_len(sk); + len = peek_head_len(rvq, sk); } return len; @@ -699,6 +776,8 @@ static void handle_rx(struct vhost_net *net) /* On error, stop handling until the next kick. */ if (unlikely(headcount < 0)) goto out; + if (nvq->rx_array) + msg.msg_control = vhost_net_buf_consume(&nvq->rxq); /* On overrun, truncate and discard */ if (unlikely(headcount > UIO_MAXIOV)) { iov_iter_init(&msg.msg_iter, READ, vq->iov, 1, 1); @@ -815,6 +894,7 @@ static int vhost_net_open(struct inode *inode, struct file *f) struct vhost_net *n; struct vhost_dev *dev; struct vhost_virtqueue **vqs; + struct sk_buff **queue; int i; n = kvmalloc(sizeof *n, GFP_KERNEL | __GFP_REPEAT); @@ -826,6 +906,15 @@ static int vhost_net_open(struct inode *inode, struct file *f) return -ENOMEM; } + queue = kmalloc_array(VHOST_RX_BATCH, sizeof(struct sk_buff *), + GFP_KERNEL); + if (!queue) { + kfree(vqs); + kvfree(n); + return -ENOMEM; + } + n->vqs[VHOST_NET_VQ_RX].rxq.queue = queue; + dev = &n->dev; vqs[VHOST_NET_VQ_TX] = &n->vqs[VHOST_NET_VQ_TX].vq; vqs[VHOST_NET_VQ_RX] = &n->vqs[VHOST_NET_VQ_RX].vq; @@ -838,6 +927,7 @@ static int vhost_net_open(struct inode *inode, struct file *f) n->vqs[i].done_idx = 0; n->vqs[i].vhost_hlen = 0; n->vqs[i].sock_hlen = 0; + vhost_net_buf_init(&n->vqs[i].rxq); } vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX); @@ -853,11 +943,14 @@ static struct socket *vhost_net_stop_vq(struct vhost_net *n, struct vhost_virtqueue *vq) { struct socket *sock; + struct vhost_net_virtqueue *nvq = + container_of(vq, struct vhost_net_virtqueue, vq); mutex_lock(&vq->mutex); sock = vq->private_data; vhost_net_disable_vq(n, vq); vq->private_data = NULL; + vhost_net_buf_unproduce(nvq); mutex_unlock(&vq->mutex); return sock; } @@ -912,6 +1005,7 @@ static int vhost_net_release(struct inode *inode, struct file *f) /* We do an extra flush before freeing memory, * since jobs can re-queue themselves. */ vhost_net_flush(n); + kfree(n->vqs[VHOST_NET_VQ_RX].rxq.queue); kfree(n->dev.vqs); kvfree(n); return 0; @@ -950,6 +1044,25 @@ err: return ERR_PTR(r); } +static struct skb_array *get_tap_skb_array(int fd) +{ + struct skb_array *array; + struct file *file = fget(fd); + + if (!file) + return NULL; + array = tun_get_skb_array(file); + if (!IS_ERR(array)) + goto out; + array = tap_get_skb_array(file); + if (!IS_ERR(array)) + goto out; + array = NULL; +out: + fput(file); + return array; +} + static struct socket *get_tap_socket(int fd) { struct file *file = fget(fd); @@ -1026,6 +1139,9 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) vhost_net_disable_vq(n, vq); vq->private_data = sock; + vhost_net_buf_unproduce(nvq); + if (index == VHOST_NET_VQ_RX) + nvq->rx_array = get_tap_skb_array(fd); r = vhost_vq_init_access(vq); if (r) goto err_used; |