Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'dsa_eee'

Florian Fainelli says:

====================
net: dsa: EEE and other PM features

This patch set allows DSA switch drivers to enable/disable/query EEE on a
per-port level, as well as control precisely which switch ports are
enable/disabled.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+205 -20
+122 -20
drivers/net/dsa/bcm_sf2.c
··· 135 135 return "Broadcom Starfighter 2"; 136 136 } 137 137 138 - static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port) 138 + static void bcm_sf2_imp_vlan_setup(struct dsa_switch *ds, int cpu_port) 139 139 { 140 140 struct bcm_sf2_priv *priv = ds_to_priv(ds); 141 141 unsigned int i; 142 + u32 reg; 143 + 144 + /* Enable the IMP Port to be in the same VLAN as the other ports 145 + * on a per-port basis such that we only have Port i and IMP in 146 + * the same VLAN. 147 + */ 148 + for (i = 0; i < priv->hw_params.num_ports; i++) { 149 + if (!((1 << i) & ds->phys_port_mask)) 150 + continue; 151 + 152 + reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i)); 153 + reg |= (1 << cpu_port); 154 + core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i)); 155 + } 156 + } 157 + 158 + static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port) 159 + { 160 + struct bcm_sf2_priv *priv = ds_to_priv(ds); 142 161 u32 reg, val; 143 162 144 163 /* Enable the port memories */ ··· 218 199 reg = core_readl(priv, CORE_STS_OVERRIDE_IMP); 219 200 reg |= (MII_SW_OR | LINK_STS); 220 201 core_writel(priv, reg, CORE_STS_OVERRIDE_IMP); 221 - 222 - /* Enable the IMP Port to be in the same VLAN as the other ports 223 - * on a per-port basis such that we only have Port i and IMP in 224 - * the same VLAN. 225 - */ 226 - for (i = 0; i < priv->hw_params.num_ports; i++) { 227 - if (!((1 << i) & ds->phys_port_mask)) 228 - continue; 229 - 230 - reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i)); 231 - reg |= (1 << port); 232 - core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i)); 233 - } 234 202 } 235 203 236 - static void bcm_sf2_port_setup(struct dsa_switch *ds, int port) 204 + static void bcm_sf2_eee_enable_set(struct dsa_switch *ds, int port, bool enable) 237 205 { 238 206 struct bcm_sf2_priv *priv = ds_to_priv(ds); 207 + u32 reg; 208 + 209 + reg = core_readl(priv, CORE_EEE_EN_CTRL); 210 + if (enable) 211 + reg |= 1 << port; 212 + else 213 + reg &= ~(1 << port); 214 + core_writel(priv, reg, CORE_EEE_EN_CTRL); 215 + } 216 + 217 + static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, 218 + struct phy_device *phy) 219 + { 220 + struct bcm_sf2_priv *priv = ds_to_priv(ds); 221 + s8 cpu_port = ds->dst[ds->index].cpu_port; 239 222 u32 reg; 240 223 241 224 /* Clear the memory power down */ ··· 257 236 reg &= ~PORT_VLAN_CTRL_MASK; 258 237 reg |= (1 << port); 259 238 core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(port)); 239 + 240 + bcm_sf2_imp_vlan_setup(ds, cpu_port); 241 + 242 + /* If EEE was enabled, restore it */ 243 + if (priv->port_sts[port].eee.eee_enabled) 244 + bcm_sf2_eee_enable_set(ds, port, true); 245 + 246 + return 0; 260 247 } 261 248 262 - static void bcm_sf2_port_disable(struct dsa_switch *ds, int port) 249 + static void bcm_sf2_port_disable(struct dsa_switch *ds, int port, 250 + struct phy_device *phy) 263 251 { 264 252 struct bcm_sf2_priv *priv = ds_to_priv(ds); 265 253 u32 off, reg; 266 254 267 255 if (priv->wol_ports_mask & (1 << port)) 268 256 return; 257 + 258 + if (port == 7) { 259 + intrl2_1_mask_set(priv, P_IRQ_MASK(P7_IRQ_OFF)); 260 + intrl2_1_writel(priv, P_IRQ_MASK(P7_IRQ_OFF), INTRL2_CPU_CLEAR); 261 + } 269 262 270 263 if (dsa_is_cpu_port(ds, port)) 271 264 off = CORE_IMP_CTL; ··· 294 259 reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL); 295 260 reg |= P_TXQ_PSM_VDD(port); 296 261 core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL); 262 + } 263 + 264 + /* Returns 0 if EEE was not enabled, or 1 otherwise 265 + */ 266 + static int bcm_sf2_eee_init(struct dsa_switch *ds, int port, 267 + struct phy_device *phy) 268 + { 269 + struct bcm_sf2_priv *priv = ds_to_priv(ds); 270 + struct ethtool_eee *p = &priv->port_sts[port].eee; 271 + int ret; 272 + 273 + p->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full); 274 + 275 + ret = phy_init_eee(phy, 0); 276 + if (ret) 277 + return 0; 278 + 279 + bcm_sf2_eee_enable_set(ds, port, true); 280 + 281 + return 1; 282 + } 283 + 284 + static int bcm_sf2_sw_get_eee(struct dsa_switch *ds, int port, 285 + struct ethtool_eee *e) 286 + { 287 + struct bcm_sf2_priv *priv = ds_to_priv(ds); 288 + struct ethtool_eee *p = &priv->port_sts[port].eee; 289 + u32 reg; 290 + 291 + reg = core_readl(priv, CORE_EEE_LPI_INDICATE); 292 + e->eee_enabled = p->eee_enabled; 293 + e->eee_active = !!(reg & (1 << port)); 294 + 295 + return 0; 296 + } 297 + 298 + static int bcm_sf2_sw_set_eee(struct dsa_switch *ds, int port, 299 + struct phy_device *phydev, 300 + struct ethtool_eee *e) 301 + { 302 + struct bcm_sf2_priv *priv = ds_to_priv(ds); 303 + struct ethtool_eee *p = &priv->port_sts[port].eee; 304 + 305 + p->eee_enabled = e->eee_enabled; 306 + 307 + if (!p->eee_enabled) { 308 + bcm_sf2_eee_enable_set(ds, port, false); 309 + } else { 310 + p->eee_enabled = bcm_sf2_eee_init(ds, port, phydev); 311 + if (!p->eee_enabled) 312 + return -EOPNOTSUPP; 313 + } 314 + 315 + return 0; 297 316 } 298 317 299 318 static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id) ··· 452 363 for (port = 0; port < priv->hw_params.num_ports; port++) { 453 364 /* IMP port receives special treatment */ 454 365 if ((1 << port) & ds->phys_port_mask) 455 - bcm_sf2_port_setup(ds, port); 366 + bcm_sf2_port_setup(ds, port, NULL); 456 367 else if (dsa_is_cpu_port(ds, port)) 457 368 bcm_sf2_imp_setup(ds, port); 458 369 else 459 - bcm_sf2_port_disable(ds, port); 370 + bcm_sf2_port_disable(ds, port, NULL); 460 371 } 461 372 462 373 /* Include the pseudo-PHY address and the broadcast PHY address to ··· 595 506 port_mode = EXT_REVMII; 596 507 break; 597 508 default: 509 + /* All other PHYs: internal and MoCA */ 510 + goto force_link; 511 + } 512 + 513 + /* If the link is down, just disable the interface to conserve power */ 514 + if (!phydev->link) { 515 + reg = reg_readl(priv, REG_RGMII_CNTRL_P(port)); 516 + reg &= ~RGMII_MODE_EN; 517 + reg_writel(priv, reg, REG_RGMII_CNTRL_P(port)); 598 518 goto force_link; 599 519 } 600 520 ··· 727 629 for (port = 0; port < DSA_MAX_PORTS; port++) { 728 630 if ((1 << port) & ds->phys_port_mask || 729 631 dsa_is_cpu_port(ds, port)) 730 - bcm_sf2_port_disable(ds, port); 632 + bcm_sf2_port_disable(ds, port, NULL); 731 633 } 732 634 733 635 return 0; ··· 783 685 784 686 for (port = 0; port < DSA_MAX_PORTS; port++) { 785 687 if ((1 << port) & ds->phys_port_mask) 786 - bcm_sf2_port_setup(ds, port); 688 + bcm_sf2_port_setup(ds, port, NULL); 787 689 else if (dsa_is_cpu_port(ds, port)) 788 690 bcm_sf2_imp_setup(ds, port); 789 691 } ··· 861 763 .resume = bcm_sf2_sw_resume, 862 764 .get_wol = bcm_sf2_sw_get_wol, 863 765 .set_wol = bcm_sf2_sw_set_wol, 766 + .port_enable = bcm_sf2_port_setup, 767 + .port_disable = bcm_sf2_port_disable, 768 + .get_eee = bcm_sf2_sw_get_eee, 769 + .set_eee = bcm_sf2_sw_set_eee, 864 770 }; 865 771 866 772 static int __init bcm_sf2_init(void)
+3
drivers/net/dsa/bcm_sf2.h
··· 18 18 #include <linux/spinlock.h> 19 19 #include <linux/mutex.h> 20 20 #include <linux/mii.h> 21 + #include <linux/ethtool.h> 21 22 22 23 #include <net/dsa.h> 23 24 ··· 44 43 45 44 struct bcm_sf2_port_status { 46 45 unsigned int link; 46 + 47 + struct ethtool_eee eee; 47 48 }; 48 49 49 50 struct bcm_sf2_priv {
+3
drivers/net/dsa/bcm_sf2_regs.h
··· 225 225 #define CORE_PORT_VLAN_CTL_PORT(x) (0xc400 + ((x) * 0x8)) 226 226 #define PORT_VLAN_CTRL_MASK 0x1ff 227 227 228 + #define CORE_EEE_EN_CTRL 0x24800 229 + #define CORE_EEE_LPI_INDICATE 0x24810 230 + 228 231 #endif /* __BCM_SF2_REGS_H */
+17
include/net/dsa.h
··· 224 224 */ 225 225 int (*suspend)(struct dsa_switch *ds); 226 226 int (*resume)(struct dsa_switch *ds); 227 + 228 + /* 229 + * Port enable/disable 230 + */ 231 + int (*port_enable)(struct dsa_switch *ds, int port, 232 + struct phy_device *phy); 233 + void (*port_disable)(struct dsa_switch *ds, int port, 234 + struct phy_device *phy); 235 + 236 + /* 237 + * EEE setttings 238 + */ 239 + int (*set_eee)(struct dsa_switch *ds, int port, 240 + struct phy_device *phydev, 241 + struct ethtool_eee *e); 242 + int (*get_eee)(struct dsa_switch *ds, int port, 243 + struct ethtool_eee *e); 227 244 }; 228 245 229 246 void register_switch_driver(struct dsa_switch_driver *type);
+60
net/dsa/slave.c
··· 62 62 { 63 63 struct dsa_slave_priv *p = netdev_priv(dev); 64 64 struct net_device *master = p->parent->dst->master_netdev; 65 + struct dsa_switch *ds = p->parent; 65 66 int err; 66 67 67 68 if (!(master->flags & IFF_UP)) ··· 85 84 goto clear_allmulti; 86 85 } 87 86 87 + if (ds->drv->port_enable) { 88 + err = ds->drv->port_enable(ds, p->port, p->phy); 89 + if (err) 90 + goto clear_promisc; 91 + } 92 + 93 + if (p->phy) 94 + phy_start(p->phy); 95 + 88 96 return 0; 89 97 98 + clear_promisc: 99 + if (dev->flags & IFF_PROMISC) 100 + dev_set_promiscuity(master, 0); 90 101 clear_allmulti: 91 102 if (dev->flags & IFF_ALLMULTI) 92 103 dev_set_allmulti(master, -1); ··· 113 100 { 114 101 struct dsa_slave_priv *p = netdev_priv(dev); 115 102 struct net_device *master = p->parent->dst->master_netdev; 103 + struct dsa_switch *ds = p->parent; 104 + 105 + if (p->phy) 106 + phy_stop(p->phy); 116 107 117 108 dev_mc_unsync(master, dev); 118 109 dev_uc_unsync(master, dev); ··· 127 110 128 111 if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) 129 112 dev_uc_del(master, dev->dev_addr); 113 + 114 + if (ds->drv->port_disable) 115 + ds->drv->port_disable(ds, p->port, p->phy); 130 116 131 117 return 0; 132 118 } ··· 342 322 return ret; 343 323 } 344 324 325 + static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e) 326 + { 327 + struct dsa_slave_priv *p = netdev_priv(dev); 328 + struct dsa_switch *ds = p->parent; 329 + int ret; 330 + 331 + if (!ds->drv->set_eee) 332 + return -EOPNOTSUPP; 333 + 334 + ret = ds->drv->set_eee(ds, p->port, p->phy, e); 335 + if (ret) 336 + return ret; 337 + 338 + if (p->phy) 339 + ret = phy_ethtool_set_eee(p->phy, e); 340 + 341 + return ret; 342 + } 343 + 344 + static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e) 345 + { 346 + struct dsa_slave_priv *p = netdev_priv(dev); 347 + struct dsa_switch *ds = p->parent; 348 + int ret; 349 + 350 + if (!ds->drv->get_eee) 351 + return -EOPNOTSUPP; 352 + 353 + ret = ds->drv->get_eee(ds, p->port, e); 354 + if (ret) 355 + return ret; 356 + 357 + if (p->phy) 358 + ret = phy_ethtool_get_eee(p->phy, e); 359 + 360 + return ret; 361 + } 362 + 345 363 static const struct ethtool_ops dsa_slave_ethtool_ops = { 346 364 .get_settings = dsa_slave_get_settings, 347 365 .set_settings = dsa_slave_set_settings, ··· 391 333 .get_sset_count = dsa_slave_get_sset_count, 392 334 .set_wol = dsa_slave_set_wol, 393 335 .get_wol = dsa_slave_get_wol, 336 + .set_eee = dsa_slave_set_eee, 337 + .get_eee = dsa_slave_get_eee, 394 338 }; 395 339 396 340 static const struct net_device_ops dsa_slave_netdev_ops = {