aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcin Wojtas <mw@semihalf.com>2018-01-18 07:31:44 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-22 10:57:04 -0500
commita75edc7c2eab329d20a4ffbbfb15f2aa4a95454f (patch)
treebab754e71353c6b87dbb51cb9c32f57d9e97290c
parent248122212f68dcf13433ec56bb03ddc799259026 (diff)
net: mvpp2: enable ACPI support in the driver
This patch introduces an alternative way of obtaining resources - via ACPI tables provided by firmware. Enabling coexistence with the DT support, in addition to the OF_*->device_*/fwnode_* API replacement, required following steps to be taken: * Add mvpp2_acpi_match table * Omit clock configuration and obtain tclk from the property - in ACPI world, the firmware is responsible for clock maintenance. * Disable comphy and syscon handling as they are not available for ACPI. * Modify way of obtaining interrupts - use newly introduced fwnode_irq_get() routine * Until proper MDIO bus and PHY handling with ACPI is established in the kernel, use only link interrupts feature in the driver. For the RGMII port it results in depending on GMAC settings done during firmware stage. * When booting with ACPI MVPP2_QDIST_MULTI_MODE is picked by default, as there is no need to keep any kind of the backward compatibility. Moreover, a memory region used by mvmdio driver is usually placed in the middle of the address space of the PP2 network controller. The MDIO base address is obtained without requesting memory region (by devm_ioremap() call) in mvmdio.c, later overlapping resources are requested by the network driver, which is responsible for avoiding a concurrent access. In case the MDIO memory region is declared in the ACPI, it can already appear as 'in-use' in the OS. Because it is overlapped by second region of the network controller, make sure it is released, before requesting it again. The care is taken by mvpp2 driver to avoid concurrent access to this memory region. Signed-off-by: Marcin Wojtas <mw@semihalf.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/marvell/mvpp2.c133
1 files changed, 94 insertions, 39 deletions
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index f16448e47dc8..a1d7b88cf083 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -10,6 +10,7 @@
10 * warranty of any kind, whether express or implied. 10 * warranty of any kind, whether express or implied.
11 */ 11 */
12 12
13#include <linux/acpi.h>
13#include <linux/kernel.h> 14#include <linux/kernel.h>
14#include <linux/netdevice.h> 15#include <linux/netdevice.h>
15#include <linux/etherdevice.h> 16#include <linux/etherdevice.h>
@@ -7502,7 +7503,10 @@ static int mvpp2_multi_queue_vectors_init(struct mvpp2_port *port,
7502 strncpy(irqname, "rx-shared", sizeof(irqname)); 7503 strncpy(irqname, "rx-shared", sizeof(irqname));
7503 } 7504 }
7504 7505
7505 v->irq = of_irq_get_byname(port_node, irqname); 7506 if (port_node)
7507 v->irq = of_irq_get_byname(port_node, irqname);
7508 else
7509 v->irq = fwnode_irq_get(port->fwnode, i);
7506 if (v->irq <= 0) { 7510 if (v->irq <= 0) {
7507 ret = -EINVAL; 7511 ret = -EINVAL;
7508 goto err; 7512 goto err;
@@ -7746,7 +7750,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
7746 struct mvpp2 *priv) 7750 struct mvpp2 *priv)
7747{ 7751{
7748 struct device_node *phy_node; 7752 struct device_node *phy_node;
7749 struct phy *comphy; 7753 struct phy *comphy = NULL;
7750 struct mvpp2_port *port; 7754 struct mvpp2_port *port;
7751 struct mvpp2_port_pcpu *port_pcpu; 7755 struct mvpp2_port_pcpu *port_pcpu;
7752 struct device_node *port_node = to_of_node(port_fwnode); 7756 struct device_node *port_node = to_of_node(port_fwnode);
@@ -7760,7 +7764,12 @@ static int mvpp2_port_probe(struct platform_device *pdev,
7760 int phy_mode; 7764 int phy_mode;
7761 int err, i, cpu; 7765 int err, i, cpu;
7762 7766
7763 has_tx_irqs = mvpp2_port_has_tx_irqs(priv, port_node); 7767 if (port_node) {
7768 has_tx_irqs = mvpp2_port_has_tx_irqs(priv, port_node);
7769 } else {
7770 has_tx_irqs = true;
7771 queue_mode = MVPP2_QDIST_MULTI_MODE;
7772 }
7764 7773
7765 if (!has_tx_irqs) 7774 if (!has_tx_irqs)
7766 queue_mode = MVPP2_QDIST_SINGLE_MODE; 7775 queue_mode = MVPP2_QDIST_SINGLE_MODE;
@@ -7775,7 +7784,11 @@ static int mvpp2_port_probe(struct platform_device *pdev,
7775 if (!dev) 7784 if (!dev)
7776 return -ENOMEM; 7785 return -ENOMEM;
7777 7786
7778 phy_node = of_parse_phandle(port_node, "phy", 0); 7787 if (port_node)
7788 phy_node = of_parse_phandle(port_node, "phy", 0);
7789 else
7790 phy_node = NULL;
7791
7779 phy_mode = fwnode_get_phy_mode(port_fwnode); 7792 phy_mode = fwnode_get_phy_mode(port_fwnode);
7780 if (phy_mode < 0) { 7793 if (phy_mode < 0) {
7781 dev_err(&pdev->dev, "incorrect phy mode\n"); 7794 dev_err(&pdev->dev, "incorrect phy mode\n");
@@ -7783,13 +7796,15 @@ static int mvpp2_port_probe(struct platform_device *pdev,
7783 goto err_free_netdev; 7796 goto err_free_netdev;
7784 } 7797 }
7785 7798
7786 comphy = devm_of_phy_get(&pdev->dev, port_node, NULL); 7799 if (port_node) {
7787 if (IS_ERR(comphy)) { 7800 comphy = devm_of_phy_get(&pdev->dev, port_node, NULL);
7788 if (PTR_ERR(comphy) == -EPROBE_DEFER) { 7801 if (IS_ERR(comphy)) {
7789 err = -EPROBE_DEFER; 7802 if (PTR_ERR(comphy) == -EPROBE_DEFER) {
7790 goto err_free_netdev; 7803 err = -EPROBE_DEFER;
7804 goto err_free_netdev;
7805 }
7806 comphy = NULL;
7791 } 7807 }
7792 comphy = NULL;
7793 } 7808 }
7794 7809
7795 if (fwnode_property_read_u32(port_fwnode, "port-id", &id)) { 7810 if (fwnode_property_read_u32(port_fwnode, "port-id", &id)) {
@@ -7805,6 +7820,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
7805 7820
7806 port = netdev_priv(dev); 7821 port = netdev_priv(dev);
7807 port->dev = dev; 7822 port->dev = dev;
7823 port->fwnode = port_fwnode;
7808 port->ntxqs = ntxqs; 7824 port->ntxqs = ntxqs;
7809 port->nrxqs = nrxqs; 7825 port->nrxqs = nrxqs;
7810 port->priv = priv; 7826 port->priv = priv;
@@ -7814,7 +7830,10 @@ static int mvpp2_port_probe(struct platform_device *pdev,
7814 if (err) 7830 if (err)
7815 goto err_free_netdev; 7831 goto err_free_netdev;
7816 7832
7817 port->link_irq = of_irq_get_byname(port_node, "link"); 7833 if (port_node)
7834 port->link_irq = of_irq_get_byname(port_node, "link");
7835 else
7836 port->link_irq = fwnode_irq_get(port_fwnode, port->nqvecs + 1);
7818 if (port->link_irq == -EPROBE_DEFER) { 7837 if (port->link_irq == -EPROBE_DEFER) {
7819 err = -EPROBE_DEFER; 7838 err = -EPROBE_DEFER;
7820 goto err_deinit_qvecs; 7839 goto err_deinit_qvecs;
@@ -8197,6 +8216,7 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
8197 8216
8198static int mvpp2_probe(struct platform_device *pdev) 8217static int mvpp2_probe(struct platform_device *pdev)
8199{ 8218{
8219 const struct acpi_device_id *acpi_id;
8200 struct fwnode_handle *fwnode = pdev->dev.fwnode; 8220 struct fwnode_handle *fwnode = pdev->dev.fwnode;
8201 struct fwnode_handle *port_fwnode; 8221 struct fwnode_handle *port_fwnode;
8202 struct mvpp2 *priv; 8222 struct mvpp2 *priv;
@@ -8209,8 +8229,14 @@ static int mvpp2_probe(struct platform_device *pdev)
8209 if (!priv) 8229 if (!priv)
8210 return -ENOMEM; 8230 return -ENOMEM;
8211 8231
8212 priv->hw_version = 8232 if (has_acpi_companion(&pdev->dev)) {
8213 (unsigned long)of_device_get_match_data(&pdev->dev); 8233 acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
8234 &pdev->dev);
8235 priv->hw_version = (unsigned long)acpi_id->driver_data;
8236 } else {
8237 priv->hw_version =
8238 (unsigned long)of_device_get_match_data(&pdev->dev);
8239 }
8214 8240
8215 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 8241 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
8216 base = devm_ioremap_resource(&pdev->dev, res); 8242 base = devm_ioremap_resource(&pdev->dev, res);
@@ -8224,10 +8250,23 @@ static int mvpp2_probe(struct platform_device *pdev)
8224 return PTR_ERR(priv->lms_base); 8250 return PTR_ERR(priv->lms_base);
8225 } else { 8251 } else {
8226 res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 8252 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
8253 if (has_acpi_companion(&pdev->dev)) {
8254 /* In case the MDIO memory region is declared in
8255 * the ACPI, it can already appear as 'in-use'
8256 * in the OS. Because it is overlapped by second
8257 * region of the network controller, make
8258 * sure it is released, before requesting it again.
8259 * The care is taken by mvpp2 driver to avoid
8260 * concurrent access to this memory region.
8261 */
8262 release_resource(res);
8263 }
8227 priv->iface_base = devm_ioremap_resource(&pdev->dev, res); 8264 priv->iface_base = devm_ioremap_resource(&pdev->dev, res);
8228 if (IS_ERR(priv->iface_base)) 8265 if (IS_ERR(priv->iface_base))
8229 return PTR_ERR(priv->iface_base); 8266 return PTR_ERR(priv->iface_base);
8267 }
8230 8268
8269 if (priv->hw_version == MVPP22 && dev_of_node(&pdev->dev)) {
8231 priv->sysctrl_base = 8270 priv->sysctrl_base =
8232 syscon_regmap_lookup_by_phandle(pdev->dev.of_node, 8271 syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
8233 "marvell,system-controller"); 8272 "marvell,system-controller");
@@ -8253,32 +8292,34 @@ static int mvpp2_probe(struct platform_device *pdev)
8253 else 8292 else
8254 priv->max_port_rxqs = 32; 8293 priv->max_port_rxqs = 32;
8255 8294
8256 priv->pp_clk = devm_clk_get(&pdev->dev, "pp_clk"); 8295 if (dev_of_node(&pdev->dev)) {
8257 if (IS_ERR(priv->pp_clk)) 8296 priv->pp_clk = devm_clk_get(&pdev->dev, "pp_clk");
8258 return PTR_ERR(priv->pp_clk); 8297 if (IS_ERR(priv->pp_clk))
8259 err = clk_prepare_enable(priv->pp_clk); 8298 return PTR_ERR(priv->pp_clk);
8260 if (err < 0) 8299 err = clk_prepare_enable(priv->pp_clk);
8261 return err; 8300 if (err < 0)
8262 8301 return err;
8263 priv->gop_clk = devm_clk_get(&pdev->dev, "gop_clk");
8264 if (IS_ERR(priv->gop_clk)) {
8265 err = PTR_ERR(priv->gop_clk);
8266 goto err_pp_clk;
8267 }
8268 err = clk_prepare_enable(priv->gop_clk);
8269 if (err < 0)
8270 goto err_pp_clk;
8271 8302
8272 if (priv->hw_version == MVPP22) { 8303 priv->gop_clk = devm_clk_get(&pdev->dev, "gop_clk");
8273 priv->mg_clk = devm_clk_get(&pdev->dev, "mg_clk"); 8304 if (IS_ERR(priv->gop_clk)) {
8274 if (IS_ERR(priv->mg_clk)) { 8305 err = PTR_ERR(priv->gop_clk);
8275 err = PTR_ERR(priv->mg_clk); 8306 goto err_pp_clk;
8276 goto err_gop_clk;
8277 } 8307 }
8278 8308 err = clk_prepare_enable(priv->gop_clk);
8279 err = clk_prepare_enable(priv->mg_clk);
8280 if (err < 0) 8309 if (err < 0)
8281 goto err_gop_clk; 8310 goto err_pp_clk;
8311
8312 if (priv->hw_version == MVPP22) {
8313 priv->mg_clk = devm_clk_get(&pdev->dev, "mg_clk");
8314 if (IS_ERR(priv->mg_clk)) {
8315 err = PTR_ERR(priv->mg_clk);
8316 goto err_gop_clk;
8317 }
8318
8319 err = clk_prepare_enable(priv->mg_clk);
8320 if (err < 0)
8321 goto err_gop_clk;
8322 }
8282 8323
8283 priv->axi_clk = devm_clk_get(&pdev->dev, "axi_clk"); 8324 priv->axi_clk = devm_clk_get(&pdev->dev, "axi_clk");
8284 if (IS_ERR(priv->axi_clk)) { 8325 if (IS_ERR(priv->axi_clk)) {
@@ -8291,10 +8332,14 @@ static int mvpp2_probe(struct platform_device *pdev)
8291 if (err < 0) 8332 if (err < 0)
8292 goto err_gop_clk; 8333 goto err_gop_clk;
8293 } 8334 }
8294 }
8295 8335
8296 /* Get system's tclk rate */ 8336 /* Get system's tclk rate */
8297 priv->tclk = clk_get_rate(priv->pp_clk); 8337 priv->tclk = clk_get_rate(priv->pp_clk);
8338 } else if (device_property_read_u32(&pdev->dev, "clock-frequency",
8339 &priv->tclk)) {
8340 dev_err(&pdev->dev, "missing clock-frequency value\n");
8341 return -EINVAL;
8342 }
8298 8343
8299 if (priv->hw_version == MVPP22) { 8344 if (priv->hw_version == MVPP22) {
8300 err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(40)); 8345 err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(40));
@@ -8399,6 +8444,9 @@ static int mvpp2_remove(struct platform_device *pdev)
8399 aggr_txq->descs_dma); 8444 aggr_txq->descs_dma);
8400 } 8445 }
8401 8446
8447 if (is_acpi_node(port_fwnode))
8448 return 0;
8449
8402 clk_disable_unprepare(priv->axi_clk); 8450 clk_disable_unprepare(priv->axi_clk);
8403 clk_disable_unprepare(priv->mg_clk); 8451 clk_disable_unprepare(priv->mg_clk);
8404 clk_disable_unprepare(priv->pp_clk); 8452 clk_disable_unprepare(priv->pp_clk);
@@ -8420,12 +8468,19 @@ static const struct of_device_id mvpp2_match[] = {
8420}; 8468};
8421MODULE_DEVICE_TABLE(of, mvpp2_match); 8469MODULE_DEVICE_TABLE(of, mvpp2_match);
8422 8470
8471static const struct acpi_device_id mvpp2_acpi_match[] = {
8472 { "MRVL0110", MVPP22 },
8473 { },
8474};
8475MODULE_DEVICE_TABLE(acpi, mvpp2_acpi_match);
8476
8423static struct platform_driver mvpp2_driver = { 8477static struct platform_driver mvpp2_driver = {
8424 .probe = mvpp2_probe, 8478 .probe = mvpp2_probe,
8425 .remove = mvpp2_remove, 8479 .remove = mvpp2_remove,
8426 .driver = { 8480 .driver = {
8427 .name = MVPP2_DRIVER_NAME, 8481 .name = MVPP2_DRIVER_NAME,
8428 .of_match_table = mvpp2_match, 8482 .of_match_table = mvpp2_match,
8483 .acpi_match_table = ACPI_PTR(mvpp2_acpi_match),
8429 }, 8484 },
8430}; 8485};
8431 8486