Commit ec9a82fb authored by David S. Miller's avatar David S. Miller

Merge branch 'macb-next'

Nicolas Ferre says:

====================
net/macb: fixes after big driver update

The recent modifications to the macb driver lead to issues with the probe
function code flow. Here are some attempt to fix them.
This time, some more issues are fixed related to the clock as reported by Boris
Brezillon.

The series is written on top of net-next.

Changes in v2:
- address Cyrille comment about exit condition of queue configuration loop
- add fixes for probe sequence related to clocks
- add ethtool register dump
- fix peripheral version test
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 34d21e3f fa693598
...@@ -2037,8 +2037,8 @@ static void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs, ...@@ -2037,8 +2037,8 @@ static void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs,
regs_buff[10] = macb_tx_dma(&bp->queues[0], tail); regs_buff[10] = macb_tx_dma(&bp->queues[0], tail);
regs_buff[11] = macb_tx_dma(&bp->queues[0], head); regs_buff[11] = macb_tx_dma(&bp->queues[0], head);
regs_buff[12] = macb_or_gem_readl(bp, USRIO);
if (macb_is_gem(bp)) { if (macb_is_gem(bp)) {
regs_buff[12] = gem_readl(bp, USRIO);
regs_buff[13] = gem_readl(bp, DMACFG); regs_buff[13] = gem_readl(bp, DMACFG);
} }
} }
...@@ -2129,17 +2129,19 @@ static const struct net_device_ops macb_netdev_ops = { ...@@ -2129,17 +2129,19 @@ static const struct net_device_ops macb_netdev_ops = {
}; };
/* /*
* Configure peripheral capacities according to device tree * Configure peripheral capabilities according to device tree
* and integration options used * and integration options used
*/ */
static void macb_configure_caps(struct macb *bp) static void macb_configure_caps(struct macb *bp, const struct macb_config *dt_conf)
{ {
u32 dcfg; u32 dcfg;
if (MACB_BFEXT(IDNUM, macb_readl(bp, MID)) == 0x2) if (dt_conf)
bp->caps = dt_conf->caps;
if (macb_is_gem_hw(bp->regs)) {
bp->caps |= MACB_CAPS_MACB_IS_GEM; bp->caps |= MACB_CAPS_MACB_IS_GEM;
if (macb_is_gem(bp)) {
dcfg = gem_readl(bp, DCFG1); dcfg = gem_readl(bp, DCFG1);
if (GEM_BFEXT(IRQCOR, dcfg) == 0) if (GEM_BFEXT(IRQCOR, dcfg) == 0)
bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE; bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE;
...@@ -2156,15 +2158,17 @@ static void macb_probe_queues(void __iomem *mem, ...@@ -2156,15 +2158,17 @@ static void macb_probe_queues(void __iomem *mem,
unsigned int *num_queues) unsigned int *num_queues)
{ {
unsigned int hw_q; unsigned int hw_q;
u32 mid;
*queue_mask = 0x1; *queue_mask = 0x1;
*num_queues = 1; *num_queues = 1;
/* is it macb or gem ? */ /* is it macb or gem ?
mid = readl_relaxed(mem + MACB_MID); *
* We need to read directly from the hardware here because
if (MACB_BFEXT(IDNUM, mid) < 0x2) * we are early in the probe process and don't have the
* MACB_CAPS_MACB_IS_GEM flag positioned
*/
if (!macb_is_gem_hw(mem))
return; return;
/* bit 0 is never set but queue 0 always exists */ /* bit 0 is never set but queue 0 always exists */
...@@ -2177,59 +2181,73 @@ static void macb_probe_queues(void __iomem *mem, ...@@ -2177,59 +2181,73 @@ static void macb_probe_queues(void __iomem *mem,
(*num_queues)++; (*num_queues)++;
} }
static int macb_init(struct platform_device *pdev) static int macb_clk_init(struct platform_device *pdev, struct clk **pclk,
struct clk **hclk, struct clk **tx_clk)
{ {
struct net_device *dev = platform_get_drvdata(pdev);
unsigned int hw_q, queue_mask, q, num_queues;
struct macb *bp = netdev_priv(dev);
struct macb_queue *queue;
int err; int err;
u32 val;
bp->pclk = devm_clk_get(&pdev->dev, "pclk"); *pclk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(bp->pclk)) { if (IS_ERR(*pclk)) {
err = PTR_ERR(bp->pclk); err = PTR_ERR(*pclk);
dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", err); dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", err);
return err; return err;
} }
bp->hclk = devm_clk_get(&pdev->dev, "hclk"); *hclk = devm_clk_get(&pdev->dev, "hclk");
if (IS_ERR(bp->hclk)) { if (IS_ERR(*hclk)) {
err = PTR_ERR(bp->hclk); err = PTR_ERR(*hclk);
dev_err(&pdev->dev, "failed to get hclk (%u)\n", err); dev_err(&pdev->dev, "failed to get hclk (%u)\n", err);
return err; return err;
} }
bp->tx_clk = devm_clk_get(&pdev->dev, "tx_clk"); *tx_clk = devm_clk_get(&pdev->dev, "tx_clk");
if (IS_ERR(bp->tx_clk)) if (IS_ERR(*tx_clk))
bp->tx_clk = NULL; *tx_clk = NULL;
err = clk_prepare_enable(bp->pclk); err = clk_prepare_enable(*pclk);
if (err) { if (err) {
dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err); dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err);
return err; return err;
} }
err = clk_prepare_enable(bp->hclk); err = clk_prepare_enable(*hclk);
if (err) { if (err) {
dev_err(&pdev->dev, "failed to enable hclk (%u)\n", err); dev_err(&pdev->dev, "failed to enable hclk (%u)\n", err);
goto err_disable_pclk; goto err_disable_pclk;
} }
err = clk_prepare_enable(bp->tx_clk); err = clk_prepare_enable(*tx_clk);
if (err) { if (err) {
dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err); dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
goto err_disable_hclk; goto err_disable_hclk;
} }
return 0;
err_disable_hclk:
clk_disable_unprepare(*hclk);
err_disable_pclk:
clk_disable_unprepare(*pclk);
return err;
}
static int macb_init(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
unsigned int hw_q, q;
struct macb *bp = netdev_priv(dev);
struct macb_queue *queue;
int err;
u32 val;
/* set the queue register mapping once for all: queue0 has a special /* set the queue register mapping once for all: queue0 has a special
* register mapping but we don't want to test the queue index then * register mapping but we don't want to test the queue index then
* compute the corresponding register offset at run time. * compute the corresponding register offset at run time.
*/ */
macb_probe_queues(bp->regs, &queue_mask, &num_queues);
for (hw_q = 0, q = 0; hw_q < MACB_MAX_QUEUES; ++hw_q) { for (hw_q = 0, q = 0; hw_q < MACB_MAX_QUEUES; ++hw_q) {
if (!(queue_mask & (1 << hw_q))) if (!(bp->queue_mask & (1 << hw_q)))
continue; continue;
queue = &bp->queues[q]; queue = &bp->queues[q];
...@@ -2261,7 +2279,7 @@ static int macb_init(struct platform_device *pdev) ...@@ -2261,7 +2279,7 @@ static int macb_init(struct platform_device *pdev)
dev_err(&pdev->dev, dev_err(&pdev->dev,
"Unable to request IRQ %d (error %d)\n", "Unable to request IRQ %d (error %d)\n",
queue->irq, err); queue->irq, err);
goto err_disable_tx_clk; return err;
} }
INIT_WORK(&queue->tx_error_task, macb_tx_error_task); INIT_WORK(&queue->tx_error_task, macb_tx_error_task);
...@@ -2311,26 +2329,12 @@ static int macb_init(struct platform_device *pdev) ...@@ -2311,26 +2329,12 @@ static int macb_init(struct platform_device *pdev)
macb_or_gem_writel(bp, USRIO, val); macb_or_gem_writel(bp, USRIO, val);
/* setup capacities */
macb_configure_caps(bp);
/* Set MII management clock divider */ /* Set MII management clock divider */
val = macb_mdc_clk_div(bp); val = macb_mdc_clk_div(bp);
val |= macb_dbw(bp); val |= macb_dbw(bp);
macb_writel(bp, NCFGR, val); macb_writel(bp, NCFGR, val);
return 0; return 0;
err_disable_tx_clk:
clk_disable_unprepare(bp->tx_clk);
err_disable_hclk:
clk_disable_unprepare(bp->hclk);
err_disable_pclk:
clk_disable_unprepare(bp->pclk);
return err;
} }
#if defined(CONFIG_OF) #if defined(CONFIG_OF)
...@@ -2598,30 +2602,41 @@ static const struct net_device_ops at91ether_netdev_ops = { ...@@ -2598,30 +2602,41 @@ static const struct net_device_ops at91ether_netdev_ops = {
#endif #endif
}; };
static int at91ether_init(struct platform_device *pdev) static int at91ether_clk_init(struct platform_device *pdev, struct clk **pclk,
struct clk **hclk, struct clk **tx_clk)
{ {
struct net_device *dev = platform_get_drvdata(pdev);
struct macb *bp = netdev_priv(dev);
int err; int err;
u32 reg;
bp->pclk = devm_clk_get(&pdev->dev, "ether_clk"); *hclk = NULL;
if (IS_ERR(bp->pclk)) *tx_clk = NULL;
return PTR_ERR(bp->pclk);
*pclk = devm_clk_get(&pdev->dev, "ether_clk");
if (IS_ERR(*pclk))
return PTR_ERR(*pclk);
err = clk_prepare_enable(bp->pclk); err = clk_prepare_enable(*pclk);
if (err) { if (err) {
dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err); dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err);
return err; return err;
} }
return 0;
}
static int at91ether_init(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct macb *bp = netdev_priv(dev);
int err;
u32 reg;
dev->netdev_ops = &at91ether_netdev_ops; dev->netdev_ops = &at91ether_netdev_ops;
dev->ethtool_ops = &macb_ethtool_ops; dev->ethtool_ops = &macb_ethtool_ops;
err = devm_request_irq(&pdev->dev, dev->irq, at91ether_interrupt, err = devm_request_irq(&pdev->dev, dev->irq, at91ether_interrupt,
0, dev->name, dev); 0, dev->name, dev);
if (err) if (err)
goto err_disable_clk; return err;
macb_writel(bp, NCR, 0); macb_writel(bp, NCR, 0);
...@@ -2632,37 +2647,37 @@ static int at91ether_init(struct platform_device *pdev) ...@@ -2632,37 +2647,37 @@ static int at91ether_init(struct platform_device *pdev)
macb_writel(bp, NCFGR, reg); macb_writel(bp, NCFGR, reg);
return 0; return 0;
err_disable_clk:
clk_disable_unprepare(bp->pclk);
return err;
} }
static const struct macb_config at91sam9260_config = { static const struct macb_config at91sam9260_config = {
.caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII, .caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII,
.clk_init = macb_clk_init,
.init = macb_init, .init = macb_init,
}; };
static const struct macb_config pc302gem_config = { static const struct macb_config pc302gem_config = {
.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE, .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
.dma_burst_length = 16, .dma_burst_length = 16,
.clk_init = macb_clk_init,
.init = macb_init, .init = macb_init,
}; };
static const struct macb_config sama5d3_config = { static const struct macb_config sama5d3_config = {
.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE, .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
.dma_burst_length = 16, .dma_burst_length = 16,
.clk_init = macb_clk_init,
.init = macb_init, .init = macb_init,
}; };
static const struct macb_config sama5d4_config = { static const struct macb_config sama5d4_config = {
.caps = 0, .caps = 0,
.dma_burst_length = 4, .dma_burst_length = 4,
.clk_init = macb_clk_init,
.init = macb_init, .init = macb_init,
}; };
static const struct macb_config emac_config = { static const struct macb_config emac_config = {
.clk_init = at91ether_clk_init,
.init = at91ether_init, .init = at91ether_init,
}; };
...@@ -2683,9 +2698,13 @@ MODULE_DEVICE_TABLE(of, macb_dt_ids); ...@@ -2683,9 +2698,13 @@ MODULE_DEVICE_TABLE(of, macb_dt_ids);
static int macb_probe(struct platform_device *pdev) static int macb_probe(struct platform_device *pdev)
{ {
int (*clk_init)(struct platform_device *, struct clk **,
struct clk **, struct clk **)
= macb_clk_init;
int (*init)(struct platform_device *) = macb_init; int (*init)(struct platform_device *) = macb_init;
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
const struct macb_config *macb_config = NULL; const struct macb_config *macb_config = NULL;
struct clk *pclk, *hclk, *tx_clk;
unsigned int queue_mask, num_queues; unsigned int queue_mask, num_queues;
struct macb_platform_data *pdata; struct macb_platform_data *pdata;
struct phy_device *phydev; struct phy_device *phydev;
...@@ -2696,15 +2715,34 @@ static int macb_probe(struct platform_device *pdev) ...@@ -2696,15 +2715,34 @@ static int macb_probe(struct platform_device *pdev)
struct macb *bp; struct macb *bp;
int err; int err;
if (np) {
const struct of_device_id *match;
match = of_match_node(macb_dt_ids, np);
if (match && match->data) {
macb_config = match->data;
clk_init = macb_config->clk_init;
init = macb_config->init;
}
}
err = clk_init(pdev, &pclk, &hclk, &tx_clk);
if (err)
return err;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mem = devm_ioremap_resource(&pdev->dev, regs); mem = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(mem)) if (IS_ERR(mem)) {
return PTR_ERR(mem); err = PTR_ERR(mem);
goto err_disable_clocks;
}
macb_probe_queues(mem, &queue_mask, &num_queues); macb_probe_queues(mem, &queue_mask, &num_queues);
dev = alloc_etherdev_mq(sizeof(*bp), num_queues); dev = alloc_etherdev_mq(sizeof(*bp), num_queues);
if (!dev) if (!dev) {
return -ENOMEM; err = -ENOMEM;
goto err_disable_clocks;
}
dev->base_addr = regs->start; dev->base_addr = regs->start;
...@@ -2715,13 +2753,24 @@ static int macb_probe(struct platform_device *pdev) ...@@ -2715,13 +2753,24 @@ static int macb_probe(struct platform_device *pdev)
bp->dev = dev; bp->dev = dev;
bp->regs = mem; bp->regs = mem;
bp->num_queues = num_queues; bp->num_queues = num_queues;
bp->queue_mask = queue_mask;
if (macb_config)
bp->dma_burst_length = macb_config->dma_burst_length;
bp->pclk = pclk;
bp->hclk = hclk;
bp->tx_clk = tx_clk;
spin_lock_init(&bp->lock); spin_lock_init(&bp->lock);
/* setup capabilities */
macb_configure_caps(bp, macb_config);
platform_set_drvdata(pdev, dev); platform_set_drvdata(pdev, dev);
dev->irq = platform_get_irq(pdev, 0); dev->irq = platform_get_irq(pdev, 0);
if (dev->irq < 0) if (dev->irq < 0) {
return dev->irq; err = dev->irq;
goto err_disable_clocks;
}
mac = of_get_mac_address(np); mac = of_get_mac_address(np);
if (mac) if (mac)
...@@ -2740,20 +2789,6 @@ static int macb_probe(struct platform_device *pdev) ...@@ -2740,20 +2789,6 @@ static int macb_probe(struct platform_device *pdev)
bp->phy_interface = err; bp->phy_interface = err;
} }
if (np) {
const struct of_device_id *match;
match = of_match_node(macb_dt_ids, np);
if (match)
macb_config = match->data;
}
if (macb_config) {
bp->caps = macb_config->caps;
bp->dma_burst_length = macb_config->dma_burst_length;
init = macb_config->init;
}
/* IP specific init */ /* IP specific init */
err = init(pdev); err = init(pdev);
if (err) if (err)
...@@ -2762,7 +2797,7 @@ static int macb_probe(struct platform_device *pdev) ...@@ -2762,7 +2797,7 @@ static int macb_probe(struct platform_device *pdev)
err = register_netdev(dev); err = register_netdev(dev);
if (err) { if (err) {
dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
goto err_disable_clocks; goto err_out_unregister_netdev;
} }
err = macb_mii_init(bp); err = macb_mii_init(bp);
...@@ -2784,14 +2819,14 @@ static int macb_probe(struct platform_device *pdev) ...@@ -2784,14 +2819,14 @@ static int macb_probe(struct platform_device *pdev)
err_out_unregister_netdev: err_out_unregister_netdev:
unregister_netdev(dev); unregister_netdev(dev);
err_disable_clocks:
clk_disable_unprepare(bp->tx_clk);
clk_disable_unprepare(bp->hclk);
clk_disable_unprepare(bp->pclk);
err_out_free_netdev: err_out_free_netdev:
free_netdev(dev); free_netdev(dev);
err_disable_clocks:
clk_disable_unprepare(tx_clk);
clk_disable_unprepare(hclk);
clk_disable_unprepare(pclk);
return err; return err;
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#define _MACB_H #define _MACB_H
#define MACB_GREGS_NBR 16 #define MACB_GREGS_NBR 16
#define MACB_GREGS_VERSION 1 #define MACB_GREGS_VERSION 2
#define MACB_MAX_QUEUES 8 #define MACB_MAX_QUEUES 8
/* MACB register offsets */ /* MACB register offsets */
...@@ -754,6 +754,8 @@ struct macb_or_gem_ops { ...@@ -754,6 +754,8 @@ struct macb_or_gem_ops {
struct macb_config { struct macb_config {
u32 caps; u32 caps;
unsigned int dma_burst_length; unsigned int dma_burst_length;
int (*clk_init)(struct platform_device *pdev, struct clk **pclk,
struct clk **hclk, struct clk **tx_clk);
int (*init)(struct platform_device *pdev); int (*init)(struct platform_device *pdev);
}; };
...@@ -785,6 +787,7 @@ struct macb { ...@@ -785,6 +787,7 @@ struct macb {
size_t rx_buffer_size; size_t rx_buffer_size;
unsigned int num_queues; unsigned int num_queues;
unsigned int queue_mask;
struct macb_queue queues[MACB_MAX_QUEUES]; struct macb_queue queues[MACB_MAX_QUEUES];
spinlock_t lock; spinlock_t lock;
...@@ -830,4 +833,9 @@ static inline bool macb_is_gem(struct macb *bp) ...@@ -830,4 +833,9 @@ static inline bool macb_is_gem(struct macb *bp)
return !!(bp->caps & MACB_CAPS_MACB_IS_GEM); return !!(bp->caps & MACB_CAPS_MACB_IS_GEM);
} }
static inline bool macb_is_gem_hw(void __iomem *addr)
{
return !!(MACB_BFEXT(IDNUM, readl_relaxed(addr + MACB_MID)) >= 0x2);
}
#endif /* _MACB_H */ #endif /* _MACB_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment