Skip to content

Commit

Permalink
net: sparx5: add hostmode with phylink support
Browse files Browse the repository at this point in the history
This patch adds netdevs and phylink support for the ports in the switch.
It also adds register based injection and extraction for these ports.

Frame DMA support for injection and extraction will be added in a later
series.

Signed-off-by: Steen Hegelund <steen.hegelund@microchip.com>
Signed-off-by: Bjarni Jonasson <bjarni.jonasson@microchip.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
steen-hegelund-mchp authored and davem330 committed Jun 24, 2021
1 parent 3cfa11b commit f3cad26
Show file tree
Hide file tree
Showing 6 changed files with 841 additions and 10 deletions.
3 changes: 2 additions & 1 deletion drivers/net/ethernet/microchip/sparx5/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@

obj-$(CONFIG_SPARX5_SWITCH) += sparx5-switch.o

sparx5-switch-objs := sparx5_main.o
sparx5-switch-objs := sparx5_main.o sparx5_packet.o \
sparx5_netdev.o sparx5_phylink.o
81 changes: 72 additions & 9 deletions drivers/net/ethernet/microchip/sparx5/sparx5_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,16 @@ static int sparx5_create_port(struct sparx5 *sparx5,
struct initial_port_config *config)
{
struct sparx5_port *spx5_port;

/* netdev creation to be added in later patches */
spx5_port = devm_kzalloc(sparx5->dev, sizeof(*spx5_port), GFP_KERNEL);
struct net_device *ndev;
struct phylink *phylink;

ndev = sparx5_create_netdev(sparx5, config->portno);
if (IS_ERR(ndev)) {
dev_err(sparx5->dev, "Could not create net device: %02u\n",
config->portno);
return PTR_ERR(ndev);
}
spx5_port = netdev_priv(ndev);
spx5_port->of_node = config->node;
spx5_port->serdes = config->serdes;
spx5_port->pvid = NULL_VID;
Expand All @@ -262,8 +269,28 @@ static int sparx5_create_port(struct sparx5 *sparx5,
spx5_port->max_vlan_tags = SPX5_PORT_MAX_TAGS_NONE;
spx5_port->vlan_type = SPX5_VLAN_PORT_TYPE_UNAWARE;
spx5_port->custom_etype = 0x8880; /* Vitesse */
spx5_port->phylink_pcs.poll = true;
spx5_port->phylink_pcs.ops = &sparx5_phylink_pcs_ops;
sparx5->ports[config->portno] = spx5_port;

spx5_port->conf = config->conf;

/* VLAN setup to be added in later patches */

/* Create a phylink for PHY management. Also handles SFPs */
spx5_port->phylink_config.dev = &spx5_port->ndev->dev;
spx5_port->phylink_config.type = PHYLINK_NETDEV;
spx5_port->phylink_config.pcs_poll = true;

phylink = phylink_create(&spx5_port->phylink_config,
of_fwnode_handle(config->node),
config->conf.phy_mode,
&sparx5_phylink_mac_ops);
if (IS_ERR(phylink))
return PTR_ERR(phylink);

/* PHYLINK support to be added in later patches */
spx5_port->phylink = phylink;
phylink_set_pcs(phylink, &spx5_port->phylink_pcs);

return 0;
}
Expand Down Expand Up @@ -525,6 +552,7 @@ static void sparx5_board_init(struct sparx5 *sparx5)
static int sparx5_start(struct sparx5 *sparx5)
{
u32 idx;
int err;

/* Setup own UPSIDs */
for (idx = 0; idx < 3; idx++) {
Expand Down Expand Up @@ -558,13 +586,34 @@ static int sparx5_start(struct sparx5 *sparx5)
/* Enable queue limitation watermarks */
sparx5_qlim_set(sparx5);

/* netdev and resource calendar support to be added in later patches */
/* Resource calendar support to be added in later patches */

err = sparx5_register_netdevs(sparx5);
if (err)
return err;

sparx5_board_init(sparx5);

/* Injection/Extraction config to be added in later patches */
/* Start register based INJ/XTR */
err = -ENXIO;
if (err && sparx5->xtr_irq >= 0) {
err = devm_request_irq(sparx5->dev, sparx5->xtr_irq,
sparx5_xtr_handler, IRQF_SHARED,
"sparx5-xtr", sparx5);
if (!err)
err = sparx5_manual_injection_mode(sparx5);
if (err)
sparx5->xtr_irq = -ENXIO;
} else {
sparx5->xtr_irq = -ENXIO;
}
return err;
}

return 0;
static void sparx5_cleanup_ports(struct sparx5 *sparx5)
{
sparx5_unregister_netdevs(sparx5);
sparx5_destroy_netdevs(sparx5);
}

static int mchp_sparx5_probe(struct platform_device *pdev)
Expand Down Expand Up @@ -674,7 +723,8 @@ static int mchp_sparx5_probe(struct platform_device *pdev)
ether_addr_copy(sparx5->base_mac, mac_addr);
}

/* Inj/Xtr IRQ support to be added in later patches */
sparx5->xtr_irq = platform_get_irq_byname(sparx5->pdev, "xtr");

/* Read chip ID to check CPU interface */
sparx5->chip_id = spx5_rd(sparx5, GCB_CHIP_ID);

Expand Down Expand Up @@ -715,14 +765,26 @@ static int mchp_sparx5_probe(struct platform_device *pdev)
goto cleanup_config;

cleanup_ports:
/* Port cleanup to be added in later patches */
sparx5_cleanup_ports(sparx5);
cleanup_config:
kfree(configs);
cleanup_pnode:
of_node_put(ports);
return err;
}

