.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Broadcom BCM7xxx System Port Ethernet MAC driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2014 Broadcom Corporation |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License version 2 as |
---|
8 | | - * published by the Free Software Foundation. |
---|
9 | 6 | */ |
---|
10 | 7 | |
---|
11 | 8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
---|
.. | .. |
---|
23 | 20 | #include <linux/phy.h> |
---|
24 | 21 | #include <linux/phy_fixed.h> |
---|
25 | 22 | #include <net/dsa.h> |
---|
| 23 | +#include <linux/clk.h> |
---|
26 | 24 | #include <net/ip.h> |
---|
27 | 25 | #include <net/ipv6.h> |
---|
28 | 26 | |
---|
.. | .. |
---|
116 | 114 | writel_relaxed(lower_32_bits(addr), d + DESC_ADDR_LO); |
---|
117 | 115 | } |
---|
118 | 116 | |
---|
119 | | -static inline void tdma_port_write_desc_addr(struct bcm_sysport_priv *priv, |
---|
120 | | - struct dma_desc *desc, |
---|
121 | | - unsigned int port) |
---|
122 | | -{ |
---|
123 | | - unsigned long desc_flags; |
---|
124 | | - |
---|
125 | | - /* Ports are latched, so write upper address first */ |
---|
126 | | - spin_lock_irqsave(&priv->desc_lock, desc_flags); |
---|
127 | | - tdma_writel(priv, desc->addr_status_len, TDMA_WRITE_PORT_HI(port)); |
---|
128 | | - tdma_writel(priv, desc->addr_lo, TDMA_WRITE_PORT_LO(port)); |
---|
129 | | - spin_unlock_irqrestore(&priv->desc_lock, desc_flags); |
---|
130 | | -} |
---|
131 | | - |
---|
132 | 117 | /* Ethtool operations */ |
---|
133 | | -static int bcm_sysport_set_rx_csum(struct net_device *dev, |
---|
134 | | - netdev_features_t wanted) |
---|
| 118 | +static void bcm_sysport_set_rx_csum(struct net_device *dev, |
---|
| 119 | + netdev_features_t wanted) |
---|
135 | 120 | { |
---|
136 | 121 | struct bcm_sysport_priv *priv = netdev_priv(dev); |
---|
137 | 122 | u32 reg; |
---|
.. | .. |
---|
165 | 150 | reg &= ~RXCHK_BRCM_TAG_EN; |
---|
166 | 151 | |
---|
167 | 152 | rxchk_writel(priv, reg, RXCHK_CONTROL); |
---|
168 | | - |
---|
169 | | - return 0; |
---|
170 | 153 | } |
---|
171 | 154 | |
---|
172 | | -static int bcm_sysport_set_tx_csum(struct net_device *dev, |
---|
173 | | - netdev_features_t wanted) |
---|
| 155 | +static void bcm_sysport_set_tx_csum(struct net_device *dev, |
---|
| 156 | + netdev_features_t wanted) |
---|
174 | 157 | { |
---|
175 | 158 | struct bcm_sysport_priv *priv = netdev_priv(dev); |
---|
176 | 159 | u32 reg; |
---|
.. | .. |
---|
178 | 161 | /* Hardware transmit checksum requires us to enable the Transmit status |
---|
179 | 162 | * block prepended to the packet contents |
---|
180 | 163 | */ |
---|
181 | | - priv->tsb_en = !!(wanted & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)); |
---|
| 164 | + priv->tsb_en = !!(wanted & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | |
---|
| 165 | + NETIF_F_HW_VLAN_CTAG_TX)); |
---|
182 | 166 | reg = tdma_readl(priv, TDMA_CONTROL); |
---|
183 | 167 | if (priv->tsb_en) |
---|
184 | 168 | reg |= tdma_control_bit(priv, TSB_EN); |
---|
185 | 169 | else |
---|
186 | 170 | reg &= ~tdma_control_bit(priv, TSB_EN); |
---|
| 171 | + /* Indicating that software inserts Broadcom tags is needed for the TX |
---|
| 172 | + * checksum to be computed correctly when using VLAN HW acceleration, |
---|
| 173 | + * else it has no effect, so it can always be turned on. |
---|
| 174 | + */ |
---|
| 175 | + if (netdev_uses_dsa(dev)) |
---|
| 176 | + reg |= tdma_control_bit(priv, SW_BRCM_TAG); |
---|
| 177 | + else |
---|
| 178 | + reg &= ~tdma_control_bit(priv, SW_BRCM_TAG); |
---|
187 | 179 | tdma_writel(priv, reg, TDMA_CONTROL); |
---|
188 | 180 | |
---|
189 | | - return 0; |
---|
| 181 | + /* Default TPID is ETH_P_8021AD, change to ETH_P_8021Q */ |
---|
| 182 | + if (wanted & NETIF_F_HW_VLAN_CTAG_TX) |
---|
| 183 | + tdma_writel(priv, ETH_P_8021Q, TDMA_TPID); |
---|
190 | 184 | } |
---|
191 | 185 | |
---|
192 | 186 | static int bcm_sysport_set_features(struct net_device *dev, |
---|
193 | 187 | netdev_features_t features) |
---|
194 | 188 | { |
---|
195 | | - netdev_features_t changed = features ^ dev->features; |
---|
196 | | - netdev_features_t wanted = dev->wanted_features; |
---|
197 | | - int ret = 0; |
---|
| 189 | + struct bcm_sysport_priv *priv = netdev_priv(dev); |
---|
| 190 | + int ret; |
---|
198 | 191 | |
---|
199 | | - if (changed & NETIF_F_RXCSUM) |
---|
200 | | - ret = bcm_sysport_set_rx_csum(dev, wanted); |
---|
201 | | - if (changed & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) |
---|
202 | | - ret = bcm_sysport_set_tx_csum(dev, wanted); |
---|
| 192 | + ret = clk_prepare_enable(priv->clk); |
---|
| 193 | + if (ret) |
---|
| 194 | + return ret; |
---|
203 | 195 | |
---|
204 | | - return ret; |
---|
| 196 | + /* Read CRC forward */ |
---|
| 197 | + if (!priv->is_lite) |
---|
| 198 | + priv->crc_fwd = !!(umac_readl(priv, UMAC_CMD) & CMD_CRC_FWD); |
---|
| 199 | + else |
---|
| 200 | + priv->crc_fwd = !((gib_readl(priv, GIB_CONTROL) & |
---|
| 201 | + GIB_FCS_STRIP) >> GIB_FCS_STRIP_SHIFT); |
---|
| 202 | + |
---|
| 203 | + bcm_sysport_set_rx_csum(dev, features); |
---|
| 204 | + bcm_sysport_set_tx_csum(dev, features); |
---|
| 205 | + |
---|
| 206 | + clk_disable_unprepare(priv->clk); |
---|
| 207 | + |
---|
| 208 | + return 0; |
---|
205 | 209 | } |
---|
206 | 210 | |
---|
207 | 211 | /* Hardware counters must be kept in sync because the order/offset |
---|
.. | .. |
---|
293 | 297 | STAT_MIB_SOFT("alloc_rx_buff_failed", mib.alloc_rx_buff_failed), |
---|
294 | 298 | STAT_MIB_SOFT("rx_dma_failed", mib.rx_dma_failed), |
---|
295 | 299 | STAT_MIB_SOFT("tx_dma_failed", mib.tx_dma_failed), |
---|
| 300 | + STAT_MIB_SOFT("tx_realloc_tsb", mib.tx_realloc_tsb), |
---|
| 301 | + STAT_MIB_SOFT("tx_realloc_tsb_failed", mib.tx_realloc_tsb_failed), |
---|
296 | 302 | /* Per TX-queue statistics are dynamically appended */ |
---|
297 | 303 | }; |
---|
298 | 304 | |
---|
.. | .. |
---|
302 | 308 | struct ethtool_drvinfo *info) |
---|
303 | 309 | { |
---|
304 | 310 | strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); |
---|
305 | | - strlcpy(info->version, "0.1", sizeof(info->version)); |
---|
306 | 311 | strlcpy(info->bus_info, "platform", sizeof(info->bus_info)); |
---|
307 | 312 | } |
---|
308 | 313 | |
---|
.. | .. |
---|
624 | 629 | struct ethtool_coalesce *ec) |
---|
625 | 630 | { |
---|
626 | 631 | struct bcm_sysport_priv *priv = netdev_priv(dev); |
---|
627 | | - struct net_dim_cq_moder moder; |
---|
| 632 | + struct dim_cq_moder moder; |
---|
628 | 633 | u32 usecs, pkts; |
---|
629 | 634 | unsigned int i; |
---|
630 | 635 | |
---|
.. | .. |
---|
639 | 644 | return -EINVAL; |
---|
640 | 645 | |
---|
641 | 646 | if ((ec->tx_coalesce_usecs == 0 && ec->tx_max_coalesced_frames == 0) || |
---|
642 | | - (ec->rx_coalesce_usecs == 0 && ec->rx_max_coalesced_frames == 0) || |
---|
643 | | - ec->use_adaptive_tx_coalesce) |
---|
| 647 | + (ec->rx_coalesce_usecs == 0 && ec->rx_max_coalesced_frames == 0)) |
---|
644 | 648 | return -EINVAL; |
---|
645 | 649 | |
---|
646 | 650 | for (i = 0; i < dev->num_tx_queues; i++) |
---|
.. | .. |
---|
724 | 728 | for (i = 0; i < priv->num_rx_bds; i++) { |
---|
725 | 729 | cb = &priv->rx_cbs[i]; |
---|
726 | 730 | skb = bcm_sysport_rx_refill(priv, cb); |
---|
727 | | - if (skb) |
---|
728 | | - dev_kfree_skb(skb); |
---|
| 731 | + dev_kfree_skb(skb); |
---|
729 | 732 | if (!cb->skb) |
---|
730 | 733 | return -ENOMEM; |
---|
731 | 734 | } |
---|
.. | .. |
---|
1008 | 1011 | { |
---|
1009 | 1012 | struct bcm_sysport_priv *priv = |
---|
1010 | 1013 | container_of(napi, struct bcm_sysport_priv, napi); |
---|
1011 | | - struct net_dim_sample dim_sample; |
---|
| 1014 | + struct dim_sample dim_sample = {}; |
---|
1012 | 1015 | unsigned int work_done = 0; |
---|
1013 | 1016 | |
---|
1014 | 1017 | work_done = bcm_sysport_desc_rx(priv, budget); |
---|
.. | .. |
---|
1032 | 1035 | } |
---|
1033 | 1036 | |
---|
1034 | 1037 | if (priv->dim.use_dim) { |
---|
1035 | | - net_dim_sample(priv->dim.event_ctr, priv->dim.packets, |
---|
1036 | | - priv->dim.bytes, &dim_sample); |
---|
| 1038 | + dim_update_sample(priv->dim.event_ctr, priv->dim.packets, |
---|
| 1039 | + priv->dim.bytes, &dim_sample); |
---|
1037 | 1040 | net_dim(&priv->dim.dim, dim_sample); |
---|
1038 | 1041 | } |
---|
1039 | 1042 | |
---|
.. | .. |
---|
1066 | 1069 | |
---|
1067 | 1070 | static void bcm_sysport_resume_from_wol(struct bcm_sysport_priv *priv) |
---|
1068 | 1071 | { |
---|
| 1072 | + unsigned int index; |
---|
1069 | 1073 | u32 reg; |
---|
1070 | 1074 | |
---|
1071 | 1075 | /* Disable RXCHK, active filters and Broadcom tag matching */ |
---|
.. | .. |
---|
1073 | 1077 | reg &= ~(RXCHK_BRCM_TAG_MATCH_MASK << |
---|
1074 | 1078 | RXCHK_BRCM_TAG_MATCH_SHIFT | RXCHK_EN | RXCHK_BRCM_TAG_EN); |
---|
1075 | 1079 | rxchk_writel(priv, reg, RXCHK_CONTROL); |
---|
| 1080 | + |
---|
| 1081 | + /* Make sure we restore correct CID index in case HW lost |
---|
| 1082 | + * its context during deep idle state |
---|
| 1083 | + */ |
---|
| 1084 | + for_each_set_bit(index, priv->filters, RXCHK_BRCM_TAG_MAX) { |
---|
| 1085 | + rxchk_writel(priv, priv->filters_loc[index] << |
---|
| 1086 | + RXCHK_BRCM_TAG_CID_SHIFT, RXCHK_BRCM_TAG(index)); |
---|
| 1087 | + rxchk_writel(priv, 0xff00ffff, RXCHK_BRCM_TAG_MASK(index)); |
---|
| 1088 | + } |
---|
1076 | 1089 | |
---|
1077 | 1090 | /* Clear the MagicPacket detection logic */ |
---|
1078 | 1091 | mpd_enable_set(priv, false); |
---|
.. | .. |
---|
1093 | 1106 | |
---|
1094 | 1107 | static void bcm_sysport_dim_work(struct work_struct *work) |
---|
1095 | 1108 | { |
---|
1096 | | - struct net_dim *dim = container_of(work, struct net_dim, work); |
---|
| 1109 | + struct dim *dim = container_of(work, struct dim, work); |
---|
1097 | 1110 | struct bcm_sysport_net_dim *ndim = |
---|
1098 | 1111 | container_of(dim, struct bcm_sysport_net_dim, dim); |
---|
1099 | 1112 | struct bcm_sysport_priv *priv = |
---|
1100 | 1113 | container_of(ndim, struct bcm_sysport_priv, dim); |
---|
1101 | | - struct net_dim_cq_moder cur_profile = |
---|
1102 | | - net_dim_get_rx_moderation(dim->mode, dim->profile_ix); |
---|
| 1114 | + struct dim_cq_moder cur_profile = net_dim_get_rx_moderation(dim->mode, |
---|
| 1115 | + dim->profile_ix); |
---|
1103 | 1116 | |
---|
1104 | 1117 | bcm_sysport_set_rx_coalesce(priv, cur_profile.usec, cur_profile.pkts); |
---|
1105 | | - dim->state = NET_DIM_START_MEASURE; |
---|
| 1118 | + dim->state = DIM_START_MEASURE; |
---|
1106 | 1119 | } |
---|
1107 | 1120 | |
---|
1108 | 1121 | /* RX and misc interrupt routine */ |
---|
.. | .. |
---|
1217 | 1230 | static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb, |
---|
1218 | 1231 | struct net_device *dev) |
---|
1219 | 1232 | { |
---|
| 1233 | + struct bcm_sysport_priv *priv = netdev_priv(dev); |
---|
1220 | 1234 | struct sk_buff *nskb; |
---|
1221 | 1235 | struct bcm_tsb *tsb; |
---|
1222 | 1236 | u32 csum_info; |
---|
.. | .. |
---|
1227 | 1241 | /* Re-allocate SKB if needed */ |
---|
1228 | 1242 | if (unlikely(skb_headroom(skb) < sizeof(*tsb))) { |
---|
1229 | 1243 | nskb = skb_realloc_headroom(skb, sizeof(*tsb)); |
---|
1230 | | - dev_kfree_skb(skb); |
---|
1231 | 1244 | if (!nskb) { |
---|
| 1245 | + dev_kfree_skb_any(skb); |
---|
| 1246 | + priv->mib.tx_realloc_tsb_failed++; |
---|
1232 | 1247 | dev->stats.tx_errors++; |
---|
1233 | 1248 | dev->stats.tx_dropped++; |
---|
1234 | 1249 | return NULL; |
---|
1235 | 1250 | } |
---|
| 1251 | + dev_consume_skb_any(skb); |
---|
1236 | 1252 | skb = nskb; |
---|
| 1253 | + priv->mib.tx_realloc_tsb++; |
---|
1237 | 1254 | } |
---|
1238 | 1255 | |
---|
1239 | 1256 | tsb = skb_push(skb, sizeof(*tsb)); |
---|
1240 | 1257 | /* Zero-out TSB by default */ |
---|
1241 | 1258 | memset(tsb, 0, sizeof(*tsb)); |
---|
| 1259 | + |
---|
| 1260 | + if (skb_vlan_tag_present(skb)) { |
---|
| 1261 | + tsb->pcp_dei_vid = skb_vlan_tag_get_prio(skb) & PCP_DEI_MASK; |
---|
| 1262 | + tsb->pcp_dei_vid |= (u32)skb_vlan_tag_get_id(skb) << VID_SHIFT; |
---|
| 1263 | + } |
---|
1242 | 1264 | |
---|
1243 | 1265 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
---|
1244 | 1266 | ip_ver = skb->protocol; |
---|
.. | .. |
---|
1255 | 1277 | |
---|
1256 | 1278 | /* Get the checksum offset and the L4 (transport) offset */ |
---|
1257 | 1279 | csum_start = skb_checksum_start_offset(skb) - sizeof(*tsb); |
---|
| 1280 | + /* Account for the HW inserted VLAN tag */ |
---|
| 1281 | + if (skb_vlan_tag_present(skb)) |
---|
| 1282 | + csum_start += VLAN_HLEN; |
---|
1258 | 1283 | csum_info = (csum_start + skb->csum_offset) & L4_CSUM_PTR_MASK; |
---|
1259 | 1284 | csum_info |= (csum_start << L4_PTR_SHIFT); |
---|
1260 | 1285 | |
---|
.. | .. |
---|
1279 | 1304 | struct bcm_sysport_priv *priv = netdev_priv(dev); |
---|
1280 | 1305 | struct device *kdev = &priv->pdev->dev; |
---|
1281 | 1306 | struct bcm_sysport_tx_ring *ring; |
---|
| 1307 | + unsigned long flags, desc_flags; |
---|
1282 | 1308 | struct bcm_sysport_cb *cb; |
---|
1283 | 1309 | struct netdev_queue *txq; |
---|
1284 | | - struct dma_desc *desc; |
---|
| 1310 | + u32 len_status, addr_lo; |
---|
1285 | 1311 | unsigned int skb_len; |
---|
1286 | | - unsigned long flags; |
---|
1287 | 1312 | dma_addr_t mapping; |
---|
1288 | | - u32 len_status; |
---|
1289 | 1313 | u16 queue; |
---|
1290 | 1314 | int ret; |
---|
1291 | 1315 | |
---|
.. | .. |
---|
1328 | 1352 | dma_unmap_addr_set(cb, dma_addr, mapping); |
---|
1329 | 1353 | dma_unmap_len_set(cb, dma_len, skb_len); |
---|
1330 | 1354 | |
---|
1331 | | - /* Fetch a descriptor entry from our pool */ |
---|
1332 | | - desc = ring->desc_cpu; |
---|
1333 | | - |
---|
1334 | | - desc->addr_lo = lower_32_bits(mapping); |
---|
| 1355 | + addr_lo = lower_32_bits(mapping); |
---|
1335 | 1356 | len_status = upper_32_bits(mapping) & DESC_ADDR_HI_MASK; |
---|
1336 | 1357 | len_status |= (skb_len << DESC_LEN_SHIFT); |
---|
1337 | 1358 | len_status |= (DESC_SOP | DESC_EOP | TX_STATUS_APP_CRC) << |
---|
1338 | 1359 | DESC_STATUS_SHIFT; |
---|
1339 | 1360 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
---|
1340 | 1361 | len_status |= (DESC_L4_CSUM << DESC_STATUS_SHIFT); |
---|
| 1362 | + if (skb_vlan_tag_present(skb)) |
---|
| 1363 | + len_status |= (TX_STATUS_VLAN_VID_TSB << DESC_STATUS_SHIFT); |
---|
1341 | 1364 | |
---|
1342 | 1365 | ring->curr_desc++; |
---|
1343 | 1366 | if (ring->curr_desc == ring->size) |
---|
1344 | 1367 | ring->curr_desc = 0; |
---|
1345 | 1368 | ring->desc_count--; |
---|
1346 | 1369 | |
---|
1347 | | - /* Ensure write completion of the descriptor status/length |
---|
1348 | | - * in DRAM before the System Port WRITE_PORT register latches |
---|
1349 | | - * the value |
---|
1350 | | - */ |
---|
1351 | | - wmb(); |
---|
1352 | | - desc->addr_status_len = len_status; |
---|
1353 | | - wmb(); |
---|
1354 | | - |
---|
1355 | | - /* Write this descriptor address to the RING write port */ |
---|
1356 | | - tdma_port_write_desc_addr(priv, desc, ring->index); |
---|
| 1370 | + /* Ports are latched, so write upper address first */ |
---|
| 1371 | + spin_lock_irqsave(&priv->desc_lock, desc_flags); |
---|
| 1372 | + tdma_writel(priv, len_status, TDMA_WRITE_PORT_HI(ring->index)); |
---|
| 1373 | + tdma_writel(priv, addr_lo, TDMA_WRITE_PORT_LO(ring->index)); |
---|
| 1374 | + spin_unlock_irqrestore(&priv->desc_lock, desc_flags); |
---|
1357 | 1375 | |
---|
1358 | 1376 | /* Check ring space and update SW control flow */ |
---|
1359 | 1377 | if (ring->desc_count == 0) |
---|
.. | .. |
---|
1368 | 1386 | return ret; |
---|
1369 | 1387 | } |
---|
1370 | 1388 | |
---|
1371 | | -static void bcm_sysport_tx_timeout(struct net_device *dev) |
---|
| 1389 | +static void bcm_sysport_tx_timeout(struct net_device *dev, unsigned int txqueue) |
---|
1372 | 1390 | { |
---|
1373 | 1391 | netdev_warn(dev, "transmit timeout!\n"); |
---|
1374 | 1392 | |
---|
.. | .. |
---|
1450 | 1468 | struct bcm_sysport_net_dim *dim = &priv->dim; |
---|
1451 | 1469 | |
---|
1452 | 1470 | INIT_WORK(&dim->dim.work, cb); |
---|
1453 | | - dim->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE; |
---|
| 1471 | + dim->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE; |
---|
1454 | 1472 | dim->event_ctr = 0; |
---|
1455 | 1473 | dim->packets = 0; |
---|
1456 | 1474 | dim->bytes = 0; |
---|
.. | .. |
---|
1459 | 1477 | static void bcm_sysport_init_rx_coalesce(struct bcm_sysport_priv *priv) |
---|
1460 | 1478 | { |
---|
1461 | 1479 | struct bcm_sysport_net_dim *dim = &priv->dim; |
---|
1462 | | - struct net_dim_cq_moder moder; |
---|
| 1480 | + struct dim_cq_moder moder; |
---|
1463 | 1481 | u32 usecs, pkts; |
---|
1464 | 1482 | |
---|
1465 | 1483 | usecs = priv->rx_coalesce_usecs; |
---|
.. | .. |
---|
1479 | 1497 | unsigned int index) |
---|
1480 | 1498 | { |
---|
1481 | 1499 | struct bcm_sysport_tx_ring *ring = &priv->tx_rings[index]; |
---|
1482 | | - struct device *kdev = &priv->pdev->dev; |
---|
1483 | 1500 | size_t size; |
---|
1484 | | - void *p; |
---|
1485 | 1501 | u32 reg; |
---|
1486 | 1502 | |
---|
1487 | 1503 | /* Simple descriptors partitioning for now */ |
---|
1488 | 1504 | size = 256; |
---|
1489 | 1505 | |
---|
1490 | | - /* We just need one DMA descriptor which is DMA-able, since writing to |
---|
1491 | | - * the port will allocate a new descriptor in its internal linked-list |
---|
1492 | | - */ |
---|
1493 | | - p = dma_zalloc_coherent(kdev, sizeof(struct dma_desc), &ring->desc_dma, |
---|
1494 | | - GFP_KERNEL); |
---|
1495 | | - if (!p) { |
---|
1496 | | - netif_err(priv, hw, priv->netdev, "DMA alloc failed\n"); |
---|
1497 | | - return -ENOMEM; |
---|
1498 | | - } |
---|
1499 | | - |
---|
1500 | 1506 | ring->cbs = kcalloc(size, sizeof(struct bcm_sysport_cb), GFP_KERNEL); |
---|
1501 | 1507 | if (!ring->cbs) { |
---|
1502 | | - dma_free_coherent(kdev, sizeof(struct dma_desc), |
---|
1503 | | - ring->desc_cpu, ring->desc_dma); |
---|
1504 | 1508 | netif_err(priv, hw, priv->netdev, "CB allocation failed\n"); |
---|
1505 | 1509 | return -ENOMEM; |
---|
1506 | 1510 | } |
---|
.. | .. |
---|
1513 | 1517 | ring->size = size; |
---|
1514 | 1518 | ring->clean_index = 0; |
---|
1515 | 1519 | ring->alloc_size = ring->size; |
---|
1516 | | - ring->desc_cpu = p; |
---|
1517 | 1520 | ring->desc_count = ring->size; |
---|
1518 | 1521 | ring->curr_desc = 0; |
---|
1519 | 1522 | |
---|
.. | .. |
---|
1533 | 1536 | reg |= RING_IGNORE_STATUS; |
---|
1534 | 1537 | } |
---|
1535 | 1538 | tdma_writel(priv, reg, TDMA_DESC_RING_MAPPING(index)); |
---|
1536 | | - tdma_writel(priv, 0, TDMA_DESC_RING_PCP_DEI_VID(index)); |
---|
| 1539 | + reg = 0; |
---|
| 1540 | + /* Adjust the packet size calculations if SYSTEMPORT is responsible |
---|
| 1541 | + * for HW insertion of VLAN tags |
---|
| 1542 | + */ |
---|
| 1543 | + if (priv->netdev->features & NETIF_F_HW_VLAN_CTAG_TX) |
---|
| 1544 | + reg = VLAN_HLEN << RING_PKT_SIZE_ADJ_SHIFT; |
---|
| 1545 | + tdma_writel(priv, reg, TDMA_DESC_RING_PCP_DEI_VID(index)); |
---|
1537 | 1546 | |
---|
1538 | 1547 | /* Enable ACB algorithm 2 */ |
---|
1539 | 1548 | reg = tdma_readl(priv, TDMA_CONTROL); |
---|
.. | .. |
---|
1568 | 1577 | napi_enable(&ring->napi); |
---|
1569 | 1578 | |
---|
1570 | 1579 | netif_dbg(priv, hw, priv->netdev, |
---|
1571 | | - "TDMA cfg, size=%d, desc_cpu=%p switch q=%d,port=%d\n", |
---|
1572 | | - ring->size, ring->desc_cpu, ring->switch_queue, |
---|
| 1580 | + "TDMA cfg, size=%d, switch q=%d,port=%d\n", |
---|
| 1581 | + ring->size, ring->switch_queue, |
---|
1573 | 1582 | ring->switch_port); |
---|
1574 | 1583 | |
---|
1575 | 1584 | return 0; |
---|
.. | .. |
---|
1579 | 1588 | unsigned int index) |
---|
1580 | 1589 | { |
---|
1581 | 1590 | struct bcm_sysport_tx_ring *ring = &priv->tx_rings[index]; |
---|
1582 | | - struct device *kdev = &priv->pdev->dev; |
---|
1583 | 1591 | u32 reg; |
---|
1584 | 1592 | |
---|
1585 | 1593 | /* Caller should stop the TDMA engine */ |
---|
.. | .. |
---|
1601 | 1609 | |
---|
1602 | 1610 | kfree(ring->cbs); |
---|
1603 | 1611 | ring->cbs = NULL; |
---|
1604 | | - |
---|
1605 | | - if (ring->desc_dma) { |
---|
1606 | | - dma_free_coherent(kdev, sizeof(struct dma_desc), |
---|
1607 | | - ring->desc_cpu, ring->desc_dma); |
---|
1608 | | - ring->desc_dma = 0; |
---|
1609 | | - } |
---|
1610 | 1612 | ring->size = 0; |
---|
1611 | 1613 | ring->alloc_size = 0; |
---|
1612 | 1614 | |
---|
.. | .. |
---|
1948 | 1950 | unsigned int i; |
---|
1949 | 1951 | int ret; |
---|
1950 | 1952 | |
---|
| 1953 | + clk_prepare_enable(priv->clk); |
---|
| 1954 | + |
---|
1951 | 1955 | /* Reset UniMAC */ |
---|
1952 | 1956 | umac_reset(priv); |
---|
1953 | 1957 | |
---|
.. | .. |
---|
1966 | 1970 | else |
---|
1967 | 1971 | gib_set_pad_extension(priv); |
---|
1968 | 1972 | |
---|
| 1973 | + /* Apply features again in case we changed them while interface was |
---|
| 1974 | + * down |
---|
| 1975 | + */ |
---|
| 1976 | + bcm_sysport_set_features(dev, dev->features); |
---|
| 1977 | + |
---|
1969 | 1978 | /* Set MAC address */ |
---|
1970 | 1979 | umac_set_hw_addr(priv, dev->dev_addr); |
---|
1971 | | - |
---|
1972 | | - /* Read CRC forward */ |
---|
1973 | | - if (!priv->is_lite) |
---|
1974 | | - priv->crc_fwd = !!(umac_readl(priv, UMAC_CMD) & CMD_CRC_FWD); |
---|
1975 | | - else |
---|
1976 | | - priv->crc_fwd = !((gib_readl(priv, GIB_CONTROL) & |
---|
1977 | | - GIB_FCS_STRIP) >> GIB_FCS_STRIP_SHIFT); |
---|
1978 | 1980 | |
---|
1979 | 1981 | phydev = of_phy_connect(dev, priv->phy_dn, bcm_sysport_adj_link, |
---|
1980 | 1982 | 0, priv->phy_interface); |
---|
1981 | 1983 | if (!phydev) { |
---|
1982 | 1984 | netdev_err(dev, "could not attach to PHY\n"); |
---|
1983 | | - return -ENODEV; |
---|
| 1985 | + ret = -ENODEV; |
---|
| 1986 | + goto out_clk_disable; |
---|
1984 | 1987 | } |
---|
1985 | 1988 | |
---|
1986 | 1989 | /* Reset house keeping link status */ |
---|
.. | .. |
---|
2059 | 2062 | free_irq(priv->irq0, dev); |
---|
2060 | 2063 | out_phy_disconnect: |
---|
2061 | 2064 | phy_disconnect(phydev); |
---|
| 2065 | +out_clk_disable: |
---|
| 2066 | + clk_disable_unprepare(priv->clk); |
---|
2062 | 2067 | return ret; |
---|
2063 | 2068 | } |
---|
2064 | 2069 | |
---|
.. | .. |
---|
2116 | 2121 | |
---|
2117 | 2122 | /* Disconnect from PHY */ |
---|
2118 | 2123 | phy_disconnect(dev->phydev); |
---|
| 2124 | + |
---|
| 2125 | + clk_disable_unprepare(priv->clk); |
---|
2119 | 2126 | |
---|
2120 | 2127 | return 0; |
---|
2121 | 2128 | } |
---|
.. | .. |
---|
2186 | 2193 | rxchk_writel(priv, reg, RXCHK_BRCM_TAG(index)); |
---|
2187 | 2194 | rxchk_writel(priv, 0xff00ffff, RXCHK_BRCM_TAG_MASK(index)); |
---|
2188 | 2195 | |
---|
| 2196 | + priv->filters_loc[index] = nfc->fs.location; |
---|
2189 | 2197 | set_bit(index, priv->filters); |
---|
2190 | 2198 | |
---|
2191 | 2199 | return 0; |
---|
.. | .. |
---|
2205 | 2213 | * be taken care of during suspend time by bcm_sysport_suspend_to_wol |
---|
2206 | 2214 | */ |
---|
2207 | 2215 | clear_bit(index, priv->filters); |
---|
| 2216 | + priv->filters_loc[index] = 0; |
---|
2208 | 2217 | |
---|
2209 | 2218 | return 0; |
---|
2210 | 2219 | } |
---|
.. | .. |
---|
2247 | 2256 | } |
---|
2248 | 2257 | |
---|
2249 | 2258 | static const struct ethtool_ops bcm_sysport_ethtool_ops = { |
---|
| 2259 | + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
---|
| 2260 | + ETHTOOL_COALESCE_MAX_FRAMES | |
---|
| 2261 | + ETHTOOL_COALESCE_USE_ADAPTIVE_RX, |
---|
2250 | 2262 | .get_drvinfo = bcm_sysport_get_drvinfo, |
---|
2251 | 2263 | .get_msglevel = bcm_sysport_get_msglvl, |
---|
2252 | 2264 | .set_msglevel = bcm_sysport_set_msglvl, |
---|
.. | .. |
---|
2265 | 2277 | }; |
---|
2266 | 2278 | |
---|
2267 | 2279 | static u16 bcm_sysport_select_queue(struct net_device *dev, struct sk_buff *skb, |
---|
2268 | | - struct net_device *sb_dev, |
---|
2269 | | - select_queue_fallback_t fallback) |
---|
| 2280 | + struct net_device *sb_dev) |
---|
2270 | 2281 | { |
---|
2271 | 2282 | struct bcm_sysport_priv *priv = netdev_priv(dev); |
---|
2272 | 2283 | u16 queue = skb_get_queue_mapping(skb); |
---|
.. | .. |
---|
2274 | 2285 | unsigned int q, port; |
---|
2275 | 2286 | |
---|
2276 | 2287 | if (!netdev_uses_dsa(dev)) |
---|
2277 | | - return fallback(dev, skb, NULL); |
---|
| 2288 | + return netdev_pick_tx(dev, skb, NULL); |
---|
2278 | 2289 | |
---|
2279 | 2290 | /* DSA tagging layer will have configured the correct queue */ |
---|
2280 | 2291 | q = BRCM_TAG_GET_QUEUE(queue); |
---|
.. | .. |
---|
2282 | 2293 | tx_ring = priv->ring_map[q + port * priv->per_port_num_tx_queues]; |
---|
2283 | 2294 | |
---|
2284 | 2295 | if (unlikely(!tx_ring)) |
---|
2285 | | - return fallback(dev, skb, NULL); |
---|
| 2296 | + return netdev_pick_tx(dev, skb, NULL); |
---|
2286 | 2297 | |
---|
2287 | 2298 | return tx_ring->index; |
---|
2288 | 2299 | } |
---|
.. | .. |
---|
2309 | 2320 | struct bcm_sysport_priv *priv; |
---|
2310 | 2321 | struct net_device *slave_dev; |
---|
2311 | 2322 | unsigned int num_tx_queues; |
---|
2312 | | - unsigned int q, start, port; |
---|
| 2323 | + unsigned int q, qp, port; |
---|
2313 | 2324 | struct net_device *dev; |
---|
2314 | 2325 | |
---|
2315 | 2326 | priv = container_of(nb, struct bcm_sysport_priv, dsa_notifier); |
---|
.. | .. |
---|
2348 | 2359 | |
---|
2349 | 2360 | priv->per_port_num_tx_queues = num_tx_queues; |
---|
2350 | 2361 | |
---|
2351 | | - start = find_first_zero_bit(&priv->queue_bitmap, dev->num_tx_queues); |
---|
2352 | | - for (q = 0; q < num_tx_queues; q++) { |
---|
2353 | | - ring = &priv->tx_rings[q + start]; |
---|
| 2362 | + for (q = 0, qp = 0; q < dev->num_tx_queues && qp < num_tx_queues; |
---|
| 2363 | + q++) { |
---|
| 2364 | + ring = &priv->tx_rings[q]; |
---|
| 2365 | + |
---|
| 2366 | + if (ring->inspect) |
---|
| 2367 | + continue; |
---|
2354 | 2368 | |
---|
2355 | 2369 | /* Just remember the mapping actual programming done |
---|
2356 | 2370 | * during bcm_sysport_init_tx_ring |
---|
2357 | 2371 | */ |
---|
2358 | | - ring->switch_queue = q; |
---|
| 2372 | + ring->switch_queue = qp; |
---|
2359 | 2373 | ring->switch_port = port; |
---|
2360 | 2374 | ring->inspect = true; |
---|
2361 | | - priv->ring_map[q + port * num_tx_queues] = ring; |
---|
| 2375 | + priv->ring_map[qp + port * num_tx_queues] = ring; |
---|
| 2376 | + qp++; |
---|
| 2377 | + } |
---|
2362 | 2378 | |
---|
2363 | | - /* Set all queues as being used now */ |
---|
2364 | | - set_bit(q + start, &priv->queue_bitmap); |
---|
| 2379 | + return 0; |
---|
| 2380 | +} |
---|
| 2381 | + |
---|
| 2382 | +static int bcm_sysport_unmap_queues(struct notifier_block *nb, |
---|
| 2383 | + struct dsa_notifier_register_info *info) |
---|
| 2384 | +{ |
---|
| 2385 | + struct bcm_sysport_tx_ring *ring; |
---|
| 2386 | + struct bcm_sysport_priv *priv; |
---|
| 2387 | + struct net_device *slave_dev; |
---|
| 2388 | + unsigned int num_tx_queues; |
---|
| 2389 | + struct net_device *dev; |
---|
| 2390 | + unsigned int q, qp, port; |
---|
| 2391 | + |
---|
| 2392 | + priv = container_of(nb, struct bcm_sysport_priv, dsa_notifier); |
---|
| 2393 | + if (priv->netdev != info->master) |
---|
| 2394 | + return 0; |
---|
| 2395 | + |
---|
| 2396 | + dev = info->master; |
---|
| 2397 | + |
---|
| 2398 | + if (dev->netdev_ops != &bcm_sysport_netdev_ops) |
---|
| 2399 | + return 0; |
---|
| 2400 | + |
---|
| 2401 | + port = info->port_number; |
---|
| 2402 | + slave_dev = info->info.dev; |
---|
| 2403 | + |
---|
| 2404 | + num_tx_queues = slave_dev->real_num_tx_queues; |
---|
| 2405 | + |
---|
| 2406 | + for (q = 0; q < dev->num_tx_queues; q++) { |
---|
| 2407 | + ring = &priv->tx_rings[q]; |
---|
| 2408 | + |
---|
| 2409 | + if (ring->switch_port != port) |
---|
| 2410 | + continue; |
---|
| 2411 | + |
---|
| 2412 | + if (!ring->inspect) |
---|
| 2413 | + continue; |
---|
| 2414 | + |
---|
| 2415 | + ring->inspect = false; |
---|
| 2416 | + qp = ring->switch_queue; |
---|
| 2417 | + priv->ring_map[qp + port * num_tx_queues] = NULL; |
---|
2365 | 2418 | } |
---|
2366 | 2419 | |
---|
2367 | 2420 | return 0; |
---|
.. | .. |
---|
2370 | 2423 | static int bcm_sysport_dsa_notifier(struct notifier_block *nb, |
---|
2371 | 2424 | unsigned long event, void *ptr) |
---|
2372 | 2425 | { |
---|
2373 | | - struct dsa_notifier_register_info *info; |
---|
| 2426 | + int ret = NOTIFY_DONE; |
---|
2374 | 2427 | |
---|
2375 | | - if (event != DSA_PORT_REGISTER) |
---|
2376 | | - return NOTIFY_DONE; |
---|
| 2428 | + switch (event) { |
---|
| 2429 | + case DSA_PORT_REGISTER: |
---|
| 2430 | + ret = bcm_sysport_map_queues(nb, ptr); |
---|
| 2431 | + break; |
---|
| 2432 | + case DSA_PORT_UNREGISTER: |
---|
| 2433 | + ret = bcm_sysport_unmap_queues(nb, ptr); |
---|
| 2434 | + break; |
---|
| 2435 | + } |
---|
2377 | 2436 | |
---|
2378 | | - info = ptr; |
---|
2379 | | - |
---|
2380 | | - return notifier_from_errno(bcm_sysport_map_queues(nb, info)); |
---|
| 2437 | + return notifier_from_errno(ret); |
---|
2381 | 2438 | } |
---|
2382 | 2439 | |
---|
2383 | 2440 | #define REV_FMT "v%2x.%02x" |
---|
.. | .. |
---|
2412 | 2469 | struct device_node *dn; |
---|
2413 | 2470 | struct net_device *dev; |
---|
2414 | 2471 | const void *macaddr; |
---|
2415 | | - struct resource *r; |
---|
2416 | 2472 | u32 txq, rxq; |
---|
2417 | 2473 | int ret; |
---|
2418 | 2474 | |
---|
2419 | 2475 | dn = pdev->dev.of_node; |
---|
2420 | | - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
2421 | 2476 | of_id = of_match_node(bcm_sysport_of_match, dn); |
---|
2422 | 2477 | if (!of_id || !of_id->data) |
---|
2423 | 2478 | return -EINVAL; |
---|
| 2479 | + |
---|
| 2480 | + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); |
---|
| 2481 | + if (ret) |
---|
| 2482 | + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); |
---|
| 2483 | + if (ret) { |
---|
| 2484 | + dev_err(&pdev->dev, "unable to set DMA mask: %d\n", ret); |
---|
| 2485 | + return ret; |
---|
| 2486 | + } |
---|
2424 | 2487 | |
---|
2425 | 2488 | /* Fairly quickly we need to know the type of adapter we have */ |
---|
2426 | 2489 | params = of_id->data; |
---|
.. | .. |
---|
2442 | 2505 | /* Initialize private members */ |
---|
2443 | 2506 | priv = netdev_priv(dev); |
---|
2444 | 2507 | |
---|
| 2508 | + priv->clk = devm_clk_get_optional(&pdev->dev, "sw_sysport"); |
---|
| 2509 | + if (IS_ERR(priv->clk)) { |
---|
| 2510 | + ret = PTR_ERR(priv->clk); |
---|
| 2511 | + goto err_free_netdev; |
---|
| 2512 | + } |
---|
| 2513 | + |
---|
2445 | 2514 | /* Allocate number of TX rings */ |
---|
2446 | 2515 | priv->tx_rings = devm_kcalloc(&pdev->dev, txq, |
---|
2447 | 2516 | sizeof(struct bcm_sysport_tx_ring), |
---|
.. | .. |
---|
2462 | 2531 | priv->wol_irq = platform_get_irq(pdev, 1); |
---|
2463 | 2532 | } |
---|
2464 | 2533 | if (priv->irq0 <= 0 || (priv->irq1 <= 0 && !priv->is_lite)) { |
---|
2465 | | - dev_err(&pdev->dev, "invalid interrupts\n"); |
---|
2466 | 2534 | ret = -EINVAL; |
---|
2467 | 2535 | goto err_free_netdev; |
---|
2468 | 2536 | } |
---|
2469 | 2537 | |
---|
2470 | | - priv->base = devm_ioremap_resource(&pdev->dev, r); |
---|
| 2538 | + priv->base = devm_platform_ioremap_resource(pdev, 0); |
---|
2471 | 2539 | if (IS_ERR(priv->base)) { |
---|
2472 | 2540 | ret = PTR_ERR(priv->base); |
---|
2473 | 2541 | goto err_free_netdev; |
---|
.. | .. |
---|
2476 | 2544 | priv->netdev = dev; |
---|
2477 | 2545 | priv->pdev = pdev; |
---|
2478 | 2546 | |
---|
2479 | | - priv->phy_interface = of_get_phy_mode(dn); |
---|
| 2547 | + ret = of_get_phy_mode(dn, &priv->phy_interface); |
---|
2480 | 2548 | /* Default to GMII interface mode */ |
---|
2481 | | - if ((int)priv->phy_interface < 0) |
---|
| 2549 | + if (ret) |
---|
2482 | 2550 | priv->phy_interface = PHY_INTERFACE_MODE_GMII; |
---|
2483 | 2551 | |
---|
2484 | 2552 | /* In the case of a fixed PHY, the DT node associated |
---|
.. | .. |
---|
2496 | 2564 | |
---|
2497 | 2565 | /* Initialize netdevice members */ |
---|
2498 | 2566 | macaddr = of_get_mac_address(dn); |
---|
2499 | | - if (!macaddr || !is_valid_ether_addr(macaddr)) { |
---|
| 2567 | + if (IS_ERR(macaddr)) { |
---|
2500 | 2568 | dev_warn(&pdev->dev, "using random Ethernet MAC\n"); |
---|
2501 | 2569 | eth_hw_addr_random(dev); |
---|
2502 | 2570 | } else { |
---|
.. | .. |
---|
2509 | 2577 | dev->netdev_ops = &bcm_sysport_netdev_ops; |
---|
2510 | 2578 | netif_napi_add(dev, &priv->napi, bcm_sysport_poll, 64); |
---|
2511 | 2579 | |
---|
2512 | | - /* HW supported features, none enabled by default */ |
---|
2513 | | - dev->hw_features |= NETIF_F_RXCSUM | NETIF_F_HIGHDMA | |
---|
2514 | | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; |
---|
| 2580 | + dev->features |= NETIF_F_RXCSUM | NETIF_F_HIGHDMA | |
---|
| 2581 | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | |
---|
| 2582 | + NETIF_F_HW_VLAN_CTAG_TX; |
---|
| 2583 | + dev->hw_features |= dev->features; |
---|
| 2584 | + dev->vlan_features |= dev->features; |
---|
2515 | 2585 | dev->max_mtu = UMAC_MAX_MTU_SIZE; |
---|
2516 | 2586 | |
---|
2517 | 2587 | /* Request the WOL interrupt and advertise suspend if available */ |
---|
.. | .. |
---|
2520 | 2590 | bcm_sysport_wol_isr, 0, dev->name, priv); |
---|
2521 | 2591 | if (!ret) |
---|
2522 | 2592 | device_set_wakeup_capable(&pdev->dev, 1); |
---|
| 2593 | + |
---|
| 2594 | + priv->wol_clk = devm_clk_get_optional(&pdev->dev, "sw_sysportwol"); |
---|
| 2595 | + if (IS_ERR(priv->wol_clk)) { |
---|
| 2596 | + ret = PTR_ERR(priv->wol_clk); |
---|
| 2597 | + goto err_deregister_fixed_link; |
---|
| 2598 | + } |
---|
2523 | 2599 | |
---|
2524 | 2600 | /* Set the needed headroom once and for all */ |
---|
2525 | 2601 | BUILD_BUG_ON(sizeof(struct bcm_tsb) != 8); |
---|
.. | .. |
---|
2545 | 2621 | goto err_deregister_notifier; |
---|
2546 | 2622 | } |
---|
2547 | 2623 | |
---|
| 2624 | + clk_prepare_enable(priv->clk); |
---|
| 2625 | + |
---|
2548 | 2626 | priv->rev = topctrl_readl(priv, REV_CNTL) & REV_MASK; |
---|
2549 | 2627 | dev_info(&pdev->dev, |
---|
2550 | | - "Broadcom SYSTEMPORT%s" REV_FMT |
---|
2551 | | - " at 0x%p (irqs: %d, %d, TXQs: %d, RXQs: %d)\n", |
---|
| 2628 | + "Broadcom SYSTEMPORT%s " REV_FMT |
---|
| 2629 | + " (irqs: %d, %d, TXQs: %d, RXQs: %d)\n", |
---|
2552 | 2630 | priv->is_lite ? " Lite" : "", |
---|
2553 | 2631 | (priv->rev >> 8) & 0xff, priv->rev & 0xff, |
---|
2554 | | - priv->base, priv->irq0, priv->irq1, txq, rxq); |
---|
| 2632 | + priv->irq0, priv->irq1, txq, rxq); |
---|
| 2633 | + |
---|
| 2634 | + clk_disable_unprepare(priv->clk); |
---|
2555 | 2635 | |
---|
2556 | 2636 | return 0; |
---|
2557 | 2637 | |
---|
.. | .. |
---|
2706 | 2786 | bcm_sysport_fini_rx_ring(priv); |
---|
2707 | 2787 | |
---|
2708 | 2788 | /* Get prepared for Wake-on-LAN */ |
---|
2709 | | - if (device_may_wakeup(d) && priv->wolopts) |
---|
| 2789 | + if (device_may_wakeup(d) && priv->wolopts) { |
---|
| 2790 | + clk_prepare_enable(priv->wol_clk); |
---|
2710 | 2791 | ret = bcm_sysport_suspend_to_wol(priv); |
---|
| 2792 | + } |
---|
| 2793 | + |
---|
| 2794 | + clk_disable_unprepare(priv->clk); |
---|
2711 | 2795 | |
---|
2712 | 2796 | return ret; |
---|
2713 | 2797 | } |
---|
.. | .. |
---|
2717 | 2801 | struct net_device *dev = dev_get_drvdata(d); |
---|
2718 | 2802 | struct bcm_sysport_priv *priv = netdev_priv(dev); |
---|
2719 | 2803 | unsigned int i; |
---|
2720 | | - u32 reg; |
---|
2721 | 2804 | int ret; |
---|
2722 | 2805 | |
---|
2723 | 2806 | if (!netif_running(dev)) |
---|
2724 | 2807 | return 0; |
---|
| 2808 | + |
---|
| 2809 | + clk_prepare_enable(priv->clk); |
---|
| 2810 | + if (priv->wolopts) |
---|
| 2811 | + clk_disable_unprepare(priv->wol_clk); |
---|
2725 | 2812 | |
---|
2726 | 2813 | umac_reset(priv); |
---|
2727 | 2814 | |
---|
.. | .. |
---|
2762 | 2849 | goto out_free_rx_ring; |
---|
2763 | 2850 | } |
---|
2764 | 2851 | |
---|
2765 | | - /* Enable rxhck */ |
---|
2766 | | - if (priv->rx_chk_en) { |
---|
2767 | | - reg = rxchk_readl(priv, RXCHK_CONTROL); |
---|
2768 | | - reg |= RXCHK_EN; |
---|
2769 | | - rxchk_writel(priv, reg, RXCHK_CONTROL); |
---|
2770 | | - } |
---|
| 2852 | + /* Restore enabled features */ |
---|
| 2853 | + bcm_sysport_set_features(dev, dev->features); |
---|
2771 | 2854 | |
---|
2772 | 2855 | rbuf_init(priv); |
---|
2773 | 2856 | |
---|
.. | .. |
---|
2806 | 2889 | out_free_tx_rings: |
---|
2807 | 2890 | for (i = 0; i < dev->num_tx_queues; i++) |
---|
2808 | 2891 | bcm_sysport_fini_tx_ring(priv, i); |
---|
| 2892 | + clk_disable_unprepare(priv->clk); |
---|
2809 | 2893 | return ret; |
---|
2810 | 2894 | } |
---|
2811 | 2895 | |
---|