/* * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet * driver for Linux. * * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #define pr_fmt(fmt) … #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/debugfs.h> #include <linux/ethtool.h> #include <linux/mdio.h> #include "t4vf_common.h" #include "t4vf_defs.h" #include "../cxgb4/t4_regs.h" #include "../cxgb4/t4_msg.h" /* * Generic information about the driver. */ #define DRV_DESC … /* * Module Parameters. * ================== */ /* * Default ethtool "message level" for adapters. */ #define DFLT_MSG_ENABLE … /* * The driver uses the best interrupt scheme available on a platform in the * order MSI-X then MSI. This parameter determines which of these schemes the * driver may consider as follows: * * msi = 2: choose from among MSI-X and MSI * msi = 1: only consider MSI interrupts * * Note that unlike the Physical Function driver, this Virtual Function driver * does _not_ support legacy INTx interrupts (this limitation is mandated by * the PCI-E SR-IOV standard). */ #define MSI_MSIX … #define MSI_MSI … #define MSI_DEFAULT … static int msi = …; module_param(msi, int, 0644); MODULE_PARM_DESC(…) …; /* * Fundamental constants. * ====================== */ enum { … }; /* * Global driver state. * ==================== */ static struct dentry *cxgb4vf_debugfs_root; /* * OS "Callback" functions. * ======================== */ /* * The link status has changed on the indicated "port" (Virtual Interface). */ void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok) { … } /* * THe port module type has changed on the indicated "port" (Virtual * Interface). */ void t4vf_os_portmod_changed(struct adapter *adapter, int pidx) { … } static int cxgb4vf_set_addr_hash(struct port_info *pi) { … } /** * cxgb4vf_change_mac - Update match filter for a MAC address. * @pi: the port_info * @viid: the VI id * @tcam_idx: TCAM index of existing filter for old value of MAC address, * or -1 * @addr: the new MAC address value * @persistent: whether a new MAC allocation should be persistent * * Modifies an MPS filter and sets it to the new MAC address if * @tcam_idx >= 0, or adds the MAC address to a new filter if * @tcam_idx < 0. In the latter case the address is added persistently * if @persist is %true. * Addresses are programmed to hash region, if tcam runs out of entries. * */ static int cxgb4vf_change_mac(struct port_info *pi, unsigned int viid, int *tcam_idx, const u8 *addr, bool persistent) { … } /* * Net device operations. * ====================== */ /* * Perform the MAC and PHY actions needed to enable a "port" (Virtual * Interface). */ static int link_start(struct net_device *dev) { … } /* * Name the MSI-X interrupts. */ static void name_msix_vecs(struct adapter *adapter) { … } /* * Request all of our MSI-X resources. */ static int request_msix_queue_irqs(struct adapter *adapter) { … } /* * Free our MSI-X resources. */ static void free_msix_queue_irqs(struct adapter *adapter) { … } /* * Turn on NAPI and start up interrupts on a response queue. */ static void qenable(struct sge_rspq *rspq) { … } /* * Enable NAPI scheduling and interrupt generation for all Receive Queues. */ static void enable_rx(struct adapter *adapter) { … } /* * Wait until all NAPI handlers are descheduled. */ static void quiesce_rx(struct adapter *adapter) { … } /* * Response queue handler for the firmware event queue. */ static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp, const struct pkt_gl *gl) { … } /* * Allocate SGE TX/RX response queues. Determine how many sets of SGE queues * to use and initializes them. We support multiple "Queue Sets" per port if * we have MSI-X, otherwise just one queue set per port. */ static int setup_sge_queues(struct adapter *adapter) { … } /* * Set up Receive Side Scaling (RSS) to distribute packets to multiple receive * queues. We configure the RSS CPU lookup table to distribute to the number * of HW receive queues, and the response queue lookup table to narrow that * down to the response queues actually configured for each "port" (Virtual * Interface). We always configure the RSS mapping for all ports since the * mapping table has plenty of entries. */ static int setup_rss(struct adapter *adapter) { … } /* * Bring the adapter up. Called whenever we go from no "ports" open to having * one open. This function performs the actions necessary to make an adapter * operational, such as completing the initialization of HW modules, and * enabling interrupts. Must be called with the rtnl lock held. (Note that * this is called "cxgb_up" in the PF Driver.) */ static int adapter_up(struct adapter *adapter) { … } /* * Bring the adapter down. Called whenever the last "port" (Virtual * Interface) closed. (Note that this routine is called "cxgb_down" in the PF * Driver.) */ static void adapter_down(struct adapter *adapter) { … } /* * Start up a net device. */ static int cxgb4vf_open(struct net_device *dev) { … } /* * Shut down a net device. This routine is called "cxgb_close" in the PF * Driver ... */ static int cxgb4vf_stop(struct net_device *dev) { … } /* * Translate our basic statistics into the standard "ifconfig" statistics. */ static struct net_device_stats *cxgb4vf_get_stats(struct net_device *dev) { … } static int cxgb4vf_mac_sync(struct net_device *netdev, const u8 *mac_addr) { … } static int cxgb4vf_mac_unsync(struct net_device *netdev, const u8 *mac_addr) { … } /* * Set RX properties of a port, such as promiscruity, address filters, and MTU. * If @mtu is -1 it is left unchanged. */ static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok) { … } /* * Set the current receive modes on the device. */ static void cxgb4vf_set_rxmode(struct net_device *dev) { … } /* * Find the entry in the interrupt holdoff timer value array which comes * closest to the specified interrupt holdoff value. */ static int closest_timer(const struct sge *s, int us) { … } static int closest_thres(const struct sge *s, int thres) { … } /* * Return a queue's interrupt hold-off time in us. 0 means no timer. */ static unsigned int qtimer_val(const struct adapter *adapter, const struct sge_rspq *rspq) { … } /** * set_rxq_intr_params - set a queue's interrupt holdoff parameters * @adapter: the adapter * @rspq: the RX response queue * @us: the hold-off time in us, or 0 to disable timer * @cnt: the hold-off packet count, or 0 to disable counter * * Sets an RX response queue's interrupt hold-off time and packet count. * At least one of the two needs to be enabled for the queue to generate * interrupts. */ static int set_rxq_intr_params(struct adapter *adapter, struct sge_rspq *rspq, unsigned int us, unsigned int cnt) { … } /* * Return a version number to identify the type of adapter. The scheme is: * - bits 0..9: chip version * - bits 10..15: chip revision */ static inline unsigned int mk_adap_vers(const struct adapter *adapter) { … } /* * Execute the specified ioctl command. */ static int cxgb4vf_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { … } /* * Change the device's MTU. */ static int cxgb4vf_change_mtu(struct net_device *dev, int new_mtu) { … } static netdev_features_t cxgb4vf_fix_features(struct net_device *dev, netdev_features_t features) { … } static int cxgb4vf_set_features(struct net_device *dev, netdev_features_t features) { … } /* * Change the devices MAC address. */ static int cxgb4vf_set_mac_addr(struct net_device *dev, void *_addr) { … } #ifdef CONFIG_NET_POLL_CONTROLLER /* * Poll all of our receive queues. This is called outside of normal interrupt * context. */ static void cxgb4vf_poll_controller(struct net_device *dev) { … } #endif /* * Ethtool operations. * =================== * * Note that we don't support any ethtool operations which change the physical * state of the port to which we're linked. */ /** * from_fw_port_mod_type - translate Firmware Port/Module type to Ethtool * @port_type: Firmware Port Type * @mod_type: Firmware Module Type * * Translate Firmware Port/Module type to Ethtool Port Type. */ static int from_fw_port_mod_type(enum fw_port_type port_type, enum fw_port_module_type mod_type) { … } /** * fw_caps_to_lmm - translate Firmware to ethtool Link Mode Mask * @port_type: Firmware Port Type * @fw_caps: Firmware Port Capabilities * @link_mode_mask: ethtool Link Mode Mask * * Translate a Firmware Port Capabilities specification to an ethtool * Link Mode Mask. */ static void fw_caps_to_lmm(enum fw_port_type port_type, unsigned int fw_caps, unsigned long *link_mode_mask) { … } static int cxgb4vf_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *link_ksettings) { … } /* Translate the Firmware FEC value into the ethtool value. */ static inline unsigned int fwcap_to_eth_fec(unsigned int fw_fec) { … } /* Translate Common Code FEC value into ethtool value. */ static inline unsigned int cc_to_eth_fec(unsigned int cc_fec) { … } static int cxgb4vf_get_fecparam(struct net_device *dev, struct ethtool_fecparam *fec) { … } /* * Return our driver information. */ static void cxgb4vf_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) { … } /* * Return current adapter message level. */ static u32 cxgb4vf_get_msglevel(struct net_device *dev) { … } /* * Set current adapter message level. */ static void cxgb4vf_set_msglevel(struct net_device *dev, u32 msglevel) { … } /* * Return the device's current Queue Set ring size parameters along with the * allowed maximum values. Since ethtool doesn't understand the concept of * multi-queue devices, we just return the current values associated with the * first Queue Set. */ static void cxgb4vf_get_ringparam(struct net_device *dev, struct ethtool_ringparam *rp, struct kernel_ethtool_ringparam *kernel_rp, struct netlink_ext_ack *extack) { … } /* * Set the Queue Set ring size parameters for the device. Again, since * ethtool doesn't allow for the concept of multiple queues per device, we'll * apply these new values across all of the Queue Sets associated with the * device -- after vetting them of course! */ static int cxgb4vf_set_ringparam(struct net_device *dev, struct ethtool_ringparam *rp, struct kernel_ethtool_ringparam *kernel_rp, struct netlink_ext_ack *extack) { … } /* * Return the interrupt holdoff timer and count for the first Queue Set on the * device. Our extension ioctl() (the cxgbtool interface) allows the * interrupt holdoff timer to be read on all of the device's Queue Sets. */ static int cxgb4vf_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coalesce, struct kernel_ethtool_coalesce *kernel_coal, struct netlink_ext_ack *extack) { … } /* * Set the RX interrupt holdoff timer and count for the first Queue Set on the * interface. Our extension ioctl() (the cxgbtool interface) allows us to set * the interrupt holdoff timer on any of the device's Queue Sets. */ static int cxgb4vf_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coalesce, struct kernel_ethtool_coalesce *kernel_coal, struct netlink_ext_ack *extack) { … } /* * Report current port link pause parameter settings. */ static void cxgb4vf_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pauseparam) { … } /* * Identify the port by blinking the port's LED. */ static int cxgb4vf_phys_id(struct net_device *dev, enum ethtool_phys_id_state state) { … } /* * Port stats maintained per queue of the port. */ struct queue_port_stats { … }; /* * Strings for the ETH_SS_STATS statistics set ("ethtool -S"). Note that * these need to match the order of statistics returned by * t4vf_get_port_stats(). */ static const char stats_strings[][ETH_GSTRING_LEN] = …; /* * Return the number of statistics in the specified statistics set. */ static int cxgb4vf_get_sset_count(struct net_device *dev, int sset) { … } /* * Return the strings for the specified statistics set. */ static void cxgb4vf_get_strings(struct net_device *dev, u32 sset, u8 *data) { … } /* * Small utility routine to accumulate queue statistics across the queues of * a "port". */ static void collect_sge_port_stats(const struct adapter *adapter, const struct port_info *pi, struct queue_port_stats *stats) { … } /* * Return the ETH_SS_STATS statistics set. */ static void cxgb4vf_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { … } /* * Return the size of our register map. */ static int cxgb4vf_get_regs_len(struct net_device *dev) { … } /* * Dump a block of registers, start to end inclusive, into a buffer. */ static void reg_block_dump(struct adapter *adapter, void *regbuf, unsigned int start, unsigned int end) { … } /* * Copy our entire register map into the provided buffer. */ static void cxgb4vf_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf) { … } /* * Report current Wake On LAN settings. */ static void cxgb4vf_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { … } /* * TCP Segmentation Offload flags which we support. */ #define TSO_FLAGS … #define VLAN_FEAT … static const struct ethtool_ops cxgb4vf_ethtool_ops = …; /* * /sys/kernel/debug/cxgb4vf support code and data. * ================================================ */ /* * Show Firmware Mailbox Command/Reply Log * * Note that we don't do any locking when dumping the Firmware Mailbox Log so * it's possible that we can catch things during a log update and therefore * see partially corrupted log entries. But i9t's probably Good Enough(tm). * If we ever decide that we want to make sure that we're dumping a coherent * log, we'd need to perform locking in the mailbox logging and in * mboxlog_open() where we'd need to grab the entire mailbox log in one go * like we do for the Firmware Device Log. But as stated above, meh ... */ static int mboxlog_show(struct seq_file *seq, void *v) { … } static inline void *mboxlog_get_idx(struct seq_file *seq, loff_t pos) { … } static void *mboxlog_start(struct seq_file *seq, loff_t *pos) { … } static void *mboxlog_next(struct seq_file *seq, void *v, loff_t *pos) { … } static void mboxlog_stop(struct seq_file *seq, void *v) { … } static const struct seq_operations mboxlog_sops = …; DEFINE_SEQ_ATTRIBUTE(…); /* * Show SGE Queue Set information. We display QPL Queues Sets per line. */ #define QPL … static int sge_qinfo_show(struct seq_file *seq, void *v) { … } /* * Return the number of "entries" in our "file". We group the multi-Queue * sections with QPL Queue Sets per "entry". The sections of the output are: * * Ethernet RX/TX Queue Sets * Firmware Event Queue * Forwarded Interrupt Queue (if in MSI mode) */ static int sge_queue_entries(const struct adapter *adapter) { … } static void *sge_queue_start(struct seq_file *seq, loff_t *pos) { … } static void sge_queue_stop(struct seq_file *seq, void *v) { … } static void *sge_queue_next(struct seq_file *seq, void *v, loff_t *pos) { … } static const struct seq_operations sge_qinfo_sops = …; DEFINE_SEQ_ATTRIBUTE(…); /* * Show SGE Queue Set statistics. We display QPL Queues Sets per line. */ #define QPL … static int sge_qstats_show(struct seq_file *seq, void *v) { … } /* * Return the number of "entries" in our "file". We group the multi-Queue * sections with QPL Queue Sets per "entry". The sections of the output are: * * Ethernet RX/TX Queue Sets * Firmware Event Queue * Forwarded Interrupt Queue (if in MSI mode) */ static int sge_qstats_entries(const struct adapter *adapter) { … } static void *sge_qstats_start(struct seq_file *seq, loff_t *pos) { … } static void sge_qstats_stop(struct seq_file *seq, void *v) { … } static void *sge_qstats_next(struct seq_file *seq, void *v, loff_t *pos) { … } static const struct seq_operations sge_qstats_sops = …; DEFINE_SEQ_ATTRIBUTE(…); /* * Show PCI-E SR-IOV Virtual Function Resource Limits. */ static int resources_show(struct seq_file *seq, void *v) { … } DEFINE_SHOW_ATTRIBUTE(…); /* * Show Virtual Interfaces. */ static int interfaces_show(struct seq_file *seq, void *v) { … } static inline void *interfaces_get_idx(struct adapter *adapter, loff_t pos) { … } static void *interfaces_start(struct seq_file *seq, loff_t *pos) { … } static void *interfaces_next(struct seq_file *seq, void *v, loff_t *pos) { … } static void interfaces_stop(struct seq_file *seq, void *v) { … } static const struct seq_operations interfaces_sops = …; DEFINE_SEQ_ATTRIBUTE(…); /* * /sys/kernel/debugfs/cxgb4vf/ files list. */ struct cxgb4vf_debugfs_entry { … }; static struct cxgb4vf_debugfs_entry debugfs_files[] = …; /* * Module and device initialization and cleanup code. * ================================================== */ /* * Set up out /sys/kernel/debug/cxgb4vf sub-nodes. We assume that the * directory (debugfs_root) has already been set up. */ static int setup_debugfs(struct adapter *adapter) { … } /* * Tear down the /sys/kernel/debug/cxgb4vf sub-nodes created above. We leave * it to our caller to tear down the directory (debugfs_root). */ static void cleanup_debugfs(struct adapter *adapter) { … } /* Figure out how many Ports and Queue Sets we can support. This depends on * knowing our Virtual Function Resources and may be called a second time if * we fall back from MSI-X to MSI Interrupt Mode. */ static void size_nports_qsets(struct adapter *adapter) { … } /* * Perform early "adapter" initialization. This is where we discover what * adapter parameters we're going to be using and initialize basic adapter * hardware support. */ static int adap_init0(struct adapter *adapter) { … } static inline void init_rspq(struct sge_rspq *rspq, u8 timer_idx, u8 pkt_cnt_idx, unsigned int size, unsigned int iqe_size) { … } /* * Perform default configuration of DMA queues depending on the number and * type of ports we found and the number of available CPUs. Most settings can * be modified by the admin via ethtool and cxgbtool prior to the adapter * being brought up for the first time. */ static void cfg_queues(struct adapter *adapter) { … } /* * Reduce the number of Ethernet queues across all ports to at most n. * n provides at least one queue per port. */ static void reduce_ethqs(struct adapter *adapter, int n) { … } /* * We need to grab enough MSI-X vectors to cover our interrupt needs. Ideally * we get a separate MSI-X vector for every "Queue Set" plus any extras we * need. Minimally we need one for every Virtual Interface plus those needed * for our "extras". Note that this process may lower the maximum number of * allowed Queue Sets ... */ static int enable_msix(struct adapter *adapter) { … } static const struct net_device_ops cxgb4vf_netdev_ops = …; /** * cxgb4vf_get_port_mask - Get port mask for the VF based on mac * address stored on the adapter * @adapter: The adapter * * Find the port mask for the VF based on the index of mac * address stored in the adapter. If no mac address is stored on * the adapter for the VF, use the port mask received from the * firmware. */ static unsigned int cxgb4vf_get_port_mask(struct adapter *adapter) { … } /* * "Probe" a device: initialize a device and construct all kernel and driver * state needed to manage the device. This routine is called "init_one" in * the PF Driver ... */ static int cxgb4vf_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { … } /* * "Remove" a device: tear down all kernel and driver state created in the * "probe" routine and quiesce the device (disable interrupts, etc.). (Note * that this is called "remove_one" in the PF Driver.) */ static void cxgb4vf_pci_remove(struct pci_dev *pdev) { … } /* * "Shutdown" quiesce the device, stopping Ingress Packet and Interrupt * delivery. */ static void cxgb4vf_pci_shutdown(struct pci_dev *pdev) { … } /* Macros needed to support the PCI Device ID Table ... */ #define CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN … #define CH_PCI_DEVICE_ID_FUNCTION … #define CH_PCI_ID_TABLE_ENTRY(devid) … #define CH_PCI_DEVICE_ID_TABLE_DEFINE_END … #include "../cxgb4/t4_pci_id_tbl.h" MODULE_DESCRIPTION(…); MODULE_AUTHOR(…) …; MODULE_LICENSE(…) …; MODULE_DEVICE_TABLE(pci, cxgb4vf_pci_tbl); static struct pci_driver cxgb4vf_driver = …; /* * Initialize global driver state. */ static int __init cxgb4vf_module_init(void) { … } /* * Tear down global driver state. */ static void __exit cxgb4vf_module_exit(void) { … } module_init(…) …; module_exit(cxgb4vf_module_exit);