Commit 802dcb43 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-ethernet-ti-am65-cpsw-add-multi-port-support-in-mac-only-mode'

Grygorii Strashko says:

====================
net: ethernet: ti: am65-cpsw: add multi port support in mac-only mode

This series adds multi-port support in mac-only mode (multi MAC mode) to TI
AM65x CPSW driver in preparation for enabling support for multi-port devices,
like Main CPSW0 on K3 J721E SoC or future CPSW3g on K3 AM64x SoC.

The multi MAC mode is implemented by configuring every enabled port in "mac-only"
mode (all ingress packets are sent only to the Host port and egress packets
directed to target Ext. Port) and creating separate net_device for
every enabled Ext. port.

This series does not affect on existing CPSW2g one Ext. Port devices and xmit
path changes are done only for multi-port devices by splitting xmit path for
one-port and multi-port devices.

Patches 1-3: Preparation patches to improve K3 CPSW configuration depending on DT
Patches 4-5: Fix VLAN offload for multi MAC mode
Patch 6: Fixes CPTS context lose issue during PM runtime transition
Patch 7: Fixes TX csum offload for multi MAC mode
Patches 8-9: add multi-port support to TI AM65x CPSW
Patch 10: handle deferred probe with new dev_err_probe() API

changes in v3:
 - rebased
 - added Reviewed-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
 - added Patch 10 which is minor optimization

changes in v2:
- patch 8: xmit path split for one-port and multi-port devices to avoid
  performance losses
- patch 9: fixed the case when Port 1 is disabled
- Patch 7: added fix for TX csum offload

v2: https://lore.kernel.org/patchwork/cover/1321608/
v1: https://lore.kernel.org/patchwork/cover/1315766/
====================

