linux/drivers/net/ethernet/marvell/sky2.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * New driver for Marvell Yukon 2 chipset.
 * Based on earlier sk98lin, and skge driver.
 *
 * This driver intentionally does not support all the features
 * of the original driver such as link fail-over and link management because
 * those should be done at higher levels.
 *
 * Copyright (C) 2005 Stephen Hemminger <[email protected]>
 */

#define pr_fmt(fmt)

#include <linux/crc32.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/dma-mapping.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/ip.h>
#include <linux/slab.h>
#include <net/ip.h>
#include <linux/tcp.h>
#include <linux/in.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/if_vlan.h>
#include <linux/prefetch.h>
#include <linux/debugfs.h>
#include <linux/mii.h>
#include <linux/of_net.h>
#include <linux/dmi.h>
#include <linux/skbuff_ref.h>

#include <asm/irq.h>

#include "sky2.h"

#define DRV_NAME
#define DRV_VERSION

/*
 * The Yukon II chipset takes 64 bit command blocks (called list elements)
 * that are organized into three (receive, transmit, status) different rings
 * similar to Tigon3.
 */

#define RX_LE_SIZE
#define RX_LE_BYTES
#define RX_MAX_PENDING
#define RX_DEF_PENDING

/* This is the worst case number of transmit list elements for a single skb:
 * VLAN:GSO + CKSUM + Data + skb_frags * DMA
 */
#define MAX_SKB_TX_LE
#define TX_MIN_PENDING
#define TX_MAX_PENDING
#define TX_DEF_PENDING

#define TX_WATCHDOG
#define PHY_RETRIES

#define SKY2_EEPROM_MAGIC

#define RING_NEXT(x, s)

static const u32 default_msg =;

static int debug =;		/* defaults above */
module_param(debug, int, 0);
MODULE_PARM_DESC();

static int copybreak __read_mostly =;
module_param(copybreak, int, 0);
MODULE_PARM_DESC();

static int disable_msi =;
module_param(disable_msi, int, 0);
MODULE_PARM_DESC();

static int legacy_pme =;
module_param(legacy_pme, int, 0);
MODULE_PARM_DESC();

static const struct pci_device_id sky2_id_table[] =;

MODULE_DEVICE_TABLE(pci, sky2_id_table);

/* Avoid conditionals by using array */
static const unsigned txqaddr[] =;
static const unsigned rxqaddr[] =;
static const u32 portirq_msk[] =;

static void sky2_set_multicast(struct net_device *dev);
static irqreturn_t sky2_intr(int irq, void *dev_id);

/* Access to PHY via serial interconnect */
static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val)
{}

static int __gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg, u16 *val)
{}

static inline u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
{}


static void sky2_power_on(struct sky2_hw *hw)
{}

static void sky2_power_aux(struct sky2_hw *hw)
{}

static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
{}

/* flow control to advertise bits */
static const u16 copper_fc_adv[] =;

/* flow control to advertise bits when using 1000BaseX */
static const u16 fiber_fc_adv[] =;

/* flow control to GMA disable bits */
static const u16 gm_fc_disable[] =;


static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
{}

static const u32 phy_power[] =;
static const u32 coma_mode[] =;

static void sky2_phy_power_up(struct sky2_hw *hw, unsigned port)
{}

static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port)
{}

/* configure IPG according to used link speed */
static void sky2_set_ipg(struct sky2_port *sky2)
{}

/* Enable Rx/Tx */
static void sky2_enable_rx_tx(struct sky2_port *sky2)
{}

/* Force a renegotiation */
static void sky2_phy_reinit(struct sky2_port *sky2)
{}

/* Put device in state to listen for Wake On Lan */
static void sky2_wol_init(struct sky2_port *sky2)
{}

static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port)
{}

static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
{}

/* Assign Ram Buffer allocation to queue */
static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, u32 space)
{}

/* Setup Bus Memory Interface */
static void sky2_qset(struct sky2_hw *hw, u16 q)
{}

/* Setup prefetch unit registers. This is the interface between
 * hardware and driver list elements
 */
static void sky2_prefetch_init(struct sky2_hw *hw, u32 qaddr,
			       dma_addr_t addr, u32 last)
{}

static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot)
{}

static void tx_init(struct sky2_port *sky2)
{}

/* Update chip's next pointer */
static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx)
{}


static inline struct sky2_rx_le *sky2_next_rx(struct sky2_port *sky2)
{}

static unsigned sky2_get_rx_threshold(struct sky2_port *sky2)
{}

static unsigned sky2_get_rx_data_size(struct sky2_port *sky2)
{}

/* Build description to hardware for one receive segment */
static void sky2_rx_add(struct sky2_port *sky2, u8 op,
			dma_addr_t map, unsigned len)
{}

