1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* Copyright 2019 NXP */
#include <linux/fsl/enetc_mdio.h>
#include <linux/of_mdio.h>
#include "enetc_pf.h"
#define NETC_EMDIO_VEN_ID 0x1131
#define NETC_EMDIO_DEV_ID 0xee00
#define ENETC_MDIO_DEV_ID 0xee01
#define ENETC_MDIO_DEV_NAME "FSL PCIe IE Central MDIO"
#define ENETC_MDIO_BUS_NAME ENETC_MDIO_DEV_NAME " Bus"
#define ENETC_MDIO_DRV_NAME ENETC_MDIO_DEV_NAME " driver"
DEFINE_STATIC_KEY_FALSE(enetc_has_err050089);
EXPORT_SYMBOL_GPL(enetc_has_err050089);
static void enetc_emdio_enable_err050089(struct pci_dev *pdev)
{
if (pdev->vendor == PCI_VENDOR_ID_FREESCALE &&
pdev->device == ENETC_MDIO_DEV_ID) {
static_branch_inc(&enetc_has_err050089);
dev_info(&pdev->dev, "Enabled ERR050089 workaround\n");
}
}
static void enetc_emdio_disable_err050089(struct pci_dev *pdev)
{
if (pdev->vendor == PCI_VENDOR_ID_FREESCALE &&
pdev->device == ENETC_MDIO_DEV_ID) {
static_branch_dec(&enetc_has_err050089);
if (!static_key_enabled(&enetc_has_err050089.key))
dev_info(&pdev->dev, "Disabled ERR050089 workaround\n");
}
}
static int enetc_pci_mdio_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct enetc_mdio_priv *mdio_priv;
struct device *dev = &pdev->dev;
void __iomem *port_regs;
struct enetc_hw *hw;
struct mii_bus *bus;
int err;
port_regs = pci_iomap(pdev, 0, 0);
if (!port_regs) {
dev_err(dev, "iomap failed\n");
err = -ENXIO;
goto err_ioremap;
}
hw = enetc_hw_alloc(dev, port_regs);
if (IS_ERR(hw)) {
err = PTR_ERR(hw);
goto err_hw_alloc;
}
bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
if (!bus) {
err = -ENOMEM;
goto err_mdiobus_alloc;
}
bus->name = ENETC_MDIO_BUS_NAME;
bus->read = enetc_mdio_read_c22;
bus->write = enetc_mdio_write_c22;
bus->read_c45 = enetc_mdio_read_c45;
bus->write_c45 = enetc_mdio_write_c45;
bus->parent = dev;
mdio_priv = bus->priv;
mdio_priv->hw = hw;
mdio_priv->mdio_base = ENETC_EMDIO_BASE;
snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
pcie_flr(pdev);
err = pci_enable_device_mem(pdev);
if (err) {
dev_err(dev, "device enable failed\n");
goto err_pci_enable;
}
err = pci_request_region(pdev, 0, KBUILD_MODNAME);
if (err) {
dev_err(dev, "pci_request_region failed\n");
goto err_pci_mem_reg;
}
enetc_emdio_enable_err050089(pdev);
err = of_mdiobus_register(bus, dev->of_node);
if (err)
goto err_mdiobus_reg;
pci_set_drvdata(pdev, bus);
return 0;
err_mdiobus_reg:
enetc_emdio_disable_err050089(pdev);
pci_release_region(pdev, 0);
err_pci_mem_reg:
pci_disable_device(pdev);
err_pci_enable:
err_mdiobus_alloc:
err_hw_alloc:
iounmap(port_regs);
err_ioremap:
return err;
}
static void enetc_pci_mdio_remove(struct pci_dev *pdev)
{
struct mii_bus *bus = pci_get_drvdata(pdev);
struct enetc_mdio_priv *mdio_priv;
mdiobus_unregister(bus);
enetc_emdio_disable_err050089(pdev);
mdio_priv = bus->priv;
iounmap(mdio_priv->hw->port);
pci_release_region(pdev, 0);
pci_disable_device(pdev);
}
static const struct pci_device_id enetc_pci_mdio_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_MDIO_DEV_ID) },
{ PCI_DEVICE(NETC_EMDIO_VEN_ID, NETC_EMDIO_DEV_ID) },
{ 0, } /* End of table. */
};
MODULE_DEVICE_TABLE(pci, enetc_pci_mdio_id_table);
static struct pci_driver enetc_pci_mdio_driver = {
.name = KBUILD_MODNAME,
.id_table = enetc_pci_mdio_id_table,
.probe = enetc_pci_mdio_probe,
.remove = enetc_pci_mdio_remove,
};
module_pci_driver(enetc_pci_mdio_driver);
MODULE_DESCRIPTION(ENETC_MDIO_DRV_NAME);
MODULE_LICENSE("Dual BSD/GPL");
|