From patchwork Thu Jun 14 11:11:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilias Apalodimas X-Patchwork-Id: 138552 Delivered-To: patch@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp1968409lji; Thu, 14 Jun 2018 04:11:49 -0700 (PDT) X-Google-Smtp-Source: ADUXVKKUJBsCD4mH/vX3y+Ytxx/tG46TLdBhWzE0FKmV2oeq4z8DOY03WFi92Xnqd1QqUA4u2HSp X-Received: by 2002:a65:58cc:: with SMTP id e12-v6mr1912631pgu.445.1528974709389; Thu, 14 Jun 2018 04:11:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1528974709; cv=none; d=google.com; s=arc-20160816; b=sYxG+vb37SwgIzNeDn2l5wGGgkNwL8mhAFDyKaSodpX9u7/wQizZDf6ZM7KlU8yC6y sEvHt0vvmazmOwoInlNHEbggLOodRjcT/lixJPbBRHM7dJsl9pRqlKynfOlVyn3e4RnS lsskLF8J2SvAgI8+ZsQqegn04muJTjnwU+L6Oij1i9+SJe1zJQMvoTuN1ovQd1ZS3+a8 3kCmIPqd9W9412zeptnOZmEnw3JoSfY4ntC6hz/G75BPanWDLbl/xwhfyIUpmbUkuYn2 sgVaI9UskYMItpKvlRhoIxZl41ATC0ZLR1918+a0w4IewqOdO8uwsI7LNk/EuXbN1V1Q 2OGw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=fe8kQSevfBPG3Ez1K4uigPXdK7HWHn6RbDGBTz6XWpk=; b=KFCKfsZz9gCIIpevSwwyKvMjZlZDaF1BCFprNPVboxCgdBdMVDeyT6tI9QW/ylN/m6 4K6xT678RGjWfnfWkmsL7J9j+yLlz0odt+zD1Q95J4tPnGO9Z2zmIaLBB/d/PvwQ9p8B L/uvuZ7FJl/6nzi2ViLgaaIfVQmE0K2eNw4p5R5kV35rHtbhDBhMZO5Dqrc0rFyAHDYx YKJJ5Yu2kvKyRqG/PphVeiI4Zi/OCh6CzW8aoJsRXS38/NlhISouUnVvHdunxX22Rvd2 rA3/nr185aQnaMtexnjqStQkhkblQQ/KucHZ57ANKAcdNSOn1/ZMw2ZWgEScfg9dXNLT XSyA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=eAL7zNk4; spf=pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=netdev-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y83-v6si5037554pfb.284.2018.06.14.04.11.49; Thu, 14 Jun 2018 04:11:49 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=eAL7zNk4; spf=pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=netdev-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755034AbeFNLLq (ORCPT + 9 others); Thu, 14 Jun 2018 07:11:46 -0400 Received: from mail-wm0-f66.google.com ([74.125.82.66]:52847 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754873AbeFNLLn (ORCPT ); Thu, 14 Jun 2018 07:11:43 -0400 Received: by mail-wm0-f66.google.com with SMTP id p126-v6so9878759wmb.2 for ; Thu, 14 Jun 2018 04:11:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=fe8kQSevfBPG3Ez1K4uigPXdK7HWHn6RbDGBTz6XWpk=; b=eAL7zNk4wBkr9RJgjeAD1WAE//IvmIf+zJq/LOql05rH3NI/qvmpPobnRbM/7H5nBc +6qW6i+Vn90X2n4Kp1GIJxtgovp3ndp2w3vOzHFlk03IwKU9Op+QA3uTdnLddD84g3/K vGDQ0Ho5NF4cs6wUyPbQPJwei132xxv+qEQ7Y= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=fe8kQSevfBPG3Ez1K4uigPXdK7HWHn6RbDGBTz6XWpk=; b=SMNK52BgCE7L7XjWcTgSiQMgPi9GHLvGjMbZbpzomNq1Va+5EAjg1t+zWSJvDuKSmB 1qEz5Om+PYWhJJlm0OKgXYwp7bKWhDULx2JL95s0VWJfY4bC8UZIjSmVFCXMKPL4qHeW VLxpp8ID+Nz+G2FONW0QaMnVo8J/K57t7fVGHx5eII9jhrsPLbIrYNcquHCPb/xiJXVr j/eePR+HrLPD7AYkcGHKnydfxkOJUMs7fkWrk/vzK68hNdhpC0+JjuvNa7aLRx68NxQk JlHLSjdjwe/1NhGphBnWkj2vXLbYIqEmqEg8tkMOHrQExuBlu7tmHqOwxI8zWMPbxxTD fv+g== X-Gm-Message-State: APt69E3SGBsdnKZNClUbpN5CPOAb5BJY5mQxvTcgDcqgkUXm/Xx+Fnp7 gMv2M1JYopkbsXQqgnP7DjUMwTgpQbs= X-Received: by 2002:a1c:c05:: with SMTP id 5-v6mr1599993wmm.117.1528974701893; Thu, 14 Jun 2018 04:11:41 -0700 (PDT) Received: from localhost.localdomain ([2a02:587:4609:4e00:6c01:5076:e5d5:7a4c]) by smtp.gmail.com with ESMTPSA id t124-v6sm3657466wmt.29.2018.06.14.04.11.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 14 Jun 2018 04:11:41 -0700 (PDT) From: Ilias Apalodimas To: netdev@vger.kernel.org, grygorii.strashko@ti.com, ivan.khoronzhuk@linaro.org, nsekhar@ti.com, jiri@resnulli.us, ivecera@redhat.com, andrew@lunn.ch, f.fainelli@gmail.com Cc: francois.ozog@linaro.org, yogeshs@ti.com, spatton@ti.com, Jose.Abreu@synopsys.com, Ilias Apalodimas Subject: [RFC v2, net-next, PATCH 1/4] net/cpsw: move common headers definitions to cpsw_priv.h Date: Thu, 14 Jun 2018 14:11:27 +0300 Message-Id: <1528974690-31600-2-git-send-email-ilias.apalodimas@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1528974690-31600-1-git-send-email-ilias.apalodimas@linaro.org> References: <1528974690-31600-1-git-send-email-ilias.apalodimas@linaro.org> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org A following patch introduces switchdev functionality. Move common definitions to a private header file Signed-off-by: Ilias Apalodimas --- drivers/net/ethernet/ti/cpsw.c | 111 +--------------------------- drivers/net/ethernet/ti/cpsw_priv.h | 141 ++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 110 deletions(-) create mode 100644 drivers/net/ethernet/ti/cpsw_priv.h -- 2.7.4 diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 534596c..d13b57f 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -42,6 +42,7 @@ #include "cpsw.h" #include "cpsw_ale.h" +#include "cpsw_priv.h" #include "cpts.h" #include "davinci_cpdma.h" @@ -89,7 +90,6 @@ do { \ #define CPSW_VERSION_3 0x19010f #define CPSW_VERSION_4 0x190112 -#define HOST_PORT_NUM 0 #define CPSW_ALE_PORTS_NUM 3 #define SLIVER_SIZE 0x40 @@ -310,16 +310,6 @@ struct cpsw_ss_regs { #define CPSW_MAX_BLKS_TX_SHIFT 4 #define CPSW_MAX_BLKS_RX 5 -struct cpsw_host_regs { - u32 max_blks; - u32 blk_cnt; - u32 tx_in_ctl; - u32 port_vlan; - u32 tx_pri_map; - u32 cpdma_tx_pri_map; - u32 cpdma_rx_chan_map; -}; - struct cpsw_sliver_regs { u32 id_ver; u32 mac_control; @@ -371,105 +361,6 @@ struct cpsw_hw_stats { u32 rxdmaoverruns; }; -struct cpsw_slave_data { - struct device_node *phy_node; - char phy_id[MII_BUS_ID_SIZE]; - int phy_if; - u8 mac_addr[ETH_ALEN]; - u16 dual_emac_res_vlan; /* Reserved VLAN for DualEMAC */ -}; - -struct cpsw_platform_data { - struct cpsw_slave_data *slave_data; - u32 ss_reg_ofs; /* Subsystem control register offset */ - u32 channels; /* number of cpdma channels (symmetric) */ - u32 slaves; /* number of slave cpgmac ports */ - u32 active_slave; /* time stamping, ethtool and SIOCGMIIPHY slave */ - u32 ale_entries; /* ale table size */ - u32 bd_ram_size; /*buffer descriptor ram size */ - u32 mac_control; /* Mac control register */ - u16 default_vlan; /* Def VLAN for ALE lookup in VLAN aware mode*/ - bool dual_emac; /* Enable Dual EMAC mode */ -}; - -struct cpsw_slave { - void __iomem *regs; - struct cpsw_sliver_regs __iomem *sliver; - int slave_num; - u32 mac_control; - struct cpsw_slave_data *data; - struct phy_device *phy; - struct net_device *ndev; - u32 port_vlan; -}; - -static inline u32 slave_read(struct cpsw_slave *slave, u32 offset) -{ - return readl_relaxed(slave->regs + offset); -} - -static inline void slave_write(struct cpsw_slave *slave, u32 val, u32 offset) -{ - writel_relaxed(val, slave->regs + offset); -} - -struct cpsw_vector { - struct cpdma_chan *ch; - int budget; -}; - -struct cpsw_common { - struct device *dev; - struct cpsw_platform_data data; - struct napi_struct napi_rx; - struct napi_struct napi_tx; - struct cpsw_ss_regs __iomem *regs; - struct cpsw_wr_regs __iomem *wr_regs; - u8 __iomem *hw_stats; - struct cpsw_host_regs __iomem *host_port_regs; - u32 version; - u32 coal_intvl; - u32 bus_freq_mhz; - int rx_packet_max; - struct cpsw_slave *slaves; - struct cpdma_ctlr *dma; - struct cpsw_vector txv[CPSW_MAX_QUEUES]; - struct cpsw_vector rxv[CPSW_MAX_QUEUES]; - struct cpsw_ale *ale; - bool quirk_irq; - bool rx_irq_disabled; - bool tx_irq_disabled; - u32 irqs_table[IRQ_NUM]; - struct cpts *cpts; - int rx_ch_num, tx_ch_num; - int speed; - int usage_count; -}; - -struct cpsw_priv { - struct net_device *ndev; - struct device *dev; - u32 msg_enable; - u8 mac_addr[ETH_ALEN]; - bool rx_pause; - bool tx_pause; - u32 emac_port; - struct cpsw_common *cpsw; -}; - -struct cpsw_stats { - char stat_string[ETH_GSTRING_LEN]; - int type; - int sizeof_stat; - int stat_offset; -}; - -enum { - CPSW_STATS, - CPDMA_RX_STATS, - CPDMA_TX_STATS, -}; - #define CPSW_STAT(m) CPSW_STATS, \ sizeof(((struct cpsw_hw_stats *)0)->m), \ offsetof(struct cpsw_hw_stats, m) diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h new file mode 100644 index 0000000..3b02a83 --- /dev/null +++ b/drivers/net/ethernet/ti/cpsw_priv.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include +#include + +#define HOST_PORT_NUM 0 +#define IRQ_NUM 2 +#define CPSW_MAX_QUEUES 8 + +#define CPSW_VERSION_1 0x19010a +#define CPSW_VERSION_2 0x19010c +#define CPSW_VERSION_3 0x19010f +#define CPSW_VERSION_4 0x190112 + +/* CPSW_PORT_V1 */ +#define CPSW1_MAX_BLKS 0x00 /* Maximum FIFO Blocks */ +#define CPSW1_BLK_CNT 0x04 /* FIFO Block Usage Count (Read Only) */ +#define CPSW1_TX_IN_CTL 0x08 /* Transmit FIFO Control */ +#define CPSW1_PORT_VLAN 0x0c /* VLAN Register */ +#define CPSW1_TX_PRI_MAP 0x10 /* Tx Header Priority to Switch Pri Mapping */ +#define CPSW1_TS_CTL 0x14 /* Time Sync Control */ +#define CPSW1_TS_SEQ_LTYPE 0x18 /* Time Sync Sequence ID Offset and Msg Type */ +#define CPSW1_TS_VLAN 0x1c /* Time Sync VLAN1 and VLAN2 */ + +/* CPSW_PORT_V2 */ +#define CPSW2_CONTROL 0x00 /* Control Register */ +#define CPSW2_MAX_BLKS 0x08 /* Maximum FIFO Blocks */ +#define CPSW2_BLK_CNT 0x0c /* FIFO Block Usage Count (Read Only) */ +#define CPSW2_TX_IN_CTL 0x10 /* Transmit FIFO Control */ +#define CPSW2_PORT_VLAN 0x14 /* VLAN Register */ +#define CPSW2_TX_PRI_MAP 0x18 /* Tx Header Priority to Switch Pri Mapping */ +#define CPSW2_TS_SEQ_MTYPE 0x1c /* Time Sync Sequence ID Offset and Msg Type */ + +struct cpsw_slave_data { + struct device_node *phy_node; + char phy_id[MII_BUS_ID_SIZE]; + int phy_if; + u8 mac_addr[ETH_ALEN]; + u16 dual_emac_res_vlan; /* Reserved VLAN for DualEMAC */ +}; + +struct cpsw_platform_data { + struct cpsw_slave_data *slave_data; + u32 ss_reg_ofs; /* Subsystem control register offset */ + u32 channels; /* number of cpdma channels (symmetric) */ + u32 slaves; /* number of slave cpgmac ports */ + u32 active_slave; /* time stamping, ethtool and SIOCGMIIPHY slave */ + u32 ale_entries; /* ale table size */ + u32 bd_ram_size; /*buffer descriptor ram size */ + u32 mac_control; /* Mac control register */ + u16 default_vlan; /* Def VLAN for ALE lookup in VLAN aware mode*/ + bool dual_emac; /* Enable Dual EMAC mode */ +}; + +struct cpsw_slave { + void __iomem *regs; + struct cpsw_sliver_regs __iomem *sliver; + int slave_num; + u32 mac_control; + struct cpsw_slave_data *data; + struct phy_device *phy; + struct net_device *ndev; + u32 port_vlan; +}; + +struct cpsw_vector { + struct cpdma_chan *ch; + int budget; +}; + +struct cpsw_common { + struct device *dev; + struct cpsw_platform_data data; + struct napi_struct napi_rx; + struct napi_struct napi_tx; + struct cpsw_ss_regs __iomem *regs; + struct cpsw_wr_regs __iomem *wr_regs; + u8 __iomem *hw_stats; + struct cpsw_host_regs __iomem *host_port_regs; + u32 version; + u32 coal_intvl; + u32 bus_freq_mhz; + int rx_packet_max; + struct cpsw_slave *slaves; + struct cpdma_ctlr *dma; + struct cpsw_vector txv[CPSW_MAX_QUEUES]; + struct cpsw_vector rxv[CPSW_MAX_QUEUES]; + struct cpsw_ale *ale; + bool quirk_irq; + bool rx_irq_disabled; + bool tx_irq_disabled; + u32 irqs_table[IRQ_NUM]; + struct cpts *cpts; + int rx_ch_num, tx_ch_num; + int speed; + int usage_count; +}; + +struct cpsw_priv { + struct net_device *ndev; + struct device *dev; + u32 msg_enable; + u8 mac_addr[ETH_ALEN]; + bool rx_pause; + bool tx_pause; + u8 port_state[3]; + u32 emac_port; + struct cpsw_common *cpsw; +}; + +struct cpsw_stats { + char stat_string[ETH_GSTRING_LEN]; + int type; + int sizeof_stat; + int stat_offset; +}; + +enum { + CPSW_STATS, + CPDMA_RX_STATS, + CPDMA_TX_STATS, +}; + +struct cpsw_host_regs { + u32 max_blks; + u32 blk_cnt; + u32 tx_in_ctl; + u32 port_vlan; + u32 tx_pri_map; + u32 cpdma_tx_pri_map; + u32 cpdma_rx_chan_map; +}; + +static inline u32 slave_read(struct cpsw_slave *slave, u32 offset) +{ + return readl_relaxed(slave->regs + offset); +} + +static inline void slave_write(struct cpsw_slave *slave, u32 val, u32 offset) +{ + writel_relaxed(val, slave->regs + offset); +} From patchwork Thu Jun 14 11:11:28 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilias Apalodimas X-Patchwork-Id: 138555 Delivered-To: patch@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp1968726lji; Thu, 14 Jun 2018 04:12:06 -0700 (PDT) X-Google-Smtp-Source: ADUXVKLIIan48V81lq8txC3i0wX/dMiOfj5XRvouwLholzjVHOLCAixSUfT863+f2GM7H8B13ilg X-Received: by 2002:a62:cd82:: with SMTP id o124-v6mr9050476pfg.250.1528974726058; Thu, 14 Jun 2018 04:12:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1528974726; cv=none; d=google.com; s=arc-20160816; b=yKcVYC7ATstrQ0//TlybfAl/vzFCakVj/s53whzl75RjvI6+tSgUeu3N45PfzN+CS6 Raq5T61nZshwo7+OEeDF7nEX1gqh8yJj+ymO79jbgM1h3jtntYm1IWGpvW0XJ7XZ64nR AmT7Zt0CdE2S9pMHoi5kH8YKHTDovx2gUN2FPfKDZwi2D4HIM+7efhY4qpZIDWxqcpDI JVZYufVB9DYh/oP5u4/8TeSdKmth6kMzZKVKWy4qjah29R60eoLL4Xtnnsy+f5ChRbDD IW5N0KwjjfzKCT+jiR0wNGbXPbMtjmuARKoc8yjJILCedItLzlrhBD9SrxoKfc26F7mt m8xA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=Wo0dNMqrIMS6HLCCh3YBvEwVNz86ABV8d0hc/UcM7cs=; b=xV8lGxQktrzXuVbADb7kcaBJPi7OKFKe+I8whR8jdKJc5R9woih3jvwqbEQhw0xZ5/ g3WHuWY/UQ4K3Akb1Ba+deoEgrAnsa3pf1G71NllNixEdjzaeFyn59EOqOiVCKUqhP89 r6nFrpl3QcNTLj1SRCQB3nzD5DKMC1LH1we10mbINSRKx1Wd9zxx5R/g1nRPmoML9oZU ng6hrRrs6KUG1DEmccadL+mPv3WDK/MUlTASLFMm5oogE5OfKcyF8UGKu1/WCkEblmNn dkqRlz5RA2alhJ+ZXX8LHGNlOLxJ0J8i4aJR4LY9nm9F7wT/G7EPWnLNsTy0meRNdJ3h 32Mw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=SopZ2m5l; spf=pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=netdev-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y83-v6si5037554pfb.284.2018.06.14.04.12.05; Thu, 14 Jun 2018 04:12:06 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=SopZ2m5l; spf=pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=netdev-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755132AbeFNLMD (ORCPT + 9 others); Thu, 14 Jun 2018 07:12:03 -0400 Received: from mail-wr0-f172.google.com ([209.85.128.172]:43816 "EHLO mail-wr0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754809AbeFNLLp (ORCPT ); Thu, 14 Jun 2018 07:11:45 -0400 Received: by mail-wr0-f172.google.com with SMTP id d2-v6so5958447wrm.10 for ; Thu, 14 Jun 2018 04:11:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Wo0dNMqrIMS6HLCCh3YBvEwVNz86ABV8d0hc/UcM7cs=; b=SopZ2m5lUDb6/0jVV2zha+Pov9GuHcJyfmPyzyzLibPKU8HkrE1UZVn2jJr6JHbTPL wp5KxL4ij1hH35fQfi/7mcYq326taD0YcHQl01mI6eLbCciSJQiSXfTwBuIZbAzIY7s0 VMqSGpNeido67ZBdCnIRQPhU3I7VWeqS8eyG8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Wo0dNMqrIMS6HLCCh3YBvEwVNz86ABV8d0hc/UcM7cs=; b=LLqLIGRcZ6kQi1DS52BNlPtQtqt3wN1OMtVvRiLs49vkvofvrrcSEiu0BNUnBrWSad vf3TQOHussHmCKLpSfDwVrGruVll56qboVdDco4lYmQXoKc17oB4+YTrUaBwpSPX5UoK nrJo6qvxGenCE/P6TaKMWmn1JotLpcgm87N6dejebQpT60ChptttN4hKbVL7Y4k594Oe KNHGvbfQFg0IEBadyGcxH24v1L59eY50GA8wo7O3zmB6YVNua2EOV1lYVCMdy/XIs4WU eZSF3GoeXapRBvOjiX/+3N2VT4wE4xIEgRB01GADYOMAmxI6IDzL4a+0h/Ehwu9d1aZb nCbg== X-Gm-Message-State: APt69E01Lhp/rJ3hdl/lYqOGqd0wnjR8kbfpSX5Vt277YIP+t0Smuwds xI848u6NEJ+X+BtHOY5qC53QkJ4j9oQ= X-Received: by 2002:adf:e084:: with SMTP id c4-v6mr1758581wri.199.1528974703781; Thu, 14 Jun 2018 04:11:43 -0700 (PDT) Received: from localhost.localdomain ([2a02:587:4609:4e00:6c01:5076:e5d5:7a4c]) by smtp.gmail.com with ESMTPSA id t124-v6sm3657466wmt.29.2018.06.14.04.11.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 14 Jun 2018 04:11:43 -0700 (PDT) From: Ilias Apalodimas To: netdev@vger.kernel.org, grygorii.strashko@ti.com, ivan.khoronzhuk@linaro.org, nsekhar@ti.com, jiri@resnulli.us, ivecera@redhat.com, andrew@lunn.ch, f.fainelli@gmail.com Cc: francois.ozog@linaro.org, yogeshs@ti.com, spatton@ti.com, Jose.Abreu@synopsys.com, Ilias Apalodimas Subject: [RFC v2, net-next, PATCH 2/4] net/cpsw_ale: add functions to modify VLANs/MDBs Date: Thu, 14 Jun 2018 14:11:28 +0300 Message-Id: <1528974690-31600-3-git-send-email-ilias.apalodimas@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1528974690-31600-1-git-send-email-ilias.apalodimas@linaro.org> References: <1528974690-31600-1-git-send-email-ilias.apalodimas@linaro.org> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org A following patch introduces switchdev functionality. Add functions to cpsw ALE engine to modify VLANs/MDBs Signed-off-by: Ilias Apalodimas --- drivers/net/ethernet/ti/cpsw_ale.c | 188 ++++++++++++++++++++++++++++++++++++- drivers/net/ethernet/ti/cpsw_ale.h | 10 ++ 2 files changed, 195 insertions(+), 3 deletions(-) -- 2.7.4 diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 93dc05c..98e6bcd 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -287,6 +287,9 @@ int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid) if (cpsw_ale_get_mcast(ale_entry)) { u8 addr[6]; + if (cpsw_ale_get_super(ale_entry)) + continue; + cpsw_ale_get_addr(ale_entry, addr); if (!is_broadcast_ether_addr(addr)) cpsw_ale_flush_mcast(ale, ale_entry, port_mask); @@ -365,7 +368,7 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid); cpsw_ale_set_addr(ale_entry, addr); - cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); + cpsw_ale_set_super(ale_entry, (flags & ALE_SUPER) ? 1 : 0); cpsw_ale_set_mcast_state(ale_entry, mcast_state); mask = cpsw_ale_get_port_mask(ale_entry, @@ -409,6 +412,46 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, } EXPORT_SYMBOL_GPL(cpsw_ale_del_mcast); +static int cpsw_ale_read_mc(struct cpsw_ale *ale, u8 *addr, int flags, u16 vid) +{ + u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; + int idx; + + idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); + if (idx >= 0) + cpsw_ale_read(ale, idx, ale_entry); + + return cpsw_ale_get_port_mask(ale_entry, ale->port_mask_bits); +} + +int cpsw_ale_mcast_add_modify(struct cpsw_ale *ale, u8 *addr, int port_mask, + int flags, u16 vid, int mcast_state) +{ + int mcast_members, ret; + + mcast_members = cpsw_ale_read_mc(ale, addr, flags, vid) | port_mask; + ret = cpsw_ale_add_mcast(ale, addr, mcast_members, flags, vid, + mcast_state); + + return ret; +} + +int cpsw_ale_mcast_del_modify(struct cpsw_ale *ale, u8 *addr, int port_mask, + int flags, u16 vid) +{ + int mcast_members, ret; + int idx; + + mcast_members = cpsw_ale_read_mc(ale, addr, flags, vid) & ~port_mask; + idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); + if (idx < 0) + return 0; + ret = cpsw_ale_del_mcast(ale, addr, mcast_members, flags, vid); + + return ret; +} +EXPORT_SYMBOL_GPL(cpsw_ale_mcast_del_modify); + /* ALE NetCP NU switch specific vlan functions */ static void cpsw_ale_set_vlan_mcast(struct cpsw_ale *ale, u32 *ale_entry, int reg_mcast, int unreg_mcast) @@ -424,6 +467,52 @@ static void cpsw_ale_set_vlan_mcast(struct cpsw_ale *ale, u32 *ale_entry, writel(unreg_mcast, ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx)); } +static int cpsw_ale_read_untagged(struct cpsw_ale *ale, u16 vid) +{ + u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; + int idx; + + idx = cpsw_ale_match_vlan(ale, vid); + if (idx >= 0) + cpsw_ale_read(ale, idx, ale_entry); + + return cpsw_ale_get_vlan_untag_force(ale_entry, ale->vlan_field_bits); +} + +/* returns mask of current members for specificed vlan */ +static int cpsw_ale_read_vlan_members(struct cpsw_ale *ale, u16 vid) +{ + u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; + int idx; + + idx = cpsw_ale_match_vlan(ale, vid); + if (idx >= 0) + cpsw_ale_read(ale, idx, ale_entry); + + return cpsw_ale_get_vlan_member_list(ale_entry, ale->vlan_field_bits); +} + +/* returns mask of registered/unregistered multicast registration */ +static int cpsw_ale_read_reg_unreg_mc(struct cpsw_ale *ale, u16 vid, bool unreg) +{ + u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; + int idx; + int ret; + + idx = cpsw_ale_match_vlan(ale, vid); + if (idx >= 0) + cpsw_ale_read(ale, idx, ale_entry); + + if (unreg) + ret = cpsw_ale_get_vlan_unreg_mcast(ale_entry, + ale->vlan_field_bits); + else + ret = cpsw_ale_get_vlan_reg_mcast(ale_entry, + ale->vlan_field_bits); + + return ret; +} + int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, int reg_mcast, int unreg_mcast) { @@ -462,6 +551,11 @@ EXPORT_SYMBOL_GPL(cpsw_ale_add_vlan); int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) { + int reg_mcast = + cpsw_ale_read_reg_unreg_mc(ale, vid, 0) & port_mask; + int unreg_mcast = + cpsw_ale_read_reg_unreg_mc(ale, vid, 1) & port_mask; + int untag = cpsw_ale_read_untagged(ale, vid) & port_mask; u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; int idx; @@ -471,17 +565,105 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) cpsw_ale_read(ale, idx, ale_entry); - if (port_mask) + if (port_mask) { + cpsw_ale_set_vlan_untag_force(ale_entry, untag, + ale->vlan_field_bits); + if (!ale->params.nu_switch_ale) { + cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast, + ale->vlan_field_bits); + cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast, + ale->vlan_field_bits); + } else { + cpsw_ale_set_vlan_mcast(ale, ale_entry, reg_mcast, + unreg_mcast); + } cpsw_ale_set_vlan_member_list(ale_entry, port_mask, ale->vlan_field_bits); - else + } else { cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); + } cpsw_ale_write(ale, idx, ale_entry); + return 0; } EXPORT_SYMBOL_GPL(cpsw_ale_del_vlan); +int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask, + int untag_mask, int reg_mask, int unreg_mask) +{ + int ret = 0; + int vlan_members = cpsw_ale_read_vlan_members(ale, vid) & ~port_mask; + int reg_mcast_members = + cpsw_ale_read_reg_unreg_mc(ale, vid, 0) & ~port_mask; + int unreg_mcast_members = + cpsw_ale_read_reg_unreg_mc(ale, vid, 1) & ~port_mask; + int untag_members = cpsw_ale_read_untagged(ale, vid) & ~port_mask; + + vlan_members |= port_mask; + untag_members |= untag_mask; + reg_mcast_members |= reg_mask; + unreg_mcast_members |= unreg_mask; + + ret = cpsw_ale_add_vlan(ale, vid, vlan_members, untag_members, + reg_mcast_members, unreg_mcast_members); + if (ret) { + dev_err(ale->params.dev, "Unable to add vlan\n"); + return ret; + } + dev_dbg(ale->params.dev, "port mask 0x%x untag 0x%x\n", vlan_members, + untag_mask); + + return ret; +} +EXPORT_SYMBOL_GPL(cpsw_ale_vlan_add_modify); + +int cpsw_ale_vlan_del_modify(struct cpsw_ale *ale, u16 vid, int port_mask) +{ + int ret = 0; + int vlan_members; + + vlan_members = cpsw_ale_read_vlan_members(ale, vid); + vlan_members &= ~port_mask; + + ret = cpsw_ale_del_vlan(ale, vid, vlan_members); + if (ret) { + dev_err(ale->params.dev, "Unable to del vlan\n"); + return ret; + } + dev_dbg(ale->params.dev, "port mask 0x%x\n", port_mask); + + return ret; +} +EXPORT_SYMBOL_GPL(cpsw_ale_vlan_del_modify); + +void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask, + bool add) +{ + u32 ale_entry[ALE_ENTRY_WORDS]; + int unreg_members = 0; + int type, idx; + + for (idx = 0; idx < ale->params.ale_entries; idx++) { + cpsw_ale_read(ale, idx, ale_entry); + type = cpsw_ale_get_entry_type(ale_entry); + if (type != ALE_TYPE_VLAN) + continue; + + unreg_members = + cpsw_ale_get_vlan_unreg_mcast(ale_entry, + ale->vlan_field_bits); + if (add) + unreg_members |= unreg_mcast_mask; + else + unreg_members &= ~unreg_mcast_mask; + cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_members, + ale->vlan_field_bits); + cpsw_ale_write(ale, idx, ale_entry); + } +} +EXPORT_SYMBOL_GPL(cpsw_ale_set_unreg_mcast); + void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti) { u32 ale_entry[ALE_ENTRY_WORDS]; diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h index d4fe901..1eef640 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.h +++ b/drivers/net/ethernet/ti/cpsw_ale.h @@ -123,4 +123,14 @@ int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control, int value); void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data); +int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask, + int untag_mask, int reg_mcast, int unreg_mcast); +int cpsw_ale_vlan_del_modify(struct cpsw_ale *ale, u16 vid, int port_mask); +int cpsw_ale_mcast_add_modify(struct cpsw_ale *ale, u8 *addr, int port_mask, + int flags, u16 vid, int mcast_state); +int cpsw_ale_mcast_del_modify(struct cpsw_ale *ale, u8 *addr, int port, + int flags, u16 vid); +void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask, + bool add); + #endif From patchwork Thu Jun 14 11:11:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilias Apalodimas X-Patchwork-Id: 138553 Delivered-To: patch@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp1968483lji; Thu, 14 Jun 2018 04:11:53 -0700 (PDT) X-Google-Smtp-Source: ADUXVKJfk1QeQvBK2iujDvwt6aeISpWA2y5dSTdAv4kZJgu5f41pM+px57SQZxcLNYNscfXr1sBm X-Received: by 2002:a62:4a0c:: with SMTP id x12-v6mr9113840pfa.142.1528974713571; Thu, 14 Jun 2018 04:11:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1528974713; cv=none; d=google.com; s=arc-20160816; b=r9Mg0mkqNlX1VQQTwM8IRRtLCe915pIGgeuuhXdfhq8X2bVe0M80tzaf0xvB1CEERY NjtnbouTRNckLxBP00liIbyWbq7C+oNj58KJqBwWl0mpR8fuuvclALLk0oo0e1le0BaQ SsiEm+h+9loLkPTmIHkqH/DFUSJ0cfRjb4dId18E/boUb8Qosi5/kOUaLZsmGSAXJJZ2 3NS0oSLWmyCzkHK66AjtH5xJnhu2bt+zWdXK8BtxQKaCs3dAq90f157hGYRA8PDe1JUr leOWr+e6hGulNgKmjXlDTIdfTb+i8jcjljtrjoVjGzGQgtL3zH/BIzLSdEB0MXyuo4xu N6EQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=RM9KYDwNvXJrUYFQBVsWA9hblCRsaI/E1BFaLvUI1yE=; b=opbBjaEuB/2enfUUFI3XoFOr880gC3JTTJvyF79KTv7YbCvTy18hTqPTsvsaT4/FEw aDdPkFF/IMuG/j+uFbsu2NfQ8QWYxRIcETduLjRc3jJHHsOC4+nFVwgvNpbzVY08SMVw lOhon2iX9YlMfl5oXojyhZ3TemYPCuV1iK2VPXjFbNQ2ofiNJn6GRIkhrNjEeC3G5e87 nu1jbftrqc7yMvfw4vV3aBkGiZW7jrDXY4yQD4Q1zYtqNKaLc2C3XfMr81o7NwR4jhhb yjvLZHUkwenXz5gusdvwJK6uxml7lNnBecuNB41Ub5z3V2JOXaGWqUlCOt0ia0/aBqUd tlWQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=WnB6OSKp; spf=pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=netdev-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y83-v6si5037554pfb.284.2018.06.14.04.11.53; Thu, 14 Jun 2018 04:11:53 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=WnB6OSKp; spf=pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=netdev-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755073AbeFNLLv (ORCPT + 9 others); Thu, 14 Jun 2018 07:11:51 -0400 Received: from mail-wm0-f68.google.com ([74.125.82.68]:33601 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754873AbeFNLLr (ORCPT ); Thu, 14 Jun 2018 07:11:47 -0400 Received: by mail-wm0-f68.google.com with SMTP id z6-v6so2728366wma.0 for ; Thu, 14 Jun 2018 04:11:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=RM9KYDwNvXJrUYFQBVsWA9hblCRsaI/E1BFaLvUI1yE=; b=WnB6OSKpis2UF570GQD9Qcr10jQ+zOnfLHcSHHhXO0S07Ci4HcMbiCGY8O7lSK4vZj w8cmaI9b+QqVPNRW4wQyvoyyW9sv77TIo2kI4gxn6lMg/ZMg8ovZKl87ghkJ+18ulyS7 kQUq2PNFH5MzQNRA0u/pJXvQQ36qY+LEoX5M4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=RM9KYDwNvXJrUYFQBVsWA9hblCRsaI/E1BFaLvUI1yE=; b=mrSuBA7OIvtABBJaNvec4CQvSdljqS9EiKrEass4OeFd5vKq/K5vmbVrDnvJ2uxmIm HpzdlyRriJtva38Kxw3+B8T2XIO5Q7rQXzrPZgapvGJl0xn02GyoX0N3673jfRQztLlV Kuj4esxngdnJzMZJuTa3CBYPH0vakmCwRPEPcKZUYn30M2gMHcon7dpbpJ6fSklq7WEz eVHq5G9doHLGLfTd/PepPh28bh3BztET018hCucMG2tzHnD/onYYPJ8advkHmILjKHWq 8hu0lp/JqpHxgI6HVNFCM2TT35y/NDs2hCS13KcUTFZgiqU7xEaiX2BuLC/oegx3kMlC FWTw== X-Gm-Message-State: APt69E2aehCZMGpKZuM5fu7gfEtX0SOz8LWkqHjaqeElnl6BYUHUQT3Y xt2TZKdY4x6xWuU0U4sACc7yCGzpX0Y= X-Received: by 2002:a1c:99cf:: with SMTP id b198-v6mr1371726wme.15.1528974705875; Thu, 14 Jun 2018 04:11:45 -0700 (PDT) Received: from localhost.localdomain ([2a02:587:4609:4e00:6c01:5076:e5d5:7a4c]) by smtp.gmail.com with ESMTPSA id t124-v6sm3657466wmt.29.2018.06.14.04.11.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 14 Jun 2018 04:11:45 -0700 (PDT) From: Ilias Apalodimas To: netdev@vger.kernel.org, grygorii.strashko@ti.com, ivan.khoronzhuk@linaro.org, nsekhar@ti.com, jiri@resnulli.us, ivecera@redhat.com, andrew@lunn.ch, f.fainelli@gmail.com Cc: francois.ozog@linaro.org, yogeshs@ti.com, spatton@ti.com, Jose.Abreu@synopsys.com, Ilias Apalodimas Subject: [RFC v2, net-next, PATCH 3/4] net/cpsw: prepare cpsw for switchdev support Date: Thu, 14 Jun 2018 14:11:29 +0300 Message-Id: <1528974690-31600-4-git-send-email-ilias.apalodimas@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1528974690-31600-1-git-send-email-ilias.apalodimas@linaro.org> References: <1528974690-31600-1-git-send-email-ilias.apalodimas@linaro.org> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org A following patch introduces switchdev functionality. Prepare cpsw driver to accommodate an extra mode of operation using switchdev. This patch does not changes the cpsw driver current functionality Signed-off-by: Ilias Apalodimas --- drivers/net/ethernet/ti/cpsw.c | 146 ++++++++++++++++++++++++------------ drivers/net/ethernet/ti/cpsw_priv.h | 7 +- 2 files changed, 104 insertions(+), 49 deletions(-) -- 2.7.4 diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index d13b57f..e5765cc 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -147,9 +147,6 @@ do { \ #define CPSW_CMINTMAX_INTVL (1000 / CPSW_CMINTMIN_CNT) #define CPSW_CMINTMIN_INTVL ((1000 / CPSW_CMINTMAX_CNT) + 1) -#define cpsw_slave_index(cpsw, priv) \ - ((cpsw->data.dual_emac) ? priv->emac_port : \ - cpsw->data.active_slave) #define IRQ_NUM 2 #define CPSW_MAX_QUEUES 8 #define CPSW_CPDMA_DESCS_POOL_SIZE_DEFAULT 256 @@ -182,6 +179,9 @@ static int descs_pool_size = CPSW_CPDMA_DESCS_POOL_SIZE_DEFAULT; module_param(descs_pool_size, int, 0444); MODULE_PARM_DESC(descs_pool_size, "Number of CPDMA CPPI descriptors in pool"); +static int cpsw_is_dual_mac(u8 switch_mode); +static int cpsw_is_switch(u8 switch_mode); + struct cpsw_wr_regs { u32 id_ver; u32 soft_reset; @@ -434,8 +434,9 @@ static const struct cpsw_stats cpsw_gstrings_ch_stats[] = { struct cpsw_slave *slave; \ struct cpsw_common *cpsw = (priv)->cpsw; \ int n; \ - if (cpsw->data.dual_emac) \ - (func)((cpsw)->slaves + priv->emac_port, ##arg);\ + if (!cpsw_is_switch(cpsw->data.switch_mode)) \ + (func)((cpsw)->slaves + priv->emac_port - 1, \ + ##arg); \ else \ for (n = cpsw->data.slaves, \ slave = cpsw->slaves; \ @@ -445,7 +446,7 @@ static const struct cpsw_stats cpsw_gstrings_ch_stats[] = { #define cpsw_dual_emac_src_port_detect(cpsw, status, ndev, skb) \ do { \ - if (!cpsw->data.dual_emac) \ + if (cpsw_is_switch(cpsw->data.switch_mode)) \ break; \ if (CPDMA_RX_SOURCE_PORT(status) == 1) { \ ndev = cpsw->slaves[0].ndev; \ @@ -457,7 +458,7 @@ static const struct cpsw_stats cpsw_gstrings_ch_stats[] = { } while (0) #define cpsw_add_mcast(cpsw, priv, addr) \ do { \ - if (cpsw->data.dual_emac) { \ + if (cpsw_is_dual_mac(cpsw->data.switch_mode)) { \ struct cpsw_slave *slave = cpsw->slaves + \ priv->emac_port; \ int slave_port = cpsw_get_slave_port( \ @@ -477,13 +478,31 @@ static inline int cpsw_get_slave_port(u32 slave_num) return slave_num + 1; } +static int cpsw_is_dual_mac(u8 switch_mode) +{ + return switch_mode == CPSW_DUAL_EMAC; +} + +static int cpsw_is_switch(u8 switch_mode) +{ + return switch_mode == CPSW_TI_SWITCH; +} + +static int cpsw_slave_index(struct cpsw_priv *priv) +{ + struct cpsw_common *cpsw = priv->cpsw; + + return cpsw->data.switch_mode ? priv->emac_port - 1 : + cpsw->data.active_slave; +} + static void cpsw_set_promiscious(struct net_device *ndev, bool enable) { struct cpsw_common *cpsw = ndev_to_cpsw(ndev); struct cpsw_ale *ale = cpsw->ale; int i; - if (cpsw->data.dual_emac) { + if (cpsw_is_dual_mac(cpsw->data.switch_mode)) { bool flag = false; /* Enabling promiscuous mode for one interface will be @@ -509,7 +528,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable) cpsw_ale_control_set(ale, 0, ALE_BYPASS, 0); dev_dbg(&ndev->dev, "promiscuity disabled\n"); } - } else { + } else if (cpsw_is_switch(cpsw->data.switch_mode)) { if (enable) { unsigned long timeout = jiffies + HZ; @@ -556,10 +575,11 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev) { struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_common *cpsw = priv->cpsw; + int slave_no = cpsw_slave_index(priv); int vid; - if (cpsw->data.dual_emac) - vid = cpsw->slaves[priv->emac_port].port_vlan; + if (cpsw_is_dual_mac(cpsw->data.switch_mode)) + vid = cpsw->slaves[slave_no].port_vlan; else vid = cpsw->data.default_vlan; @@ -630,8 +650,9 @@ static void cpsw_tx_handler(void *token, int len, int status) static void cpsw_rx_vlan_encap(struct sk_buff *skb) { struct cpsw_priv *priv = netdev_priv(skb->dev); - struct cpsw_common *cpsw = priv->cpsw; u32 rx_vlan_encap_hdr = *((u32 *)skb->data); + struct cpsw_common *cpsw = priv->cpsw; + int slave_no = cpsw_slave_index(priv); u16 vtag, vid, prio, pkt_type; /* Remove VLAN header encapsulation word */ @@ -652,8 +673,8 @@ static void cpsw_rx_vlan_encap(struct sk_buff *skb) if (!vid) return; /* Ignore default vlans in dual mac mode */ - if (cpsw->data.dual_emac && - vid == cpsw->slaves[priv->emac_port].port_vlan) + if (cpsw_is_dual_mac(cpsw->data.switch_mode) && + vid == cpsw->slaves[slave_no].port_vlan) return; prio = (rx_vlan_encap_hdr >> @@ -682,9 +703,9 @@ static void cpsw_rx_handler(void *token, int len, int status) cpsw_dual_emac_src_port_detect(cpsw, status, ndev, skb); if (unlikely(status < 0) || unlikely(!netif_running(ndev))) { - /* In dual emac mode check for all interfaces */ - if (cpsw->data.dual_emac && cpsw->usage_count && - (status >= 0)) { + /* In any other that switch mode check for all interfaces */ + if (!cpsw_is_switch(cpsw->data.switch_mode) && + cpsw->usage_count && status >= 0) { /* The packet received is for the interface which * is already down and the other interface is up * and running, instead of freeing which results @@ -1235,11 +1256,11 @@ static inline int cpsw_tx_packet_submit(struct cpsw_priv *priv, struct sk_buff *skb, struct cpdma_chan *txch) { - struct cpsw_common *cpsw = priv->cpsw; skb_tx_timestamp(skb); + return cpdma_chan_submit(txch, skb, skb->data, skb->len, - priv->emac_port + cpsw->data.dual_emac); + priv->emac_port); } static inline void cpsw_add_dual_emac_def_ale_entries( @@ -1314,7 +1335,7 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) slave_port = cpsw_get_slave_port(slave->slave_num); - if (cpsw->data.dual_emac) + if (cpsw_is_dual_mac(cpsw->data.switch_mode)) cpsw_add_dual_emac_def_ale_entries(priv, slave, slave_port); else cpsw_ale_add_mcast(cpsw->ale, priv->ndev->broadcast, @@ -1393,8 +1414,8 @@ static void cpsw_init_host_port(struct cpsw_priv *priv) control_reg = readl(&cpsw->regs->control); control_reg |= CPSW_VLAN_AWARE | CPSW_RX_VLAN_ENCAP; writel(control_reg, &cpsw->regs->control); - fifo_mode = (cpsw->data.dual_emac) ? CPSW_FIFO_DUAL_MAC_MODE : - CPSW_FIFO_NORMAL_MODE; + fifo_mode = cpsw_is_dual_mac(cpsw->data.switch_mode) ? + CPSW_FIFO_DUAL_MAC_MODE : CPSW_FIFO_NORMAL_MODE; writel(fifo_mode, &cpsw->host_port_regs->tx_in_ctl); /* setup host port priority mapping */ @@ -1405,7 +1426,7 @@ static void cpsw_init_host_port(struct cpsw_priv *priv) cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); - if (!cpsw->data.dual_emac) { + if (!cpsw_is_dual_mac(cpsw->data.switch_mode)) { cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr, HOST_PORT_NUM, 0, 0); cpsw_ale_add_mcast(cpsw->ale, priv->ndev->broadcast, @@ -1508,7 +1529,7 @@ static int cpsw_ndo_open(struct net_device *ndev) for_each_slave(priv, cpsw_slave_open, priv); /* Add default VLAN */ - if (!cpsw->data.dual_emac) + if (!cpsw_is_dual_mac(cpsw->data.switch_mode)) cpsw_add_default_vlan(priv); else cpsw_ale_add_vlan(cpsw->ale, cpsw->data.default_vlan, @@ -1685,9 +1706,13 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv) { struct cpsw_slave *slave; struct cpsw_common *cpsw = priv->cpsw; + int slave_no = cpsw_slave_index(priv); u32 ctrl, mtype; - slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; + if (slave_no < 0) + return; + + slave = &cpsw->slaves[slave_no]; ctrl = slave_read(slave, CPSW2_CONTROL); switch (cpsw->version) { @@ -1822,7 +1847,7 @@ static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd) { struct cpsw_priv *priv = netdev_priv(dev); struct cpsw_common *cpsw = priv->cpsw; - int slave_no = cpsw_slave_index(cpsw, priv); + int slave_no = cpsw_slave_index(priv); if (!netif_running(dev)) return -EINVAL; @@ -1863,6 +1888,7 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) struct cpsw_priv *priv = netdev_priv(ndev); struct sockaddr *addr = (struct sockaddr *)p; struct cpsw_common *cpsw = priv->cpsw; + int slave_no = cpsw_slave_index(priv); int flags = 0; u16 vid = 0; int ret; @@ -1876,8 +1902,8 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) return ret; } - if (cpsw->data.dual_emac) { - vid = cpsw->slaves[priv->emac_port].port_vlan; + if (cpsw_is_dual_mac(cpsw->data.switch_mode)) { + vid = cpsw->slaves[slave_no].port_vlan; flags = ALE_VLAN; } @@ -1915,8 +1941,8 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv, u32 port_mask; struct cpsw_common *cpsw = priv->cpsw; - if (cpsw->data.dual_emac) { - port_mask = (1 << (priv->emac_port + 1)) | ALE_PORT_HOST; + if (cpsw_is_dual_mac(cpsw->data.switch_mode)) { + port_mask = (1 << priv->emac_port) | ALE_PORT_HOST; if (priv->ndev->flags & IFF_ALLMULTI) unreg_mcast_mask = port_mask; @@ -1969,7 +1995,7 @@ static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev, return ret; } - if (cpsw->data.dual_emac) { + if (cpsw_is_dual_mac(cpsw->data.switch_mode)) { /* In dual EMAC, reserved VLAN id should not be used for * creating VLAN interfaces as this can break the dual * EMAC port separation @@ -2005,7 +2031,7 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, return ret; } - if (cpsw->data.dual_emac) { + if (cpsw_is_dual_mac(cpsw->data.switch_mode)) { int i; for (i = 0; i < cpsw->data.slaves; i++) { @@ -2183,7 +2209,10 @@ static int cpsw_get_link_ksettings(struct net_device *ndev, { struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_common *cpsw = priv->cpsw; - int slave_no = cpsw_slave_index(cpsw, priv); + int slave_no = cpsw_slave_index(priv); + + if (slave_no < 0) + return -EOPNOTSUPP; if (!cpsw->slaves[slave_no].phy) return -EOPNOTSUPP; @@ -2197,7 +2226,10 @@ static int cpsw_set_link_ksettings(struct net_device *ndev, { struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_common *cpsw = priv->cpsw; - int slave_no = cpsw_slave_index(cpsw, priv); + int slave_no = cpsw_slave_index(priv); + + if (slave_no < 0) + return -EOPNOTSUPP; if (cpsw->slaves[slave_no].phy) return phy_ethtool_ksettings_set(cpsw->slaves[slave_no].phy, @@ -2210,7 +2242,10 @@ static void cpsw_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) { struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_common *cpsw = priv->cpsw; - int slave_no = cpsw_slave_index(cpsw, priv); + int slave_no = cpsw_slave_index(priv); + + if (slave_no < 0) + return; wol->supported = 0; wol->wolopts = 0; @@ -2223,7 +2258,10 @@ static int cpsw_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) { struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_common *cpsw = priv->cpsw; - int slave_no = cpsw_slave_index(cpsw, priv); + int slave_no = cpsw_slave_index(priv); + + if (slave_no < 0) + return -EOPNOTSUPP; if (cpsw->slaves[slave_no].phy) return phy_ethtool_set_wol(cpsw->slaves[slave_no].phy, wol); @@ -2487,7 +2525,10 @@ static int cpsw_get_eee(struct net_device *ndev, struct ethtool_eee *edata) { struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_common *cpsw = priv->cpsw; - int slave_no = cpsw_slave_index(cpsw, priv); + int slave_no = cpsw_slave_index(priv); + + if (slave_no < 0) + return -EOPNOTSUPP; if (cpsw->slaves[slave_no].phy) return phy_ethtool_get_eee(cpsw->slaves[slave_no].phy, edata); @@ -2499,7 +2540,10 @@ static int cpsw_set_eee(struct net_device *ndev, struct ethtool_eee *edata) { struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_common *cpsw = priv->cpsw; - int slave_no = cpsw_slave_index(cpsw, priv); + int slave_no = cpsw_slave_index(priv); + + if (slave_no < 0) + return -EOPNOTSUPP; if (cpsw->slaves[slave_no].phy) return phy_ethtool_set_eee(cpsw->slaves[slave_no].phy, edata); @@ -2511,7 +2555,10 @@ static int cpsw_nway_reset(struct net_device *ndev) { struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_common *cpsw = priv->cpsw; - int slave_no = cpsw_slave_index(cpsw, priv); + int slave_no = cpsw_slave_index(priv); + + if (slave_no < 0) + return -EOPNOTSUPP; if (cpsw->slaves[slave_no].phy) return genphy_restart_aneg(cpsw->slaves[slave_no].phy); @@ -2662,7 +2709,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, data->mac_control = prop; if (of_property_read_bool(node, "dual_emac")) - data->dual_emac = 1; + data->switch_mode = CPSW_DUAL_EMAC; /* * Populate all the child nodes here... @@ -2743,7 +2790,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, if (ret) return ret; } - if (data->dual_emac) { + if (cpsw_is_dual_mac(data->switch_mode)) { if (of_property_read_u32(slave_node, "dual_emac_res_vlan", &prop)) { dev_err(&pdev->dev, "Missing dual_emac_res_vlan in DT.\n"); @@ -2823,7 +2870,7 @@ static int cpsw_probe_dual_emac(struct cpsw_priv *priv) } memcpy(ndev->dev_addr, priv_sl2->mac_addr, ETH_ALEN); - priv_sl2->emac_port = 1; + priv_sl2->emac_port = 2; cpsw->slaves[1].ndev = ndev; ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; @@ -2947,7 +2994,10 @@ static int cpsw_probe(struct platform_device *pdev) cpsw->slaves[i].slave_num = i; cpsw->slaves[0].ndev = ndev; - priv->emac_port = 0; + if (cpsw_is_switch(cpsw->data.switch_mode)) + priv->emac_port = HOST_PORT_NUM; + else + priv->emac_port = 1; clk = devm_clk_get(&pdev->dev, "fck"); if (IS_ERR(clk)) { @@ -3106,7 +3156,7 @@ static int cpsw_probe(struct platform_device *pdev) goto clean_dma_ret; } - if (cpsw->data.dual_emac) { + if (!cpsw_is_switch(cpsw->data.switch_mode)) { ret = cpsw_probe_dual_emac(priv); if (ret) { cpsw_err(priv, probe, "error probe slave 2 emac interface\n"); @@ -3186,7 +3236,7 @@ static int cpsw_remove(struct platform_device *pdev) return ret; } - if (cpsw->data.dual_emac) + if (!cpsw_is_switch(cpsw->data.switch_mode)) unregister_netdev(cpsw->slaves[1].ndev); unregister_netdev(ndev); @@ -3195,7 +3245,7 @@ static int cpsw_remove(struct platform_device *pdev) cpsw_remove_dt(pdev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (cpsw->data.dual_emac) + if (!cpsw_is_switch(cpsw->data.switch_mode)) free_netdev(cpsw->slaves[1].ndev); free_netdev(ndev); return 0; @@ -3208,7 +3258,7 @@ static int cpsw_suspend(struct device *dev) struct net_device *ndev = platform_get_drvdata(pdev); struct cpsw_common *cpsw = ndev_to_cpsw(ndev); - if (cpsw->data.dual_emac) { + if (!cpsw_is_switch(cpsw->data.switch_mode)) { int i; for (i = 0; i < cpsw->data.slaves; i++) { @@ -3237,7 +3287,7 @@ static int cpsw_resume(struct device *dev) /* shut up ASSERT_RTNL() warning in netif_set_real_num_tx/rx_queues */ rtnl_lock(); - if (cpsw->data.dual_emac) { + if (!cpsw_is_switch(cpsw->data.switch_mode)) { int i; for (i = 0; i < cpsw->data.slaves; i++) { diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h index 3b02a83..86a2709 100644 --- a/drivers/net/ethernet/ti/cpsw_priv.h +++ b/drivers/net/ethernet/ti/cpsw_priv.h @@ -30,6 +30,11 @@ #define CPSW2_TX_PRI_MAP 0x18 /* Tx Header Priority to Switch Pri Mapping */ #define CPSW2_TS_SEQ_MTYPE 0x1c /* Time Sync Sequence ID Offset and Msg Type */ +enum { + CPSW_TI_SWITCH, + CPSW_DUAL_EMAC, +}; + struct cpsw_slave_data { struct device_node *phy_node; char phy_id[MII_BUS_ID_SIZE]; @@ -48,7 +53,7 @@ struct cpsw_platform_data { u32 bd_ram_size; /*buffer descriptor ram size */ u32 mac_control; /* Mac control register */ u16 default_vlan; /* Def VLAN for ALE lookup in VLAN aware mode*/ - bool dual_emac; /* Enable Dual EMAC mode */ + u8 switch_mode; /* Enable Dual EMAC/switchdev mode */ }; struct cpsw_slave { From patchwork Thu Jun 14 11:11:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilias Apalodimas X-Patchwork-Id: 138554 Delivered-To: patch@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp1968583lji; Thu, 14 Jun 2018 04:11:58 -0700 (PDT) X-Google-Smtp-Source: ADUXVKIkF7mBZS9lfxP/xdin3urWNFEgefUEDzx02u3mfZvarfINpg3r8nx2mKKjUoB9ToSlGKbP X-Received: by 2002:a63:6fce:: with SMTP id k197-v6mr1918510pgc.307.1528974718683; Thu, 14 Jun 2018 04:11:58 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1528974718; cv=none; d=google.com; s=arc-20160816; b=L/WVI+uxG85FnccxBGuVGbq4tEyAnF+3Ar9hfjvlg4DYfxD02uVEwTO96AI7+j6RmZ 6vWKrYbmLjJwiWhbVe96Mc8guskBvQiK3HhLuk8BlIfbWRzanYb1qf+5cvSGOKun+iiz aKzMkeI8S0HAu3QwEGSRGEzQz4QsWYgDHA2G84P9uQAfxgKv+luAyxxrz2sh0AfbexsB Qhi59H3S4ZHv33RIEnS/xQZQok1qAwvLIuxhLIN/gbSebVWgutubc41wUo/sS/pYKGKB 0AxmDkb+1lBeldBrMutE6XuyC86j6kiktciS07U7AI2bc2Pm1HbbRc/UPZc69IrALoEg J6GA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=CWxuPrMwNoeMlD2H7BonnuHPHftjhAXmqkhLnCzvUUs=; b=wVPFu1ZbCqNqTGz5Y+bggOwtE+luFja9T9BznNE8EiJc7CBLmngXKstodNCN4e+iDc 7IIT6Db/ot9Ud6tSn8/hHlq2gjct2I0rK9ii86eKwEujjKOwoom7/8FvRYSNfa8/Bo0F HREynwfTHfnrGEHs1t5OvcGuZ0rQjykERGNNpJkXr4FjV5PfLJ+TpPUlbVJB85xhxLo3 TdcdlRvBUhWSRWOQwsf3bQX1sr8OCNHkofKSsRRs3MmnYhzRgXqCHdSkI98jbA1R4g2g v+gVBBnKVqwvji8FJA+4nLrNbPlCxK42jk1EcDOrNO1jnMC2/RgSH/XeZcXH9TpsvEU2 zFAQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=HELfBkIl; spf=pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=netdev-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y83-v6si5037554pfb.284.2018.06.14.04.11.58; Thu, 14 Jun 2018 04:11:58 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=HELfBkIl; spf=pass (google.com: best guess record for domain of netdev-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=netdev-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755106AbeFNLL4 (ORCPT + 9 others); Thu, 14 Jun 2018 07:11:56 -0400 Received: from mail-wm0-f66.google.com ([74.125.82.66]:36729 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755055AbeFNLLu (ORCPT ); Thu, 14 Jun 2018 07:11:50 -0400 Received: by mail-wm0-f66.google.com with SMTP id v131-v6so11206944wma.1 for ; Thu, 14 Jun 2018 04:11:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=CWxuPrMwNoeMlD2H7BonnuHPHftjhAXmqkhLnCzvUUs=; b=HELfBkIl7RMKjLIh9rfvRNSymNsQeqoSxPle4VqtCLDuDmBLAVLaAaIX+j+tvo3iAI 2Jm7OfruYvnzwxM2uQdHSMZXlEE+Ux38sBw59sEMRdGpJ4kJnmVNY3FMuHq0+ntbMPa7 5rfjndH2Sc3B+NsrFVp+p9YYVulBg9ovHrPsk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=CWxuPrMwNoeMlD2H7BonnuHPHftjhAXmqkhLnCzvUUs=; b=Ai50BXTZ3BelfvUqFGka4qxdnHIY4C961c4oFVqyw2dIqmPyNo0yU9aNpAPrZsGm0r Fbvbh552pAgV5tPLuKMO3VtTvn+aD5CKMEd8bl1zHujFnH9RhXYAHirhddJIOnrh4R8p k3J5BZ6DdHQFHQbCjgEbPjYoENX/F08/i3h8yN5IuDnspyiVK69XTuF/dQuoGE5/CeEM kOLF3BVb2gWEHh5AWAwRrmk5Xw/SBuwQymeMh/zM+z5XyBZBZjaBxmu3wBo7Pb1zR3Ey 1zXTsh/Yv9jW7Vd7He1qdAUhaFt9YKKLRSbEg1JJ5SXVdXVINn3T/mYmd0WpHgFELcMn sQYw== X-Gm-Message-State: APt69E3EDLyIhTWZLUMyEOPB+Abnj0ZdtwFAkdbITrFrR1D5oWCvRd55 CHGTfRGS23h0uqjupvmCWGvXE3fsJww= X-Received: by 2002:a1c:b50b:: with SMTP id e11-v6mr1451965wmf.84.1528974708031; Thu, 14 Jun 2018 04:11:48 -0700 (PDT) Received: from localhost.localdomain ([2a02:587:4609:4e00:6c01:5076:e5d5:7a4c]) by smtp.gmail.com with ESMTPSA id t124-v6sm3657466wmt.29.2018.06.14.04.11.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 14 Jun 2018 04:11:47 -0700 (PDT) From: Ilias Apalodimas To: netdev@vger.kernel.org, grygorii.strashko@ti.com, ivan.khoronzhuk@linaro.org, nsekhar@ti.com, jiri@resnulli.us, ivecera@redhat.com, andrew@lunn.ch, f.fainelli@gmail.com Cc: francois.ozog@linaro.org, yogeshs@ti.com, spatton@ti.com, Jose.Abreu@synopsys.com, Ilias Apalodimas Subject: [RFC v2, net-next, PATCH 4/4] net/cpsw_switchdev: add switchdev mode of operation on cpsw driver Date: Thu, 14 Jun 2018 14:11:30 +0300 Message-Id: <1528974690-31600-5-git-send-email-ilias.apalodimas@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1528974690-31600-1-git-send-email-ilias.apalodimas@linaro.org> References: <1528974690-31600-1-git-send-email-ilias.apalodimas@linaro.org> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch enables switchdev funtionality on the driver based on a .config option(CONFIG_TI_CPSW_SWITCHDEV). CPSW driver used a DTS option called dual_emac to enable switch or dual emac mode. The new config option will override this configuration. It creates 2 ports, eth0 and eth1(that can be renamed to sw0p1 and sw0p2 via udev rules). sw0p1 and sw0p2 are the netdev interfaces connected to PHY devices. This hardware also has a CPU port which is configured invidividually in the case of VLANs. On device init all netdevices (including the CPU port) will operate on VLAN 0. sw0p1 and sw0p2 will operate as normal netdev interfaces. Once they are added in a bridge the default bridge vlan will not be added to the CPU port. In order to get an ip address on br0 you'll need to add the CPU port on that vlan by issuing: bridge vlan add dev br0 vid pvid untagged self Multicast traffic: setting IFF_MULTICAST on and off will affect registered multicast on that port(if enabled port will be added on registered multicast traffic mask). This muct occur before adding VLANs on the interfaces. If you change the flag after the VLAN configuration you need to re-issue the VLAN config commands. MDBs/FDBs: If the CPU port is member of the appropriate VLANs then switchdev API will add FDB/MDB entries uppon detection. If the CPU port is not a member the user can manually specify the entries. ALE_P0_UNI_FLOOD will be enabled when the first interface joins the bridge and will be disabled once the last interface leaves the bridge Signed-off-by: Ilias Apalodimas --- drivers/net/ethernet/ti/Kconfig | 9 + drivers/net/ethernet/ti/Makefile | 1 + drivers/net/ethernet/ti/cpsw.c | 306 +++++++++++++++++++++- drivers/net/ethernet/ti/cpsw_priv.h | 2 + drivers/net/ethernet/ti/cpsw_switchdev.c | 418 +++++++++++++++++++++++++++++++ drivers/net/ethernet/ti/cpsw_switchdev.h | 4 + 6 files changed, 731 insertions(+), 9 deletions(-) create mode 100644 drivers/net/ethernet/ti/cpsw_switchdev.c create mode 100644 drivers/net/ethernet/ti/cpsw_switchdev.h -- 2.7.4 diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index 9263d63..a299d86 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -73,6 +73,15 @@ config TI_CPSW To compile this driver as a module, choose M here: the module will be called cpsw. +config TI_CPSW_SWITCHDEV + bool "TI CPSW switchdev support" + depends on TI_CPSW + depends on NET_SWITCHDEV + help + Enable switchdev support on TI's CPSW Ethernet Switch. + + This will allow you to configure the switch using standard tools. + config TI_CPTS bool "TI Common Platform Time Sync (CPTS) Support" depends on TI_CPSW || TI_KEYSTONE_NETCP || COMPILE_TEST diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index 0be551d..d6eb2a2 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_TI_CPSW_PHY_SEL) += cpsw-phy-sel.o obj-$(CONFIG_TI_CPSW_ALE) += cpsw_ale.o obj-$(CONFIG_TI_CPTS_MOD) += cpts.o obj-$(CONFIG_TI_CPSW) += ti_cpsw.o +obj-$(CONFIG_TI_CPSW_SWITCHDEV) += cpsw_switchdev.o ti_cpsw-y := cpsw.o obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index e5765cc..b501908 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -18,12 +18,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -43,6 +41,7 @@ #include "cpsw.h" #include "cpsw_ale.h" #include "cpsw_priv.h" +#include "cpsw_switchdev.h" #include "cpts.h" #include "davinci_cpdma.h" @@ -361,6 +360,13 @@ struct cpsw_hw_stats { u32 rxdmaoverruns; }; +struct cpsw_switchdev_event_work { + struct work_struct work; + struct switchdev_notifier_fdb_info fdb_info; + struct cpsw_priv *priv; + unsigned long event; +}; + #define CPSW_STAT(m) CPSW_STATS, \ sizeof(((struct cpsw_hw_stats *)0)->m), \ offsetof(struct cpsw_hw_stats, m) @@ -488,14 +494,32 @@ static int cpsw_is_switch(u8 switch_mode) return switch_mode == CPSW_TI_SWITCH; } +static int cpsw_is_switchdev(u8 switch_mode) +{ + return switch_mode == CPSW_SWITCHDEV; +} + static int cpsw_slave_index(struct cpsw_priv *priv) { struct cpsw_common *cpsw = priv->cpsw; +#if IS_ENABLED(CONFIG_TI_CPSW_SWITCHDEV) + if (priv->emac_port == HOST_PORT_NUM) + return -1; +#endif + return cpsw->data.switch_mode ? priv->emac_port - 1 : cpsw->data.active_slave; } +static void cpsw_switchdev_port_enable(struct net_device *ndev) +{ +#if IS_ENABLED(CONFIG_TI_CPSW_SWITCHDEV) + cpsw_port_switchdev_init(ndev); + ndev->features |= NETIF_F_NETNS_LOCAL; +#endif +} + static void cpsw_set_promiscious(struct net_device *ndev, bool enable) { struct cpsw_common *cpsw = ndev_to_cpsw(ndev); @@ -521,6 +545,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable) if (enable) { /* Enable Bypass */ cpsw_ale_control_set(ale, 0, ALE_BYPASS, 1); + cpsw_ale_set_allmulti(ale, IFF_ALLMULTI); dev_dbg(&ndev->dev, "promiscuity enabled\n"); } else { @@ -554,6 +579,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable) /* Flood All Unicast Packets to Host port */ cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 1); + cpsw_ale_set_allmulti(ale, IFF_ALLMULTI); dev_dbg(&ndev->dev, "promiscuity enabled\n"); } else { /* Don't Flood All Unicast Packets to Host port */ @@ -568,6 +594,19 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable) } dev_dbg(&ndev->dev, "promiscuity disabled\n"); } + } else if (cpsw_is_switchdev(cpsw->data.switch_mode)) { + /* When interfaces are placed into a bridge they'll switch to + * promiscuous mode. In switchdev case ALE_P0_UNI_FLOOD is + * changed whether any switch port participates in the bridge + * or not + */ + struct cpsw_priv *priv = netdev_priv(ndev); + int slave_idx = cpsw_slave_index(priv); + int slave_num; + + slave_num = cpsw_get_slave_port(slave_idx); + cpsw_ale_control_set(ale, slave_num, ALE_PORT_NOLEARN, 0); + cpsw_ale_control_set(ale, slave_num, ALE_PORT_NO_SA_UPDATE, 0); } } @@ -586,7 +625,6 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev) if (ndev->flags & IFF_PROMISC) { /* Enable promiscuous mode */ cpsw_set_promiscious(ndev, true); - cpsw_ale_set_allmulti(cpsw->ale, IFF_ALLMULTI); return; } else { /* Disable promiscuous mode */ @@ -721,6 +759,10 @@ static void cpsw_rx_handler(void *token, int len, int status) return; } +#if IS_ENABLED(CONFIG_TI_CPSW_SWITCHDEV) + if (cpsw_is_switchdev(cpsw->data.switch_mode)) + skb->offload_fwd_mark = 1; +#endif new_skb = netdev_alloc_skb_ip_align(ndev, cpsw->rx_packet_max); if (new_skb) { skb_copy_queue_mapping(new_skb, skb); @@ -1427,10 +1469,13 @@ static void cpsw_init_host_port(struct cpsw_priv *priv) ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); if (!cpsw_is_dual_mac(cpsw->data.switch_mode)) { - cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr, HOST_PORT_NUM, - 0, 0); + char stpa[] = {0x01, 0x80, 0xc2, 0x0, 0x0, 0x0}; + cpsw_ale_add_mcast(cpsw->ale, priv->ndev->broadcast, ALE_PORT_HOST, 0, 0, ALE_MCAST_FWD_2); + cpsw_ale_add_mcast(cpsw->ale, stpa, + ALE_PORT_HOST, ALE_SUPER, 0, + ALE_MCAST_BLOCK_LEARN_FWD); } } @@ -1529,11 +1574,14 @@ static int cpsw_ndo_open(struct net_device *ndev) for_each_slave(priv, cpsw_slave_open, priv); /* Add default VLAN */ - if (!cpsw_is_dual_mac(cpsw->data.switch_mode)) + if (!cpsw_is_dual_mac(cpsw->data.switch_mode)) { cpsw_add_default_vlan(priv); - else + cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr, HOST_PORT_NUM, 0, + 0); + } else { cpsw_ale_add_vlan(cpsw->ale, cpsw->data.default_vlan, ALE_ALL_PORTS, ALE_ALL_PORTS, 0, 0); + } /* initialize shared resources for every ndev */ if (!cpsw->usage_count) { @@ -1852,6 +1900,9 @@ static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd) if (!netif_running(dev)) return -EINVAL; + if (slave_no < 0) + return -EOPNOTSUPP; + switch (cmd) { case SIOCSHWTSTAMP: return cpsw_hwtstamp_set(dev, req); @@ -1941,7 +1992,7 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv, u32 port_mask; struct cpsw_common *cpsw = priv->cpsw; - if (cpsw_is_dual_mac(cpsw->data.switch_mode)) { + if (!cpsw_is_switch(cpsw->data.switch_mode)) { port_mask = (1 << priv->emac_port) | ALE_PORT_HOST; if (priv->ndev->flags & IFF_ALLMULTI) @@ -1989,6 +2040,10 @@ static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev, if (vid == cpsw->data.default_vlan) return 0; + if (cpsw_is_switchdev(cpsw->data.switch_mode) && + (netif_is_bridge_port(ndev))) + return -EOPNOTSUPP; + ret = pm_runtime_get_sync(cpsw->dev); if (ret < 0) { pm_runtime_put_noidle(cpsw->dev); @@ -2025,6 +2080,10 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, if (vid == cpsw->data.default_vlan) return 0; + if (cpsw_is_switchdev(cpsw->data.switch_mode) && + (netif_is_bridge_port(ndev))) + return -EOPNOTSUPP; + ret = pm_runtime_get_sync(cpsw->dev); if (ret < 0) { pm_runtime_put_noidle(cpsw->dev); @@ -2056,6 +2115,24 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, return ret; } +static int cpsw_ndo_get_phys_port_name(struct net_device *ndev, char *name, + size_t len) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + int err; + + if (!cpsw_is_switchdev(cpsw->data.switch_mode)) + return -EOPNOTSUPP; + + err = snprintf(name, len, "p%d", priv->emac_port); + + if (err >= len) + return -EINVAL; + + return 0; +} + static int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate) { struct cpsw_priv *priv = netdev_priv(ndev); @@ -2122,6 +2199,7 @@ static const struct net_device_ops cpsw_netdev_ops = { #endif .ndo_vlan_rx_add_vid = cpsw_ndo_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = cpsw_ndo_vlan_rx_kill_vid, + .ndo_get_phys_port_name = cpsw_ndo_get_phys_port_name, }; static int cpsw_get_regs_len(struct net_device *ndev) @@ -2711,6 +2789,10 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, if (of_property_read_bool(node, "dual_emac")) data->switch_mode = CPSW_DUAL_EMAC; + /* switchdev overrides DTS */ + if (IS_ENABLED(CONFIG_TI_CPSW_SWITCHDEV)) + data->switch_mode = CPSW_SWITCHDEV; + /* * Populate all the child nodes here... */ @@ -2874,6 +2956,9 @@ static int cpsw_probe_dual_emac(struct cpsw_priv *priv) cpsw->slaves[1].ndev = ndev; ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; + if (cpsw_is_switchdev(cpsw->data.switch_mode)) + cpsw_switchdev_port_enable(ndev); + ndev->netdev_ops = &cpsw_netdev_ops; ndev->ethtool_ops = &cpsw_ethtool_ops; @@ -2903,6 +2988,196 @@ static const struct soc_device_attribute cpsw_soc_devices[] = { { /* sentinel */ } }; +static bool cpsw_port_dev_check(const struct net_device *dev) +{ + return dev->netdev_ops == &cpsw_netdev_ops; +} + +static void cpsw_fdb_offload_notify(struct net_device *ndev, + struct switchdev_notifier_fdb_info *rcv) +{ + struct switchdev_notifier_fdb_info info; + + info.addr = rcv->addr; + info.vid = rcv->vid; + call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, + ndev, &info.info); +} + +static void cpsw_switchdev_event_work(struct work_struct *work) +{ + struct cpsw_switchdev_event_work *switchdev_work = + container_of(work, struct cpsw_switchdev_event_work, work); + struct cpsw_priv *priv = switchdev_work->priv; + struct switchdev_notifier_fdb_info *fdb; + struct cpsw_common *cpsw = priv->cpsw; + int port = priv->emac_port; + + rtnl_lock(); + switch (switchdev_work->event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + fdb = &switchdev_work->fdb_info; + if (memcmp(priv->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0) + port = HOST_PORT_NUM; + cpsw_ale_add_ucast(cpsw->ale, (u8 *)fdb->addr, port, ALE_VLAN, + fdb->vid); + cpsw_fdb_offload_notify(priv->ndev, fdb); + break; + case SWITCHDEV_FDB_DEL_TO_DEVICE: + fdb = &switchdev_work->fdb_info; + if (memcmp(priv->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0) + port = HOST_PORT_NUM; + cpsw_ale_del_ucast(cpsw->ale, (u8 *)fdb->addr, port, ALE_VLAN, + fdb->vid); + break; + default: + break; + } + rtnl_unlock(); + + kfree(switchdev_work->fdb_info.addr); + kfree(switchdev_work); + dev_put(priv->ndev); +} + +/* called under rcu_read_lock() */ +static int cpsw_switchdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *ndev = switchdev_notifier_info_to_dev(ptr); + struct switchdev_notifier_fdb_info *fdb_info = ptr; + struct cpsw_switchdev_event_work *switchdev_work; + struct cpsw_priv *priv = netdev_priv(ndev); + + if (!cpsw_port_dev_check(ndev)) + return NOTIFY_DONE; + + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); + if (WARN_ON(!switchdev_work)) + return NOTIFY_BAD; + + INIT_WORK(&switchdev_work->work, cpsw_switchdev_event_work); + switchdev_work->priv = priv; + switchdev_work->event = event; + + switch (event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + case SWITCHDEV_FDB_DEL_TO_DEVICE: + memcpy(&switchdev_work->fdb_info, ptr, + sizeof(switchdev_work->fdb_info)); + switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); + ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, + fdb_info->addr); + dev_hold(ndev); + break; + default: + kfree(switchdev_work); + return NOTIFY_DONE; + } + + queue_work(system_long_wq, &switchdev_work->work); + + return NOTIFY_DONE; +} + +static struct notifier_block cpsw_switchdev_notifier = { + .notifier_call = cpsw_switchdev_event, +}; + +static void cpsw_netdevice_port_link(struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + + if (!cpsw->br_members) { + cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_P0_UNI_FLOOD, + 1); + dev_dbg(&ndev->dev, "Set P0_UNI_FLOOD\n"); + } + cpsw->br_members++; +} + +static void cpsw_netdevice_port_unlink(struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + + cpsw->br_members--; + if (!cpsw->br_members) { + cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_P0_UNI_FLOOD, + 0); + dev_dbg(&ndev->dev, "unset P0_UNI_FLOOD\n"); + } +} + +/* netdev notifier */ +static int cpsw_netdevice_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *ndev = netdev_notifier_info_to_dev(ptr); + struct netdev_notifier_changeupper_info *info; + + switch (event) { + case NETDEV_CHANGEUPPER: + info = ptr; + if (!info->master) + goto out; + if (info->linking) + cpsw_netdevice_port_link(ndev); + else + cpsw_netdevice_port_unlink(ndev); + break; + default: + return NOTIFY_DONE; + } + +out: + return NOTIFY_DONE; +} + +static struct notifier_block cpsw_netdevice_nb __read_mostly = { + .notifier_call = cpsw_netdevice_event, +}; + +static int cpsw_register_notifiers(struct cpsw_priv *priv) +{ + int ret; + + ret = register_netdevice_notifier(&cpsw_netdevice_nb); + if (ret) { + cpsw_err(priv, probe, "can't register netdevice notifier\n"); + return ret; + } + + ret = register_switchdev_notifier(&cpsw_switchdev_notifier); + if (ret) { + cpsw_err(priv, probe, "can't register switchdev notifier\n"); + goto unreg_netdevice; + } + + return ret; + +unreg_netdevice: + ret = unregister_netdevice_notifier(&cpsw_netdevice_nb); + + return ret; +} + +static int cpsw_unregister_notifiers(struct cpsw_priv *priv) +{ + int ret; + + ret = unregister_switchdev_notifier(&cpsw_switchdev_notifier); + if (ret) + dev_err(priv->dev, "can't unregister switchdev notifier\n"); + + ret += unregister_netdevice_notifier(&cpsw_netdevice_nb); + if (ret) + dev_err(priv->dev, "can't unregister netdevice notifier\n"); + + return ret; +} + static int cpsw_probe(struct platform_device *pdev) { struct clk *clk; @@ -3135,6 +3410,9 @@ static int cpsw_probe(struct platform_device *pdev) goto clean_dma_ret; } + if (cpsw_is_switchdev(cpsw->data.switch_mode)) + cpsw_switchdev_port_enable(ndev); + ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_RX; ndev->netdev_ops = &cpsw_netdev_ops; @@ -3202,6 +3480,12 @@ static int cpsw_probe(struct platform_device *pdev) goto clean_dma_ret; } + if (cpsw_is_switchdev(cpsw->data.switch_mode)) { + ret = cpsw_register_notifiers(priv); + if (ret) + goto clean_dma_ret; + } + cpsw_notice(priv, probe, "initialized device (regs %pa, irq %d, pool size %d)\n", &ss_res->start, ndev->irq, dma_params.descs_pool_size); @@ -3227,7 +3511,8 @@ static int cpsw_probe(struct platform_device *pdev) static int cpsw_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); - struct cpsw_common *cpsw = ndev_to_cpsw(ndev); + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; int ret; ret = pm_runtime_get_sync(&pdev->dev); @@ -3236,6 +3521,9 @@ static int cpsw_remove(struct platform_device *pdev) return ret; } + if (cpsw_is_switchdev(cpsw->data.switch_mode)) + ret = cpsw_unregister_notifiers(priv); + if (!cpsw_is_switch(cpsw->data.switch_mode)) unregister_netdev(cpsw->slaves[1].ndev); unregister_netdev(ndev); diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h index 86a2709..4380b1c 100644 --- a/drivers/net/ethernet/ti/cpsw_priv.h +++ b/drivers/net/ethernet/ti/cpsw_priv.h @@ -33,6 +33,7 @@ enum { CPSW_TI_SWITCH, CPSW_DUAL_EMAC, + CPSW_SWITCHDEV, }; struct cpsw_slave_data { @@ -98,6 +99,7 @@ struct cpsw_common { int rx_ch_num, tx_ch_num; int speed; int usage_count; + u8 br_members; }; struct cpsw_priv { diff --git a/drivers/net/ethernet/ti/cpsw_switchdev.c b/drivers/net/ethernet/ti/cpsw_switchdev.c new file mode 100644 index 0000000..528e99e --- /dev/null +++ b/drivers/net/ethernet/ti/cpsw_switchdev.c @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Texas Instruments switchdev Driver + * + * Copyright (C) 2018 Texas Instruments + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include "cpsw.h" +#include "cpsw_priv.h" +#include "cpsw_ale.h" + +static u32 cpsw_switchdev_get_ver(struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + + return cpsw->version; +} + +static int cpsw_port_stp_state_set(struct cpsw_priv *priv, + struct switchdev_trans *trans, u8 state) +{ + struct cpsw_common *cpsw = priv->cpsw; + u8 cpsw_state; + int ret = 0; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + switch (state) { + case BR_STATE_FORWARDING: + cpsw_state = ALE_PORT_STATE_FORWARD; + break; + case BR_STATE_LEARNING: + cpsw_state = ALE_PORT_STATE_LEARN; + break; + case BR_STATE_DISABLED: + cpsw_state = ALE_PORT_STATE_DISABLE; + break; + case BR_STATE_LISTENING: + case BR_STATE_BLOCKING: + cpsw_state = ALE_PORT_STATE_BLOCK; + break; + default: + return -EOPNOTSUPP; + } + + ret = cpsw_ale_control_set(cpsw->ale, priv->emac_port, + ALE_PORT_STATE, cpsw_state); + dev_dbg(priv->dev, "ale state: %u\n", cpsw_state); + + return ret; +} + +static int cpsw_port_attr_br_flags_set(struct cpsw_priv *priv, + struct switchdev_trans *trans, + struct net_device *orig_dev, + unsigned long brport_flags) +{ + struct cpsw_common *cpsw = priv->cpsw; + bool unreg_mcast_add = false; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + if (brport_flags & BR_MCAST_FLOOD) + unreg_mcast_add = true; + cpsw_ale_set_unreg_mcast(cpsw->ale, BIT(priv->emac_port), + unreg_mcast_add); + + return 0; +} + +static int cpsw_port_attr_set(struct net_device *ndev, + const struct switchdev_attr *attr, + struct switchdev_trans *trans) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + u8 state; + int ret; + + dev_dbg(priv->dev, "attr: id %u dev: %s port: %u\n", attr->id, + priv->ndev->name, priv->emac_port); + + switch (attr->id) { + case SWITCHDEV_ATTR_ID_PORT_STP_STATE: + ret = cpsw_port_stp_state_set(priv, trans, attr->u.stp_state); + dev_dbg(priv->dev, "stp state: %u\n", state); + break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: + ret = cpsw_port_attr_br_flags_set(priv, trans, attr->orig_dev, + attr->u.brport_flags); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static int cpsw_port_attr_get(struct net_device *dev, + struct switchdev_attr *attr) +{ + u32 cpsw_ver; + int err = 0; + + switch (attr->id) { + case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: + cpsw_ver = cpsw_switchdev_get_ver(dev); + attr->u.ppid.id_len = sizeof(cpsw_ver); + memcpy(&attr->u.ppid.id, &cpsw_ver, attr->u.ppid.id_len); + break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT: + attr->u.brport_flags_support = BR_MCAST_FLOOD; + break; + default: + return -EOPNOTSUPP; + } + + return err; +} + +static u16 cpsw_get_pvid(struct cpsw_priv *priv) +{ + struct cpsw_common *cpsw = priv->cpsw; + u32 __iomem *port_vlan_reg; + u32 pvid; + + if (priv->emac_port) { + int reg = CPSW2_PORT_VLAN; + + if (cpsw->version == CPSW_VERSION_1) + reg = CPSW1_PORT_VLAN; + pvid = slave_read(cpsw->slaves + (priv->emac_port - 1), reg); + } else { + port_vlan_reg = &cpsw->host_port_regs->port_vlan; + pvid = readl(port_vlan_reg); + } + + pvid = pvid & 0xfff; + + return pvid; +} + +static void cpsw_set_pvid(struct cpsw_priv *priv, u16 vid, bool cfi, u32 cos) +{ + struct cpsw_common *cpsw = priv->cpsw; + void __iomem *port_vlan_reg; + u32 pvid; + + pvid = vid; + pvid |= cfi ? BIT(12) : 0; + pvid |= (cos & 0x7) << 13; + + if (priv->emac_port) { + int reg = CPSW2_PORT_VLAN; + + if (cpsw->version == CPSW_VERSION_1) + reg = CPSW1_PORT_VLAN; + /* no barrier */ + slave_write(cpsw->slaves + (priv->emac_port - 1), pvid, reg); + } else { + /* CPU port */ + port_vlan_reg = &cpsw->host_port_regs->port_vlan; + writel(pvid, port_vlan_reg); + } +} + +static int cpsw_port_vlan_add(struct cpsw_priv *priv, bool untag, bool pvid, + u16 vid, struct net_device *orig_dev) +{ + bool cpu_port = netif_is_bridge_master(orig_dev); + struct cpsw_common *cpsw = priv->cpsw; + int unreg_mcast_mask = 0; + int reg_mcast_mask = 0; + int untag_mask = 0; + int port_mask; + int ret = 0; + u32 flags; + + if (cpu_port) { + port_mask = BIT(HOST_PORT_NUM); + flags = orig_dev->flags; + unreg_mcast_mask = port_mask; + } else { + port_mask = BIT(priv->emac_port); + flags = priv->ndev->flags; + } + + if (flags & IFF_MULTICAST) + reg_mcast_mask = port_mask; + + if (untag) + untag_mask = port_mask; + + ret = cpsw_ale_vlan_add_modify(cpsw->ale, vid, port_mask, untag_mask, + reg_mcast_mask, unreg_mcast_mask); + if (ret) { + dev_err(priv->dev, "Unable to add vlan\n"); + return ret; + } + + if (!pvid) + return ret; + + cpsw_set_pvid(priv, vid, 0, 0); + + dev_dbg(priv->dev, "VID add: %u dev: %s port: %u\n", vid, + priv->ndev->name, priv->emac_port); + + return ret; +} + +static int cpsw_port_vlan_del(struct cpsw_priv *priv, u16 vid, + struct net_device *orig_dev) +{ + bool cpu_port = netif_is_bridge_master(orig_dev); + struct cpsw_common *cpsw = priv->cpsw; + int port_mask; + int ret = 0; + + if (cpu_port) + port_mask = BIT(HOST_PORT_NUM); + else + port_mask = BIT(priv->emac_port); + + ret = cpsw_ale_vlan_del_modify(cpsw->ale, vid, port_mask); + if (ret != 0) + return ret; + + /* We don't care for the return value here, error is returned only if + * the unicast entry is not present + */ + cpsw_ale_del_ucast(cpsw->ale, priv->mac_addr, + HOST_PORT_NUM, ALE_VLAN, vid); + + if (vid == cpsw_get_pvid(priv)) + cpsw_set_pvid(priv, 0, 0, 0); + + /* We don't care for the return value here, error is returned only if + * the multicast entry is not present + */ + cpsw_ale_del_mcast(cpsw->ale, priv->ndev->broadcast, + 0, ALE_VLAN, vid); + + dev_dbg(priv->dev, "VID del: %u dev: %s port: %u\n", vid, + priv->ndev->name, priv->emac_port); + + return ret; +} + +static int cpsw_port_vlans_add(struct cpsw_priv *priv, + const struct switchdev_obj_port_vlan *vlan, + struct switchdev_trans *trans) +{ + bool untag = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + struct net_device *orig_dev = vlan->obj.orig_dev; + bool cpu_port = netif_is_bridge_master(orig_dev); + bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; + u16 vid; + + if (cpu_port && !(vlan->flags & BRIDGE_VLAN_INFO_BRENTRY)) + return 0; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + int err; + + err = cpsw_port_vlan_add(priv, untag, pvid, vid, orig_dev); + if (err) + return err; + } + + return 0; +} + +static int cpsw_port_vlans_del(struct cpsw_priv *priv, + const struct switchdev_obj_port_vlan *vlan) + +{ + struct net_device *orig_dev = vlan->obj.orig_dev; + u16 vid; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + int err; + + err = cpsw_port_vlan_del(priv, vid, orig_dev); + if (err) + return err; + } + + return 0; +} + +static int cpsw_port_mdb_add(struct cpsw_priv *priv, + struct switchdev_obj_port_mdb *mdb, + struct switchdev_trans *trans) + +{ + struct net_device *orig_dev = mdb->obj.orig_dev; + bool cpu_port = netif_is_bridge_master(orig_dev); + struct cpsw_common *cpsw = priv->cpsw; + int port_mask; + int err; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + if (cpu_port) + port_mask = BIT(HOST_PORT_NUM); + else + port_mask = BIT(priv->emac_port); + + err = cpsw_ale_mcast_add_modify(cpsw->ale, mdb->addr, port_mask, + ALE_VLAN, mdb->vid, 0); + + dev_dbg(priv->dev, "MDB add: %pM dev: %s vid %u port: %u\n", mdb->addr, + priv->ndev->name, mdb->vid, priv->emac_port); + + return err; +} + +static int cpsw_port_mdb_del(struct cpsw_priv *priv, + struct switchdev_obj_port_mdb *mdb) + +{ + struct net_device *orig_dev = mdb->obj.orig_dev; + bool cpu_port = netif_is_bridge_master(orig_dev); + struct cpsw_common *cpsw = priv->cpsw; + int del_mask; + int err; + + if (cpu_port) + del_mask = BIT(HOST_PORT_NUM); + else + del_mask = BIT(priv->emac_port); + err = cpsw_ale_mcast_del_modify(cpsw->ale, mdb->addr, del_mask, + ALE_VLAN, mdb->vid); + dev_dbg(priv->dev, "MDB del: %pM dev: %s vid %u port: %u\n", mdb->addr, + priv->ndev->name, mdb->vid, priv->emac_port); + + return err; +} + +static int cpsw_port_obj_add(struct net_device *ndev, + const struct switchdev_obj *obj, + struct switchdev_trans *trans) +{ + struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); + struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj); + struct cpsw_priv *priv = netdev_priv(ndev); + int err = 0; + + switch (obj->id) { + case SWITCHDEV_OBJ_ID_PORT_VLAN: + err = cpsw_port_vlans_add(priv, vlan, trans); + break; + case SWITCHDEV_OBJ_ID_PORT_MDB: + case SWITCHDEV_OBJ_ID_HOST_MDB: + err = cpsw_port_mdb_add(priv, mdb, trans); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static int cpsw_port_obj_del(struct net_device *ndev, + const struct switchdev_obj *obj) +{ + struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); + struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj); + struct cpsw_priv *priv = netdev_priv(ndev); + int err = 0; + + switch (obj->id) { + case SWITCHDEV_OBJ_ID_PORT_VLAN: + err = cpsw_port_vlans_del(priv, vlan); + break; + case SWITCHDEV_OBJ_ID_PORT_MDB: + case SWITCHDEV_OBJ_ID_HOST_MDB: + err = cpsw_port_mdb_del(priv, mdb); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static const struct switchdev_ops cpsw_port_switchdev_ops = { + .switchdev_port_attr_set = cpsw_port_attr_set, + .switchdev_port_attr_get = cpsw_port_attr_get, + .switchdev_port_obj_add = cpsw_port_obj_add, + .switchdev_port_obj_del = cpsw_port_obj_del, +}; + +void cpsw_port_switchdev_init(struct net_device *ndev) +{ + ndev->switchdev_ops = &cpsw_port_switchdev_ops; +} diff --git a/drivers/net/ethernet/ti/cpsw_switchdev.h b/drivers/net/ethernet/ti/cpsw_switchdev.h new file mode 100644 index 0000000..4940462 --- /dev/null +++ b/drivers/net/ethernet/ti/cpsw_switchdev.h @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include + +void cpsw_port_switchdev_init(struct net_device *ndev);