/* Build description to hardware for one possibly fragmented skb */
static void sky2_rx_submit(struct sky2_port *sky2,
			   const struct rx_ring_info *re)
{}


static int sky2_rx_map_skb(struct pci_dev *pdev, struct rx_ring_info *re,
			    unsigned size)
{}

static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re)
{}

/* Tell chip where to start receive checksum.
 * Actually has two checksums, but set both same to avoid possible byte
 * order problems.
 */
static void rx_set_checksum(struct sky2_port *sky2)
{}

/* Enable/disable receive hash calculation (RSS) */
static void rx_set_rss(struct net_device *dev, netdev_features_t features)
{}

/*
 * The RX Stop command will not work for Yukon-2 if the BMU does not
 * reach the end of packet and since we can't make sure that we have
 * incoming data, we must reset the BMU while it is not doing a DMA
 * transfer. Since it is possible that the RX path is still active,
 * the RX RAM buffer will be stopped first, so any possible incoming
 * data will not trigger a DMA. After the RAM buffer is stopped, the
 * BMU is polled until any DMA in progress is ended and only then it
 * will be reset.
 */
static void sky2_rx_stop(struct sky2_port *sky2)
{}

/* Clean out receive buffer area, assumes receiver hardware stopped */
static void sky2_rx_clean(struct sky2_port *sky2)
{}

/* Basic MII support */
static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{}

#define SKY2_VLAN_OFFLOADS

static void sky2_vlan_mode(struct net_device *dev, netdev_features_t features)
{}

/* Amount of required worst case padding in rx buffer */
static inline unsigned sky2_rx_pad(const struct sky2_hw *hw)
{}

/*
 * Allocate an skb for receiving. If the MTU is large enough
 * make the skb non-linear with a fragment list of pages.
 */
static struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2, gfp_t gfp)
{}

static inline void sky2_rx_update(struct sky2_port *sky2, unsigned rxq)
{}

static int sky2_alloc_rx_skbs(struct sky2_port *sky2)
{}

/*
 * Setup receiver buffer pool.
 * Normal case this ends up creating one list element for skb
 * in the receive ring. Worst case if using large MTU and each
 * allocation falls on a different 64 bit region, that results
 * in 6 list elements per ring entry.
 * One element is used for checksum enable/disable, and one
 * extra to avoid wrap.
 */
static void sky2_rx_start(struct sky2_port *sky2)
{}

static int sky2_alloc_buffers(struct sky2_port *sky2)
{}

static void sky2_free_buffers(struct sky2_port *sky2)
{}

static void sky2_hw_up(struct sky2_port *sky2)
{}

/* Setup device IRQ and enable napi to process */
static int sky2_setup_irq(struct sky2_hw *hw, const char *name)
{}


/* Bring up network interface. */
static int sky2_open(struct net_device *dev)
{}

/* Modular subtraction in ring */
static inline int tx_inuse(const struct sky2_port *sky2)
{}

/* Number of list elements available for next tx */
static inline int tx_avail(const struct sky2_port *sky2)
{}

/* Estimate of number of transmit list elements required */
static unsigned tx_le_req(const struct sk_buff *skb)
{}

static void sky2_tx_unmap(struct pci_dev *pdev, struct tx_ring_info *re)
{}

/*
 * Put one packet in ring for transmit.
 * A single packet can generate multiple list elements, and
 * the number of ring elements will probably be less than the number
 * of list elements used.
 */
static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
				   struct net_device *dev)
{}

/*
 * Free ring elements from starting at tx_cons until "done"
 *
 * NB:
 *  1. The hardware will tell us about partial completion of multi-part
 *     buffers so make sure not to free skb to early.
 *  2. This may run in parallel start_xmit because the it only
 *     looks at the tail of the queue of FIFO (tx_cons), not
 *     the head (tx_prod)
 */
static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
{}

static void sky2_tx_reset(struct sky2_hw *hw, unsigned port)
{}

static void sky2_hw_down(struct sky2_port *sky2)
{}

/* Network shutdown */
static int sky2_close(struct net_device *dev)
{}

static u16 sky2_phy_speed(const struct sky2_hw *hw, u16 aux)
{}

static void sky2_link_up(struct sky2_port *sky2)
{}

static void sky2_link_down(struct sky2_port *sky2)
{}

static enum flow_control sky2_flow(int rx, int tx)
{}

static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
{}

/* Interrupt from PHY */
static void sky2_phy_intr(struct sky2_hw *hw, unsigned port)
{}

/* Special quick link interrupt (Yukon-2 Optima only) */
static void sky2_qlink_intr(struct sky2_hw *hw)
{}

