@@ -521,7 +521,7 @@ static void bcm_sysport_get_wol(struct net_device *dev,
521
521
struct bcm_sysport_priv * priv = netdev_priv (dev );
522
522
u32 reg ;
523
523
524
- wol -> supported = WAKE_MAGIC | WAKE_MAGICSECURE ;
524
+ wol -> supported = WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER ;
525
525
wol -> wolopts = priv -> wolopts ;
526
526
527
527
if (!(priv -> wolopts & WAKE_MAGICSECURE ))
@@ -539,7 +539,7 @@ static int bcm_sysport_set_wol(struct net_device *dev,
539
539
{
540
540
struct bcm_sysport_priv * priv = netdev_priv (dev );
541
541
struct device * kdev = & priv -> pdev -> dev ;
542
- u32 supported = WAKE_MAGIC | WAKE_MAGICSECURE ;
542
+ u32 supported = WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER ;
543
543
544
544
if (!device_can_wakeup (kdev ))
545
545
return - ENOTSUPP ;
@@ -1043,20 +1043,40 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget)
1043
1043
1044
1044
static void mpd_enable_set (struct bcm_sysport_priv * priv , bool enable )
1045
1045
{
1046
- u32 reg ;
1046
+ u32 reg , bit ;
1047
1047
1048
1048
reg = umac_readl (priv , UMAC_MPD_CTRL );
1049
1049
if (enable )
1050
1050
reg |= MPD_EN ;
1051
1051
else
1052
1052
reg &= ~MPD_EN ;
1053
1053
umac_writel (priv , reg , UMAC_MPD_CTRL );
1054
+
1055
+ if (priv -> is_lite )
1056
+ bit = RBUF_ACPI_EN_LITE ;
1057
+ else
1058
+ bit = RBUF_ACPI_EN ;
1059
+
1060
+ reg = rbuf_readl (priv , RBUF_CONTROL );
1061
+ if (enable )
1062
+ reg |= bit ;
1063
+ else
1064
+ reg &= ~bit ;
1065
+ rbuf_writel (priv , reg , RBUF_CONTROL );
1054
1066
}
1055
1067
1056
1068
static void bcm_sysport_resume_from_wol (struct bcm_sysport_priv * priv )
1057
1069
{
1070
+ u32 reg ;
1071
+
1058
1072
/* Stop monitoring MPD interrupt */
1059
- intrl2_0_mask_set (priv , INTRL2_0_MPD );
1073
+ intrl2_0_mask_set (priv , INTRL2_0_MPD | INTRL2_0_BRCM_MATCH_TAG );
1074
+
1075
+ /* Disable RXCHK, active filters and Broadcom tag matching */
1076
+ reg = rxchk_readl (priv , RXCHK_CONTROL );
1077
+ reg &= ~(RXCHK_BRCM_TAG_MATCH_MASK <<
1078
+ RXCHK_BRCM_TAG_MATCH_SHIFT | RXCHK_EN | RXCHK_BRCM_TAG_EN );
1079
+ rxchk_writel (priv , reg , RXCHK_CONTROL );
1060
1080
1061
1081
/* Clear the MagicPacket detection logic */
1062
1082
mpd_enable_set (priv , false);
@@ -1085,6 +1105,7 @@ static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
1085
1105
struct bcm_sysport_priv * priv = netdev_priv (dev );
1086
1106
struct bcm_sysport_tx_ring * txr ;
1087
1107
unsigned int ring , ring_bit ;
1108
+ u32 reg ;
1088
1109
1089
1110
priv -> irq0_stat = intrl2_0_readl (priv , INTRL2_CPU_STATUS ) &
1090
1111
~intrl2_0_readl (priv , INTRL2_CPU_MASK_STATUS );
@@ -1111,7 +1132,14 @@ static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
1111
1132
bcm_sysport_tx_reclaim_all (priv );
1112
1133
1113
1134
if (priv -> irq0_stat & INTRL2_0_MPD )
1114
- netdev_info (priv -> netdev , "Wake-on-LAN interrupt!\n" );
1135
+ netdev_info (priv -> netdev , "Wake-on-LAN (MPD) interrupt!\n" );
1136
+
1137
+ if (priv -> irq0_stat & INTRL2_0_BRCM_MATCH_TAG ) {
1138
+ reg = rxchk_readl (priv , RXCHK_BRCM_TAG_MATCH_STATUS ) &
1139
+ RXCHK_BRCM_TAG_MATCH_MASK ;
1140
+ netdev_info (priv -> netdev ,
1141
+ "Wake-on-LAN (filters 0x%02x) interrupt!\n" , reg );
1142
+ }
1115
1143
1116
1144
if (!priv -> is_lite )
1117
1145
goto out ;
@@ -2096,6 +2124,132 @@ static int bcm_sysport_stop(struct net_device *dev)
2096
2124
return 0 ;
2097
2125
}
2098
2126
2127
+ static int bcm_sysport_rule_find (struct bcm_sysport_priv * priv ,
2128
+ u64 location )
2129
+ {
2130
+ unsigned int index ;
2131
+ u32 reg ;
2132
+
2133
+ for_each_set_bit (index , priv -> filters , RXCHK_BRCM_TAG_MAX ) {
2134
+ reg = rxchk_readl (priv , RXCHK_BRCM_TAG (index ));
2135
+ reg >>= RXCHK_BRCM_TAG_CID_SHIFT ;
2136
+ reg &= RXCHK_BRCM_TAG_CID_MASK ;
2137
+ if (reg == location )
2138
+ return index ;
2139
+ }
2140
+
2141
+ return - EINVAL ;
2142
+ }
2143
+
2144
+ static int bcm_sysport_rule_get (struct bcm_sysport_priv * priv ,
2145
+ struct ethtool_rxnfc * nfc )
2146
+ {
2147
+ int index ;
2148
+
2149
+ /* This is not a rule that we know about */
2150
+ index = bcm_sysport_rule_find (priv , nfc -> fs .location );
2151
+ if (index < 0 )
2152
+ return - EOPNOTSUPP ;
2153
+
2154
+ nfc -> fs .ring_cookie = RX_CLS_FLOW_WAKE ;
2155
+
2156
+ return 0 ;
2157
+ }
2158
+
2159
+ static int bcm_sysport_rule_set (struct bcm_sysport_priv * priv ,
2160
+ struct ethtool_rxnfc * nfc )
2161
+ {
2162
+ unsigned int index ;
2163
+ u32 reg ;
2164
+
2165
+ /* We cannot match locations greater than what the classification ID
2166
+ * permits (256 entries)
2167
+ */
2168
+ if (nfc -> fs .location > RXCHK_BRCM_TAG_CID_MASK )
2169
+ return - E2BIG ;
2170
+
2171
+ /* We cannot support flows that are not destined for a wake-up */
2172
+ if (nfc -> fs .ring_cookie != RX_CLS_FLOW_WAKE )
2173
+ return - EOPNOTSUPP ;
2174
+
2175
+ /* All filters are already in use, we cannot match more rules */
2176
+ if (bitmap_weight (priv -> filters , RXCHK_BRCM_TAG_MAX ) ==
2177
+ RXCHK_BRCM_TAG_MAX )
2178
+ return - ENOSPC ;
2179
+
2180
+ index = find_first_zero_bit (priv -> filters , RXCHK_BRCM_TAG_MAX );
2181
+ if (index > RXCHK_BRCM_TAG_MAX )
2182
+ return - ENOSPC ;
2183
+
2184
+ /* Location is the classification ID, and index is the position
2185
+ * within one of our 8 possible filters to be programmed
2186
+ */
2187
+ reg = rxchk_readl (priv , RXCHK_BRCM_TAG (index ));
2188
+ reg &= ~(RXCHK_BRCM_TAG_CID_MASK << RXCHK_BRCM_TAG_CID_SHIFT );
2189
+ reg |= nfc -> fs .location << RXCHK_BRCM_TAG_CID_SHIFT ;
2190
+ rxchk_writel (priv , reg , RXCHK_BRCM_TAG (index ));
2191
+ rxchk_writel (priv , 0xff00ffff , RXCHK_BRCM_TAG_MASK (index ));
2192
+
2193
+ set_bit (index , priv -> filters );
2194
+
2195
+ return 0 ;
2196
+ }
2197
+
2198
+ static int bcm_sysport_rule_del (struct bcm_sysport_priv * priv ,
2199
+ u64 location )
2200
+ {
2201
+ int index ;
2202
+
2203
+ /* This is not a rule that we know about */
2204
+ index = bcm_sysport_rule_find (priv , location );
2205
+ if (index < 0 )
2206
+ return - EOPNOTSUPP ;
2207
+
2208
+ /* No need to disable this filter if it was enabled, this will
2209
+ * be taken care of during suspend time by bcm_sysport_suspend_to_wol
2210
+ */
2211
+ clear_bit (index , priv -> filters );
2212
+
2213
+ return 0 ;
2214
+ }
2215
+
2216
+ static int bcm_sysport_get_rxnfc (struct net_device * dev ,
2217
+ struct ethtool_rxnfc * nfc , u32 * rule_locs )
2218
+ {
2219
+ struct bcm_sysport_priv * priv = netdev_priv (dev );
2220
+ int ret = - EOPNOTSUPP ;
2221
+
2222
+ switch (nfc -> cmd ) {
2223
+ case ETHTOOL_GRXCLSRULE :
2224
+ ret = bcm_sysport_rule_get (priv , nfc );
2225
+ break ;
2226
+ default :
2227
+ break ;
2228
+ }
2229
+
2230
+ return ret ;
2231
+ }
2232
+
2233
+ static int bcm_sysport_set_rxnfc (struct net_device * dev ,
2234
+ struct ethtool_rxnfc * nfc )
2235
+ {
2236
+ struct bcm_sysport_priv * priv = netdev_priv (dev );
2237
+ int ret = - EOPNOTSUPP ;
2238
+
2239
+ switch (nfc -> cmd ) {
2240
+ case ETHTOOL_SRXCLSRLINS :
2241
+ ret = bcm_sysport_rule_set (priv , nfc );
2242
+ break ;
2243
+ case ETHTOOL_SRXCLSRLDEL :
2244
+ ret = bcm_sysport_rule_del (priv , nfc -> fs .location );
2245
+ break ;
2246
+ default :
2247
+ break ;
2248
+ }
2249
+
2250
+ return ret ;
2251
+ }
2252
+
2099
2253
static const struct ethtool_ops bcm_sysport_ethtool_ops = {
2100
2254
.get_drvinfo = bcm_sysport_get_drvinfo ,
2101
2255
.get_msglevel = bcm_sysport_get_msglvl ,
@@ -2110,6 +2264,8 @@ static const struct ethtool_ops bcm_sysport_ethtool_ops = {
2110
2264
.set_coalesce = bcm_sysport_set_coalesce ,
2111
2265
.get_link_ksettings = phy_ethtool_get_link_ksettings ,
2112
2266
.set_link_ksettings = phy_ethtool_set_link_ksettings ,
2267
+ .get_rxnfc = bcm_sysport_get_rxnfc ,
2268
+ .set_rxnfc = bcm_sysport_set_rxnfc ,
2113
2269
};
2114
2270
2115
2271
static u16 bcm_sysport_select_queue (struct net_device * dev , struct sk_buff * skb ,
@@ -2434,16 +2590,39 @@ static int bcm_sysport_suspend_to_wol(struct bcm_sysport_priv *priv)
2434
2590
{
2435
2591
struct net_device * ndev = priv -> netdev ;
2436
2592
unsigned int timeout = 1000 ;
2593
+ unsigned int index , i = 0 ;
2437
2594
u32 reg ;
2438
2595
2439
2596
/* Password has already been programmed */
2440
2597
reg = umac_readl (priv , UMAC_MPD_CTRL );
2441
- reg |= MPD_EN ;
2598
+ if (priv -> wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE ))
2599
+ reg |= MPD_EN ;
2442
2600
reg &= ~PSW_EN ;
2443
2601
if (priv -> wolopts & WAKE_MAGICSECURE )
2444
2602
reg |= PSW_EN ;
2445
2603
umac_writel (priv , reg , UMAC_MPD_CTRL );
2446
2604
2605
+ if (priv -> wolopts & WAKE_FILTER ) {
2606
+ /* Turn on ACPI matching to steal packets from RBUF */
2607
+ reg = rbuf_readl (priv , RBUF_CONTROL );
2608
+ if (priv -> is_lite )
2609
+ reg |= RBUF_ACPI_EN_LITE ;
2610
+ else
2611
+ reg |= RBUF_ACPI_EN ;
2612
+ rbuf_writel (priv , reg , RBUF_CONTROL );
2613
+
2614
+ /* Enable RXCHK, active filters and Broadcom tag matching */
2615
+ reg = rxchk_readl (priv , RXCHK_CONTROL );
2616
+ reg &= ~(RXCHK_BRCM_TAG_MATCH_MASK <<
2617
+ RXCHK_BRCM_TAG_MATCH_SHIFT );
2618
+ for_each_set_bit (index , priv -> filters , RXCHK_BRCM_TAG_MAX ) {
2619
+ reg |= BIT (RXCHK_BRCM_TAG_MATCH_SHIFT + i );
2620
+ i ++ ;
2621
+ }
2622
+ reg |= RXCHK_EN | RXCHK_BRCM_TAG_EN ;
2623
+ rxchk_writel (priv , reg , RXCHK_CONTROL );
2624
+ }
2625
+
2447
2626
/* Make sure RBUF entered WoL mode as result */
2448
2627
do {
2449
2628
reg = rbuf_readl (priv , RBUF_STATUS );
@@ -2464,7 +2643,7 @@ static int bcm_sysport_suspend_to_wol(struct bcm_sysport_priv *priv)
2464
2643
umac_enable_set (priv , CMD_RX_EN , 1 );
2465
2644
2466
2645
/* Enable the interrupt wake-up source */
2467
- intrl2_0_mask_clear (priv , INTRL2_0_MPD );
2646
+ intrl2_0_mask_clear (priv , INTRL2_0_MPD | INTRL2_0_BRCM_MATCH_TAG );
2468
2647
2469
2648
netif_dbg (priv , wol , ndev , "entered WOL mode\n" );
2470
2649
0 commit comments