File Index
Files and directories
Sign in
FILE

bcmasp.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/broadcom/asp2/bcmasp.c C
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Broadcom STB ASP 2.0 Driver
   4 *
   5 * Copyright (c) 2023 Broadcom
   6 */
   7#include <linux/etherdevice.h>
   8#include <linux/if_vlan.h>
   9#include <linux/init.h>
  10#include <linux/interrupt.h>
  11#include <linux/module.h>
  12#include <linux/kernel.h>
  13#include <linux/platform_device.h>
  14#include <linux/of.h>
  15#include <linux/of_address.h>
  16#include <linux/of_platform.h>
  17#include <linux/clk.h>
  18
  19#include "bcmasp.h"
  20#include "bcmasp_intf_defs.h"
  21
  22static void _intr2_mask_clear(struct bcmasp_priv *priv, u32 mask)
  23{
  24	intr2_core_wl(priv, mask, ASP_INTR2_MASK_CLEAR);
  25	priv->irq_mask &= ~mask;
  26}
  27
  28static void _intr2_mask_set(struct bcmasp_priv *priv, u32 mask)
  29{
  30	intr2_core_wl(priv, mask, ASP_INTR2_MASK_SET);
  31	priv->irq_mask |= mask;
  32}
  33
  34void bcmasp_enable_phy_irq(struct bcmasp_intf *intf, int en)
  35{
  36	struct bcmasp_priv *priv = intf->parent;
  37
  38	/* Only supported with internal phys */
  39	if (!intf->internal_phy)
  40		return;
  41
  42	if (en)
  43		_intr2_mask_clear(priv, ASP_INTR2_PHY_EVENT(intf->channel));
  44	else
  45		_intr2_mask_set(priv, ASP_INTR2_PHY_EVENT(intf->channel));
  46}
  47
  48void bcmasp_enable_tx_irq(struct bcmasp_intf *intf, int en)
  49{
  50	struct bcmasp_priv *priv = intf->parent;
  51
  52	if (en)
  53		_intr2_mask_clear(priv, ASP_INTR2_TX_DESC(intf->channel));
  54	else
  55		_intr2_mask_set(priv, ASP_INTR2_TX_DESC(intf->channel));
  56}
  57EXPORT_SYMBOL_GPL(bcmasp_enable_tx_irq);
  58
  59void bcmasp_enable_rx_irq(struct bcmasp_intf *intf, int en)
  60{
  61	struct bcmasp_priv *priv = intf->parent;
  62
  63	if (en)
  64		_intr2_mask_clear(priv, ASP_INTR2_RX_ECH(intf->channel));
  65	else
  66		_intr2_mask_set(priv, ASP_INTR2_RX_ECH(intf->channel));
  67}
  68EXPORT_SYMBOL_GPL(bcmasp_enable_rx_irq);
  69
  70static void bcmasp_intr2_mask_set_all(struct bcmasp_priv *priv)
  71{
  72	_intr2_mask_set(priv, 0xffffffff);
  73	priv->irq_mask = 0xffffffff;
  74}
  75
  76static void bcmasp_intr2_clear_all(struct bcmasp_priv *priv)
  77{
  78	intr2_core_wl(priv, 0xffffffff, ASP_INTR2_CLEAR);
  79}
  80
  81static void bcmasp_intr2_handling(struct bcmasp_intf *intf, u32 status)
  82{
  83	if (status & ASP_INTR2_RX_ECH(intf->channel)) {
  84		if (likely(napi_schedule_prep(&intf->rx_napi))) {
  85			bcmasp_enable_rx_irq(intf, 0);
  86			__napi_schedule_irqoff(&intf->rx_napi);
  87		}
  88	}
  89
  90	if (status & ASP_INTR2_TX_DESC(intf->channel)) {
  91		if (likely(napi_schedule_prep(&intf->tx_napi))) {
  92			bcmasp_enable_tx_irq(intf, 0);
  93			__napi_schedule_irqoff(&intf->tx_napi);
  94		}
  95	}
  96
  97	if (status & ASP_INTR2_PHY_EVENT(intf->channel))
  98		phy_mac_interrupt(intf->ndev->phydev);
  99}
 100
 101static irqreturn_t bcmasp_isr(int irq, void *data)
 102{
 103	struct bcmasp_priv *priv = data;
 104	struct bcmasp_intf *intf;
 105	u32 status;
 106
 107	status = intr2_core_rl(priv, ASP_INTR2_STATUS) &
 108		~intr2_core_rl(priv, ASP_INTR2_MASK_STATUS);
 109
 110	intr2_core_wl(priv, status, ASP_INTR2_CLEAR);
 111
 112	if (unlikely(status == 0)) {
 113		dev_warn(&priv->pdev->dev, "l2 spurious interrupt\n");
 114		return IRQ_NONE;
 115	}
 116
 117	/* Handle intferfaces */
 118	list_for_each_entry(intf, &priv->intfs, list)
 119		bcmasp_intr2_handling(intf, status);
 120
 121	return IRQ_HANDLED;
 122}
 123
 124void bcmasp_flush_rx_port(struct bcmasp_intf *intf)
 125{
 126	struct bcmasp_priv *priv = intf->parent;
 127	u32 mask;
 128
 129	switch (intf->port) {
 130	case 0:
 131		mask = ASP_CTRL_UMAC0_FLUSH_MASK;
 132		break;
 133	case 1:
 134		mask = ASP_CTRL_UMAC1_FLUSH_MASK;
 135		break;
 136	case 2:
 137		mask = ASP_CTRL_SPB_FLUSH_MASK;
 138		break;
 139	default:
 140		/* Not valid port */
 141		return;
 142	}
 143
 144	rx_ctrl_core_wl(priv, mask, ASP_RX_CTRL_FLUSH);
 145}
 146
 147static void bcmasp_netfilt_hw_en_wake(struct bcmasp_priv *priv,
 148				      struct bcmasp_net_filter *nfilt)
 149{
 150	rx_filter_core_wl(priv, ASP_RX_FILTER_NET_OFFSET_L3_1(64),
 151			  ASP_RX_FILTER_NET_OFFSET(nfilt->hw_index));
 152
 153	rx_filter_core_wl(priv, ASP_RX_FILTER_NET_OFFSET_L2(32) |
 154			  ASP_RX_FILTER_NET_OFFSET_L3_0(32) |
 155			  ASP_RX_FILTER_NET_OFFSET_L3_1(96) |
 156			  ASP_RX_FILTER_NET_OFFSET_L4(32),
 157			  ASP_RX_FILTER_NET_OFFSET(nfilt->hw_index + 1));
 158
 159	rx_filter_core_wl(priv, ASP_RX_FILTER_NET_CFG_CH(nfilt->ch) |
 160			  ASP_RX_FILTER_NET_CFG_EN |
 161			  ASP_RX_FILTER_NET_CFG_L2_EN |
 162			  ASP_RX_FILTER_NET_CFG_L3_EN |
 163			  ASP_RX_FILTER_NET_CFG_L4_EN |
 164			  ASP_RX_FILTER_NET_CFG_L3_FRM(2) |
 165			  ASP_RX_FILTER_NET_CFG_L4_FRM(2) |
 166			  ASP_RX_FILTER_NET_CFG_UMC(nfilt->port),
 167			  ASP_RX_FILTER_NET_CFG(nfilt->hw_index));
 168
 169	rx_filter_core_wl(priv, ASP_RX_FILTER_NET_CFG_CH(nfilt->ch) |
 170			  ASP_RX_FILTER_NET_CFG_EN |
 171			  ASP_RX_FILTER_NET_CFG_L2_EN |
 172			  ASP_RX_FILTER_NET_CFG_L3_EN |
 173			  ASP_RX_FILTER_NET_CFG_L4_EN |
 174			  ASP_RX_FILTER_NET_CFG_L3_FRM(2) |
 175			  ASP_RX_FILTER_NET_CFG_L4_FRM(2) |
 176			  ASP_RX_FILTER_NET_CFG_UMC(nfilt->port),
 177			  ASP_RX_FILTER_NET_CFG(nfilt->hw_index + 1));
 178}
 179
 180#define MAX_WAKE_FILTER_SIZE		256
 181enum asp_netfilt_reg_type {
 182	ASP_NETFILT_MATCH = 0,
 183	ASP_NETFILT_MASK,
 184	ASP_NETFILT_MAX
 185};
 186
 187static int bcmasp_netfilt_get_reg_offset(struct bcmasp_priv *priv,
 188					 struct bcmasp_net_filter *nfilt,
 189					 enum asp_netfilt_reg_type reg_type,
 190					 u32 offset)
 191{
 192	u32 block_index, filter_sel;
 193
 194	if (offset < 32) {
 195		block_index = ASP_RX_FILTER_NET_L2;
 196		filter_sel = nfilt->hw_index;
 197	} else if (offset < 64) {
 198		block_index = ASP_RX_FILTER_NET_L2;
 199		filter_sel = nfilt->hw_index + 1;
 200	} else if (offset < 96) {
 201		block_index = ASP_RX_FILTER_NET_L3_0;
 202		filter_sel = nfilt->hw_index;
 203	} else if (offset < 128) {
 204		block_index = ASP_RX_FILTER_NET_L3_0;
 205		filter_sel = nfilt->hw_index + 1;
 206	} else if (offset < 160) {
 207		block_index = ASP_RX_FILTER_NET_L3_1;
 208		filter_sel = nfilt->hw_index;
 209	} else if (offset < 192) {
 210		block_index = ASP_RX_FILTER_NET_L3_1;
 211		filter_sel = nfilt->hw_index + 1;
 212	} else if (offset < 224) {
 213		block_index = ASP_RX_FILTER_NET_L4;
 214		filter_sel = nfilt->hw_index;
 215	} else if (offset < 256) {
 216		block_index = ASP_RX_FILTER_NET_L4;
 217		filter_sel = nfilt->hw_index + 1;
 218	} else {
 219		return -EINVAL;
 220	}
 221
 222	switch (reg_type) {
 223	case ASP_NETFILT_MATCH:
 224		return ASP_RX_FILTER_NET_PAT(filter_sel, block_index,
 225					     (offset % 32));
 226	case ASP_NETFILT_MASK:
 227		return ASP_RX_FILTER_NET_MASK(filter_sel, block_index,
 228					      (offset % 32));
 229	default:
 230		return -EINVAL;
 231	}
 232}
 233
 234static void bcmasp_netfilt_wr(struct bcmasp_priv *priv,
 235			      struct bcmasp_net_filter *nfilt,
 236			      enum asp_netfilt_reg_type reg_type,
 237			      u32 val, u32 offset)
 238{
 239	int reg_offset;
 240
 241	/* HW only accepts 4 byte aligned writes */
 242	if (!IS_ALIGNED(offset, 4) || offset > MAX_WAKE_FILTER_SIZE)
 243		return;
 244
 245	reg_offset = bcmasp_netfilt_get_reg_offset(priv, nfilt, reg_type,
 246						   offset);
 247
 248	rx_filter_core_wl(priv, val, reg_offset);
 249}
 250
 251static u32 bcmasp_netfilt_rd(struct bcmasp_priv *priv,
 252			     struct bcmasp_net_filter *nfilt,
 253			     enum asp_netfilt_reg_type reg_type,
 254			     u32 offset)
 255{
 256	int reg_offset;
 257
 258	/* HW only accepts 4 byte aligned writes */
 259	if (!IS_ALIGNED(offset, 4) || offset > MAX_WAKE_FILTER_SIZE)
 260		return 0;
 261
 262	reg_offset = bcmasp_netfilt_get_reg_offset(priv, nfilt, reg_type,
 263						   offset);
 264
 265	return rx_filter_core_rl(priv, reg_offset);
 266}
 267
 268static int bcmasp_netfilt_wr_m_wake(struct bcmasp_priv *priv,
 269				    struct bcmasp_net_filter *nfilt,
 270				    u32 offset, void *match, void *mask,
 271				    size_t size)
 272{
 273	u32 shift, mask_val = 0, match_val = 0;
 274	bool first_byte = true;
 275
 276	if ((offset + size) > MAX_WAKE_FILTER_SIZE)
 277		return -EINVAL;
 278
 279	while (size--) {
 280		/* The HW only accepts 4 byte aligned writes, so if we
 281		 * begin unaligned or if remaining bytes less than 4,
 282		 * we need to read then write to avoid losing current
 283		 * register state
 284		 */
 285		if (first_byte && (!IS_ALIGNED(offset, 4) || size < 3)) {
 286			match_val = bcmasp_netfilt_rd(priv, nfilt,
 287						      ASP_NETFILT_MATCH,
 288						      ALIGN_DOWN(offset, 4));
 289			mask_val = bcmasp_netfilt_rd(priv, nfilt,
 290						     ASP_NETFILT_MASK,
 291						     ALIGN_DOWN(offset, 4));
 292		}
 293
 294		shift = (3 - (offset % 4)) * 8;
 295		match_val &= ~GENMASK(shift + 7, shift);
 296		mask_val &= ~GENMASK(shift + 7, shift);
 297		match_val |= (u32)(*((u8 *)match) << shift);
 298		mask_val |= (u32)(*((u8 *)mask) << shift);
 299
 300		/* If last byte or last byte of word, write to reg */
 301		if (!size || ((offset % 4) == 3)) {
 302			bcmasp_netfilt_wr(priv, nfilt, ASP_NETFILT_MATCH,
 303					  match_val, ALIGN_DOWN(offset, 4));
 304			bcmasp_netfilt_wr(priv, nfilt, ASP_NETFILT_MASK,
 305					  mask_val, ALIGN_DOWN(offset, 4));
 306			first_byte = true;
 307		} else {
 308			first_byte = false;
 309		}
 310
 311		offset++;
 312		match++;
 313		mask++;
 314	}
 315
 316	return 0;
 317}
 318
 319static void bcmasp_netfilt_reset_hw(struct bcmasp_priv *priv,
 320				    struct bcmasp_net_filter *nfilt)
 321{
 322	int i;
 323
 324	for (i = 0; i < MAX_WAKE_FILTER_SIZE; i += 4) {
 325		bcmasp_netfilt_wr(priv, nfilt, ASP_NETFILT_MATCH, 0, i);
 326		bcmasp_netfilt_wr(priv, nfilt, ASP_NETFILT_MASK, 0, i);
 327	}
 328}
 329
 330static void bcmasp_netfilt_tcpip4_wr(struct bcmasp_priv *priv,
 331				     struct bcmasp_net_filter *nfilt,
 332				     struct ethtool_tcpip4_spec *match,
 333				     struct ethtool_tcpip4_spec *mask,
 334				     u32 offset)
 335{
 336	__be16 val_16, mask_16;
 337
 338	val_16 = htons(ETH_P_IP);
 339	mask_16 = htons(0xFFFF);
 340	bcmasp_netfilt_wr_m_wake(priv, nfilt, (ETH_ALEN * 2) + offset,
 341				 &val_16, &mask_16, sizeof(val_16));
 342	bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 1,
 343				 &match->tos, &mask->tos,
 344				 sizeof(match->tos));
 345	bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 12,
 346				 &match->ip4src, &mask->ip4src,
 347				 sizeof(match->ip4src));
 348	bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 16,
 349				 &match->ip4dst, &mask->ip4dst,
 350				 sizeof(match->ip4dst));
 351	bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 20,
 352				 &match->psrc, &mask->psrc,
 353				 sizeof(match->psrc));
 354	bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 22,
 355				 &match->pdst, &mask->pdst,
 356				 sizeof(match->pdst));
 357}
 358
 359static void bcmasp_netfilt_tcpip6_wr(struct bcmasp_priv *priv,
 360				     struct bcmasp_net_filter *nfilt,
 361				     struct ethtool_tcpip6_spec *match,
 362				     struct ethtool_tcpip6_spec *mask,
 363				     u32 offset)
 364{
 365	__be16 val_16, mask_16;
 366
 367	val_16 = htons(ETH_P_IPV6);
 368	mask_16 = htons(0xFFFF);
 369	bcmasp_netfilt_wr_m_wake(priv, nfilt, (ETH_ALEN * 2) + offset,
 370				 &val_16, &mask_16, sizeof(val_16));
 371	val_16 = htons(match->tclass << 4);
 372	mask_16 = htons(mask->tclass << 4);
 373	bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset,
 374				 &val_16, &mask_16, sizeof(val_16));
 375	bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 8,
 376				 &match->ip6src, &mask->ip6src,
 377				 sizeof(match->ip6src));
 378	bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 24,
 379				 &match->ip6dst, &mask->ip6dst,
 380				 sizeof(match->ip6dst));
 381	bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 40,
 382				 &match->psrc, &mask->psrc,
 383				 sizeof(match->psrc));
 384	bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 42,
 385				 &match->pdst, &mask->pdst,
 386				 sizeof(match->pdst));
 387}
 388
 389static int bcmasp_netfilt_wr_to_hw(struct bcmasp_priv *priv,
 390				   struct bcmasp_net_filter *nfilt)
 391{
 392	struct ethtool_rx_flow_spec *fs = &nfilt->fs;
 393	unsigned int offset = 0;
 394	__be16 val_16, mask_16;
 395	u8 val_8, mask_8;
 396
 397	/* Currently only supports wake filters */
 398	if (!nfilt->wake_filter)
 399		return -EINVAL;
 400
 401	bcmasp_netfilt_reset_hw(priv, nfilt);
 402
 403	if (fs->flow_type & FLOW_MAC_EXT) {
 404		bcmasp_netfilt_wr_m_wake(priv, nfilt, 0, &fs->h_ext.h_dest,
 405					 &fs->m_ext.h_dest,
 406					 sizeof(fs->h_ext.h_dest));
 407	}
 408
 409	if ((fs->flow_type & FLOW_EXT) &&
 410	    (fs->m_ext.vlan_etype || fs->m_ext.vlan_tci)) {
 411		bcmasp_netfilt_wr_m_wake(priv, nfilt, (ETH_ALEN * 2),
 412					 &fs->h_ext.vlan_etype,
 413					 &fs->m_ext.vlan_etype,
 414					 sizeof(fs->h_ext.vlan_etype));
 415		bcmasp_netfilt_wr_m_wake(priv, nfilt, ((ETH_ALEN * 2) + 2),
 416					 &fs->h_ext.vlan_tci,
 417					 &fs->m_ext.vlan_tci,
 418					 sizeof(fs->h_ext.vlan_tci));
 419		offset += VLAN_HLEN;
 420	}
 421
 422	switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
 423	case ETHER_FLOW:
 424		bcmasp_netfilt_wr_m_wake(priv, nfilt, 0,
 425					 &fs->h_u.ether_spec.h_dest,
 426					 &fs->m_u.ether_spec.h_dest,
 427					 sizeof(fs->h_u.ether_spec.h_dest));
 428		bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_ALEN,
 429					 &fs->h_u.ether_spec.h_source,
 430					 &fs->m_u.ether_spec.h_source,
 431					 sizeof(fs->h_u.ether_spec.h_source));
 432		bcmasp_netfilt_wr_m_wake(priv, nfilt, (ETH_ALEN * 2) + offset,
 433					 &fs->h_u.ether_spec.h_proto,
 434					 &fs->m_u.ether_spec.h_proto,
 435					 sizeof(fs->h_u.ether_spec.h_proto));
 436
 437		break;
 438	case IP_USER_FLOW:
 439		val_16 = htons(ETH_P_IP);
 440		mask_16 = htons(0xFFFF);
 441		bcmasp_netfilt_wr_m_wake(priv, nfilt, (ETH_ALEN * 2) + offset,
 442					 &val_16, &mask_16, sizeof(val_16));
 443		bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 1,
 444					 &fs->h_u.usr_ip4_spec.tos,
 445					 &fs->m_u.usr_ip4_spec.tos,
 446					 sizeof(fs->h_u.usr_ip4_spec.tos));
 447		bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 9,
 448					 &fs->h_u.usr_ip4_spec.proto,
 449					 &fs->m_u.usr_ip4_spec.proto,
 450					 sizeof(fs->h_u.usr_ip4_spec.proto));
 451		bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 12,
 452					 &fs->h_u.usr_ip4_spec.ip4src,
 453					 &fs->m_u.usr_ip4_spec.ip4src,
 454					 sizeof(fs->h_u.usr_ip4_spec.ip4src));
 455		bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 16,
 456					 &fs->h_u.usr_ip4_spec.ip4dst,
 457					 &fs->m_u.usr_ip4_spec.ip4dst,
 458					 sizeof(fs->h_u.usr_ip4_spec.ip4dst));
 459		if (!fs->m_u.usr_ip4_spec.l4_4_bytes)
 460			break;
 461
 462		/* Only supports 20 byte IPv4 header */
 463		val_8 = 0x45;
 464		mask_8 = 0xFF;
 465		bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset,
 466					 &val_8, &mask_8, sizeof(val_8));
 467		bcmasp_netfilt_wr_m_wake(priv, nfilt,
 468					 ETH_HLEN + 20 + offset,
 469					 &fs->h_u.usr_ip4_spec.l4_4_bytes,
 470					 &fs->m_u.usr_ip4_spec.l4_4_bytes,
 471					 sizeof(fs->h_u.usr_ip4_spec.l4_4_bytes)
 472					 );
 473		break;
 474	case TCP_V4_FLOW:
 475		val_8 = IPPROTO_TCP;
 476		mask_8 = 0xFF;
 477		bcmasp_netfilt_tcpip4_wr(priv, nfilt, &fs->h_u.tcp_ip4_spec,
 478					 &fs->m_u.tcp_ip4_spec, offset);
 479		bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 9,
 480					 &val_8, &mask_8, sizeof(val_8));
 481		break;
 482	case UDP_V4_FLOW:
 483		val_8 = IPPROTO_UDP;
 484		mask_8 = 0xFF;
 485		bcmasp_netfilt_tcpip4_wr(priv, nfilt, &fs->h_u.udp_ip4_spec,
 486					 &fs->m_u.udp_ip4_spec, offset);
 487
 488		bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 9,
 489					 &val_8, &mask_8, sizeof(val_8));
 490		break;
 491	case TCP_V6_FLOW:
 492		val_8 = IPPROTO_TCP;
 493		mask_8 = 0xFF;
 494		bcmasp_netfilt_tcpip6_wr(priv, nfilt, &fs->h_u.tcp_ip6_spec,
 495					 &fs->m_u.tcp_ip6_spec, offset);
 496		bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 6,
 497					 &val_8, &mask_8, sizeof(val_8));
 498		break;
 499	case UDP_V6_FLOW:
 500		val_8 = IPPROTO_UDP;
 501		mask_8 = 0xFF;
 502		bcmasp_netfilt_tcpip6_wr(priv, nfilt, &fs->h_u.udp_ip6_spec,
 503					 &fs->m_u.udp_ip6_spec, offset);
 504		bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 6,
 505					 &val_8, &mask_8, sizeof(val_8));
 506		break;
 507	}
 508
 509	bcmasp_netfilt_hw_en_wake(priv, nfilt);
 510
 511	return 0;
 512}
 513
 514void bcmasp_netfilt_suspend(struct bcmasp_intf *intf)
 515{
 516	struct bcmasp_priv *priv = intf->parent;
 517	bool write = false;
 518	int ret, i;
 519
 520	/* Write all filters to HW */
 521	for (i = 0; i < priv->num_net_filters; i++) {
 522		/* If the filter does not match the port, skip programming. */
 523		if (!priv->net_filters[i].claimed ||
 524		    priv->net_filters[i].port != intf->port)
 525			continue;
 526
 527		if (i > 0 && (i % 2) &&
 528		    priv->net_filters[i].wake_filter &&
 529		    priv->net_filters[i - 1].wake_filter)
 530			continue;
 531
 532		ret = bcmasp_netfilt_wr_to_hw(priv, &priv->net_filters[i]);
 533		if (!ret)
 534			write = true;
 535	}
 536
 537	/* Successfully programmed at least one wake filter
 538	 * so enable top level wake config
 539	 */
 540	if (write)
 541		rx_filter_core_wl(priv, (ASP_RX_FILTER_OPUT_EN |
 542				  ASP_RX_FILTER_LNR_MD |
 543				  ASP_RX_FILTER_GEN_WK_EN |
 544				  ASP_RX_FILTER_NT_FLT_EN),
 545				  ASP_RX_FILTER_BLK_CTRL);
 546}
 547
 548int bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs,
 549				  u32 *rule_cnt)
 550{
 551	struct bcmasp_priv *priv = intf->parent;
 552	int j = 0, i;
 553
 554	for (i = 0; i < priv->num_net_filters; i++) {
 555		if (!priv->net_filters[i].claimed ||
 556		    priv->net_filters[i].port != intf->port)
 557			continue;
 558
 559		if (i > 0 && (i % 2) &&
 560		    priv->net_filters[i].wake_filter &&
 561		    priv->net_filters[i - 1].wake_filter)
 562			continue;
 563
 564		if (j == *rule_cnt)
 565			return -EMSGSIZE;
 566
 567		rule_locs[j++] = priv->net_filters[i].fs.location;
 568	}
 569
 570	*rule_cnt = j;
 571
 572	return 0;
 573}
 574
 575int bcmasp_netfilt_get_active(struct bcmasp_intf *intf)
 576{
 577	struct bcmasp_priv *priv = intf->parent;
 578	int cnt = 0, i;
 579
 580	for (i = 0; i < priv->num_net_filters; i++) {
 581		if (!priv->net_filters[i].claimed ||
 582		    priv->net_filters[i].port != intf->port)
 583			continue;
 584
 585		/* Skip over a wake filter pair */
 586		if (i > 0 && (i % 2) &&
 587		    priv->net_filters[i].wake_filter &&
 588		    priv->net_filters[i - 1].wake_filter)
 589			continue;
 590
 591		cnt++;
 592	}
 593
 594	return cnt;
 595}
 596
 597bool bcmasp_netfilt_check_dup(struct bcmasp_intf *intf,
 598			      struct ethtool_rx_flow_spec *fs)
 599{
 600	struct bcmasp_priv *priv = intf->parent;
 601	struct ethtool_rx_flow_spec *cur;
 602	size_t fs_size = 0;
 603	int i;
 604
 605	for (i = 0; i < priv->num_net_filters; i++) {
 606		if (!priv->net_filters[i].claimed ||
 607		    priv->net_filters[i].port != intf->port)
 608			continue;
 609
 610		cur = &priv->net_filters[i].fs;
 611
 612		if (cur->flow_type != fs->flow_type ||
 613		    cur->ring_cookie != fs->ring_cookie)
 614			continue;
 615
 616		switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
 617		case ETHER_FLOW:
 618			fs_size = sizeof(struct ethhdr);
 619			break;
 620		case IP_USER_FLOW:
 621			fs_size = sizeof(struct ethtool_usrip4_spec);
 622			break;
 623		case TCP_V6_FLOW:
 624		case UDP_V6_FLOW:
 625			fs_size = sizeof(struct ethtool_tcpip6_spec);
 626			break;
 627		case TCP_V4_FLOW:
 628		case UDP_V4_FLOW:
 629			fs_size = sizeof(struct ethtool_tcpip4_spec);
 630			break;
 631		default:
 632			continue;
 633		}
 634
 635		if (memcmp(&cur->h_u, &fs->h_u, fs_size) ||
 636		    memcmp(&cur->m_u, &fs->m_u, fs_size))
 637			continue;
 638
 639		if (cur->flow_type & FLOW_EXT) {
 640			if (cur->h_ext.vlan_etype != fs->h_ext.vlan_etype ||
 641			    cur->m_ext.vlan_etype != fs->m_ext.vlan_etype ||
 642			    cur->h_ext.vlan_tci != fs->h_ext.vlan_tci ||
 643			    cur->m_ext.vlan_tci != fs->m_ext.vlan_tci ||
 644			    cur->h_ext.data[0] != fs->h_ext.data[0])
 645				continue;
 646		}
 647		if (cur->flow_type & FLOW_MAC_EXT) {
 648			if (memcmp(&cur->h_ext.h_dest,
 649				   &fs->h_ext.h_dest, ETH_ALEN) ||
 650			    memcmp(&cur->m_ext.h_dest,
 651				   &fs->m_ext.h_dest, ETH_ALEN))
 652				continue;
 653		}
 654
 655		return true;
 656	}
 657
 658	return false;
 659}
 660
 661/* If no network filter found, return open filter.
 662 * If no more open filters return NULL
 663 */
 664struct bcmasp_net_filter *bcmasp_netfilt_get_init(struct bcmasp_intf *intf,
 665						  u32 loc, bool wake_filter,
 666						  bool init)
 667{
 668	struct bcmasp_net_filter *nfilter = NULL;
 669	struct bcmasp_priv *priv = intf->parent;
 670	int i, open_index = -1;
 671
 672	/* Check whether we exceed the filter table capacity */
 673	if (loc != RX_CLS_LOC_ANY && loc >= priv->num_net_filters)
 674		return ERR_PTR(-EINVAL);
 675
 676	/* If the filter location is busy (already claimed) and we are initializing
 677	 * the filter (insertion), return a busy error code.
 678	 */
 679	if (loc != RX_CLS_LOC_ANY && init && priv->net_filters[loc].claimed)
 680		return ERR_PTR(-EBUSY);
 681
 682	/* We need two filters for wake-up, so we cannot use an odd filter */
 683	if (wake_filter && loc != RX_CLS_LOC_ANY && (loc % 2))
 684		return ERR_PTR(-EINVAL);
 685
 686	/* Initialize the loop index based on the desired location or from 0 */
 687	i = loc == RX_CLS_LOC_ANY ? 0 : loc;
 688
 689	for ( ; i < priv->num_net_filters; i++) {
 690		/* Found matching network filter */
 691		if (!init &&
 692		    priv->net_filters[i].claimed &&
 693		    priv->net_filters[i].hw_index == i &&
 694		    priv->net_filters[i].port == intf->port)
 695			return &priv->net_filters[i];
 696
 697		/* If we don't need a new filter or new filter already found */
 698		if (!init || open_index >= 0)
 699			continue;
 700
 701		/* Wake filter conslidates two filters to cover more bytes
 702		 * Wake filter is open if...
 703		 * 1. It is an even filter
 704		 * 2. The current and next filter is not claimed
 705		 */
 706		if (wake_filter && !(i % 2) && !priv->net_filters[i].claimed &&
 707		    !priv->net_filters[i + 1].claimed)
 708			open_index = i;
 709		else if (!priv->net_filters[i].claimed)
 710			open_index = i;
 711	}
 712
 713	if (open_index >= 0) {
 714		nfilter = &priv->net_filters[open_index];
 715		nfilter->claimed = true;
 716		nfilter->port = intf->port;
 717		nfilter->ch = intf->channel + priv->tx_chan_offset;
 718		nfilter->hw_index = open_index;
 719	}
 720
 721	if (wake_filter && open_index >= 0) {
 722		/* Claim next filter */
 723		priv->net_filters[open_index + 1].claimed = true;
 724		priv->net_filters[open_index + 1].wake_filter = true;
 725		nfilter->wake_filter = true;
 726	}
 727
 728	return nfilter ? nfilter : ERR_PTR(-EINVAL);
 729}
 730
 731void bcmasp_netfilt_release(struct bcmasp_intf *intf,
 732			    struct bcmasp_net_filter *nfilt)
 733{
 734	struct bcmasp_priv *priv = intf->parent;
 735
 736	if (nfilt->wake_filter) {
 737		memset(&priv->net_filters[nfilt->hw_index + 1], 0,
 738		       sizeof(struct bcmasp_net_filter));
 739	}
 740
 741	memset(nfilt, 0, sizeof(struct bcmasp_net_filter));
 742}
 743
 744static void bcmasp_addr_to_uint(unsigned char *addr, u32 *high, u32 *low)
 745{
 746	*high = (u32)(addr[0] << 8 | addr[1]);
 747	*low = (u32)(addr[2] << 24 | addr[3] << 16 | addr[4] << 8 |
 748		     addr[5]);
 749}
 750
 751static void bcmasp_set_mda_filter(struct bcmasp_intf *intf,
 752				  const unsigned char *addr,
 753				  unsigned char *mask,
 754				  unsigned int i)
 755{
 756	struct bcmasp_priv *priv = intf->parent;
 757	u32 addr_h, addr_l, mask_h, mask_l;
 758
 759	/* Set local copy */
 760	ether_addr_copy(priv->mda_filters[i].mask, mask);
 761	ether_addr_copy(priv->mda_filters[i].addr, addr);
 762
 763	/* Write to HW */
 764	bcmasp_addr_to_uint(priv->mda_filters[i].mask, &mask_h, &mask_l);
 765	bcmasp_addr_to_uint(priv->mda_filters[i].addr, &addr_h, &addr_l);
 766	rx_filter_core_wl(priv, addr_h, ASP_RX_FILTER_MDA_PAT_H(i));
 767	rx_filter_core_wl(priv, addr_l, ASP_RX_FILTER_MDA_PAT_L(i));
 768	rx_filter_core_wl(priv, mask_h, ASP_RX_FILTER_MDA_MSK_H(i));
 769	rx_filter_core_wl(priv, mask_l, ASP_RX_FILTER_MDA_MSK_L(i));
 770}
 771
 772static void bcmasp_en_mda_filter(struct bcmasp_intf *intf, bool en,
 773				 unsigned int i)
 774{
 775	struct bcmasp_priv *priv = intf->parent;
 776
 777	if (priv->mda_filters[i].en == en)
 778		return;
 779
 780	priv->mda_filters[i].en = en;
 781	priv->mda_filters[i].port = intf->port;
 782
 783	rx_filter_core_wl(priv, ((intf->channel + priv->tx_chan_offset) |
 784			  (en << ASP_RX_FILTER_MDA_CFG_EN_SHIFT) |
 785			  ASP_RX_FILTER_MDA_CFG_UMC_SEL(intf->port)),
 786			  ASP_RX_FILTER_MDA_CFG(i));
 787}
 788
 789/* There are 32 MDA filters shared between all ports, we reserve 4 filters per
 790 * port for the following.
 791 * - Promisc: Filter to allow all packets when promisc is enabled
 792 * - All Multicast
 793 * - Broadcast
 794 * - Own address
 795 *
 796 * The reserved filters are identified as so.
 797 * - Promisc: (index * 4) + 0
 798 * - All Multicast: (index * 4) + 1
 799 * - Broadcast: (index * 4) + 2
 800 * - Own address: (index * 4) + 3
 801 */
 802enum asp_rx_filter_id {
 803	ASP_RX_FILTER_MDA_PROMISC = 0,
 804	ASP_RX_FILTER_MDA_ALLMULTI,
 805	ASP_RX_FILTER_MDA_BROADCAST,
 806	ASP_RX_FILTER_MDA_OWN_ADDR,
 807	ASP_RX_FILTER_MDA_RES_MAX,
 808};
 809
 810#define ASP_RX_FILT_MDA(intf, name)	(((intf)->index * \
 811					  ASP_RX_FILTER_MDA_RES_MAX) \
 812					 + ASP_RX_FILTER_MDA_##name)
 813
 814static int bcmasp_total_res_mda_cnt(struct bcmasp_priv *priv)
 815{
 816	return list_count_nodes(&priv->intfs) * ASP_RX_FILTER_MDA_RES_MAX;
 817}
 818
 819void bcmasp_set_promisc(struct bcmasp_intf *intf, bool en)
 820{
 821	unsigned int i = ASP_RX_FILT_MDA(intf, PROMISC);
 822	unsigned char promisc[ETH_ALEN];
 823
 824	eth_zero_addr(promisc);
 825	/* Set mask to 00:00:00:00:00:00 to match all packets */
 826	bcmasp_set_mda_filter(intf, promisc, promisc, i);
 827	bcmasp_en_mda_filter(intf, en, i);
 828}
 829
 830void bcmasp_set_allmulti(struct bcmasp_intf *intf, bool en)
 831{
 832	unsigned char allmulti[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
 833	unsigned int i = ASP_RX_FILT_MDA(intf, ALLMULTI);
 834
 835	/* Set mask to 01:00:00:00:00:00 to match all multicast */
 836	bcmasp_set_mda_filter(intf, allmulti, allmulti, i);
 837	bcmasp_en_mda_filter(intf, en, i);
 838}
 839
 840void bcmasp_set_broad(struct bcmasp_intf *intf, bool en)
 841{
 842	unsigned int i = ASP_RX_FILT_MDA(intf, BROADCAST);
 843	unsigned char addr[ETH_ALEN];
 844
 845	eth_broadcast_addr(addr);
 846	bcmasp_set_mda_filter(intf, addr, addr, i);
 847	bcmasp_en_mda_filter(intf, en, i);
 848}
 849
 850void bcmasp_set_oaddr(struct bcmasp_intf *intf, const unsigned char *addr,
 851		      bool en)
 852{
 853	unsigned char mask[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 854	unsigned int i = ASP_RX_FILT_MDA(intf, OWN_ADDR);
 855
 856	bcmasp_set_mda_filter(intf, addr, mask, i);
 857	bcmasp_en_mda_filter(intf, en, i);
 858}
 859
 860void bcmasp_disable_all_filters(struct bcmasp_intf *intf)
 861{
 862	struct bcmasp_priv *priv = intf->parent;
 863	unsigned int i;
 864	int res_count;
 865
 866	res_count = bcmasp_total_res_mda_cnt(intf->parent);
 867
 868	/* Disable all filters held by this port */
 869	for (i = res_count; i < priv->num_mda_filters; i++) {
 870		if (priv->mda_filters[i].en &&
 871		    priv->mda_filters[i].port == intf->port)
 872			bcmasp_en_mda_filter(intf, 0, i);
 873	}
 874}
 875
 876static int bcmasp_combine_set_filter(struct bcmasp_intf *intf,
 877				     unsigned char *addr, unsigned char *mask,
 878				     int i)
 879{
 880	struct bcmasp_priv *priv = intf->parent;
 881	u64 addr1, addr2, mask1, mask2, mask3;
 882
 883	/* Switch to u64 to help with the calculations */
 884	addr1 = ether_addr_to_u64(priv->mda_filters[i].addr);
 885	mask1 = ether_addr_to_u64(priv->mda_filters[i].mask);
 886	addr2 = ether_addr_to_u64(addr);
 887	mask2 = ether_addr_to_u64(mask);
 888
 889	/* Check if one filter resides within the other */
 890	mask3 = mask1 & mask2;
 891	if (mask3 == mask1 && ((addr1 & mask1) == (addr2 & mask1))) {
 892		/* Filter 2 resides within filter 1, so everything is good */
 893		return 0;
 894	} else if (mask3 == mask2 && ((addr1 & mask2) == (addr2 & mask2))) {
 895		/* Filter 1 resides within filter 2, so swap filters */
 896		bcmasp_set_mda_filter(intf, addr, mask, i);
 897		return 0;
 898	}
 899
 900	/* Unable to combine */
 901	return -EINVAL;
 902}
 903
 904int bcmasp_set_en_mda_filter(struct bcmasp_intf *intf, unsigned char *addr,
 905			     unsigned char *mask)
 906{
 907	struct bcmasp_priv *priv = intf->parent;
 908	int ret, res_count;
 909	unsigned int i;
 910
 911	res_count = bcmasp_total_res_mda_cnt(intf->parent);
 912
 913	for (i = res_count; i < priv->num_mda_filters; i++) {
 914		/* If filter not enabled or belongs to another port skip */
 915		if (!priv->mda_filters[i].en ||
 916		    priv->mda_filters[i].port != intf->port)
 917			continue;
 918
 919		/* Attempt to combine filters */
 920		ret = bcmasp_combine_set_filter(intf, addr, mask, i);
 921		if (!ret) {
 922			intf->mib.filters_combine_cnt++;
 923			return 0;
 924		}
 925	}
 926
 927	/* Create new filter if possible */
 928	for (i = res_count; i < priv->num_mda_filters; i++) {
 929		if (priv->mda_filters[i].en)
 930			continue;
 931
 932		bcmasp_set_mda_filter(intf, addr, mask, i);
 933		bcmasp_en_mda_filter(intf, 1, i);
 934		return 0;
 935	}
 936
 937	/* No room for new filter */
 938	return -EINVAL;
 939}
 940
 941static void bcmasp_core_init_filters(struct bcmasp_priv *priv)
 942{
 943	unsigned int i;
 944
 945	/* Disable all filters and reset software view since the HW
 946	 * can lose context while in deep sleep suspend states
 947	 */
 948	for (i = 0; i < priv->num_mda_filters; i++) {
 949		rx_filter_core_wl(priv, 0x0, ASP_RX_FILTER_MDA_CFG(i));
 950		priv->mda_filters[i].en = 0;
 951	}
 952
 953	for (i = 0; i < priv->num_net_filters; i++)
 954		rx_filter_core_wl(priv, 0x0, ASP_RX_FILTER_NET_CFG(i));
 955
 956	/* Top level filter enable bit should be enabled at all times, set
 957	 * GEN_WAKE_CLEAR to clear the network filter wake-up which would
 958	 * otherwise be sticky
 959	 */
 960	rx_filter_core_wl(priv, (ASP_RX_FILTER_OPUT_EN |
 961			  ASP_RX_FILTER_MDA_EN |
 962			  ASP_RX_FILTER_GEN_WK_CLR |
 963			  ASP_RX_FILTER_NT_FLT_EN),
 964			  ASP_RX_FILTER_BLK_CTRL);
 965}
 966
 967/* ASP core initialization */
 968static void bcmasp_core_init(struct bcmasp_priv *priv)
 969{
 970	rx_edpkt_core_wl(priv, 0x1b, ASP_EDPKT_BURST_BUF_PSCAL_TOUT);
 971	rx_edpkt_core_wl(priv, 0x3e8, ASP_EDPKT_BURST_BUF_WRITE_TOUT);
 972
 973	rx_edpkt_core_wl(priv, ASP_EDPKT_ENABLE_EN, ASP_EDPKT_ENABLE);
 974
 975	/* Disable and clear both UniMAC's wake-up interrupts to avoid
 976	 * sticky interrupts.
 977	 */
 978	_intr2_mask_set(priv, ASP_INTR2_UMC0_WAKE | ASP_INTR2_UMC1_WAKE);
 979	intr2_core_wl(priv, ASP_INTR2_UMC0_WAKE | ASP_INTR2_UMC1_WAKE,
 980		      ASP_INTR2_CLEAR);
 981}
 982
 983static void bcmasp_core_clock_select_many(struct bcmasp_priv *priv, bool slow)
 984{
 985	u32 reg;
 986
 987	reg = ctrl2_core_rl(priv, ASP_CTRL2_CORE_CLOCK_SELECT);
 988	if (slow)
 989		reg &= ~ASP_CTRL2_CORE_CLOCK_SELECT_MAIN;
 990	else
 991		reg |= ASP_CTRL2_CORE_CLOCK_SELECT_MAIN;
 992	ctrl2_core_wl(priv, reg, ASP_CTRL2_CORE_CLOCK_SELECT);
 993
 994	reg = ctrl2_core_rl(priv, ASP_CTRL2_CPU_CLOCK_SELECT);
 995	if (slow)
 996		reg &= ~ASP_CTRL2_CPU_CLOCK_SELECT_MAIN;
 997	else
 998		reg |= ASP_CTRL2_CPU_CLOCK_SELECT_MAIN;
 999	ctrl2_core_wl(priv, reg, ASP_CTRL2_CPU_CLOCK_SELECT);
1000}
1001
1002static void bcmasp_core_clock_select_one(struct bcmasp_priv *priv, bool slow)
1003{
1004	u32 reg;
1005
1006	reg = ctrl_core_rl(priv, ASP_CTRL_CORE_CLOCK_SELECT);
1007	if (slow)
1008		reg &= ~ASP_CTRL_CORE_CLOCK_SELECT_MAIN;
1009	else
1010		reg |= ASP_CTRL_CORE_CLOCK_SELECT_MAIN;
1011	ctrl_core_wl(priv, reg, ASP_CTRL_CORE_CLOCK_SELECT);
1012}
1013
1014static void bcmasp_core_clock_select_one_ctrl2(struct bcmasp_priv *priv, bool slow)
1015{
1016	u32 reg;
1017
1018	reg = ctrl2_core_rl(priv, ASP_CTRL2_CORE_CLOCK_SELECT);
1019	if (slow)
1020		reg &= ~ASP_CTRL2_CORE_CLOCK_SELECT_MAIN;
1021	else
1022		reg |= ASP_CTRL2_CORE_CLOCK_SELECT_MAIN;
1023	ctrl2_core_wl(priv, reg, ASP_CTRL2_CORE_CLOCK_SELECT);
1024}
1025
1026static void bcmasp_core_clock_set_ll(struct bcmasp_priv *priv, u32 clr, u32 set)
1027{
1028	u32 reg;
1029
1030	reg = ctrl_core_rl(priv, ASP_CTRL_CLOCK_CTRL);
1031	reg &= ~clr;
1032	reg |= set;
1033	ctrl_core_wl(priv, reg, ASP_CTRL_CLOCK_CTRL);
1034
1035	reg = ctrl_core_rl(priv, ASP_CTRL_SCRATCH_0);
1036	reg &= ~clr;
1037	reg |= set;
1038	ctrl_core_wl(priv, reg, ASP_CTRL_SCRATCH_0);
1039}
1040
1041static void bcmasp_core_clock_set(struct bcmasp_priv *priv, u32 clr, u32 set)
1042{
1043	unsigned long flags;
1044
1045	spin_lock_irqsave(&priv->clk_lock, flags);
1046	bcmasp_core_clock_set_ll(priv, clr, set);
1047	spin_unlock_irqrestore(&priv->clk_lock, flags);
1048}
1049
1050void bcmasp_core_clock_set_intf(struct bcmasp_intf *intf, bool en)
1051{
1052	u32 intf_mask = ASP_CTRL_CLOCK_CTRL_ASP_RGMII_DIS(intf->port);
1053	struct bcmasp_priv *priv = intf->parent;
1054	unsigned long flags;
1055	u32 reg;
1056
1057	/* When enabling an interface, if the RX or TX clocks were not enabled,
1058	 * enable them. Conversely, while disabling an interface, if this is
1059	 * the last one enabled, we can turn off the shared RX and TX clocks as
1060	 * well. We control enable bits which is why we test for equality on
1061	 * the RGMII clock bit mask.
1062	 */
1063	spin_lock_irqsave(&priv->clk_lock, flags);
1064	if (en) {
1065		intf_mask |= ASP_CTRL_CLOCK_CTRL_ASP_TX_DISABLE |
1066			     ASP_CTRL_CLOCK_CTRL_ASP_RX_DISABLE;
1067		bcmasp_core_clock_set_ll(priv, intf_mask, 0);
1068	} else {
1069		reg = ctrl_core_rl(priv, ASP_CTRL_SCRATCH_0) | intf_mask;
1070		if ((reg & ASP_CTRL_CLOCK_CTRL_ASP_RGMII_MASK) ==
1071		    ASP_CTRL_CLOCK_CTRL_ASP_RGMII_MASK)
1072			intf_mask |= ASP_CTRL_CLOCK_CTRL_ASP_TX_DISABLE |
1073				     ASP_CTRL_CLOCK_CTRL_ASP_RX_DISABLE;
1074		bcmasp_core_clock_set_ll(priv, 0, intf_mask);
1075	}
1076	spin_unlock_irqrestore(&priv->clk_lock, flags);
1077}
1078
1079static irqreturn_t bcmasp_isr_wol(int irq, void *data)
1080{
1081	struct bcmasp_priv *priv = data;
1082	u32 status;
1083
1084	/* No L3 IRQ, so we good */
1085	if (priv->wol_irq <= 0)
1086		goto irq_handled;
1087
1088	status = wakeup_intr2_core_rl(priv, ASP_WAKEUP_INTR2_STATUS) &
1089		~wakeup_intr2_core_rl(priv, ASP_WAKEUP_INTR2_MASK_STATUS);
1090	wakeup_intr2_core_wl(priv, status, ASP_WAKEUP_INTR2_CLEAR);
1091
1092irq_handled:
1093	pm_wakeup_event(&priv->pdev->dev, 0);
1094	return IRQ_HANDLED;
1095}
1096
1097static int bcmasp_get_and_request_irq(struct bcmasp_priv *priv, int i)
1098{
1099	struct platform_device *pdev = priv->pdev;
1100	int irq, ret;
1101
1102	irq = platform_get_irq_optional(pdev, i);
1103	if (irq < 0)
1104		return irq;
1105
1106	ret = devm_request_irq(&pdev->dev, irq, bcmasp_isr_wol, 0,
1107			       pdev->name, priv);
1108	if (ret)
1109		return ret;
1110
1111	return irq;
1112}
1113
1114static void bcmasp_init_wol(struct bcmasp_priv *priv)
1115{
1116	struct platform_device *pdev = priv->pdev;
1117	struct device *dev = &pdev->dev;
1118	int irq;
1119
1120	irq = bcmasp_get_and_request_irq(priv, 1);
1121	if (irq < 0) {
1122		dev_warn(dev, "Failed to init WoL irq: %d\n", irq);
1123		return;
1124	}
1125
1126	priv->wol_irq = irq;
1127	priv->wol_irq_enabled_mask = 0;
1128	device_set_wakeup_capable(&pdev->dev, 1);
1129}
1130
1131void bcmasp_enable_wol(struct bcmasp_intf *intf, bool en)
1132{
1133	struct bcmasp_priv *priv = intf->parent;
1134	struct device *dev = &priv->pdev->dev;
1135
1136	if (en) {
1137		if (priv->wol_irq_enabled_mask) {
1138			set_bit(intf->port, &priv->wol_irq_enabled_mask);
1139			return;
1140		}
1141
1142		/* First enable */
1143		set_bit(intf->port, &priv->wol_irq_enabled_mask);
1144		enable_irq_wake(priv->wol_irq);
1145		device_set_wakeup_enable(dev, 1);
1146	} else {
1147		if (!priv->wol_irq_enabled_mask)
1148			return;
1149
1150		clear_bit(intf->port, &priv->wol_irq_enabled_mask);
1151		if (priv->wol_irq_enabled_mask)
1152			return;
1153
1154		/* Last disable */
1155		disable_irq_wake(priv->wol_irq);
1156		device_set_wakeup_enable(dev, 0);
1157	}
1158}
1159
1160static void bcmasp_eee_fixup(struct bcmasp_intf *intf, bool en)
1161{
1162	u32 reg, phy_lpi_overwrite;
1163
1164	reg = rx_edpkt_core_rl(intf->parent, ASP_EDPKT_SPARE_REG);
1165	phy_lpi_overwrite = intf->internal_phy ? ASP_EDPKT_SPARE_REG_EPHY_LPI :
1166			    ASP_EDPKT_SPARE_REG_GPHY_LPI;
1167
1168	if (en)
1169		reg |= phy_lpi_overwrite;
1170	else
1171		reg &= ~phy_lpi_overwrite;
1172
1173	rx_edpkt_core_wl(intf->parent, reg, ASP_EDPKT_SPARE_REG);
1174
1175	usleep_range(50, 100);
1176}
1177
1178static const struct bcmasp_plat_data v21_plat_data = {
1179	.core_clock_select = bcmasp_core_clock_select_one,
1180	.num_mda_filters = 32,
1181	.num_net_filters = 32,
1182	.tx_chan_offset = 8,
1183	.rx_ctrl_offset = 0x0,
1184};
1185
1186static const struct bcmasp_plat_data v22_plat_data = {
1187	.core_clock_select = bcmasp_core_clock_select_many,
1188	.eee_fixup = bcmasp_eee_fixup,
1189	.num_mda_filters = 32,
1190	.num_net_filters = 32,
1191	.tx_chan_offset = 8,
1192	.rx_ctrl_offset = 0x0,
1193};
1194
1195static const struct bcmasp_plat_data v30_plat_data = {
1196	.core_clock_select = bcmasp_core_clock_select_one_ctrl2,
1197	.num_mda_filters = 20,
1198	.num_net_filters = 16,
1199	.tx_chan_offset = 0,
1200	.rx_ctrl_offset = 0x10000,
1201};
1202
1203static void bcmasp_set_pdata(struct bcmasp_priv *priv, const struct bcmasp_plat_data *pdata)
1204{
1205	priv->core_clock_select = pdata->core_clock_select;
1206	priv->eee_fixup = pdata->eee_fixup;
1207	priv->num_mda_filters = pdata->num_mda_filters;
1208	priv->num_net_filters = pdata->num_net_filters;
1209	priv->tx_chan_offset = pdata->tx_chan_offset;
1210	priv->rx_ctrl_offset = pdata->rx_ctrl_offset;
1211}
1212
1213static const struct of_device_id bcmasp_of_match[] = {
1214	{ .compatible = "brcm,asp-v2.1", .data = &v21_plat_data },
1215	{ .compatible = "brcm,asp-v2.2", .data = &v22_plat_data },
1216	{ .compatible = "brcm,asp-v3.0", .data = &v30_plat_data },
1217	{ /* sentinel */ },
1218};
1219MODULE_DEVICE_TABLE(of, bcmasp_of_match);
1220
1221static const struct of_device_id bcmasp_mdio_of_match[] = {
1222	{ .compatible = "brcm,asp-v2.1-mdio", },
1223	{ .compatible = "brcm,asp-v2.2-mdio", },
1224	{ .compatible = "brcm,asp-v3.0-mdio", },
1225	{ /* sentinel */ },
1226};
1227MODULE_DEVICE_TABLE(of, bcmasp_mdio_of_match);
1228
1229static void bcmasp_remove_intfs(struct bcmasp_priv *priv)
1230{
1231	struct bcmasp_intf *intf, *n;
1232
1233	list_for_each_entry_safe(intf, n, &priv->intfs, list) {
1234		list_del(&intf->list);
1235		bcmasp_interface_destroy(intf);
1236	}
1237}
1238
1239static int bcmasp_probe(struct platform_device *pdev)
1240{
1241	const struct bcmasp_plat_data *pdata;
1242	struct device *dev = &pdev->dev;
1243	struct device_node *ports_node;
1244	struct bcmasp_priv *priv;
1245	struct bcmasp_intf *intf;
1246	int ret = 0, count = 0;
1247	unsigned int i;
1248
1249	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
1250	if (!priv)
1251		return -ENOMEM;
1252
1253	priv->irq = platform_get_irq(pdev, 0);
1254	if (priv->irq <= 0)
1255		return -EINVAL;
1256
1257	priv->clk = devm_clk_get_optional(dev, "sw_asp");
1258	if (IS_ERR(priv->clk))
1259		return dev_err_probe(dev, PTR_ERR(priv->clk),
1260				     "failed to request clock\n");
1261
1262	/* Base from parent node */
1263	priv->base = devm_platform_ioremap_resource(pdev, 0);
1264	if (IS_ERR(priv->base))
1265		return dev_err_probe(dev, PTR_ERR(priv->base), "failed to iomap\n");
1266
1267	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40));
1268	if (ret)
1269		return dev_err_probe(dev, ret, "unable to set DMA mask: %d\n", ret);
1270
1271	dev_set_drvdata(&pdev->dev, priv);
1272	priv->pdev = pdev;
1273	spin_lock_init(&priv->mda_lock);
1274	spin_lock_init(&priv->clk_lock);
1275	mutex_init(&priv->wol_lock);
1276	mutex_init(&priv->net_lock);
1277	INIT_LIST_HEAD(&priv->intfs);
1278
1279	pdata = device_get_match_data(&pdev->dev);
1280	if (!pdata)
1281		return dev_err_probe(dev, -EINVAL, "unable to find platform data\n");
1282
1283	bcmasp_set_pdata(priv, pdata);
1284
1285	ret = clk_prepare_enable(priv->clk);
1286	if (ret)
1287		return dev_err_probe(dev, ret, "failed to start clock\n");
1288
1289	/* Enable all clocks to ensure successful probing */
1290	bcmasp_core_clock_set(priv, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE, 0);
1291
1292	/* Switch to the main clock */
1293	priv->core_clock_select(priv, false);
1294
1295	bcmasp_intr2_mask_set_all(priv);
1296	bcmasp_intr2_clear_all(priv);
1297
1298	ret = devm_request_irq(&pdev->dev, priv->irq, bcmasp_isr, 0,
1299			       pdev->name, priv);
1300	if (ret) {
1301		dev_err(dev, "Failed to request ASP interrupt: %d", ret);
1302		goto err_clock_disable;
1303	}
1304
1305	/* Register mdio child nodes */
1306	of_platform_populate(dev->of_node, bcmasp_mdio_of_match, NULL, dev);
1307
1308	/* ASP specific initialization, Needs to be done regardless of
1309	 * how many interfaces come up.
1310	 */
1311	bcmasp_core_init(priv);
1312
1313	priv->mda_filters = devm_kcalloc(dev, priv->num_mda_filters,
1314					 sizeof(*priv->mda_filters), GFP_KERNEL);
1315	if (!priv->mda_filters) {
1316		ret = -ENOMEM;
1317		goto err_clock_disable;
1318	}
1319
1320	priv->net_filters = devm_kcalloc(dev, priv->num_net_filters,
1321					 sizeof(*priv->net_filters), GFP_KERNEL);
1322	if (!priv->net_filters) {
1323		ret = -ENOMEM;
1324		goto err_clock_disable;
1325	}
1326
1327	bcmasp_core_init_filters(priv);
1328
1329	bcmasp_init_wol(priv);
1330
1331	ports_node = of_find_node_by_name(dev->of_node, "ethernet-ports");
1332	if (!ports_node) {
1333		dev_warn(dev, "No ports found\n");
1334		ret = -EINVAL;
1335		goto err_clock_disable;
1336	}
1337
1338	i = 0;
1339	for_each_available_child_of_node_scoped(ports_node, intf_node) {
1340		intf = bcmasp_interface_create(priv, intf_node, i);
1341		if (!intf) {
1342			dev_err(dev, "Cannot create eth interface %d\n", i);
1343			of_node_put(ports_node);
1344			ret = -EINVAL;
1345			goto err_cleanup;
1346		}
1347		list_add_tail(&intf->list, &priv->intfs);
1348		i++;
1349	}
1350	of_node_put(ports_node);
1351
1352	/* Drop the clock reference count now and let ndo_open()/ndo_close()
1353	 * manage it for us from now on.
1354	 */
1355	bcmasp_core_clock_set(priv, 0, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE);
1356
1357	/* Now do the registration of the network ports which will take care
1358	 * of managing the clock properly.
1359	 */
1360	list_for_each_entry(intf, &priv->intfs, list) {
1361		ret = register_netdev(intf->ndev);
1362		if (ret) {
1363			dev_err(dev, "failed to register net_device: %d\n", ret);
1364			goto err_cleanup;
1365		}
1366		count++;
1367	}
1368
1369	clk_disable_unprepare(priv->clk);
1370
1371	dev_info(dev, "Initialized %d port(s)\n", count);
1372
1373	return ret;
1374
1375err_cleanup:
1376	bcmasp_remove_intfs(priv);
1377err_clock_disable:
1378	clk_disable_unprepare(priv->clk);
1379
1380	return ret;
1381}
1382
1383static void bcmasp_remove(struct platform_device *pdev)
1384{
1385	struct bcmasp_priv *priv = dev_get_drvdata(&pdev->dev);
1386
1387	if (!priv)
1388		return;
1389
1390	bcmasp_remove_intfs(priv);
1391}
1392
1393static void bcmasp_shutdown(struct platform_device *pdev)
1394{
1395	bcmasp_remove(pdev);
1396}
1397
1398static int __maybe_unused bcmasp_suspend(struct device *d)
1399{
1400	struct bcmasp_priv *priv = dev_get_drvdata(d);
1401	struct bcmasp_intf *intf;
1402	int ret;
1403
1404	list_for_each_entry(intf, &priv->intfs, list) {
1405		ret = bcmasp_interface_suspend(intf);
1406		if (ret)
1407			break;
1408	}
1409
1410	ret = clk_prepare_enable(priv->clk);
1411	if (ret)
1412		return ret;
1413
1414	/* Whether Wake-on-LAN is enabled or not, we can always disable
1415	 * the shared TX clock
1416	 */
1417	bcmasp_core_clock_set(priv, 0, ASP_CTRL_CLOCK_CTRL_ASP_TX_DISABLE);
1418
1419	priv->core_clock_select(priv, true);
1420
1421	clk_disable_unprepare(priv->clk);
1422
1423	return ret;
1424}
1425
1426static int __maybe_unused bcmasp_resume(struct device *d)
1427{
1428	struct bcmasp_priv *priv = dev_get_drvdata(d);
1429	struct bcmasp_intf *intf;
1430	int ret;
1431
1432	ret = clk_prepare_enable(priv->clk);
1433	if (ret)
1434		return ret;
1435
1436	/* Switch to the main clock domain */
1437	priv->core_clock_select(priv, false);
1438
1439	/* Re-enable all clocks for re-initialization */
1440	bcmasp_core_clock_set(priv, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE, 0);
1441
1442	bcmasp_core_init(priv);
1443	bcmasp_core_init_filters(priv);
1444
1445	/* And disable them to let the network devices take care of them */
1446	bcmasp_core_clock_set(priv, 0, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE);
1447
1448	clk_disable_unprepare(priv->clk);
1449
1450	list_for_each_entry(intf, &priv->intfs, list) {
1451		ret = bcmasp_interface_resume(intf);
1452		if (ret)
1453			break;
1454	}
1455
1456	return ret;
1457}
1458
1459static SIMPLE_DEV_PM_OPS(bcmasp_pm_ops,
1460			 bcmasp_suspend, bcmasp_resume);
1461
1462static struct platform_driver bcmasp_driver = {
1463	.probe = bcmasp_probe,
1464	.remove = bcmasp_remove,
1465	.shutdown = bcmasp_shutdown,
1466	.driver = {
1467		.name = "brcm,asp-v2",
1468		.of_match_table = bcmasp_of_match,
1469		.pm = &bcmasp_pm_ops,
1470	},
1471};
1472module_platform_driver(bcmasp_driver);
1473
1474MODULE_DESCRIPTION("Broadcom ASP 2.0 Ethernet controller driver");
1475MODULE_ALIAS("platform:brcm,asp-v2");
1476MODULE_LICENSE("GPL");
~/ Read-only file preview.