Commit 35c891e1 authored by David S. Miller's avatar David S. Miller

Merge branch 'New-DSA-driver-for-VSC9953-Seville-switch'

Vladimir Oltean says:

====================
New DSA driver for VSC9953 Seville switch

Looking at the Felix and Ocelot drivers, Maxim asked if it would be
possible to use them as a base for a new driver for the Seville switch
inside NXP T1040. Turns out, it is! The result is that the mscc_felix
driver was extended to probe on Seville.

The biggest challenge seems to be getting register read/write API
generic enough to cover such wild bitfield variations between hardware
generations.

Currently, both felix and seville are built under the same kernel config
option (NET_DSA_MSCC_FELIX). This has both some advantages (no need to
duplicate the Lynx PCS code from felix_vsc9959.c) and some disadvantages
(Seville needs to depend on PCI and on ENETC_MDIO). This will be further
refined as time progresses.

The driver has been completely reviewed. Previous submission was here,
it wasn't accepted due to a conflict with Mark Brown's tree, very late
in the release cycle:

https://patchwork.ozlabs.org/project/netdev/cover/20200531122640.1375715-1-olteanv@gmail.com/

So this is more of a repost, with the only changes being related to
rebasing on top of the cleanup I had to do in Ocelot.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5d037b4d 77710929
...@@ -4,10 +4,15 @@ Microchip Ocelot switch driver family ...@@ -4,10 +4,15 @@ Microchip Ocelot switch driver family
Felix Felix
----- -----
The VSC9959 core is currently the only switch supported by the driver, and is Currently the switches supported by the felix driver are:
found in the NXP LS1028A. It is a PCI device, part of the larger ENETC root
complex. As a result, the ethernet-switch node is a sub-node of the PCIe root - VSC9959 (Felix)
complex node and its "reg" property conforms to the parent node bindings: - VSC9953 (Seville)
The VSC9959 switch is found in the NXP LS1028A. It is a PCI device, part of the
larger ENETC root complex. As a result, the ethernet-switch node is a sub-node
of the PCIe root complex node and its "reg" property conforms to the parent
node bindings:
* reg: Specifies PCIe Device Number and Function Number of the endpoint device, * reg: Specifies PCIe Device Number and Function Number of the endpoint device,
in this case for the Ethernet L2Switch it is PF5 (of device 0, bus 0). in this case for the Ethernet L2Switch it is PF5 (of device 0, bus 0).
...@@ -114,3 +119,95 @@ Example: ...@@ -114,3 +119,95 @@ Example:
}; };
}; };
}; };
The VSC9953 switch is found inside NXP T1040. It is a platform device with the
following required properties:
- compatible:
Must be "mscc,vsc9953-switch".
Supported PHY interface types (appropriate SerDes protocol setting changes are
needed in the RCW binary):
* phy_mode = "internal": on ports 8 and 9
* phy_mode = "sgmii": on ports 0, 1, 2, 3, 4, 5, 6, 7
* phy_mode = "qsgmii": on ports 0, 1, 2, 3, 4, 5, 6, 7
Example:
&soc {
ethernet-switch@800000 {
#address-cells = <0x1>;
#size-cells = <0x0>;
compatible = "mscc,vsc9953-switch";
little-endian;
reg = <0x800000 0x290000>;
ports {
#address-cells = <0x1>;
#size-cells = <0x0>;
port@0 {
reg = <0x0>;
label = "swp0";
};
port@1 {
reg = <0x1>;
label = "swp1";
};
port@2 {
reg = <0x2>;
label = "swp2";
};
port@3 {
reg = <0x3>;
label = "swp3";
};
port@4 {
reg = <0x4>;
label = "swp4";
};
port@5 {
reg = <0x5>;
label = "swp5";
};
port@6 {
reg = <0x6>;
label = "swp6";
};
port@7 {
reg = <0x7>;
label = "swp7";
};
port@8 {
reg = <0x8>;
phy-mode = "internal";
ethernet = <&enet0>;
fixed-link {
speed = <2500>;
full-duplex;
};
};
port@9 {
reg = <0x9>;
phy-mode = "internal";
status = "disabled";
fixed-link {
speed = <2500>;
full-duplex;
};
};
};
};
};
...@@ -10,7 +10,11 @@ config NET_DSA_MSCC_FELIX ...@@ -10,7 +10,11 @@ config NET_DSA_MSCC_FELIX
select NET_DSA_TAG_OCELOT select NET_DSA_TAG_OCELOT
select FSL_ENETC_MDIO select FSL_ENETC_MDIO
help help
This driver supports the VSC9959 network switch, which is a member of This driver supports network switches from the the Vitesse /
the Vitesse / Microsemi / Microchip Ocelot family of switching cores. Microsemi / Microchip Ocelot family of switching cores that are
It is embedded as a PCIe function of the NXP LS1028A ENETC integrated connected to their host CPU via Ethernet.
endpoint. The following switches are supported:
- VSC9959 (Felix): embedded as a PCIe function of the NXP LS1028A
ENETC integrated endpoint.
- VSC9953 (Seville): embedded as a platform device on the
NXP T1040 SoC.
...@@ -3,4 +3,5 @@ obj-$(CONFIG_NET_DSA_MSCC_FELIX) += mscc_felix.o ...@@ -3,4 +3,5 @@ obj-$(CONFIG_NET_DSA_MSCC_FELIX) += mscc_felix.o
mscc_felix-objs := \ mscc_felix-objs := \
felix.o \ felix.o \
felix_vsc9959.o felix_vsc9959.o \
seville_vsc9953.o
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* Copyright 2019 NXP Semiconductors /* Copyright 2019 NXP Semiconductors
*
* This is an umbrella module for all network switches that are
* register-compatible with Ocelot and that perform I/O to their host CPU
* through an NPI (Node Processor Interface) Ethernet port.
*/ */
#include <uapi/linux/if_bridge.h> #include <uapi/linux/if_bridge.h>
#include <soc/mscc/ocelot_vcap.h> #include <soc/mscc/ocelot_vcap.h>
...@@ -9,6 +13,7 @@ ...@@ -9,6 +13,7 @@
#include <soc/mscc/ocelot_ana.h> #include <soc/mscc/ocelot_ana.h>
#include <soc/mscc/ocelot_ptp.h> #include <soc/mscc/ocelot_ptp.h>
#include <soc/mscc/ocelot.h> #include <soc/mscc/ocelot.h>
#include <linux/platform_device.h>
#include <linux/packing.h> #include <linux/packing.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_net.h> #include <linux/of_net.h>
...@@ -185,37 +190,10 @@ static void felix_phylink_validate(struct dsa_switch *ds, int port, ...@@ -185,37 +190,10 @@ static void felix_phylink_validate(struct dsa_switch *ds, int port,
struct phylink_link_state *state) struct phylink_link_state *state)
{ {
struct ocelot *ocelot = ds->priv; struct ocelot *ocelot = ds->priv;
struct ocelot_port *ocelot_port = ocelot->ports[port]; struct felix *felix = ocelot_to_felix(ocelot);
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
if (state->interface != PHY_INTERFACE_MODE_NA &&
state->interface != ocelot_port->phy_mode) {
bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
return;
}
phylink_set_port_modes(mask);
phylink_set(mask, Autoneg);
phylink_set(mask, Pause);
phylink_set(mask, Asym_Pause);
phylink_set(mask, 10baseT_Half);
phylink_set(mask, 10baseT_Full);
phylink_set(mask, 100baseT_Half);
phylink_set(mask, 100baseT_Full);
phylink_set(mask, 1000baseT_Half);
phylink_set(mask, 1000baseT_Full);
if (state->interface == PHY_INTERFACE_MODE_INTERNAL ||
state->interface == PHY_INTERFACE_MODE_2500BASEX ||
state->interface == PHY_INTERFACE_MODE_USXGMII) {
phylink_set(mask, 2500baseT_Full);
phylink_set(mask, 2500baseX_Full);
}
bitmap_and(supported, supported, mask, if (felix->info->phylink_validate)
__ETHTOOL_LINK_MODE_MASK_NBITS); felix->info->phylink_validate(ocelot, port, supported, state);
bitmap_and(state->advertising, state->advertising, mask,
__ETHTOOL_LINK_MODE_MASK_NBITS);
} }
static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port, static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port,
...@@ -249,8 +227,7 @@ static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, ...@@ -249,8 +227,7 @@ static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port,
struct ocelot_port *ocelot_port = ocelot->ports[port]; struct ocelot_port *ocelot_port = ocelot->ports[port];
ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG);
ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, ocelot_fields_write(ocelot, port, QSYS_SWITCH_PORT_MODE_PORT_ENA, 0);
QSYS_SWITCH_PORT_MODE, port);
} }
static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
...@@ -326,10 +303,8 @@ static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, ...@@ -326,10 +303,8 @@ static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
ANA_PORT_PORT_CFG, port); ANA_PORT_PORT_CFG, port);
/* Core: Enable port for frame transfer */ /* Core: Enable port for frame transfer */
ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | ocelot_fields_write(ocelot, port,
QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | QSYS_SWITCH_PORT_MODE_PORT_ENA, 1);
QSYS_SWITCH_PORT_MODE_PORT_ENA,
QSYS_SWITCH_PORT_MODE, port);
if (felix->info->pcs_link_up) if (felix->info->pcs_link_up)
felix->info->pcs_link_up(ocelot, port, link_an_mode, interface, felix->info->pcs_link_up(ocelot, port, link_an_mode, interface,
...@@ -459,7 +434,6 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) ...@@ -459,7 +434,6 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
{ {
struct ocelot *ocelot = &felix->ocelot; struct ocelot *ocelot = &felix->ocelot;
phy_interface_t *port_phy_modes; phy_interface_t *port_phy_modes;
resource_size_t switch_base;
struct resource res; struct resource res;
int port, i, err; int port, i, err;
...@@ -490,9 +464,6 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) ...@@ -490,9 +464,6 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
return err; return err;
} }
switch_base = pci_resource_start(felix->pdev,
felix->info->switch_pci_bar);
for (i = 0; i < TARGET_MAX; i++) { for (i = 0; i < TARGET_MAX; i++) {
struct regmap *target; struct regmap *target;
...@@ -501,8 +472,8 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) ...@@ -501,8 +472,8 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
memcpy(&res, &felix->info->target_io_res[i], sizeof(res)); memcpy(&res, &felix->info->target_io_res[i], sizeof(res));
res.flags = IORESOURCE_MEM; res.flags = IORESOURCE_MEM;
res.start += switch_base; res.start += felix->switch_base;
res.end += switch_base; res.end += felix->switch_base;
target = ocelot_regmap_init(ocelot, &res); target = ocelot_regmap_init(ocelot, &res);
if (IS_ERR(target)) { if (IS_ERR(target)) {
...@@ -524,7 +495,8 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) ...@@ -524,7 +495,8 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
for (port = 0; port < num_phys_ports; port++) { for (port = 0; port < num_phys_ports; port++) {
struct ocelot_port *ocelot_port; struct ocelot_port *ocelot_port;
void __iomem *port_regs; struct regmap *target;
u8 *template;
ocelot_port = devm_kzalloc(ocelot->dev, ocelot_port = devm_kzalloc(ocelot->dev,
sizeof(struct ocelot_port), sizeof(struct ocelot_port),
...@@ -538,21 +510,34 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) ...@@ -538,21 +510,34 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
memcpy(&res, &felix->info->port_io_res[port], sizeof(res)); memcpy(&res, &felix->info->port_io_res[port], sizeof(res));
res.flags = IORESOURCE_MEM; res.flags = IORESOURCE_MEM;
res.start += switch_base; res.start += felix->switch_base;
res.end += switch_base; res.end += felix->switch_base;
port_regs = devm_ioremap_resource(ocelot->dev, &res); target = ocelot_regmap_init(ocelot, &res);
if (IS_ERR(port_regs)) { if (IS_ERR(target)) {
dev_err(ocelot->dev, dev_err(ocelot->dev,
"failed to map registers for port %d\n", port); "Failed to map memory space for port %d\n",
port);
kfree(port_phy_modes); kfree(port_phy_modes);
return PTR_ERR(port_regs); return PTR_ERR(target);
}
template = devm_kzalloc(ocelot->dev, OCELOT_TAG_LEN,
GFP_KERNEL);
if (!template) {
dev_err(ocelot->dev,
"Failed to allocate memory for DSA tag\n");
kfree(port_phy_modes);
return -ENOMEM;
} }
ocelot_port->phy_mode = port_phy_modes[port]; ocelot_port->phy_mode = port_phy_modes[port];
ocelot_port->ocelot = ocelot; ocelot_port->ocelot = ocelot;
ocelot_port->regs = port_regs; ocelot_port->target = target;
ocelot_port->xmit_template = template;
ocelot->ports[port] = ocelot_port; ocelot->ports[port] = ocelot_port;
felix->info->xmit_template_populate(ocelot, port);
} }
kfree(port_phy_modes); kfree(port_phy_modes);
...@@ -791,7 +776,7 @@ static int felix_port_setup_tc(struct dsa_switch *ds, int port, ...@@ -791,7 +776,7 @@ static int felix_port_setup_tc(struct dsa_switch *ds, int port,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static const struct dsa_switch_ops felix_switch_ops = { const struct dsa_switch_ops felix_switch_ops = {
.get_tag_protocol = felix_get_tag_protocol, .get_tag_protocol = felix_get_tag_protocol,
.setup = felix_setup, .setup = felix_setup,
.teardown = felix_teardown, .teardown = felix_teardown,
...@@ -834,149 +819,28 @@ static const struct dsa_switch_ops felix_switch_ops = { ...@@ -834,149 +819,28 @@ static const struct dsa_switch_ops felix_switch_ops = {
.port_setup_tc = felix_port_setup_tc, .port_setup_tc = felix_port_setup_tc,
}; };
static struct felix_info *felix_instance_tbl[] = { static int __init felix_init(void)
[FELIX_INSTANCE_VSC9959] = &felix_info_vsc9959,
};
static irqreturn_t felix_irq_handler(int irq, void *data)
{ {
struct ocelot *ocelot = (struct ocelot *)data;
/* The INTB interrupt is used for both PTP TX timestamp interrupt
* and preemption status change interrupt on each port.
*
* - Get txtstamp if have
* - TODO: handle preemption. Without handling it, driver may get
* interrupt storm.
*/
ocelot_get_txtstamp(ocelot);
return IRQ_HANDLED;
}
static int felix_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
enum felix_instance instance = id->driver_data;
struct dsa_switch *ds;
struct ocelot *ocelot;
struct felix *felix;
int err; int err;
if (pdev->dev.of_node && !of_device_is_available(pdev->dev.of_node)) { err = pci_register_driver(&felix_vsc9959_pci_driver);
dev_info(&pdev->dev, "device is disabled, skipping\n"); if (err)
return -ENODEV; return err;
}
err = pci_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "device enable failed\n");
goto err_pci_enable;
}
/* set up for high or low dma */
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
if (err) {
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (err) {
dev_err(&pdev->dev,
"DMA configuration failed: 0x%x\n", err);
goto err_dma;
}
}
felix = kzalloc(sizeof(struct felix), GFP_KERNEL);
if (!felix) {
err = -ENOMEM;
dev_err(&pdev->dev, "Failed to allocate driver memory\n");
goto err_alloc_felix;
}
pci_set_drvdata(pdev, felix);
ocelot = &felix->ocelot;
ocelot->dev = &pdev->dev;
felix->pdev = pdev;
felix->info = felix_instance_tbl[instance];
pci_set_master(pdev);
err = devm_request_threaded_irq(&pdev->dev, pdev->irq, NULL,
&felix_irq_handler, IRQF_ONESHOT,
"felix-intb", ocelot);
if (err) {
dev_err(&pdev->dev, "Failed to request irq\n");
goto err_alloc_irq;
}
ocelot->ptp = 1;
ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL);
if (!ds) {
err = -ENOMEM;
dev_err(&pdev->dev, "Failed to allocate DSA switch\n");
goto err_alloc_ds;
}
ds->dev = &pdev->dev;
ds->num_ports = felix->info->num_ports;
ds->num_tx_queues = felix->info->num_tx_queues;
ds->ops = &felix_switch_ops;
ds->priv = ocelot;
felix->ds = ds;
err = dsa_register_switch(ds); err = platform_driver_register(&seville_vsc9953_driver);
if (err) { if (err)
dev_err(&pdev->dev, "Failed to register DSA switch: %d\n", err); return err;
goto err_register_ds;
}
return 0; return 0;
err_register_ds:
kfree(ds);
err_alloc_ds:
err_alloc_irq:
err_alloc_felix:
kfree(felix);
err_dma:
pci_disable_device(pdev);
err_pci_enable:
return err;
} }
module_init(felix_init);
static void felix_pci_remove(struct pci_dev *pdev) static void __exit felix_exit(void)
{ {
struct felix *felix; pci_unregister_driver(&felix_vsc9959_pci_driver);
platform_driver_unregister(&seville_vsc9953_driver);
felix = pci_get_drvdata(pdev);
dsa_unregister_switch(felix->ds);
kfree(felix->ds);
kfree(felix);
pci_disable_device(pdev);
} }
module_exit(felix_exit);
static struct pci_device_id felix_ids[] = {
{
/* NXP LS1028A */
PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0xEEF0),
.driver_data = FELIX_INSTANCE_VSC9959,
},
{ 0, }
};
MODULE_DEVICE_TABLE(pci, felix_ids);
static struct pci_driver felix_pci_driver = {
.name = KBUILD_MODNAME,
.id_table = felix_ids,
.probe = felix_pci_probe,
.remove = felix_pci_remove,
};
module_pci_driver(felix_pci_driver);
MODULE_DESCRIPTION("Felix Switch driver"); MODULE_DESCRIPTION("Felix Switch driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -37,28 +37,42 @@ struct felix_info { ...@@ -37,28 +37,42 @@ struct felix_info {
int speed, int duplex); int speed, int duplex);
void (*pcs_link_state)(struct ocelot *ocelot, int port, void (*pcs_link_state)(struct ocelot *ocelot, int port,
struct phylink_link_state *state); struct phylink_link_state *state);
void (*phylink_validate)(struct ocelot *ocelot, int port,
unsigned long *supported,
struct phylink_link_state *state);
int (*prevalidate_phy_mode)(struct ocelot *ocelot, int port, int (*prevalidate_phy_mode)(struct ocelot *ocelot, int port,
phy_interface_t phy_mode); phy_interface_t phy_mode);
int (*port_setup_tc)(struct dsa_switch *ds, int port, int (*port_setup_tc)(struct dsa_switch *ds, int port,
enum tc_setup_type type, void *type_data); enum tc_setup_type type, void *type_data);
void (*port_sched_speed_set)(struct ocelot *ocelot, int port, void (*port_sched_speed_set)(struct ocelot *ocelot, int port,
u32 speed); u32 speed);
void (*xmit_template_populate)(struct ocelot *ocelot, int port);
}; };
extern struct felix_info felix_info_vsc9959; extern const struct dsa_switch_ops felix_switch_ops;
extern struct pci_driver felix_vsc9959_pci_driver;
enum felix_instance { extern struct platform_driver seville_vsc9953_driver;
FELIX_INSTANCE_VSC9959 = 0,
};
/* DSA glue / front-end for struct ocelot */ /* DSA glue / front-end for struct ocelot */
struct felix { struct felix {
struct dsa_switch *ds; struct dsa_switch *ds;
struct pci_dev *pdev; const struct felix_info *info;
struct felix_info *info;
struct ocelot ocelot; struct ocelot ocelot;
struct mii_bus *imdio; struct mii_bus *imdio;
struct phy_device **pcs; struct phy_device **pcs;
resource_size_t switch_base;
resource_size_t imdio_base;
}; };
void vsc9959_pcs_link_state(struct ocelot *ocelot, int port,
struct phylink_link_state *state);
void vsc9959_pcs_config(struct ocelot *ocelot, int port,
unsigned int link_an_mode,
const struct phylink_link_state *state);
void vsc9959_pcs_link_up(struct ocelot *ocelot, int port,
unsigned int link_an_mode,
phy_interface_t interface,
int speed, int duplex);
void vsc9959_mdio_bus_free(struct ocelot *ocelot);
#endif #endif
This diff is collapsed.
This diff is collapsed.
...@@ -309,18 +309,6 @@ static void ocelot_vlan_init(struct ocelot *ocelot) ...@@ -309,18 +309,6 @@ static void ocelot_vlan_init(struct ocelot *ocelot)
} }
} }
/* Watermark encode
* Bit 8: Unit; 0:1, 1:16
* Bit 7-0: Value to be multiplied with unit
*/
static u16 ocelot_wm_enc(u16 value)
{
if (value >= BIT(8))
return BIT(8) | (value / 16);
return value;
}
void ocelot_adjust_link(struct ocelot *ocelot, int port, void ocelot_adjust_link(struct ocelot *ocelot, int port,
struct phy_device *phydev) struct phy_device *phydev)
{ {
...@@ -389,10 +377,8 @@ void ocelot_adjust_link(struct ocelot *ocelot, int port, ...@@ -389,10 +377,8 @@ void ocelot_adjust_link(struct ocelot *ocelot, int port,
ANA_PFC_PFC_CFG, port); ANA_PFC_PFC_CFG, port);
/* Core: Enable port for frame transfer */ /* Core: Enable port for frame transfer */
ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | ocelot_fields_write(ocelot, port,
QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | QSYS_SWITCH_PORT_MODE_PORT_ENA, 1);
QSYS_SWITCH_PORT_MODE_PORT_ENA,
QSYS_SWITCH_PORT_MODE, port);
/* Flow control */ /* Flow control */
ocelot_write_rix(ocelot, SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | ocelot_write_rix(ocelot, SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) |
...@@ -423,8 +409,7 @@ void ocelot_port_disable(struct ocelot *ocelot, int port) ...@@ -423,8 +409,7 @@ void ocelot_port_disable(struct ocelot *ocelot, int port)
struct ocelot_port *ocelot_port = ocelot->ports[port]; struct ocelot_port *ocelot_port = ocelot->ports[port];
ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG);
ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, ocelot_fields_write(ocelot, port, QSYS_SWITCH_PORT_MODE_PORT_ENA, 0);
QSYS_SWITCH_PORT_MODE, port);
} }
EXPORT_SYMBOL(ocelot_port_disable); EXPORT_SYMBOL(ocelot_port_disable);
...@@ -1262,6 +1247,7 @@ void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu) ...@@ -1262,6 +1247,7 @@ void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu)
{ {
struct ocelot_port *ocelot_port = ocelot->ports[port]; struct ocelot_port *ocelot_port = ocelot->ports[port];
int maxlen = sdu + ETH_HLEN + ETH_FCS_LEN; int maxlen = sdu + ETH_HLEN + ETH_FCS_LEN;
int pause_start, pause_stop;
int atop_wm; int atop_wm;
if (port == ocelot->npi) { if (port == ocelot->npi) {
...@@ -1275,20 +1261,20 @@ void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu) ...@@ -1275,20 +1261,20 @@ void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu)
ocelot_port_writel(ocelot_port, maxlen, DEV_MAC_MAXLEN_CFG); ocelot_port_writel(ocelot_port, maxlen, DEV_MAC_MAXLEN_CFG);
/* Set Pause WM hysteresis /* Set Pause watermark hysteresis */
* 152 = 6 * maxlen / OCELOT_BUFFER_CELL_SZ pause_start = 6 * maxlen / OCELOT_BUFFER_CELL_SZ;
* 101 = 4 * maxlen / OCELOT_BUFFER_CELL_SZ pause_stop = 4 * maxlen / OCELOT_BUFFER_CELL_SZ;
*/ ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_START,
ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA | pause_start);
SYS_PAUSE_CFG_PAUSE_STOP(101) | ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_STOP,
SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port); pause_stop);
/* Tail dropping watermark */ /* Tail dropping watermark */
atop_wm = (ocelot->shared_queue_sz - 9 * maxlen) / atop_wm = (ocelot->shared_queue_sz - 9 * maxlen) /
OCELOT_BUFFER_CELL_SZ; OCELOT_BUFFER_CELL_SZ;
ocelot_write_rix(ocelot, ocelot_wm_enc(9 * maxlen), ocelot_write_rix(ocelot, ocelot->ops->wm_enc(9 * maxlen),
SYS_ATOP, port); SYS_ATOP, port);
ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG); ocelot_write(ocelot, ocelot->ops->wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
} }
EXPORT_SYMBOL(ocelot_port_set_maxlen); EXPORT_SYMBOL(ocelot_port_set_maxlen);
...@@ -1344,6 +1330,9 @@ void ocelot_init_port(struct ocelot *ocelot, int port) ...@@ -1344,6 +1330,9 @@ void ocelot_init_port(struct ocelot *ocelot, int port)
ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_HIGH_CFG); ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_HIGH_CFG);
ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_LOW_CFG); ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_LOW_CFG);
/* Enable transmission of pause frames */
ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 1);
/* Drop frames with multicast source address */ /* Drop frames with multicast source address */
ocelot_rmw_gix(ocelot, ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA, ocelot_rmw_gix(ocelot, ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA,
ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA, ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA,
...@@ -1392,27 +1381,25 @@ void ocelot_configure_cpu(struct ocelot *ocelot, int npi, ...@@ -1392,27 +1381,25 @@ void ocelot_configure_cpu(struct ocelot *ocelot, int npi,
QSYS_EXT_CPU_CFG); QSYS_EXT_CPU_CFG);
/* Enable NPI port */ /* Enable NPI port */
ocelot_write_rix(ocelot, ocelot_fields_write(ocelot, npi,
QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | QSYS_SWITCH_PORT_MODE_PORT_ENA, 1);
QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) |
QSYS_SWITCH_PORT_MODE_PORT_ENA,
QSYS_SWITCH_PORT_MODE, npi);
/* NPI port Injection/Extraction configuration */ /* NPI port Injection/Extraction configuration */
ocelot_write_rix(ocelot, ocelot_fields_write(ocelot, npi, SYS_PORT_MODE_INCL_XTR_HDR,
SYS_PORT_MODE_INCL_XTR_HDR(extraction) | extraction);
SYS_PORT_MODE_INCL_INJ_HDR(injection), ocelot_fields_write(ocelot, npi, SYS_PORT_MODE_INCL_INJ_HDR,
SYS_PORT_MODE, npi); injection);
/* Disable transmission of pause frames */
ocelot_fields_write(ocelot, npi, SYS_PAUSE_CFG_PAUSE_ENA, 0);
} }
/* Enable CPU port module */ /* Enable CPU port module */
ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | ocelot_fields_write(ocelot, cpu, QSYS_SWITCH_PORT_MODE_PORT_ENA, 1);
QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) |
QSYS_SWITCH_PORT_MODE_PORT_ENA,
QSYS_SWITCH_PORT_MODE, cpu);
/* CPU port Injection/Extraction configuration */ /* CPU port Injection/Extraction configuration */
ocelot_write_rix(ocelot, SYS_PORT_MODE_INCL_XTR_HDR(extraction) | ocelot_fields_write(ocelot, cpu, SYS_PORT_MODE_INCL_XTR_HDR,
SYS_PORT_MODE_INCL_INJ_HDR(injection), extraction);
SYS_PORT_MODE, cpu); ocelot_fields_write(ocelot, cpu, SYS_PORT_MODE_INCL_INJ_HDR,
injection);
/* Configure the CPU port to be VLAN aware */ /* Configure the CPU port to be VLAN aware */
ocelot_write_gix(ocelot, ANA_PORT_VLAN_CFG_VLAN_VID(0) | ocelot_write_gix(ocelot, ANA_PORT_VLAN_CFG_VLAN_VID(0) |
......
...@@ -102,11 +102,7 @@ void ocelot_port_lag_leave(struct ocelot *ocelot, int port, ...@@ -102,11 +102,7 @@ void ocelot_port_lag_leave(struct ocelot *ocelot, int port,
u32 ocelot_port_readl(struct ocelot_port *port, u32 reg); u32 ocelot_port_readl(struct ocelot_port *port, u32 reg);
void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg); void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg);
#define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val)) int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target,
#define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val))
int ocelot_probe_port(struct ocelot *ocelot, u8 port,
void __iomem *regs,
struct phy_device *phy); struct phy_device *phy);
void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu, void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu,
...@@ -117,7 +113,4 @@ extern struct notifier_block ocelot_netdevice_nb; ...@@ -117,7 +113,4 @@ extern struct notifier_block ocelot_netdevice_nb;
extern struct notifier_block ocelot_switchdev_nb; extern struct notifier_block ocelot_switchdev_nb;
extern struct notifier_block ocelot_switchdev_blocking_nb; extern struct notifier_block ocelot_switchdev_blocking_nb;
#define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val))
#define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val))
#endif #endif
...@@ -49,13 +49,25 @@ EXPORT_SYMBOL(__ocelot_rmw_ix); ...@@ -49,13 +49,25 @@ EXPORT_SYMBOL(__ocelot_rmw_ix);
u32 ocelot_port_readl(struct ocelot_port *port, u32 reg) u32 ocelot_port_readl(struct ocelot_port *port, u32 reg)
{ {
return readl(port->regs + reg); struct ocelot *ocelot = port->ocelot;
u16 target = reg >> TARGET_OFFSET;
u32 val;
WARN_ON(!target);
regmap_read(port->target, ocelot->map[target][reg & REG_MASK], &val);
return val;
} }
EXPORT_SYMBOL(ocelot_port_readl); EXPORT_SYMBOL(ocelot_port_readl);
void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg) void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg)
{ {
writel(val, port->regs + reg); struct ocelot *ocelot = port->ocelot;
u16 target = reg >> TARGET_OFFSET;
WARN_ON(!target);
regmap_write(port->target, ocelot->map[target][reg & REG_MASK], val);
} }
EXPORT_SYMBOL(ocelot_port_writel); EXPORT_SYMBOL(ocelot_port_writel);
...@@ -77,6 +89,8 @@ int ocelot_regfields_init(struct ocelot *ocelot, ...@@ -77,6 +89,8 @@ int ocelot_regfields_init(struct ocelot *ocelot,
regfield.reg = ocelot->map[target][reg & REG_MASK]; regfield.reg = ocelot->map[target][reg & REG_MASK];
regfield.lsb = regfields[i].lsb; regfield.lsb = regfields[i].lsb;
regfield.msb = regfields[i].msb; regfield.msb = regfields[i].msb;
regfield.id_size = regfields[i].id_size;
regfield.id_offset = regfields[i].id_offset;
ocelot->regfields[i] = ocelot->regfields[i] =
devm_regmap_field_alloc(ocelot->dev, devm_regmap_field_alloc(ocelot->dev,
......
...@@ -1005,8 +1005,7 @@ struct notifier_block ocelot_switchdev_blocking_nb __read_mostly = { ...@@ -1005,8 +1005,7 @@ struct notifier_block ocelot_switchdev_blocking_nb __read_mostly = {
.notifier_call = ocelot_switchdev_blocking_event, .notifier_call = ocelot_switchdev_blocking_event,
}; };
int ocelot_probe_port(struct ocelot *ocelot, u8 port, int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target,
void __iomem *regs,
struct phy_device *phy) struct phy_device *phy)
{ {
struct ocelot_port_private *priv; struct ocelot_port_private *priv;
...@@ -1024,7 +1023,7 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port, ...@@ -1024,7 +1023,7 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
priv->chip_port = port; priv->chip_port = port;
ocelot_port = &priv->port; ocelot_port = &priv->port;
ocelot_port->ocelot = ocelot; ocelot_port->ocelot = ocelot;
ocelot_port->regs = regs; ocelot_port->target = target;
ocelot->ports[port] = ocelot_port; ocelot->ports[port] = ocelot_port;
dev->netdev_ops = &ocelot_port_netdev_ops; dev->netdev_ops = &ocelot_port_netdev_ops;
......
...@@ -263,7 +263,49 @@ static const u32 ocelot_ptp_regmap[] = { ...@@ -263,7 +263,49 @@ static const u32 ocelot_ptp_regmap[] = {
REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8), REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8),
}; };
static const u32 *ocelot_regmap[] = { static const u32 ocelot_dev_gmii_regmap[] = {
REG(DEV_CLOCK_CFG, 0x0),
REG(DEV_PORT_MISC, 0x4),
REG(DEV_EVENTS, 0x8),
REG(DEV_EEE_CFG, 0xc),
REG(DEV_RX_PATH_DELAY, 0x10),
REG(DEV_TX_PATH_DELAY, 0x14),
REG(DEV_PTP_PREDICT_CFG, 0x18),
REG(DEV_MAC_ENA_CFG, 0x1c),
REG(DEV_MAC_MODE_CFG, 0x20),
REG(DEV_MAC_MAXLEN_CFG, 0x24),
REG(DEV_MAC_TAGS_CFG, 0x28),
REG(DEV_MAC_ADV_CHK_CFG, 0x2c),
REG(DEV_MAC_IFG_CFG, 0x30),
REG(DEV_MAC_HDX_CFG, 0x34),
REG(DEV_MAC_DBG_CFG, 0x38),
REG(DEV_MAC_FC_MAC_LOW_CFG, 0x3c),
REG(DEV_MAC_FC_MAC_HIGH_CFG, 0x40),
REG(DEV_MAC_STICKY, 0x44),
REG(PCS1G_CFG, 0x48),
REG(PCS1G_MODE_CFG, 0x4c),
REG(PCS1G_SD_CFG, 0x50),
REG(PCS1G_ANEG_CFG, 0x54),
REG(PCS1G_ANEG_NP_CFG, 0x58),
REG(PCS1G_LB_CFG, 0x5c),
REG(PCS1G_DBG_CFG, 0x60),
REG(PCS1G_CDET_CFG, 0x64),
REG(PCS1G_ANEG_STATUS, 0x68),
REG(PCS1G_ANEG_NP_STATUS, 0x6c),
REG(PCS1G_LINK_STATUS, 0x70),
REG(PCS1G_LINK_DOWN_CNT, 0x74),
REG(PCS1G_STICKY, 0x78),
REG(PCS1G_DEBUG_STATUS, 0x7c),
REG(PCS1G_LPI_CFG, 0x80),
REG(PCS1G_LPI_WAKE_ERROR_CNT, 0x84),
REG(PCS1G_LPI_STATUS, 0x88),
REG(PCS1G_TSTPAT_MODE_CFG, 0x8c),
REG(PCS1G_TSTPAT_STATUS, 0x90),
REG(DEV_PCS_FX100_CFG, 0x94),
REG(DEV_PCS_FX100_STATUS, 0x98),
};
static const u32 *ocelot_regmap[TARGET_MAX] = {
[ANA] = ocelot_ana_regmap, [ANA] = ocelot_ana_regmap,
[QS] = ocelot_qs_regmap, [QS] = ocelot_qs_regmap,
[QSYS] = ocelot_qsys_regmap, [QSYS] = ocelot_qsys_regmap,
...@@ -271,9 +313,10 @@ static const u32 *ocelot_regmap[] = { ...@@ -271,9 +313,10 @@ static const u32 *ocelot_regmap[] = {
[SYS] = ocelot_sys_regmap, [SYS] = ocelot_sys_regmap,
[S2] = ocelot_s2_regmap, [S2] = ocelot_s2_regmap,
[PTP] = ocelot_ptp_regmap, [PTP] = ocelot_ptp_regmap,
[DEV_GMII] = ocelot_dev_gmii_regmap,
}; };
static const struct reg_field ocelot_regfields[] = { static const struct reg_field ocelot_regfields[REGFIELD_MAX] = {
[ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 11, 11), [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 11, 11),
[ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 10), [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 10),
[ANA_ANEVENTS_MSTI_DROP] = REG_FIELD(ANA_ANEVENTS, 27, 27), [ANA_ANEVENTS_MSTI_DROP] = REG_FIELD(ANA_ANEVENTS, 27, 27),
...@@ -315,6 +358,20 @@ static const struct reg_field ocelot_regfields[] = { ...@@ -315,6 +358,20 @@ static const struct reg_field ocelot_regfields[] = {
[SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 2, 2), [SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 2, 2),
[SYS_RESET_CFG_MEM_ENA] = REG_FIELD(SYS_RESET_CFG, 1, 1), [SYS_RESET_CFG_MEM_ENA] = REG_FIELD(SYS_RESET_CFG, 1, 1),
[SYS_RESET_CFG_MEM_INIT] = REG_FIELD(SYS_RESET_CFG, 0, 0), [SYS_RESET_CFG_MEM_INIT] = REG_FIELD(SYS_RESET_CFG, 0, 0),
/* Replicated per number of ports (11), register size 4 per port */
[QSYS_SWITCH_PORT_MODE_PORT_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 14, 14, 11, 4),
[QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 11, 13, 11, 4),
[QSYS_SWITCH_PORT_MODE_YEL_RSRVD] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 10, 10, 11, 4),
[QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 9, 9, 11, 4),
[QSYS_SWITCH_PORT_MODE_TX_PFC_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 1, 8, 11, 4),
[QSYS_SWITCH_PORT_MODE_TX_PFC_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 0, 0, 11, 4),
[SYS_PORT_MODE_DATA_WO_TS] = REG_FIELD_ID(SYS_PORT_MODE, 5, 6, 11, 4),
[SYS_PORT_MODE_INCL_INJ_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 3, 4, 11, 4),
[SYS_PORT_MODE_INCL_XTR_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 1, 2, 11, 4),
[SYS_PORT_MODE_INCL_HDR_ERR] = REG_FIELD_ID(SYS_PORT_MODE, 0, 0, 11, 4),
[SYS_PAUSE_CFG_PAUSE_START] = REG_FIELD_ID(SYS_PAUSE_CFG, 10, 18, 11, 4),
[SYS_PAUSE_CFG_PAUSE_STOP] = REG_FIELD_ID(SYS_PAUSE_CFG, 1, 9, 11, 4),
[SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 11, 4),
}; };
static const struct ocelot_stat_layout ocelot_stats_layout[] = { static const struct ocelot_stat_layout ocelot_stats_layout[] = {
...@@ -682,8 +739,21 @@ static int ocelot_reset(struct ocelot *ocelot) ...@@ -682,8 +739,21 @@ static int ocelot_reset(struct ocelot *ocelot)
return 0; return 0;
} }
/* Watermark encode
* Bit 8: Unit; 0:1, 1:16
* Bit 7-0: Value to be multiplied with unit
*/
static u16 ocelot_wm_enc(u16 value)
{
if (value >= BIT(8))
return BIT(8) | (value / 16);
return value;
}
static const struct ocelot_ops ocelot_ops = { static const struct ocelot_ops ocelot_ops = {
.reset = ocelot_reset, .reset = ocelot_reset,
.wm_enc = ocelot_wm_enc,
}; };
static const struct vcap_field vsc7514_vcap_is2_keys[] = { static const struct vcap_field vsc7514_vcap_is2_keys[] = {
...@@ -948,9 +1018,9 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -948,9 +1018,9 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
struct device_node *phy_node; struct device_node *phy_node;
phy_interface_t phy_mode; phy_interface_t phy_mode;
struct phy_device *phy; struct phy_device *phy;
struct regmap *target;
struct resource *res; struct resource *res;
struct phy *serdes; struct phy *serdes;
void __iomem *regs;
char res_name[8]; char res_name[8];
u32 port; u32 port;
...@@ -961,8 +1031,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -961,8 +1031,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
res_name); res_name);
regs = devm_ioremap_resource(&pdev->dev, res); target = ocelot_regmap_init(ocelot, res);
if (IS_ERR(regs)) if (IS_ERR(target))
continue; continue;
phy_node = of_parse_phandle(portnp, "phy-handle", 0); phy_node = of_parse_phandle(portnp, "phy-handle", 0);
...@@ -974,7 +1044,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -974,7 +1044,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
if (!phy) if (!phy)
continue; continue;
err = ocelot_probe_port(ocelot, port, regs, phy); err = ocelot_probe_port(ocelot, port, target, phy);
if (err) { if (err) {
of_node_put(portnp); of_node_put(portnp);
goto out_put_ports; goto out_put_ports;
......
...@@ -126,6 +126,7 @@ enum ocelot_target { ...@@ -126,6 +126,7 @@ enum ocelot_target {
HSIO, HSIO,
PTP, PTP,
GCB, GCB,
DEV_GMII,
TARGET_MAX, TARGET_MAX,
}; };
...@@ -408,6 +409,48 @@ enum ocelot_reg { ...@@ -408,6 +409,48 @@ enum ocelot_reg {
PTP_CLK_CFG_ADJ_CFG, PTP_CLK_CFG_ADJ_CFG,
PTP_CLK_CFG_ADJ_FREQ, PTP_CLK_CFG_ADJ_FREQ,
GCB_SOFT_RST = GCB << TARGET_OFFSET, GCB_SOFT_RST = GCB << TARGET_OFFSET,
GCB_MIIM_MII_STATUS,
GCB_MIIM_MII_CMD,
GCB_MIIM_MII_DATA,
DEV_CLOCK_CFG = DEV_GMII << TARGET_OFFSET,
DEV_PORT_MISC,
DEV_EVENTS,
DEV_EEE_CFG,
DEV_RX_PATH_DELAY,
DEV_TX_PATH_DELAY,
DEV_PTP_PREDICT_CFG,
DEV_MAC_ENA_CFG,
DEV_MAC_MODE_CFG,
DEV_MAC_MAXLEN_CFG,
DEV_MAC_TAGS_CFG,
DEV_MAC_ADV_CHK_CFG,
DEV_MAC_IFG_CFG,
DEV_MAC_HDX_CFG,
DEV_MAC_DBG_CFG,
DEV_MAC_FC_MAC_LOW_CFG,
DEV_MAC_FC_MAC_HIGH_CFG,
DEV_MAC_STICKY,
PCS1G_CFG,
PCS1G_MODE_CFG,
PCS1G_SD_CFG,
PCS1G_ANEG_CFG,
PCS1G_ANEG_NP_CFG,
PCS1G_LB_CFG,
PCS1G_DBG_CFG,
PCS1G_CDET_CFG,
PCS1G_ANEG_STATUS,
PCS1G_ANEG_NP_STATUS,
PCS1G_LINK_STATUS,
PCS1G_LINK_DOWN_CNT,
PCS1G_STICKY,
PCS1G_DEBUG_STATUS,
PCS1G_LPI_CFG,
PCS1G_LPI_WAKE_ERROR_CNT,
PCS1G_LPI_STATUS,
PCS1G_TSTPAT_MODE_CFG,
PCS1G_TSTPAT_STATUS,
DEV_PCS_FX100_CFG,
DEV_PCS_FX100_STATUS,
}; };
enum ocelot_regfield { enum ocelot_regfield {
...@@ -447,15 +490,30 @@ enum ocelot_regfield { ...@@ -447,15 +490,30 @@ enum ocelot_regfield {
ANA_TABLES_MACACCESS_B_DOM, ANA_TABLES_MACACCESS_B_DOM,
ANA_TABLES_MACTINDX_BUCKET, ANA_TABLES_MACTINDX_BUCKET,
ANA_TABLES_MACTINDX_M_INDEX, ANA_TABLES_MACTINDX_M_INDEX,
QSYS_SWITCH_PORT_MODE_PORT_ENA,
QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG,
QSYS_SWITCH_PORT_MODE_YEL_RSRVD,
QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE,
QSYS_SWITCH_PORT_MODE_TX_PFC_ENA,
QSYS_SWITCH_PORT_MODE_TX_PFC_MODE,
QSYS_TIMED_FRAME_ENTRY_TFRM_VLD, QSYS_TIMED_FRAME_ENTRY_TFRM_VLD,
QSYS_TIMED_FRAME_ENTRY_TFRM_FP, QSYS_TIMED_FRAME_ENTRY_TFRM_FP,
QSYS_TIMED_FRAME_ENTRY_TFRM_PORTNO, QSYS_TIMED_FRAME_ENTRY_TFRM_PORTNO,
QSYS_TIMED_FRAME_ENTRY_TFRM_TM_SEL, QSYS_TIMED_FRAME_ENTRY_TFRM_TM_SEL,
QSYS_TIMED_FRAME_ENTRY_TFRM_TM_T, QSYS_TIMED_FRAME_ENTRY_TFRM_TM_T,
SYS_PORT_MODE_DATA_WO_TS,
SYS_PORT_MODE_INCL_INJ_HDR,
SYS_PORT_MODE_INCL_XTR_HDR,
SYS_PORT_MODE_INCL_HDR_ERR,
SYS_RESET_CFG_CORE_ENA, SYS_RESET_CFG_CORE_ENA,
SYS_RESET_CFG_MEM_ENA, SYS_RESET_CFG_MEM_ENA,
SYS_RESET_CFG_MEM_INIT, SYS_RESET_CFG_MEM_INIT,
GCB_SOFT_RST_SWC_RST, GCB_SOFT_RST_SWC_RST,
GCB_MIIM_MII_STATUS_PENDING,
GCB_MIIM_MII_STATUS_BUSY,
SYS_PAUSE_CFG_PAUSE_START,
SYS_PAUSE_CFG_PAUSE_STOP,
SYS_PAUSE_CFG_PAUSE_ENA,
REGFIELD_MAX REGFIELD_MAX
}; };
...@@ -483,6 +541,7 @@ struct ocelot; ...@@ -483,6 +541,7 @@ struct ocelot;
struct ocelot_ops { struct ocelot_ops {
int (*reset)(struct ocelot *ocelot); int (*reset)(struct ocelot *ocelot);
u16 (*wm_enc)(u16 value);
}; };
struct ocelot_vcap_block { struct ocelot_vcap_block {
...@@ -494,7 +553,7 @@ struct ocelot_vcap_block { ...@@ -494,7 +553,7 @@ struct ocelot_vcap_block {
struct ocelot_port { struct ocelot_port {
struct ocelot *ocelot; struct ocelot *ocelot;
void __iomem *regs; struct regmap *target;
bool vlan_aware; bool vlan_aware;
...@@ -509,6 +568,8 @@ struct ocelot_port { ...@@ -509,6 +568,8 @@ struct ocelot_port {
u8 ts_id; u8 ts_id;
phy_interface_t phy_mode; phy_interface_t phy_mode;
u8 *xmit_template;
}; };
struct ocelot { struct ocelot {
...@@ -593,6 +654,11 @@ struct ocelot_policer { ...@@ -593,6 +654,11 @@ struct ocelot_policer {
#define ocelot_rmw_rix(ocelot, val, m, reg, ri) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_RSZ * (ri)) #define ocelot_rmw_rix(ocelot, val, m, reg, ri) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_RSZ * (ri))
#define ocelot_rmw(ocelot, val, m, reg) __ocelot_rmw_ix(ocelot, val, m, reg, 0) #define ocelot_rmw(ocelot, val, m, reg) __ocelot_rmw_ix(ocelot, val, m, reg, 0)
#define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val))
#define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val))
#define ocelot_fields_write(ocelot, id, reg, val) regmap_fields_write((ocelot)->regfields[(reg)], (id), (val))
#define ocelot_fields_read(ocelot, id, reg, val) regmap_fields_read((ocelot)->regfields[(reg)], (id), (val))
/* I/O */ /* I/O */
u32 ocelot_port_readl(struct ocelot_port *port, u32 reg); u32 ocelot_port_readl(struct ocelot_port *port, u32 reg);
void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg); void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg);
......
This diff is collapsed.
...@@ -13,19 +13,6 @@ ...@@ -13,19 +13,6 @@
#define QSYS_PORT_MODE_DEQUEUE_DIS BIT(1) #define QSYS_PORT_MODE_DEQUEUE_DIS BIT(1)
#define QSYS_PORT_MODE_DEQUEUE_LATE BIT(0) #define QSYS_PORT_MODE_DEQUEUE_LATE BIT(0)
#define QSYS_SWITCH_PORT_MODE_RSZ 0x4
#define QSYS_SWITCH_PORT_MODE_PORT_ENA BIT(14)
#define QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(x) (((x) << 11) & GENMASK(13, 11))
#define QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG_M GENMASK(13, 11)
#define QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG_X(x) (((x) & GENMASK(13, 11)) >> 11)
#define QSYS_SWITCH_PORT_MODE_YEL_RSRVD BIT(10)
#define QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE BIT(9)
#define QSYS_SWITCH_PORT_MODE_TX_PFC_ENA(x) (((x) << 1) & GENMASK(8, 1))
#define QSYS_SWITCH_PORT_MODE_TX_PFC_ENA_M GENMASK(8, 1)
#define QSYS_SWITCH_PORT_MODE_TX_PFC_ENA_X(x) (((x) & GENMASK(8, 1)) >> 1)
#define QSYS_SWITCH_PORT_MODE_TX_PFC_MODE BIT(0)
#define QSYS_STAT_CNT_CFG_TX_GREEN_CNT_MODE BIT(5) #define QSYS_STAT_CNT_CFG_TX_GREEN_CNT_MODE BIT(5)
#define QSYS_STAT_CNT_CFG_TX_YELLOW_CNT_MODE BIT(4) #define QSYS_STAT_CNT_CFG_TX_YELLOW_CNT_MODE BIT(4)
#define QSYS_STAT_CNT_CFG_DROP_GREEN_CNT_MODE BIT(3) #define QSYS_STAT_CNT_CFG_DROP_GREEN_CNT_MODE BIT(3)
......
...@@ -12,19 +12,6 @@ ...@@ -12,19 +12,6 @@
#define SYS_COUNT_TX_OCTETS_RSZ 0x4 #define SYS_COUNT_TX_OCTETS_RSZ 0x4
#define SYS_PORT_MODE_RSZ 0x4
#define SYS_PORT_MODE_DATA_WO_TS(x) (((x) << 5) & GENMASK(6, 5))
#define SYS_PORT_MODE_DATA_WO_TS_M GENMASK(6, 5)
#define SYS_PORT_MODE_DATA_WO_TS_X(x) (((x) & GENMASK(6, 5)) >> 5)
#define SYS_PORT_MODE_INCL_INJ_HDR(x) (((x) << 3) & GENMASK(4, 3))
#define SYS_PORT_MODE_INCL_INJ_HDR_M GENMASK(4, 3)
#define SYS_PORT_MODE_INCL_INJ_HDR_X(x) (((x) & GENMASK(4, 3)) >> 3)
#define SYS_PORT_MODE_INCL_XTR_HDR(x) (((x) << 1) & GENMASK(2, 1))
#define SYS_PORT_MODE_INCL_XTR_HDR_M GENMASK(2, 1)
#define SYS_PORT_MODE_INCL_XTR_HDR_X(x) (((x) & GENMASK(2, 1)) >> 1)
#define SYS_PORT_MODE_INJ_HDR_ERR BIT(0)
#define SYS_FRONT_PORT_MODE_RSZ 0x4 #define SYS_FRONT_PORT_MODE_RSZ 0x4
#define SYS_FRONT_PORT_MODE_HDX_MODE BIT(0) #define SYS_FRONT_PORT_MODE_HDX_MODE BIT(0)
...@@ -56,16 +43,6 @@ ...@@ -56,16 +43,6 @@
#define SYS_TIMESTAMP_OFFSET_TIMESTAMP_OFFSET(x) ((x) & GENMASK(5, 0)) #define SYS_TIMESTAMP_OFFSET_TIMESTAMP_OFFSET(x) ((x) & GENMASK(5, 0))
#define SYS_TIMESTAMP_OFFSET_TIMESTAMP_OFFSET_M GENMASK(5, 0) #define SYS_TIMESTAMP_OFFSET_TIMESTAMP_OFFSET_M GENMASK(5, 0)
#define SYS_PAUSE_CFG_RSZ 0x4
#define SYS_PAUSE_CFG_PAUSE_START(x) (((x) << 10) & GENMASK(18, 10))
#define SYS_PAUSE_CFG_PAUSE_START_M GENMASK(18, 10)
#define SYS_PAUSE_CFG_PAUSE_START_X(x) (((x) & GENMASK(18, 10)) >> 10)
#define SYS_PAUSE_CFG_PAUSE_STOP(x) (((x) << 1) & GENMASK(9, 1))
#define SYS_PAUSE_CFG_PAUSE_STOP_M GENMASK(9, 1)
#define SYS_PAUSE_CFG_PAUSE_STOP_X(x) (((x) & GENMASK(9, 1)) >> 1)
#define SYS_PAUSE_CFG_PAUSE_ENA BIT(0)
#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START(x) (((x) << 9) & GENMASK(17, 9)) #define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START(x) (((x) << 9) & GENMASK(17, 9))
#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START_M GENMASK(17, 9) #define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START_M GENMASK(17, 9)
#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START_X(x) (((x) & GENMASK(17, 9)) >> 9) #define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START_X(x) (((x) & GENMASK(17, 9)) >> 9)
......
...@@ -137,11 +137,10 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb, ...@@ -137,11 +137,10 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
struct net_device *netdev) struct net_device *netdev)
{ {
struct dsa_port *dp = dsa_slave_to_port(netdev); struct dsa_port *dp = dsa_slave_to_port(netdev);
u64 bypass, dest, src, qos_class, rew_op;
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
int port = dp->index;
struct ocelot *ocelot = ds->priv; struct ocelot *ocelot = ds->priv;
struct ocelot_port *ocelot_port = ocelot->ports[port]; struct ocelot_port *ocelot_port;
u64 qos_class, rew_op;
u8 *injection; u8 *injection;
if (unlikely(skb_cow_head(skb, OCELOT_TAG_LEN) < 0)) { if (unlikely(skb_cow_head(skb, OCELOT_TAG_LEN) < 0)) {
...@@ -149,19 +148,15 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb, ...@@ -149,19 +148,15 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
return NULL; return NULL;
} }
injection = skb_push(skb, OCELOT_TAG_LEN); ocelot_port = ocelot->ports[dp->index];
memset(injection, 0, OCELOT_TAG_LEN); injection = skb_push(skb, OCELOT_TAG_LEN);
/* Set the source port as the CPU port module and not the NPI port */ memcpy(injection, ocelot_port->xmit_template, OCELOT_TAG_LEN);
src = ocelot->num_phys_ports; /* Fix up the fields which are not statically determined
dest = BIT(port); * in the template
bypass = true; */
qos_class = skb->priority; qos_class = skb->priority;
packing(injection, &bypass, 127, 127, OCELOT_TAG_LEN, PACK, 0);
packing(injection, &dest, 68, 56, OCELOT_TAG_LEN, PACK, 0);
packing(injection, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0);
packing(injection, &qos_class, 19, 17, OCELOT_TAG_LEN, PACK, 0); packing(injection, &qos_class, 19, 17, OCELOT_TAG_LEN, PACK, 0);
if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
......
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