/* Transmit timeout is only called if we are running, carrier is up
 * and tx queue is full (stopped).
 */
static void sky2_tx_timeout(struct net_device *dev, unsigned int txqueue)
{}

static int sky2_change_mtu(struct net_device *dev, int new_mtu)
{}

static inline bool needs_copy(const struct rx_ring_info *re,
			      unsigned length)
{}

/* For small just reuse existing skb for next receive */
static struct sk_buff *receive_copy(struct sky2_port *sky2,
				    const struct rx_ring_info *re,
				    unsigned length)
{}

/* Adjust length of skb with fragments to match received data */
static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
			  unsigned int length)
{}

/* Normal packet - take skb from ring element and put in a new one  */
static struct sk_buff *receive_new(struct sky2_port *sky2,
				   struct rx_ring_info *re,
				   unsigned int length)
{}

/*
 * Receive one packet.
 * For larger packets, get new buffer.
 */
static struct sk_buff *sky2_receive(struct net_device *dev,
				    u16 length, u32 status)
{}

/* Transmit complete */
static inline void sky2_tx_done(struct net_device *dev, u16 last)
{}

static inline void sky2_skb_rx(const struct sky2_port *sky2,
			       struct sk_buff *skb)
{}

static inline void sky2_rx_done(struct sky2_hw *hw, unsigned port,
				unsigned packets, unsigned bytes)
{}

static void sky2_rx_checksum(struct sky2_port *sky2, u32 status)
{}

static void sky2_rx_tag(struct sky2_port *sky2, u16 length)
{}

static void sky2_rx_hash(struct sky2_port *sky2, u32 status)
{}

/* Process status response ring */
static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
{}

static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status)
{}

static void sky2_hw_intr(struct sky2_hw *hw)
{}

static void sky2_mac_intr(struct sky2_hw *hw, unsigned port)
{}

/* This should never happen it is a bug. */
static void sky2_le_error(struct sky2_hw *hw, unsigned port, u16 q)
{}

static int sky2_rx_hung(struct net_device *dev)
{}

static void sky2_watchdog(struct timer_list *t)
{}

/* Hardware/software error handling */
static void sky2_err_intr(struct sky2_hw *hw, u32 status)
{}

static int sky2_poll(struct napi_struct *napi, int work_limit)
{}

static irqreturn_t sky2_intr(int irq, void *dev_id)
{}

#ifdef CONFIG_NET_POLL_CONTROLLER
static void sky2_netpoll(struct net_device *dev)
{}
#endif

/* Chip internal frequency for clock calculations */
static u32 sky2_mhz(const struct sky2_hw *hw)
{}

static inline u32 sky2_us2clk(const struct sky2_hw *hw, u32 us)
{}

static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk)
{}


static int sky2_init(struct sky2_hw *hw)
{}

static void sky2_reset(struct sky2_hw *hw)
{}

/* Take device down (offline).
 * Equivalent to doing dev_stop() but this does not
 * inform upper layers of the transition.
 */
static void sky2_detach(struct net_device *dev)
{}

/* Bring device back after doing sky2_detach */
static int sky2_reattach(struct net_device *dev)
{}

static void sky2_all_down(struct sky2_hw *hw)
{}

static void sky2_all_up(struct sky2_hw *hw)
{}

static void sky2_restart(struct work_struct *work)
{}

static inline u8 sky2_wol_supported(const struct sky2_hw *hw)
{}

static void sky2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{}

static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{}

static u32 sky2_supported_modes(const struct sky2_hw *hw)
{}

static int sky2_get_link_ksettings(struct net_device *dev,
				   struct ethtool_link_ksettings *cmd)
{}

static int sky2_set_link_ksettings(struct net_device *dev,
				   const struct ethtool_link_ksettings *cmd)
{}

static void sky2_get_drvinfo(struct net_device *dev,
			     struct ethtool_drvinfo *info)
{}

static const struct sky2_stat {} sky2_stats[] =;

static u32 sky2_get_msglevel(struct net_device *netdev)
{}

static int sky2_nway_reset(struct net_device *dev)
{}

static void sky2_phy_stats(struct sky2_port *sky2, u64 * data, unsigned count)
{}

static void sky2_set_msglevel(struct net_device *netdev, u32 value)
{}

static int sky2_get_sset_count(struct net_device *dev, int sset)
{}

static void sky2_get_ethtool_stats(struct net_device *dev,
				   struct ethtool_stats *stats, u64 * data)
{}

static void sky2_get_strings(struct net_device *dev, u32 stringset, u8 * data)
{}

static int sky2_set_mac_address(struct net_device *dev, void *p)
{}

static inline void sky2_add_filter(u8 filter[8], const u8 *addr)
{}

