| .. | .. |
|---|
| 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 | |
|---|