1291ab06eSStefan Wahren /* 2291ab06eSStefan Wahren * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. 3291ab06eSStefan Wahren * Copyright (c) 2014, I2SE GmbH 4291ab06eSStefan Wahren * 5291ab06eSStefan Wahren * Permission to use, copy, modify, and/or distribute this software 6291ab06eSStefan Wahren * for any purpose with or without fee is hereby granted, provided 7291ab06eSStefan Wahren * that the above copyright notice and this permission notice appear 8291ab06eSStefan Wahren * in all copies. 9291ab06eSStefan Wahren * 10291ab06eSStefan Wahren * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11291ab06eSStefan Wahren * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12291ab06eSStefan Wahren * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 13291ab06eSStefan Wahren * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 14291ab06eSStefan Wahren * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15291ab06eSStefan Wahren * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 16291ab06eSStefan Wahren * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 17291ab06eSStefan Wahren * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18291ab06eSStefan Wahren */ 19291ab06eSStefan Wahren 20291ab06eSStefan Wahren /* This file contains debugging routines for use in the QCA7K driver. 21291ab06eSStefan Wahren */ 22291ab06eSStefan Wahren 23291ab06eSStefan Wahren #include <linux/debugfs.h> 24291ab06eSStefan Wahren #include <linux/ethtool.h> 25291ab06eSStefan Wahren #include <linux/seq_file.h> 26291ab06eSStefan Wahren #include <linux/types.h> 27291ab06eSStefan Wahren 28291ab06eSStefan Wahren #include "qca_7k.h" 29291ab06eSStefan Wahren #include "qca_debug.h" 30291ab06eSStefan Wahren 31291ab06eSStefan Wahren #define QCASPI_MAX_REGS 0x20 32291ab06eSStefan Wahren 33291ab06eSStefan Wahren static const u16 qcaspi_spi_regs[] = { 34291ab06eSStefan Wahren SPI_REG_BFR_SIZE, 35291ab06eSStefan Wahren SPI_REG_WRBUF_SPC_AVA, 36291ab06eSStefan Wahren SPI_REG_RDBUF_BYTE_AVA, 37291ab06eSStefan Wahren SPI_REG_SPI_CONFIG, 38291ab06eSStefan Wahren SPI_REG_SPI_STATUS, 39291ab06eSStefan Wahren SPI_REG_INTR_CAUSE, 40291ab06eSStefan Wahren SPI_REG_INTR_ENABLE, 41291ab06eSStefan Wahren SPI_REG_RDBUF_WATERMARK, 42291ab06eSStefan Wahren SPI_REG_WRBUF_WATERMARK, 43291ab06eSStefan Wahren SPI_REG_SIGNATURE, 44291ab06eSStefan Wahren SPI_REG_ACTION_CTRL 45291ab06eSStefan Wahren }; 46291ab06eSStefan Wahren 47291ab06eSStefan Wahren /* The order of these strings must match the order of the fields in 48291ab06eSStefan Wahren * struct qcaspi_stats 49291ab06eSStefan Wahren * See qca_spi.h 50291ab06eSStefan Wahren */ 51291ab06eSStefan Wahren static const char qcaspi_gstrings_stats[][ETH_GSTRING_LEN] = { 52291ab06eSStefan Wahren "Triggered resets", 53291ab06eSStefan Wahren "Device resets", 54291ab06eSStefan Wahren "Reset timeouts", 55291ab06eSStefan Wahren "Read errors", 56291ab06eSStefan Wahren "Write errors", 57291ab06eSStefan Wahren "Read buffer errors", 58291ab06eSStefan Wahren "Write buffer errors", 59291ab06eSStefan Wahren "Out of memory", 60291ab06eSStefan Wahren "Write buffer misses", 61291ab06eSStefan Wahren "Transmit ring full", 62291ab06eSStefan Wahren "SPI errors", 6348c1699eSStefan Wahren "Write verify errors", 64026b907dSStefan Wahren "Buffer available errors", 65291ab06eSStefan Wahren }; 66291ab06eSStefan Wahren 67291ab06eSStefan Wahren #ifdef CONFIG_DEBUG_FS 68291ab06eSStefan Wahren 69291ab06eSStefan Wahren static int 70291ab06eSStefan Wahren qcaspi_info_show(struct seq_file *s, void *what) 71291ab06eSStefan Wahren { 72291ab06eSStefan Wahren struct qcaspi *qca = s->private; 73291ab06eSStefan Wahren 74291ab06eSStefan Wahren seq_printf(s, "RX buffer size : %lu\n", 75291ab06eSStefan Wahren (unsigned long)qca->buffer_size); 76291ab06eSStefan Wahren 77291ab06eSStefan Wahren seq_puts(s, "TX ring state : "); 78291ab06eSStefan Wahren 79291ab06eSStefan Wahren if (qca->txr.skb[qca->txr.head] == NULL) 80291ab06eSStefan Wahren seq_puts(s, "empty"); 81291ab06eSStefan Wahren else if (qca->txr.skb[qca->txr.tail]) 82291ab06eSStefan Wahren seq_puts(s, "full"); 83291ab06eSStefan Wahren else 84291ab06eSStefan Wahren seq_puts(s, "in use"); 85291ab06eSStefan Wahren 86291ab06eSStefan Wahren seq_puts(s, "\n"); 87291ab06eSStefan Wahren 88291ab06eSStefan Wahren seq_printf(s, "TX ring size : %u\n", 89291ab06eSStefan Wahren qca->txr.size); 90291ab06eSStefan Wahren 91291ab06eSStefan Wahren seq_printf(s, "Sync state : %u (", 92291ab06eSStefan Wahren (unsigned int)qca->sync); 93291ab06eSStefan Wahren switch (qca->sync) { 94291ab06eSStefan Wahren case QCASPI_SYNC_UNKNOWN: 95291ab06eSStefan Wahren seq_puts(s, "QCASPI_SYNC_UNKNOWN"); 96291ab06eSStefan Wahren break; 97291ab06eSStefan Wahren case QCASPI_SYNC_RESET: 98291ab06eSStefan Wahren seq_puts(s, "QCASPI_SYNC_RESET"); 99291ab06eSStefan Wahren break; 100291ab06eSStefan Wahren case QCASPI_SYNC_READY: 101291ab06eSStefan Wahren seq_puts(s, "QCASPI_SYNC_READY"); 102291ab06eSStefan Wahren break; 103291ab06eSStefan Wahren default: 104291ab06eSStefan Wahren seq_puts(s, "INVALID"); 105291ab06eSStefan Wahren break; 106291ab06eSStefan Wahren } 107291ab06eSStefan Wahren seq_puts(s, ")\n"); 108291ab06eSStefan Wahren 109291ab06eSStefan Wahren seq_printf(s, "IRQ : %d\n", 110291ab06eSStefan Wahren qca->spi_dev->irq); 111291ab06eSStefan Wahren seq_printf(s, "INTR REQ : %u\n", 112291ab06eSStefan Wahren qca->intr_req); 113291ab06eSStefan Wahren seq_printf(s, "INTR SVC : %u\n", 114291ab06eSStefan Wahren qca->intr_svc); 115291ab06eSStefan Wahren 116291ab06eSStefan Wahren seq_printf(s, "SPI max speed : %lu\n", 117291ab06eSStefan Wahren (unsigned long)qca->spi_dev->max_speed_hz); 118291ab06eSStefan Wahren seq_printf(s, "SPI mode : %x\n", 119291ab06eSStefan Wahren qca->spi_dev->mode); 120291ab06eSStefan Wahren seq_printf(s, "SPI chip select : %u\n", 121291ab06eSStefan Wahren (unsigned int)qca->spi_dev->chip_select); 122291ab06eSStefan Wahren seq_printf(s, "SPI legacy mode : %u\n", 123291ab06eSStefan Wahren (unsigned int)qca->legacy_mode); 124291ab06eSStefan Wahren seq_printf(s, "SPI burst length : %u\n", 125291ab06eSStefan Wahren (unsigned int)qca->burst_len); 126291ab06eSStefan Wahren 127291ab06eSStefan Wahren return 0; 128291ab06eSStefan Wahren } 12925079154SYangtao Li DEFINE_SHOW_ATTRIBUTE(qcaspi_info); 130291ab06eSStefan Wahren 131291ab06eSStefan Wahren void 132291ab06eSStefan Wahren qcaspi_init_device_debugfs(struct qcaspi *qca) 133291ab06eSStefan Wahren { 134291ab06eSStefan Wahren struct dentry *device_root; 135291ab06eSStefan Wahren 136291ab06eSStefan Wahren device_root = debugfs_create_dir(dev_name(&qca->net_dev->dev), NULL); 137291ab06eSStefan Wahren qca->device_root = device_root; 138291ab06eSStefan Wahren 139291ab06eSStefan Wahren if (IS_ERR(device_root) || !device_root) { 140291ab06eSStefan Wahren pr_warn("failed to create debugfs directory for %s\n", 141291ab06eSStefan Wahren dev_name(&qca->net_dev->dev)); 142291ab06eSStefan Wahren return; 143291ab06eSStefan Wahren } 144d3757ba4SJoe Perches debugfs_create_file("info", S_IFREG | 0444, device_root, qca, 14525079154SYangtao Li &qcaspi_info_fops); 146291ab06eSStefan Wahren } 147291ab06eSStefan Wahren 148291ab06eSStefan Wahren void 149291ab06eSStefan Wahren qcaspi_remove_device_debugfs(struct qcaspi *qca) 150291ab06eSStefan Wahren { 151291ab06eSStefan Wahren debugfs_remove_recursive(qca->device_root); 152291ab06eSStefan Wahren } 153291ab06eSStefan Wahren 154291ab06eSStefan Wahren #else /* CONFIG_DEBUG_FS */ 155291ab06eSStefan Wahren 156291ab06eSStefan Wahren void 157291ab06eSStefan Wahren qcaspi_init_device_debugfs(struct qcaspi *qca) 158291ab06eSStefan Wahren { 159291ab06eSStefan Wahren } 160291ab06eSStefan Wahren 161291ab06eSStefan Wahren void 162291ab06eSStefan Wahren qcaspi_remove_device_debugfs(struct qcaspi *qca) 163291ab06eSStefan Wahren { 164291ab06eSStefan Wahren } 165291ab06eSStefan Wahren 166291ab06eSStefan Wahren #endif 167291ab06eSStefan Wahren 168291ab06eSStefan Wahren static void 169291ab06eSStefan Wahren qcaspi_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *p) 170291ab06eSStefan Wahren { 171291ab06eSStefan Wahren struct qcaspi *qca = netdev_priv(dev); 172291ab06eSStefan Wahren 173291ab06eSStefan Wahren strlcpy(p->driver, QCASPI_DRV_NAME, sizeof(p->driver)); 174291ab06eSStefan Wahren strlcpy(p->version, QCASPI_DRV_VERSION, sizeof(p->version)); 175291ab06eSStefan Wahren strlcpy(p->fw_version, "QCA7000", sizeof(p->fw_version)); 176291ab06eSStefan Wahren strlcpy(p->bus_info, dev_name(&qca->spi_dev->dev), 177291ab06eSStefan Wahren sizeof(p->bus_info)); 178291ab06eSStefan Wahren } 179291ab06eSStefan Wahren 180291ab06eSStefan Wahren static int 1812cf8a897SPhilippe Reynes qcaspi_get_link_ksettings(struct net_device *dev, 1822cf8a897SPhilippe Reynes struct ethtool_link_ksettings *cmd) 183291ab06eSStefan Wahren { 1842cf8a897SPhilippe Reynes ethtool_link_ksettings_zero_link_mode(cmd, supported); 1852cf8a897SPhilippe Reynes ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Half); 1862cf8a897SPhilippe Reynes 1872cf8a897SPhilippe Reynes cmd->base.speed = SPEED_10; 1882cf8a897SPhilippe Reynes cmd->base.duplex = DUPLEX_HALF; 1892cf8a897SPhilippe Reynes cmd->base.port = PORT_OTHER; 1902cf8a897SPhilippe Reynes cmd->base.autoneg = AUTONEG_DISABLE; 191291ab06eSStefan Wahren 192291ab06eSStefan Wahren return 0; 193291ab06eSStefan Wahren } 194291ab06eSStefan Wahren 195291ab06eSStefan Wahren static void 196291ab06eSStefan Wahren qcaspi_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, u64 *data) 197291ab06eSStefan Wahren { 198291ab06eSStefan Wahren struct qcaspi *qca = netdev_priv(dev); 199291ab06eSStefan Wahren struct qcaspi_stats *st = &qca->stats; 200291ab06eSStefan Wahren 201291ab06eSStefan Wahren memcpy(data, st, ARRAY_SIZE(qcaspi_gstrings_stats) * sizeof(u64)); 202291ab06eSStefan Wahren } 203291ab06eSStefan Wahren 204291ab06eSStefan Wahren static void 205291ab06eSStefan Wahren qcaspi_get_strings(struct net_device *dev, u32 stringset, u8 *buf) 206291ab06eSStefan Wahren { 207291ab06eSStefan Wahren switch (stringset) { 208291ab06eSStefan Wahren case ETH_SS_STATS: 209291ab06eSStefan Wahren memcpy(buf, &qcaspi_gstrings_stats, 210291ab06eSStefan Wahren sizeof(qcaspi_gstrings_stats)); 211291ab06eSStefan Wahren break; 212291ab06eSStefan Wahren default: 213291ab06eSStefan Wahren WARN_ON(1); 214291ab06eSStefan Wahren break; 215291ab06eSStefan Wahren } 216291ab06eSStefan Wahren } 217291ab06eSStefan Wahren 218291ab06eSStefan Wahren static int 219291ab06eSStefan Wahren qcaspi_get_sset_count(struct net_device *dev, int sset) 220291ab06eSStefan Wahren { 221291ab06eSStefan Wahren switch (sset) { 222291ab06eSStefan Wahren case ETH_SS_STATS: 223291ab06eSStefan Wahren return ARRAY_SIZE(qcaspi_gstrings_stats); 224291ab06eSStefan Wahren default: 225291ab06eSStefan Wahren return -EINVAL; 226291ab06eSStefan Wahren } 227291ab06eSStefan Wahren } 228291ab06eSStefan Wahren 229291ab06eSStefan Wahren static int 230291ab06eSStefan Wahren qcaspi_get_regs_len(struct net_device *dev) 231291ab06eSStefan Wahren { 232291ab06eSStefan Wahren return sizeof(u32) * QCASPI_MAX_REGS; 233291ab06eSStefan Wahren } 234291ab06eSStefan Wahren 235291ab06eSStefan Wahren static void 236291ab06eSStefan Wahren qcaspi_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) 237291ab06eSStefan Wahren { 238291ab06eSStefan Wahren struct qcaspi *qca = netdev_priv(dev); 239291ab06eSStefan Wahren u32 *regs_buff = p; 240291ab06eSStefan Wahren unsigned int i; 241291ab06eSStefan Wahren 242291ab06eSStefan Wahren regs->version = 1; 243291ab06eSStefan Wahren memset(regs_buff, 0, sizeof(u32) * QCASPI_MAX_REGS); 244291ab06eSStefan Wahren 245291ab06eSStefan Wahren for (i = 0; i < ARRAY_SIZE(qcaspi_spi_regs); i++) { 246291ab06eSStefan Wahren u16 offset, value; 247291ab06eSStefan Wahren 248291ab06eSStefan Wahren qcaspi_read_register(qca, qcaspi_spi_regs[i], &value); 249291ab06eSStefan Wahren offset = qcaspi_spi_regs[i] >> 8; 250291ab06eSStefan Wahren regs_buff[offset] = value; 251291ab06eSStefan Wahren } 252291ab06eSStefan Wahren } 253291ab06eSStefan Wahren 254291ab06eSStefan Wahren static void 255291ab06eSStefan Wahren qcaspi_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) 256291ab06eSStefan Wahren { 257291ab06eSStefan Wahren struct qcaspi *qca = netdev_priv(dev); 258291ab06eSStefan Wahren 259291ab06eSStefan Wahren ring->rx_max_pending = 4; 260291ab06eSStefan Wahren ring->tx_max_pending = TX_RING_MAX_LEN; 261291ab06eSStefan Wahren ring->rx_pending = 4; 262291ab06eSStefan Wahren ring->tx_pending = qca->txr.count; 263291ab06eSStefan Wahren } 264291ab06eSStefan Wahren 265291ab06eSStefan Wahren static int 266291ab06eSStefan Wahren qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) 267291ab06eSStefan Wahren { 2680324e75dSStefan Wahren const struct net_device_ops *ops = dev->netdev_ops; 269291ab06eSStefan Wahren struct qcaspi *qca = netdev_priv(dev); 270291ab06eSStefan Wahren 271291ab06eSStefan Wahren if ((ring->rx_pending) || 272291ab06eSStefan Wahren (ring->rx_mini_pending) || 273291ab06eSStefan Wahren (ring->rx_jumbo_pending)) 274291ab06eSStefan Wahren return -EINVAL; 275291ab06eSStefan Wahren 276291ab06eSStefan Wahren if (netif_running(dev)) 2770324e75dSStefan Wahren ops->ndo_stop(dev); 278291ab06eSStefan Wahren 279291ab06eSStefan Wahren qca->txr.count = max_t(u32, ring->tx_pending, TX_RING_MIN_LEN); 280291ab06eSStefan Wahren qca->txr.count = min_t(u16, qca->txr.count, TX_RING_MAX_LEN); 281291ab06eSStefan Wahren 282291ab06eSStefan Wahren if (netif_running(dev)) 2830324e75dSStefan Wahren ops->ndo_open(dev); 284291ab06eSStefan Wahren 285291ab06eSStefan Wahren return 0; 286291ab06eSStefan Wahren } 287291ab06eSStefan Wahren 288291ab06eSStefan Wahren static const struct ethtool_ops qcaspi_ethtool_ops = { 289291ab06eSStefan Wahren .get_drvinfo = qcaspi_get_drvinfo, 290291ab06eSStefan Wahren .get_link = ethtool_op_get_link, 291291ab06eSStefan Wahren .get_ethtool_stats = qcaspi_get_ethtool_stats, 292291ab06eSStefan Wahren .get_strings = qcaspi_get_strings, 293291ab06eSStefan Wahren .get_sset_count = qcaspi_get_sset_count, 294291ab06eSStefan Wahren .get_regs_len = qcaspi_get_regs_len, 295291ab06eSStefan Wahren .get_regs = qcaspi_get_regs, 296291ab06eSStefan Wahren .get_ringparam = qcaspi_get_ringparam, 297291ab06eSStefan Wahren .set_ringparam = qcaspi_set_ringparam, 2982cf8a897SPhilippe Reynes .get_link_ksettings = qcaspi_get_link_ksettings, 299291ab06eSStefan Wahren }; 300291ab06eSStefan Wahren 301291ab06eSStefan Wahren void qcaspi_set_ethtool_ops(struct net_device *dev) 302291ab06eSStefan Wahren { 303291ab06eSStefan Wahren dev->ethtool_ops = &qcaspi_ethtool_ops; 304291ab06eSStefan Wahren } 305