static void sky2_set_multicast(struct net_device *dev)
{}

static void sky2_get_stats(struct net_device *dev,
			   struct rtnl_link_stats64 *stats)
{}

/* Can have one global because blinking is controlled by
 * ethtool and that is always under RTNL mutex
 */
static void sky2_led(struct sky2_port *sky2, enum led_mode mode)
{}

/* blink LED's for finding board */
static int sky2_set_phys_id(struct net_device *dev,
			    enum ethtool_phys_id_state state)
{}

static void sky2_get_pauseparam(struct net_device *dev,
				struct ethtool_pauseparam *ecmd)
{}

static int sky2_set_pauseparam(struct net_device *dev,
			       struct ethtool_pauseparam *ecmd)
{}

static int sky2_get_coalesce(struct net_device *dev,
			     struct ethtool_coalesce *ecmd,
			     struct kernel_ethtool_coalesce *kernel_coal,
			     struct netlink_ext_ack *extack)
{}

/* Note: this affect both ports */
static int sky2_set_coalesce(struct net_device *dev,
			     struct ethtool_coalesce *ecmd,
			     struct kernel_ethtool_coalesce *kernel_coal,
			     struct netlink_ext_ack *extack)
{}

/*
 * Hardware is limited to min of 128 and max of 2048 for ring size
 * and  rounded up to next power of two
 * to avoid division in modulus calculation
 */
static unsigned long roundup_ring_size(unsigned long pending)
{}

static void sky2_get_ringparam(struct net_device *dev,
			       struct ethtool_ringparam *ering,
			       struct kernel_ethtool_ringparam *kernel_ering,
			       struct netlink_ext_ack *extack)
{}

static int sky2_set_ringparam(struct net_device *dev,
			      struct ethtool_ringparam *ering,
			      struct kernel_ethtool_ringparam *kernel_ering,
			      struct netlink_ext_ack *extack)
{}

static int sky2_get_regs_len(struct net_device *dev)
{}

static int sky2_reg_access_ok(struct sky2_hw *hw, unsigned int b)
{}

/*
 * Returns copy of control register region
 * Note: ethtool_get_regs always provides full size (16k) buffer
 */
static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
			  void *p)
{}

static int sky2_get_eeprom_len(struct net_device *dev)
{}

static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
			   u8 *data)
{}

static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
			   u8 *data)
{}

static netdev_features_t sky2_fix_features(struct net_device *dev,
	netdev_features_t features)
{}

static int sky2_set_features(struct net_device *dev, netdev_features_t features)
{}

static const struct ethtool_ops sky2_ethtool_ops =;

#ifdef CONFIG_SKY2_DEBUG

static struct dentry *sky2_debug;

static int sky2_debug_show(struct seq_file *seq, void *v)
{}
DEFINE_SHOW_ATTRIBUTE();

/*
 * Use network device events to create/remove/rename
 * debugfs file entries
 */
static int sky2_device_event(struct notifier_block *unused,
			     unsigned long event, void *ptr)
{}

static struct notifier_block sky2_notifier =;


static __init void sky2_debug_init(void)
{}

static __exit void sky2_debug_cleanup(void)
{}

#else
#define sky2_debug_init
#define sky2_debug_cleanup
#endif

/* Two copies of network device operations to handle special case of
 * not allowing netpoll on second port
 */
static const struct net_device_ops sky2_netdev_ops[2] =;

/* Initialize network device */
static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port,
					   int highmem, int wol)
{}

static void sky2_show_addr(struct net_device *dev)
{}

/* Handle software interrupt used during MSI test */
static irqreturn_t sky2_test_intr(int irq, void *dev_id)
{}

/* Test interrupt path by forcing a software IRQ */
static int sky2_test_msi(struct sky2_hw *hw)
{}

/* This driver supports yukon2 chipset only */
static const char *sky2_name(u8 chipid, char *buf, int sz)
{}

static const struct dmi_system_id msi_blacklist[] =;

static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{}

static void sky2_remove(struct pci_dev *pdev)
{}

static int sky2_suspend(struct device *dev)
{}

#ifdef CONFIG_PM_SLEEP
static int sky2_resume(struct device *dev)
{}

static SIMPLE_DEV_PM_OPS(sky2_pm_ops, sky2_suspend, sky2_resume);
#define SKY2_PM_OPS

#else

#define SKY2_PM_OPS
#endif

static void sky2_shutdown(struct pci_dev *pdev)
{}

static struct pci_driver sky2_driver =;

static int __init sky2_init_module(void)
{}

static void __exit sky2_cleanup_module(void)
{}

module_init();
module_exit(sky2_cleanup_module);

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();
MODULE_VERSION();