Link: https://lore.kernel.org/r/20201030200707.24294-1-grygorii.strashko@ti.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 2c4de211 8fbc2f9e
This diff is collapsed.
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/soc/ti/k3-ringacc.h>
#include "am65-cpsw-qos.h" #include "am65-cpsw-qos.h"
struct am65_cpts; struct am65_cpts;
...@@ -59,6 +60,7 @@ struct am65_cpsw_tx_chn { ...@@ -59,6 +60,7 @@ struct am65_cpsw_tx_chn {
struct am65_cpsw_common *common; struct am65_cpsw_common *common;
struct k3_cppi_desc_pool *desc_pool; struct k3_cppi_desc_pool *desc_pool;
struct k3_udma_glue_tx_channel *tx_chn; struct k3_udma_glue_tx_channel *tx_chn;
spinlock_t lock; /* protect TX rings in multi-port mode */
int irq; int irq;
u32 id; u32 id;
u32 descs_num; u32 descs_num;
...@@ -77,6 +79,8 @@ struct am65_cpsw_rx_chn { ...@@ -77,6 +79,8 @@ struct am65_cpsw_rx_chn {
struct am65_cpsw_pdata { struct am65_cpsw_pdata {
u32 quirks; u32 quirks;
enum k3_ring_mode fdqring_mode;
const char *ale_dev_id;
}; };
struct am65_cpsw_common { struct am65_cpsw_common {
...@@ -91,6 +95,7 @@ struct am65_cpsw_common { ...@@ -91,6 +95,7 @@ struct am65_cpsw_common {
struct am65_cpsw_host host; struct am65_cpsw_host host;
struct am65_cpsw_port *ports; struct am65_cpsw_port *ports;
u32 disabled_ports_mask; u32 disabled_ports_mask;
struct net_device *dma_ndev;
int usage_count; /* number of opened ports */ int usage_count; /* number of opened ports */
struct cpsw_ale *ale; struct cpsw_ale *ale;
......
...@@ -634,8 +634,8 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port_mask, int untag, ...@@ -634,8 +634,8 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port_mask, int untag,
return 0; return 0;
} }
static void cpsw_ale_del_vlan_modify(struct cpsw_ale *ale, u32 *ale_entry, static void cpsw_ale_vlan_del_modify_int(struct cpsw_ale *ale, u32 *ale_entry,
u16 vid, int port_mask) u16 vid, int port_mask)
{ {
int reg_mcast, unreg_mcast; int reg_mcast, unreg_mcast;
int members, untag; int members, untag;
...@@ -644,6 +644,7 @@ static void cpsw_ale_del_vlan_modify(struct cpsw_ale *ale, u32 *ale_entry, ...@@ -644,6 +644,7 @@ static void cpsw_ale_del_vlan_modify(struct cpsw_ale *ale, u32 *ale_entry,
ALE_ENT_VID_MEMBER_LIST); ALE_ENT_VID_MEMBER_LIST);
members &= ~port_mask; members &= ~port_mask;
if (!members) { if (!members) {
cpsw_ale_set_vlan_untag(ale, ale_entry, vid, 0);
cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
return; return;
} }
...@@ -673,7 +674,7 @@ static void cpsw_ale_del_vlan_modify(struct cpsw_ale *ale, u32 *ale_entry, ...@@ -673,7 +674,7 @@ static void cpsw_ale_del_vlan_modify(struct cpsw_ale *ale, u32 *ale_entry,
ALE_ENT_VID_MEMBER_LIST, members); ALE_ENT_VID_MEMBER_LIST, members);
} }
int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) int cpsw_ale_vlan_del_modify(struct cpsw_ale *ale, u16 vid, int port_mask)
{ {
u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
int idx; int idx;
...@@ -684,11 +685,39 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) ...@@ -684,11 +685,39 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
cpsw_ale_read(ale, idx, ale_entry); cpsw_ale_read(ale, idx, ale_entry);
if (port_mask) { cpsw_ale_vlan_del_modify_int(ale, ale_entry, vid, port_mask);
cpsw_ale_del_vlan_modify(ale, ale_entry, vid, port_mask); cpsw_ale_write(ale, idx, ale_entry);
} else {
return 0;
}
int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
{
u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
int members, idx;
idx = cpsw_ale_match_vlan(ale, vid);
if (idx < 0)
return -ENOENT;
cpsw_ale_read(ale, idx, ale_entry);
/* if !port_mask - force remove VLAN (legacy).
* Check if there are other VLAN members ports
* if no - remove VLAN.
* if yes it means same VLAN was added to >1 port in multi port mode, so
* remove port_mask ports from VLAN ALE entry excluding Host port.
*/
members = cpsw_ale_vlan_get_fld(ale, ale_entry, ALE_ENT_VID_MEMBER_LIST);
members &= ~port_mask;
if (!port_mask || !members) {
/* last port or force remove - remove VLAN */
cpsw_ale_set_vlan_untag(ale, ale_entry, vid, 0); cpsw_ale_set_vlan_untag(ale, ale_entry, vid, 0);
cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
} else {
port_mask &= ~ALE_PORT_HOST;
cpsw_ale_vlan_del_modify_int(ale, ale_entry, vid, port_mask);
} }
cpsw_ale_write(ale, idx, ale_entry); cpsw_ale_write(ale, idx, ale_entry);
......
...@@ -134,6 +134,7 @@ static inline int cpsw_ale_get_vlan_p0_untag(struct cpsw_ale *ale, u16 vid) ...@@ -134,6 +134,7 @@ static inline int cpsw_ale_get_vlan_p0_untag(struct cpsw_ale *ale, u16 vid)
int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask, 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 untag_mask, int reg_mcast, int unreg_mcast);
int cpsw_ale_vlan_del_modify(struct cpsw_ale *ale, u16 vid, int port_mask);
void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask, void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask,
bool add); bool add);
......
...@@ -227,7 +227,7 @@ static int cpsw_port_vlan_del(struct cpsw_priv *priv, u16 vid, ...@@ -227,7 +227,7 @@ static int cpsw_port_vlan_del(struct cpsw_priv *priv, u16 vid,
else else
port_mask = BIT(priv->emac_port); port_mask = BIT(priv->emac_port);
ret = cpsw_ale_del_vlan(cpsw->ale, vid, port_mask); ret = cpsw_ale_vlan_del_modify(cpsw->ale, vid, port_mask);
if (ret != 0) if (ret != 0)
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment