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

stmmac: unify MAC and PHY configuration parameters (V2)

Prior to this change, most PHY configuration parameters were passed
into the STMMAC device as a separate PHY device. As well as being
unusual, this made it difficult to make changes to the MAC/PHY
relationship.

This patch moves all the PHY parameters into the MAC configuration
structure, mainly as a separate structure. This allows us to completely
ignore the MDIO bus attached to a stmmac if desired, and not create
the PHY bus. It also allows the stmmac driver to use a different PHY
from the one it is connected to, for example a fixed PHY or bit banging
PHY.

Also derive the stmmac/PHY connection type (MII/RMII etc) from the
mode can be passed into <platf>_configure_ethernet.
STLinux kernel at git://git.stlinux.com/stm/linux-sh4-2.6.32.y.git
provides several examples how to use this new infrastructure (that
actually is easier to maintain and clearer).

Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Giuseppe CAVALLARO and committed by
David S. Miller
36bcfe7d f3240e28

+77 -131
+1 -5
drivers/net/stmmac/stmmac.h
··· 56 56 struct stmmac_extra_stats xstats; 57 57 struct napi_struct napi; 58 58 59 - phy_interface_t phy_interface; 60 - int phy_addr; 61 - int phy_mask; 62 - int (*phy_reset) (void *priv); 63 59 int rx_coe; 64 60 int no_csum_insertion; 65 61 66 - int phy_irq; 67 62 struct phy_device *phydev; 68 63 int oldlink; 69 64 int speed; ··· 66 71 unsigned int flow_ctrl; 67 72 unsigned int pause; 68 73 struct mii_bus *mii; 74 + int mii_irq[PHY_MAX_ADDR]; 69 75 70 76 u32 msg_enable; 71 77 spinlock_t lock;
+7 -88
drivers/net/stmmac/stmmac_main.c
··· 49 49 #include "stmmac.h" 50 50 51 51 #define STMMAC_RESOURCE_NAME "stmmaceth" 52 - #define PHY_RESOURCE_NAME "stmmacphy" 53 52 54 53 #undef STMMAC_DEBUG 55 54 /*#define STMMAC_DEBUG*/ ··· 304 305 priv->speed = 0; 305 306 priv->oldduplex = -1; 306 307 307 - if (priv->phy_addr == -1) { 308 - /* We don't have a PHY, so do nothing */ 309 - return 0; 310 - } 311 - 312 308 snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id); 313 309 snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, 314 - priv->phy_addr); 310 + priv->plat->phy_addr); 315 311 pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id); 316 312 317 313 phydev = phy_connect(dev, phy_id, &stmmac_adjust_link, 0, 318 - priv->phy_interface); 314 + priv->plat->interface); 319 315 320 316 if (IS_ERR(phydev)) { 321 317 pr_err("%s: Could not attach to PHY\n", dev->name); ··· 329 335 return -ENODEV; 330 336 } 331 337 pr_debug("stmmac_init_phy: %s: attached to PHY (UID 0x%x)" 332 - " Link = %d\n", dev->name, phydev->phy_id, phydev->link); 338 + " Link = %d\n", dev->name, phydev->phy_id, phydev->link); 333 339 334 340 priv->phydev = phydev; 335 341 ··· 1522 1528 return 0; 1523 1529 } 1524 1530 1525 - static int stmmacphy_dvr_probe(struct platform_device *pdev) 1526 - { 1527 - struct plat_stmmacphy_data *plat_dat = pdev->dev.platform_data; 1528 - 1529 - pr_debug("stmmacphy_dvr_probe: added phy for bus %d\n", 1530 - plat_dat->bus_id); 1531 - 1532 - return 0; 1533 - } 1534 - 1535 - static int stmmacphy_dvr_remove(struct platform_device *pdev) 1536 - { 1537 - return 0; 1538 - } 1539 - 1540 - static struct platform_driver stmmacphy_driver = { 1541 - .driver = { 1542 - .name = PHY_RESOURCE_NAME, 1543 - }, 1544 - .probe = stmmacphy_dvr_probe, 1545 - .remove = stmmacphy_dvr_remove, 1546 - }; 1547 - 1548 - /** 1549 - * stmmac_associate_phy 1550 - * @dev: pointer to device structure 1551 - * @data: points to the private structure. 1552 - * Description: Scans through all the PHYs we have registered and checks if 1553 - * any are associated with our MAC. If so, then just fill in 1554 - * the blanks in our local context structure 1555 - */ 1556 - static int stmmac_associate_phy(struct device *dev, void *data) 1557 - { 1558 - struct stmmac_priv *priv = (struct stmmac_priv *)data; 1559 - struct plat_stmmacphy_data *plat_dat = dev->platform_data; 1560 - 1561 - DBG(probe, DEBUG, "%s: checking phy for bus %d\n", __func__, 1562 - plat_dat->bus_id); 1563 - 1564 - /* Check that this phy is for the MAC being initialised */ 1565 - if (priv->plat->bus_id != plat_dat->bus_id) 1566 - return 0; 1567 - 1568 - /* OK, this PHY is connected to the MAC. 1569 - Go ahead and get the parameters */ 1570 - DBG(probe, DEBUG, "%s: OK. Found PHY config\n", __func__); 1571 - priv->phy_irq = 1572 - platform_get_irq_byname(to_platform_device(dev), "phyirq"); 1573 - DBG(probe, DEBUG, "%s: PHY irq on bus %d is %d\n", __func__, 1574 - plat_dat->bus_id, priv->phy_irq); 1575 - 1576 - /* Override with kernel parameters if supplied XXX CRS XXX 1577 - * this needs to have multiple instances */ 1578 - if ((phyaddr >= 0) && (phyaddr <= 31)) 1579 - plat_dat->phy_addr = phyaddr; 1580 - 1581 - priv->phy_addr = plat_dat->phy_addr; 1582 - priv->phy_mask = plat_dat->phy_mask; 1583 - priv->phy_interface = plat_dat->interface; 1584 - priv->phy_reset = plat_dat->phy_reset; 1585 - 1586 - DBG(probe, DEBUG, "%s: exiting\n", __func__); 1587 - return 1; /* forces exit of driver_for_each_device() */ 1588 - } 1589 - 1590 1531 /** 1591 1532 * stmmac_dvr_probe 1592 1533 * @pdev: platform device pointer ··· 1612 1683 if (ret < 0) 1613 1684 goto out_plat_exit; 1614 1685 1615 - /* associate a PHY - it is provided by another platform bus */ 1616 - if (!driver_for_each_device 1617 - (&(stmmacphy_driver.driver), NULL, (void *)priv, 1618 - stmmac_associate_phy)) { 1619 - pr_err("No PHY device is associated with this MAC!\n"); 1620 - ret = -ENODEV; 1621 - goto out_unregister; 1622 - } 1686 + /* Override with kernel parameters if supplied XXX CRS XXX 1687 + * this needs to have multiple instances */ 1688 + if ((phyaddr >= 0) && (phyaddr <= 31)) 1689 + priv->plat->phy_addr = phyaddr; 1623 1690 1624 1691 pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n" 1625 1692 "\tIO base addr: 0x%p)\n", ndev->name, pdev->name, ··· 1815 1890 { 1816 1891 int ret; 1817 1892 1818 - if (platform_driver_register(&stmmacphy_driver)) { 1819 - pr_err("No PHY devices registered!\n"); 1820 - return -ENODEV; 1821 - } 1822 - 1823 1893 ret = platform_driver_register(&stmmac_driver); 1824 1894 return ret; 1825 1895 } ··· 1825 1905 */ 1826 1906 static void __exit stmmac_cleanup_module(void) 1827 1907 { 1828 - platform_driver_unregister(&stmmacphy_driver); 1829 1908 platform_driver_unregister(&stmmac_driver); 1830 1909 } 1831 1910
+57 -26
drivers/net/stmmac/stmmac_mdio.c
··· 113 113 struct stmmac_priv *priv = netdev_priv(ndev); 114 114 unsigned int mii_address = priv->hw->mii.addr; 115 115 116 - if (priv->phy_reset) { 116 + if (priv->plat->mdio_bus_data->phy_reset) { 117 117 pr_debug("stmmac_mdio_reset: calling phy_reset\n"); 118 - priv->phy_reset(priv->plat->bsp_priv); 118 + priv->plat->mdio_bus_data->phy_reset(priv->plat->bsp_priv); 119 119 } 120 120 121 121 /* This is a workaround for problems with the STE101P PHY. ··· 138 138 struct mii_bus *new_bus; 139 139 int *irqlist; 140 140 struct stmmac_priv *priv = netdev_priv(ndev); 141 + struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data; 141 142 int addr, found; 143 + 144 + if (!mdio_bus_data) 145 + return 0; 142 146 143 147 new_bus = mdiobus_alloc(); 144 148 if (new_bus == NULL) 145 149 return -ENOMEM; 146 150 147 - irqlist = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); 148 - if (irqlist == NULL) { 149 - err = -ENOMEM; 150 - goto irqlist_alloc_fail; 151 - } 152 - 153 - /* Assign IRQ to phy at address phy_addr */ 154 - if (priv->phy_addr != -1) 155 - irqlist[priv->phy_addr] = priv->phy_irq; 151 + if (mdio_bus_data->irqs) 152 + irqlist = mdio_bus_data->irqs; 153 + else 154 + irqlist = priv->mii_irq; 156 155 157 156 new_bus->name = "STMMAC MII Bus"; 158 157 new_bus->read = &stmmac_mdio_read; 159 158 new_bus->write = &stmmac_mdio_write; 160 159 new_bus->reset = &stmmac_mdio_reset; 161 - snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id); 160 + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", mdio_bus_data->bus_id); 162 161 new_bus->priv = ndev; 163 162 new_bus->irq = irqlist; 164 - new_bus->phy_mask = priv->phy_mask; 163 + new_bus->phy_mask = mdio_bus_data->phy_mask; 165 164 new_bus->parent = priv->device; 166 165 err = mdiobus_register(new_bus); 167 166 if (err != 0) { ··· 171 172 priv->mii = new_bus; 172 173 173 174 found = 0; 174 - for (addr = 0; addr < 32; addr++) { 175 + for (addr = 0; addr < PHY_MAX_ADDR; addr++) { 175 176 struct phy_device *phydev = new_bus->phy_map[addr]; 176 177 if (phydev) { 177 - if (priv->phy_addr == -1) { 178 - priv->phy_addr = addr; 179 - phydev->irq = priv->phy_irq; 180 - irqlist[addr] = priv->phy_irq; 178 + int act = 0; 179 + char irq_num[4]; 180 + char *irq_str; 181 + 182 + /* 183 + * If an IRQ was provided to be assigned after 184 + * the bus probe, do it here. 185 + */ 186 + if ((mdio_bus_data->irqs == NULL) && 187 + (mdio_bus_data->probed_phy_irq > 0)) { 188 + irqlist[addr] = mdio_bus_data->probed_phy_irq; 189 + phydev->irq = mdio_bus_data->probed_phy_irq; 181 190 } 182 - pr_info("%s: PHY ID %08x at %d IRQ %d (%s)%s\n", 183 - ndev->name, phydev->phy_id, addr, 184 - phydev->irq, dev_name(&phydev->dev), 185 - (addr == priv->phy_addr) ? " active" : ""); 191 + 192 + /* 193 + * If we're going to bind the MAC to this PHY bus, 194 + * and no PHY number was provided to the MAC, 195 + * use the one probed here. 196 + */ 197 + if ((priv->plat->bus_id == mdio_bus_data->bus_id) && 198 + (priv->plat->phy_addr == -1)) 199 + priv->plat->phy_addr = addr; 200 + 201 + act = (priv->plat->bus_id == mdio_bus_data->bus_id) && 202 + (priv->plat->phy_addr == addr); 203 + switch (phydev->irq) { 204 + case PHY_POLL: 205 + irq_str = "POLL"; 206 + break; 207 + case PHY_IGNORE_INTERRUPT: 208 + irq_str = "IGNORE"; 209 + break; 210 + default: 211 + sprintf(irq_num, "%d", phydev->irq); 212 + irq_str = irq_num; 213 + break; 214 + } 215 + pr_info("%s: PHY ID %08x at %d IRQ %s (%s)%s\n", 216 + ndev->name, phydev->phy_id, addr, 217 + irq_str, dev_name(&phydev->dev), 218 + act ? " active" : ""); 186 219 found = 1; 187 220 } 188 221 } ··· 223 192 pr_warning("%s: No PHY found\n", ndev->name); 224 193 225 194 return 0; 195 + 226 196 bus_register_fail: 227 - kfree(irqlist); 228 - irqlist_alloc_fail: 229 - kfree(new_bus); 197 + mdiobus_free(new_bus); 230 198 return err; 231 199 } 232 200 ··· 240 210 241 211 mdiobus_unregister(priv->mii); 242 212 priv->mii->priv = NULL; 243 - kfree(priv->mii); 213 + mdiobus_free(priv->mii); 214 + priv->mii = NULL; 244 215 245 216 return 0; 246 217 }
+12 -12
include/linux/stmmac.h
··· 28 28 29 29 #include <linux/platform_device.h> 30 30 31 - /* platform data for platform device structure's platform_data field */ 31 + /* Platfrom data for platform device structure's platform_data field */ 32 32 33 - /* Private data for the STM on-board ethernet driver */ 33 + struct stmmac_mdio_bus_data { 34 + int bus_id; 35 + int (*phy_reset)(void *priv); 36 + unsigned int phy_mask; 37 + int *irqs; 38 + int probed_phy_irq; 39 + }; 40 + 34 41 struct plat_stmmacenet_data { 35 42 int bus_id; 43 + int phy_addr; 44 + int interface; 45 + struct stmmac_mdio_bus_data *mdio_bus_data; 36 46 int pbl; 37 47 int clk_csr; 38 48 int has_gmac; ··· 58 48 void *custom_cfg; 59 49 void *bsp_priv; 60 50 }; 61 - 62 - struct plat_stmmacphy_data { 63 - int bus_id; 64 - int phy_addr; 65 - unsigned int phy_mask; 66 - int interface; 67 - int (*phy_reset)(void *priv); 68 - void *priv; 69 - }; 70 51 #endif 71 -