static int mchp_sparx5_remove(struct platform_device *pdev)
{
struct sparx5 *sparx5 = platform_get_drvdata(pdev);

if (sparx5->xtr_irq) {
disable_irq(sparx5->xtr_irq);
sparx5->xtr_irq = -ENXIO;
}
sparx5_cleanup_ports(sparx5);
return 0;
}

static const struct of_device_id mchp_sparx5_match[] = {
{ .compatible = "microchip,sparx5-switch" },
{ }
Expand All @@ -731,6 +793,7 @@ MODULE_DEVICE_TABLE(of, mchp_sparx5_match);

static struct platform_driver mchp_sparx5_driver = {
.probe = mchp_sparx5_probe,
.remove = mchp_sparx5_remove,
.driver = {
.name = "sparx5-switch",
.of_match_table = mchp_sparx5_match,
Expand Down
33 changes: 33 additions & 0 deletions drivers/net/ethernet/microchip/sparx5/sparx5_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/if_vlan.h>
#include <linux/bitmap.h>
#include <linux/phylink.h>
#include <linux/hrtimer.h>

/* Target chip type */
enum spx5_target_chiptype {
Expand Down Expand Up @@ -69,6 +70,9 @@ enum sparx5_vlan_port_type {
#define SPX5_BUFFER_CELL_SZ 184 /* Cell size */
#define SPX5_BUFFER_MEMORY 4194280 /* 22795 words * 184 bytes */

#define XTR_QUEUE 0
#define INJ_QUEUE 0

struct sparx5;

struct sparx5_port_config {
Expand All @@ -93,6 +97,9 @@ struct sparx5_port {
struct device_node *of_node;
struct phy *serdes;
struct sparx5_port_config conf;
struct phylink_config phylink_config;
struct phylink *phylink;
struct phylink_pcs phylink_pcs;
u16 portno;
/* Ingress default VLAN (pvid) */
u16 pvid;
Expand All @@ -107,6 +114,7 @@ struct sparx5_port {
u32 custom_etype;
u32 ifh[IFH_LEN];
bool vlan_aware;
struct hrtimer inj_timer;
};

enum sparx5_core_clockfreq {
Expand All @@ -130,8 +138,23 @@ struct sparx5 {
u8 base_mac[ETH_ALEN];
/* Board specifics */
bool sd_sgpio_remapping;
/* Register based inj/xtr */
int xtr_irq;
};

/* sparx5_packet.c */
irqreturn_t sparx5_xtr_handler(int irq, void *_priv);
int sparx5_port_xmit_impl(struct sk_buff *skb, struct net_device *dev);
int sparx5_manual_injection_mode(struct sparx5 *sparx5);
void sparx5_port_inj_timer_setup(struct sparx5_port *port);

/* sparx5_netdev.c */
bool sparx5_netdevice_check(const struct net_device *dev);
struct net_device *sparx5_create_netdev(struct sparx5 *sparx5, u32 portno);
int sparx5_register_netdevs(struct sparx5 *sparx5);
void sparx5_destroy_netdevs(struct sparx5 *sparx5);
void sparx5_unregister_netdevs(struct sparx5 *sparx5);

/* Clock period in picoseconds */
static inline u32 sparx5_clk_period(enum sparx5_core_clockfreq cclock)
{
Expand All @@ -146,6 +169,16 @@ static inline u32 sparx5_clk_period(enum sparx5_core_clockfreq cclock)
}
}

static inline bool sparx5_is_baser(phy_interface_t interface)
{
return interface == PHY_INTERFACE_MODE_5GBASER ||
interface == PHY_INTERFACE_MODE_10GBASER ||
interface == PHY_INTERFACE_MODE_25GBASER;
}

extern const struct phylink_mac_ops sparx5_phylink_mac_ops;
extern const struct phylink_pcs_ops sparx5_phylink_pcs_ops;

/* Calculate raw offset */
static inline __pure int spx5_offset(int id, int tinst, int tcnt,
int gbase, int ginst,
Expand Down

0 comments on commit f3cad26

Please sign in to comment.