diff options
author | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-05-15 21:46:41 -0700 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-08-11 16:28:56 -0700 |
commit | ef7f54297df683665145859501f63c801f6c7ea8 (patch) | |
tree | b41a8cc3d8b786984859e0ba483ddbe796314ff7 /drivers/net/tehuti.c | |
parent | ded19addf9c937d83b9bfb4d73a836732569041b (diff) | |
download | linux-ef7f54297df683665145859501f63c801f6c7ea8.tar.gz linux-ef7f54297df683665145859501f63c801f6c7ea8.tar.bz2 linux-ef7f54297df683665145859501f63c801f6c7ea8.zip |
tehuti: Move the Tehuti driver
Move the Tehuti driver into drivers/net/ethernet/tehuti/ and
make the necessary Kconfig and Makefile changes.
CC: Alexander Indenbaum <baum@tehutinetworks.net>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/tehuti.c')
-rw-r--r-- | drivers/net/tehuti.c | 2470 |
1 files changed, 0 insertions, 2470 deletions
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c deleted file mode 100644 index 749bbf18dc6a..000000000000 --- a/drivers/net/tehuti.c +++ /dev/null @@ -1,2470 +0,0 @@ -/* - * Tehuti Networks(R) Network Driver - * ethtool interface implementation - * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -/* - * RX HW/SW interaction overview - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * There are 2 types of RX communication channels between driver and NIC. - * 1) RX Free Fifo - RXF - holds descriptors of empty buffers to accept incoming - * traffic. This Fifo is filled by SW and is readen by HW. Each descriptor holds - * info about buffer's location, size and ID. An ID field is used to identify a - * buffer when it's returned with data via RXD Fifo (see below) - * 2) RX Data Fifo - RXD - holds descriptors of full buffers. This Fifo is - * filled by HW and is readen by SW. Each descriptor holds status and ID. - * HW pops descriptor from RXF Fifo, stores ID, fills buffer with incoming data, - * via dma moves it into host memory, builds new RXD descriptor with same ID, - * pushes it into RXD Fifo and raises interrupt to indicate new RX data. - * - * Current NIC configuration (registers + firmware) makes NIC use 2 RXF Fifos. - * One holds 1.5K packets and another - 26K packets. Depending on incoming - * packet size, HW desides on a RXF Fifo to pop buffer from. When packet is - * filled with data, HW builds new RXD descriptor for it and push it into single - * RXD Fifo. - * - * RX SW Data Structures - * ~~~~~~~~~~~~~~~~~~~~~ - * skb db - used to keep track of all skbs owned by SW and their dma addresses. - * For RX case, ownership lasts from allocating new empty skb for RXF until - * accepting full skb from RXD and passing it to OS. Each RXF Fifo has its own - * skb db. Implemented as array with bitmask. - * fifo - keeps info about fifo's size and location, relevant HW registers, - * usage and skb db. Each RXD and RXF Fifo has its own fifo structure. - * Implemented as simple struct. - * - * RX SW Execution Flow - * ~~~~~~~~~~~~~~~~~~~~ - * Upon initialization (ifconfig up) driver creates RX fifos and initializes - * relevant registers. At the end of init phase, driver enables interrupts. - * NIC sees that there is no RXF buffers and raises - * RD_INTR interrupt, isr fills skbs and Rx begins. - * Driver has two receive operation modes: - * NAPI - interrupt-driven mixed with polling - * interrupt-driven only - * - * Interrupt-driven only flow is following. When buffer is ready, HW raises - * interrupt and isr is called. isr collects all available packets - * (bdx_rx_receive), refills skbs (bdx_rx_alloc_skbs) and exit. - - * Rx buffer allocation note - * ~~~~~~~~~~~~~~~~~~~~~~~~~ - * Driver cares to feed such amount of RxF descriptors that respective amount of - * RxD descriptors can not fill entire RxD fifo. The main reason is lack of - * overflow check in Bordeaux for RxD fifo free/used size. - * FIXME: this is NOT fully implemented, more work should be done - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include "tehuti.h" - -static DEFINE_PCI_DEVICE_TABLE(bdx_pci_tbl) = { - {0x1FC9, 0x3009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x1FC9, 0x3010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x1FC9, 0x3014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0} -}; - -MODULE_DEVICE_TABLE(pci, bdx_pci_tbl); - -/* Definitions needed by ISR or NAPI functions */ -static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f); -static void bdx_tx_cleanup(struct bdx_priv *priv); -static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget); - -/* Definitions needed by FW loading */ -static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size); - -/* Definitions needed by hw_start */ -static int bdx_tx_init(struct bdx_priv *priv); -static int bdx_rx_init(struct bdx_priv *priv); - -/* Definitions needed by bdx_close */ -static void bdx_rx_free(struct bdx_priv *priv); -static void bdx_tx_free(struct bdx_priv *priv); - -/* Definitions needed by bdx_probe */ -static void bdx_set_ethtool_ops(struct net_device *netdev); - -/************************************************************************* - * Print Info * - *************************************************************************/ - -static void print_hw_id(struct pci_dev *pdev) -{ - struct pci_nic *nic = pci_get_drvdata(pdev); - u16 pci_link_status = 0; - u16 pci_ctrl = 0; - - pci_read_config_word(pdev, PCI_LINK_STATUS_REG, &pci_link_status); - pci_read_config_word(pdev, PCI_DEV_CTRL_REG, &pci_ctrl); - - pr_info("%s%s\n", BDX_NIC_NAME, - nic->port_num == 1 ? "" : ", 2-Port"); - pr_info("srom 0x%x fpga %d build %u lane# %d max_pl 0x%x mrrs 0x%x\n", - readl(nic->regs + SROM_VER), readl(nic->regs + FPGA_VER) & 0xFFF, - readl(nic->regs + FPGA_SEED), - GET_LINK_STATUS_LANES(pci_link_status), - GET_DEV_CTRL_MAXPL(pci_ctrl), GET_DEV_CTRL_MRRS(pci_ctrl)); -} - -static void print_fw_id(struct pci_nic *nic) -{ - pr_info("fw 0x%x\n", readl(nic->regs + FW_VER)); -} - -static void print_eth_id(struct net_device *ndev) -{ - netdev_info(ndev, "%s, Port %c\n", - BDX_NIC_NAME, (ndev->if_port == 0) ? 'A' : 'B'); - -} - -/************************************************************************* - * Code * - *************************************************************************/ - -#define bdx_enable_interrupts(priv) \ - do { WRITE_REG(priv, regIMR, IR_RUN); } while (0) -#define bdx_disable_interrupts(priv) \ - do { WRITE_REG(priv, regIMR, 0); } while (0) - -/* bdx_fifo_init - * create TX/RX descriptor fifo for host-NIC communication. - * 1K extra space is allocated at the end of the fifo to simplify - * processing of descriptors that wraps around fifo's end - * @priv - NIC private structure - * @f - fifo to initialize - * @fsz_type - fifo size type: 0-4KB, 1-8KB, 2-16KB, 3-32KB - * @reg_XXX - offsets of registers relative to base address - * - * Returns 0 on success, negative value on failure - * - */ -static int -bdx_fifo_init(struct bdx_priv *priv, struct fifo *f, int fsz_type, - u16 reg_CFG0, u16 reg_CFG1, u16 reg_RPTR, u16 reg_WPTR) -{ - u16 memsz = FIFO_SIZE * (1 << fsz_type); - - memset(f, 0, sizeof(struct fifo)); - /* pci_alloc_consistent gives us 4k-aligned memory */ - f->va = pci_alloc_consistent(priv->pdev, - memsz + FIFO_EXTRA_SPACE, &f->da); - if (!f->va) { - pr_err("pci_alloc_consistent failed\n"); - RET(-ENOMEM); - } - f->reg_CFG0 = reg_CFG0; - f->reg_CFG1 = reg_CFG1; - f->reg_RPTR = reg_RPTR; - f->reg_WPTR = reg_WPTR; - f->rptr = 0; - f->wptr = 0; - f->memsz = memsz; - f->size_mask = memsz - 1; - WRITE_REG(priv, reg_CFG0, (u32) ((f->da & TX_RX_CFG0_BASE) | fsz_type)); - WRITE_REG(priv, reg_CFG1, H32_64(f->da)); - - RET(0); -} - -/* bdx_fifo_free - free all resources used by fifo - * @priv - NIC private structure - * @f - fifo to release - */ -static void bdx_fifo_free(struct bdx_priv *priv, struct fifo *f) -{ - ENTER; - if (f->va) { - pci_free_consistent(priv->pdev, - f->memsz + FIFO_EXTRA_SPACE, f->va, f->da); - f->va = NULL; - } - RET(); -} - -/* - * bdx_link_changed - notifies OS about hw link state. - * @bdx_priv - hw adapter structure - */ -static void bdx_link_changed(struct bdx_priv *priv) -{ - u32 link = READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT; - - if (!link) { - if (netif_carrier_ok(priv->ndev)) { - netif_stop_queue(priv->ndev); - netif_carrier_off(priv->ndev); - netdev_err(priv->ndev, "Link Down\n"); - } - } else { - if (!netif_carrier_ok(priv->ndev)) { - netif_wake_queue(priv->ndev); - netif_carrier_on(priv->ndev); - netdev_err(priv->ndev, "Link Up\n"); - } - } -} - -static void bdx_isr_extra(struct bdx_priv *priv, u32 isr) -{ - if (isr & IR_RX_FREE_0) { - bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0); - DBG("RX_FREE_0\n"); - } - - if (isr & IR_LNKCHG0) - bdx_link_changed(priv); - - if (isr & IR_PCIE_LINK) - netdev_err(priv->ndev, "PCI-E Link Fault\n"); - - if (isr & IR_PCIE_TOUT) - netdev_err(priv->ndev, "PCI-E Time Out\n"); - -} - -/* bdx_isr - Interrupt Service Routine for Bordeaux NIC - * @irq - interrupt number - * @ndev - network device - * @regs - CPU registers - * - * Return IRQ_NONE if it was not our interrupt, IRQ_HANDLED - otherwise - * - * It reads ISR register to know interrupt reasons, and proceed them one by one. - * Reasons of interest are: - * RX_DESC - new packet has arrived and RXD fifo holds its descriptor - * RX_FREE - number of free Rx buffers in RXF fifo gets low - * TX_FREE - packet was transmited and RXF fifo holds its descriptor - */ - -static irqreturn_t bdx_isr_napi(int irq, void *dev) -{ - struct net_device *ndev = dev; - struct bdx_priv *priv = netdev_priv(ndev); - u32 isr; - - ENTER; - isr = (READ_REG(priv, regISR) & IR_RUN); - if (unlikely(!isr)) { - bdx_enable_interrupts(priv); - return IRQ_NONE; /* Not our interrupt */ - } - - if (isr & IR_EXTRA) - bdx_isr_extra(priv, isr); - - if (isr & (IR_RX_DESC_0 | IR_TX_FREE_0)) { - if (likely(napi_schedule_prep(&priv->napi))) { - __napi_schedule(&priv->napi); - RET(IRQ_HANDLED); - } else { - /* NOTE: we get here if intr has slipped into window - * between these lines in bdx_poll: - * bdx_enable_interrupts(priv); - * return 0; - * currently intrs are disabled (since we read ISR), - * and we have failed to register next poll. - * so we read the regs to trigger chip - * and allow further interupts. */ - READ_REG(priv, regTXF_WPTR_0); - READ_REG(priv, regRXD_WPTR_0); - } - } - - bdx_enable_interrupts(priv); - RET(IRQ_HANDLED); -} - -static int bdx_poll(struct napi_struct *napi, int budget) -{ - struct bdx_priv *priv = container_of(napi, struct bdx_priv, napi); - int work_done; - - ENTER; - bdx_tx_cleanup(priv); - work_done = bdx_rx_receive(priv, &priv->rxd_fifo0, budget); - if ((work_done < budget) || - (priv->napi_stop++ >= 30)) { - DBG("rx poll is done. backing to isr-driven\n"); - - /* from time to time we exit to let NAPI layer release - * device lock and allow waiting tasks (eg rmmod) to advance) */ - priv->napi_stop = 0; - - napi_complete(napi); - bdx_enable_interrupts(priv); - } - return work_done; -} - -/* bdx_fw_load - loads firmware to NIC - * @priv - NIC private structure - * Firmware is loaded via TXD fifo, so it must be initialized first. - * Firware must be loaded once per NIC not per PCI device provided by NIC (NIC - * can have few of them). So all drivers use semaphore register to choose one - * that will actually load FW to NIC. - */ - -static int bdx_fw_load(struct bdx_priv *priv) -{ - const struct firmware *fw = NULL; - int master, i; - int rc; - - ENTER; - master = READ_REG(priv, regINIT_SEMAPHORE); - if (!READ_REG(priv, regINIT_STATUS) && master) { - rc = request_firmware(&fw, "tehuti/bdx.bin", &priv->pdev->dev); - if (rc) - goto out; - bdx_tx_push_desc_safe(priv, (char *)fw->data, fw->size); - mdelay(100); - } - for (i = 0; i < 200; i++) { - if (READ_REG(priv, regINIT_STATUS)) { - rc = 0; - goto out; - } - mdelay(2); - } - rc = -EIO; -out: - if (master) - WRITE_REG(priv, regINIT_SEMAPHORE, 1); - if (fw) - release_firmware(fw); - - if (rc) { - netdev_err(priv->ndev, "firmware loading failed\n"); - if (rc == -EIO) - DBG("VPC = 0x%x VIC = 0x%x INIT_STATUS = 0x%x i=%d\n", - READ_REG(priv, regVPC), - READ_REG(priv, regVIC), - READ_REG(priv, regINIT_STATUS), i); - RET(rc); - } else { - DBG("%s: firmware loading success\n", priv->ndev->name); - RET(0); - } -} - -static void bdx_restore_mac(struct net_device *ndev, struct bdx_priv *priv) -{ - u32 val; - - ENTER; - DBG("mac0=%x mac1=%x mac2=%x\n", - READ_REG(priv, regUNC_MAC0_A), - READ_REG(priv, regUNC_MAC1_A), READ_REG(priv, regUNC_MAC2_A)); - - val = (ndev->dev_addr[0] << 8) | (ndev->dev_addr[1]); - WRITE_REG(priv, regUNC_MAC2_A, val); - val = (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]); - WRITE_REG(priv, regUNC_MAC1_A, val); - val = (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]); - WRITE_REG(priv, regUNC_MAC0_A, val); - - DBG("mac0=%x mac1=%x mac2=%x\n", - READ_REG(priv, regUNC_MAC0_A), - READ_REG(priv, regUNC_MAC1_A), READ_REG(priv, regUNC_MAC2_A)); - RET(); -} - -/* bdx_hw_start - inits registers and starts HW's Rx and Tx engines - * @priv - NIC private structure - */ -static int bdx_hw_start(struct bdx_priv *priv) -{ - int rc = -EIO; - struct net_device *ndev = priv->ndev; - - ENTER; - bdx_link_changed(priv); - - /* 10G overall max length (vlan, eth&ip header, ip payload, crc) */ - WRITE_REG(priv, regFRM_LENGTH, 0X3FE0); - WRITE_REG(priv, regPAUSE_QUANT, 0x96); - WRITE_REG(priv, regRX_FIFO_SECTION, 0x800010); - WRITE_REG(priv, regTX_FIFO_SECTION, 0xE00010); - WRITE_REG(priv, regRX_FULLNESS, 0); - WRITE_REG(priv, regTX_FULLNESS, 0); - WRITE_REG(priv, regCTRLST, - regCTRLST_BASE | regCTRLST_RX_ENA | regCTRLST_TX_ENA); - - WRITE_REG(priv, regVGLB, 0); - WRITE_REG(priv, regMAX_FRAME_A, - priv->rxf_fifo0.m.pktsz & MAX_FRAME_AB_VAL); - - DBG("RDINTCM=%08x\n", priv->rdintcm); /*NOTE: test script uses this */ - WRITE_REG(priv, regRDINTCM0, priv->rdintcm); - WRITE_REG(priv, regRDINTCM2, 0); /*cpu_to_le32(rcm.val)); */ - - DBG("TDINTCM=%08x\n", priv->tdintcm); /*NOTE: test script uses this */ - WRITE_REG(priv, regTDINTCM0, priv->tdintcm); /* old val = 0x300064 */ - - /* Enable timer interrupt once in 2 secs. */ - /*WRITE_REG(priv, regGTMR0, ((GTMR_SEC * 2) & GTMR_DATA)); */ - bdx_restore_mac(priv->ndev, priv); - - WRITE_REG(priv, regGMAC_RXF_A, GMAC_RX_FILTER_OSEN | - GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB); - -#define BDX_IRQ_TYPE ((priv->nic->irq_type == IRQ_MSI) ? 0 : IRQF_SHARED) - - rc = request_irq(priv->pdev->irq, bdx_isr_napi, BDX_IRQ_TYPE, - ndev->name, ndev); - if (rc) - goto err_irq; - bdx_enable_interrupts(priv); - - RET(0); - -err_irq: - RET(rc); -} - -static void bdx_hw_stop(struct bdx_priv *priv) -{ - ENTER; - bdx_disable_interrupts(priv); - free_irq(priv->pdev->irq, priv->ndev); - - netif_carrier_off(priv->ndev); - netif_stop_queue(priv->ndev); - - RET(); -} - -static int bdx_hw_reset_direct(void __iomem *regs) -{ - u32 val, i; - ENTER; - - /* reset sequences: read, write 1, read, write 0 */ - val = readl(regs + regCLKPLL); - writel((val | CLKPLL_SFTRST) + 0x8, regs + regCLKPLL); - udelay(50); - val = readl(regs + regCLKPLL); - writel(val & ~CLKPLL_SFTRST, regs + regCLKPLL); - - /* check that the PLLs are locked and reset ended */ - for (i = 0; i < 70; i++, mdelay(10)) - if ((readl(regs + regCLKPLL) & CLKPLL_LKD) == CLKPLL_LKD) { - /* do any PCI-E read transaction */ - readl(regs + regRXD_CFG0_0); - return 0; - } - pr_err("HW reset failed\n"); - return 1; /* failure */ -} - -static int bdx_hw_reset(struct bdx_priv *priv) -{ - u32 val, i; - ENTER; - - if (priv->port == 0) { - /* reset sequences: read, write 1, read, write 0 */ - val = READ_REG(priv, regCLKPLL); - WRITE_REG(priv, regCLKPLL, (val | CLKPLL_SFTRST) + 0x8); - udelay(50); - val = READ_REG(priv, regCLKPLL); - WRITE_REG(priv, regCLKPLL, val & ~CLKPLL_SFTRST); - } - /* check that the PLLs are locked and reset ended */ - for (i = 0; i < 70; i++, mdelay(10)) - if ((READ_REG(priv, regCLKPLL) & CLKPLL_LKD) == CLKPLL_LKD) { - /* do any PCI-E read transaction */ - READ_REG(priv, regRXD_CFG0_0); - return 0; - } - pr_err("HW reset failed\n"); - return 1; /* failure */ -} - -static int bdx_sw_reset(struct bdx_priv *priv) -{ - int i; - - ENTER; - /* 1. load MAC (obsolete) */ - /* 2. disable Rx (and Tx) */ - WRITE_REG(priv, regGMAC_RXF_A, 0); - mdelay(100); - /* 3. disable port */ - WRITE_REG(priv, regDIS_PORT, 1); - /* 4. disable queue */ - WRITE_REG(priv, regDIS_QU, 1); - /* 5. wait until hw is disabled */ - for (i = 0; i < 50; i++) { - if (READ_REG(priv, regRST_PORT) & 1) - break; - mdelay(10); - } - if (i == 50) - netdev_err(priv->ndev, "SW reset timeout. continuing anyway\n"); - - /* 6. disable intrs */ - WRITE_REG(priv, regRDINTCM0, 0); - WRITE_REG(priv, regTDINTCM0, 0); - WRITE_REG(priv, regIMR, 0); - READ_REG(priv, regISR); - - /* 7. reset queue */ - WRITE_REG(priv, regRST_QU, 1); - /* 8. reset port */ - WRITE_REG(priv, regRST_PORT, 1); - /* 9. zero all read and write pointers */ - for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10) - DBG("%x = %x\n", i, READ_REG(priv, i) & TXF_WPTR_WR_PTR); - for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10) - WRITE_REG(priv, i, 0); - /* 10. unseet port disable */ - WRITE_REG(priv, regDIS_PORT, 0); - /* 11. unset queue disable */ - WRITE_REG(priv, regDIS_QU, 0); - /* 12. unset queue reset */ - WRITE_REG(priv, regRST_QU, 0); - /* 13. unset port reset */ - WRITE_REG(priv, regRST_PORT, 0); - /* 14. enable Rx */ - /* skiped. will be done later */ - /* 15. save MAC (obsolete) */ - for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10) - DBG("%x = %x\n", i, READ_REG(priv, i) & TXF_WPTR_WR_PTR); - - RET(0); -} - -/* bdx_reset - performs right type of reset depending on hw type */ -static int bdx_reset(struct bdx_priv *priv) -{ - ENTER; - RET((priv->pdev->device == 0x3009) - ? bdx_hw_reset(priv) - : bdx_sw_reset(priv)); -} - -/** - * bdx_close - Disables a network interface - * @netdev: network interface device structure - * - * Returns 0, this is not allowed to fail - * - * The close entry point is called when an interface is de-activated - * by the OS. The hardware is still under the drivers control, but - * needs to be disabled. A global MAC reset is issued to stop the - * hardware, and all transmit and receive resources are freed. - **/ -static int bdx_close(struct net_device *ndev) -{ - struct bdx_priv *priv = NULL; - - ENTER; - priv = netdev_priv(ndev); - - napi_disable(&priv->napi); - - bdx_reset(priv); - bdx_hw_stop(priv); - bdx_rx_free(priv); - bdx_tx_free(priv); - RET(0); -} - -/** - * bdx_open - Called when a network interface is made active - * @netdev: network interface device structure - * - * Returns 0 on success, negative value on failure - * - * The open entry point is called when a network interface is made - * active by the system (IFF_UP). At this point all resources needed - * for transmit and receive operations are allocated, the interrupt - * handler is registered with the OS, the watchdog timer is started, - * and the stack is notified that the interface is ready. - **/ -static int bdx_open(struct net_device *ndev) -{ - struct bdx_priv *priv; - int rc; - - ENTER; - priv = netdev_priv(ndev); - bdx_reset(priv); - if (netif_running(ndev)) - netif_stop_queue(priv->ndev); - - if ((rc = bdx_tx_init(priv)) || - (rc = bdx_rx_init(priv)) || - (rc = bdx_fw_load(priv))) - goto err; - - bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0); - - rc = bdx_hw_start(priv); - if (rc) - goto err; - - napi_enable(&priv->napi); - - print_fw_id(priv->nic); - - RET(0); - -err: - bdx_close(ndev); - RET(rc); -} - -static int bdx_range_check(struct bdx_priv *priv, u32 offset) -{ - return (offset > (u32) (BDX_REGS_SIZE / priv->nic->port_num)) ? - -EINVAL : 0; -} - -static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) -{ - struct bdx_priv *priv = netdev_priv(ndev); - u32 data[3]; - int error; - - ENTER; - - DBG("jiffies=%ld cmd=%d\n", jiffies, cmd); - if (cmd != SIOCDEVPRIVATE) { - error = copy_from_user(data, ifr->ifr_data, sizeof(data)); - if (error) { - pr_err("can't copy from user\n"); - RET(-EFAULT); - } - DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]); - } - - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - - switch (data[0]) { - - case BDX_OP_READ: - error = bdx_range_check(priv, data[1]); - if (error < 0) - return error; - data[2] = READ_REG(priv, data[1]); - DBG("read_reg(0x%x)=0x%x (dec %d)\n", data[1], data[2], - data[2]); - error = copy_to_user(ifr->ifr_data, data, sizeof(data)); - if (error) - RET(-EFAULT); - break; - - case BDX_OP_WRITE: - error = bdx_range_check(priv, data[1]); - if (error < 0) - return error; - WRITE_REG(priv, data[1], data[2]); - DBG("write_reg(0x%x, 0x%x)\n", data[1], data[2]); - break; - - default: - RET(-EOPNOTSUPP); - } - return 0; -} - -static int bdx_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) -{ - ENTER; - if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) - RET(bdx_ioctl_priv(ndev, ifr, cmd)); - else - RET(-EOPNOTSUPP); -} - -/* - * __bdx_vlan_rx_vid - private helper for adding/killing VLAN vid - * by passing VLAN filter table to hardware - * @ndev network device - * @vid VLAN vid - * @op add or kill operation - */ -static void __bdx_vlan_rx_vid(struct net_device *ndev, uint16_t vid, int enable) -{ - struct bdx_priv *priv = netdev_priv(ndev); - u32 reg, bit, val; - - ENTER; - DBG2("vid=%d value=%d\n", (int)vid, enable); - if (unlikely(vid >= 4096)) { - pr_err("invalid VID: %u (> 4096)\n", vid); - RET(); - } - reg = regVLAN_0 + (vid / 32) * 4; - bit = 1 << vid % 32; - val = READ_REG(priv, reg); - DBG2("reg=%x, val=%x, bit=%d\n", reg, val, bit); - if (enable) - val |= bit; - else - val &= ~bit; - DBG2("new val %x\n", val); - WRITE_REG(priv, reg, val); - RET(); -} - -/* - * bdx_vlan_rx_add_vid - kernel hook for adding VLAN vid to hw filtering table - * @ndev network device - * @vid VLAN vid to add - */ -static void bdx_vlan_rx_add_vid(struct net_device *ndev, uint16_t vid) -{ - __bdx_vlan_rx_vid(ndev, vid, 1); -} - -/* - * bdx_vlan_rx_kill_vid - kernel hook for killing VLAN vid in hw filtering table - * @ndev network device - * @vid VLAN vid to kill - */ -static void bdx_vlan_rx_kill_vid(struct net_device *ndev, unsigned short vid) -{ - __bdx_vlan_rx_vid(ndev, vid, 0); -} - -/** - * bdx_change_mtu - Change the Maximum Transfer Unit - * @netdev: network interface device structure - * @new_mtu: new value for maximum frame size - * - * Returns 0 on success, negative on failure - */ -static int bdx_change_mtu(struct net_device *ndev, int new_mtu) -{ - ENTER; - - if (new_mtu == ndev->mtu) - RET(0); - - /* enforce minimum frame size */ - if (new_mtu < ETH_ZLEN) { - netdev_err(ndev, "mtu %d is less then minimal %d\n", - new_mtu, ETH_ZLEN); - RET(-EINVAL); - } - - ndev->mtu = new_mtu; - if (netif_running(ndev)) { - bdx_close(ndev); - bdx_open(ndev); - } - RET(0); -} - -static void bdx_setmulti(struct net_device *ndev) -{ - struct bdx_priv *priv = netdev_priv(ndev); - - u32 rxf_val = - GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB | GMAC_RX_FILTER_OSEN; - int i; - - ENTER; - /* IMF - imperfect (hash) rx multicat filter */ - /* PMF - perfect rx multicat filter */ - - /* FIXME: RXE(OFF) */ - if (ndev->flags & IFF_PROMISC) { - rxf_val |= GMAC_RX_FILTER_PRM; - } else if (ndev->flags & IFF_ALLMULTI) { - /* set IMF to accept all multicast frmaes */ - for (i = 0; i < MAC_MCST_HASH_NUM; i++) - WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, ~0); - } else if (!netdev_mc_empty(ndev)) { - u8 hash; - struct netdev_hw_addr *ha; - u32 reg, val; - - /* set IMF to deny all multicast frames */ - for (i = 0; i < MAC_MCST_HASH_NUM; i++) - WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, 0); - /* set PMF to deny all multicast frames */ - for (i = 0; i < MAC_MCST_NUM; i++) { - WRITE_REG(priv, regRX_MAC_MCST0 + i * 8, 0); - WRITE_REG(priv, regRX_MAC_MCST1 + i * 8, 0); - } - - /* use PMF to accept first MAC_MCST_NUM (15) addresses */ - /* TBD: sort addresses and write them in ascending order - * into RX_MAC_MCST regs. we skip this phase now and accept ALL - * multicast frames throu IMF */ - /* accept the rest of addresses throu IMF */ - netdev_for_each_mc_addr(ha, ndev) { - hash = 0; - for (i = 0; i < ETH_ALEN; i++) - hash ^= ha->addr[i]; - reg = regRX_MCST_HASH0 + ((hash >> 5) << 2); - val = READ_REG(priv, reg); - val |= (1 << (hash % 32)); - WRITE_REG(priv, reg, val); - } - - } else { - DBG("only own mac %d\n", netdev_mc_count(ndev)); - rxf_val |= GMAC_RX_FILTER_AB; - } - WRITE_REG(priv, regGMAC_RXF_A, rxf_val); - /* enable RX */ - /* FIXME: RXE(ON) */ - RET(); -} - -static int bdx_set_mac(struct net_device *ndev, void *p) -{ - struct bdx_priv *priv = netdev_priv(ndev); - struct sockaddr *addr = p; - - ENTER; - /* - if (netif_running(dev)) - return -EBUSY - */ - memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); - bdx_restore_mac(ndev, priv); - RET(0); -} - -static int bdx_read_mac(struct bdx_priv *priv) -{ - u16 macAddress[3], i; - ENTER; - - macAddress[2] = READ_REG(priv, regUNC_MAC0_A); - macAddress[2] = READ_REG(priv, regUNC_MAC0_A); - macAddress[1] = READ_REG(priv, regUNC_MAC1_A); - macAddress[1] = READ_REG(priv, regUNC_MAC1_A); - macAddress[0] = READ_REG(priv, regUNC_MAC2_A); - macAddress[0] = READ_REG(priv, regUNC_MAC2_A); - for (i = 0; i < 3; i++) { - priv->ndev->dev_addr[i * 2 + 1] = macAddress[i]; - priv->ndev->dev_addr[i * 2] = macAddress[i] >> 8; - } - RET(0); -} - -static u64 bdx_read_l2stat(struct bdx_priv *priv, int reg) -{ - u64 val; - - val = READ_REG(priv, reg); - val |= ((u64) READ_REG(priv, reg + 8)) << 32; - return val; -} - -/*Do the statistics-update work*/ -static void bdx_update_stats(struct bdx_priv *priv) -{ - struct bdx_stats *stats = &priv->hw_stats; - u64 *stats_vector = (u64 *) stats; - int i; - int addr; - - /*Fill HW structure */ - addr = 0x7200; - /*First 12 statistics - 0x7200 - 0x72B0 */ - for (i = 0; i < 12; i++) { - stats_vector[i] = bdx_read_l2stat(priv, addr); - addr += 0x10; - } - BDX_ASSERT(addr != 0x72C0); - /* 0x72C0-0x72E0 RSRV */ - addr = 0x72F0; - for (; i < 16; i++) { - stats_vector[i] = bdx_read_l2stat(priv, addr); - addr += 0x10; - } - BDX_ASSERT(addr != 0x7330); - /* 0x7330-0x7360 RSRV */ - addr = 0x7370; - for (; i < 19; i++) { - stats_vector[i] = bdx_read_l2stat(priv, addr); - addr += 0x10; - } - BDX_ASSERT(addr != 0x73A0); - /* 0x73A0-0x73B0 RSRV */ - addr = 0x73C0; - for (; i < 23; i++) { - stats_vector[i] = bdx_read_l2stat(priv, addr); - addr += 0x10; - } - BDX_ASSERT(addr != 0x7400); - BDX_ASSERT((sizeof(struct bdx_stats) / sizeof(u64)) != i); -} - -static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len, - u16 rxd_vlan); -static void print_rxfd(struct rxf_desc *rxfd); - -/************************************************************************* - * Rx DB * - *************************************************************************/ - -static void bdx_rxdb_destroy(struct rxdb *db) -{ - vfree(db); -} - -static struct rxdb *bdx_rxdb_create(int nelem) -{ - struct rxdb *db; - int i; - - db = vmalloc(sizeof(struct rxdb) - + (nelem * sizeof(int)) - + (nelem * sizeof(struct rx_map))); - if (likely(db != NULL)) { - db->stack = (int *)(db + 1); - db->elems = (void *)(db->stack + nelem); - db->nelem = nelem; - db->top = nelem; - for (i = 0; i < nelem; i++) - db->stack[i] = nelem - i - 1; /* to make first allocs - close to db struct*/ - } - - return db; -} - -static inline int bdx_rxdb_alloc_elem(struct rxdb *db) -{ - BDX_ASSERT(db->top <= 0); - return db->stack[--(db->top)]; -} - -static inline void *bdx_rxdb_addr_elem(struct rxdb *db, int n) -{ - BDX_ASSERT((n < 0) || (n >= db->nelem)); - return db->elems + n; -} - -static inline int bdx_rxdb_available(struct rxdb *db) -{ - return db->top; -} - -static inline void bdx_rxdb_free_elem(struct rxdb *db, int n) -{ - BDX_ASSERT((n >= db->nelem) || (n < 0)); - db->stack[(db->top)++] = n; -} - -/************************************************************************* - * Rx Init * - *************************************************************************/ - -/* bdx_rx_init - initialize RX all related HW and SW resources - * @priv - NIC private structure - * - * Returns 0 on success, negative value on failure - * - * It creates rxf and rxd fifos, update relevant HW registers, preallocate - * skb for rx. It assumes that Rx is desabled in HW - * funcs are grouped for better cache usage - * - * RxD fifo is smaller than RxF fifo by design. Upon high load, RxD will be - * filled and packets will be dropped by nic without getting into host or - * cousing interrupt. Anyway, in that condition, host has no chance to process - * all packets, but dropping in nic is cheaper, since it takes 0 cpu cycles - */ - -/* TBD: ensure proper packet size */ - -static int bdx_rx_init(struct bdx_priv *priv) -{ - ENTER; - - if (bdx_fifo_init(priv, &priv->rxd_fifo0.m, priv->rxd_size, - regRXD_CFG0_0, regRXD_CFG1_0, - regRXD_RPTR_0, regRXD_WPTR_0)) - goto err_mem; - if (bdx_fifo_init(priv, &priv->rxf_fifo0.m, priv->rxf_size, - regRXF_CFG0_0, regRXF_CFG1_0, - regRXF_RPTR_0, regRXF_WPTR_0)) - goto err_mem; - priv->rxdb = bdx_rxdb_create(priv->rxf_fifo0.m.memsz / - sizeof(struct rxf_desc)); - if (!priv->rxdb) - goto err_mem; - - priv->rxf_fifo0.m.pktsz = priv->ndev->mtu + VLAN_ETH_HLEN; - return 0; - -err_mem: - netdev_err(priv->ndev, "Rx init failed\n"); - return -ENOMEM; -} - -/* bdx_rx_free_skbs - frees and unmaps all skbs allocated for the fifo - * @priv - NIC private structure - * @f - RXF fifo - */ -static void bdx_rx_free_skbs(struct bdx_priv *priv, struct rxf_fifo *f) -{ - struct rx_map *dm; - struct rxdb *db = priv->rxdb; - u16 i; - - ENTER; - DBG("total=%d free=%d busy=%d\n", db->nelem, bdx_rxdb_available(db), - db->nelem - bdx_rxdb_available(db)); - while (bdx_rxdb_available(db) > 0) { - i = bdx_rxdb_alloc_elem(db); - dm = bdx_rxdb_addr_elem(db, i); - dm->dma = 0; - } - for (i = 0; i < db->nelem; i++) { - dm = bdx_rxdb_addr_elem(db, i); - if (dm->dma) { - pci_unmap_single(priv->pdev, - dm->dma, f->m.pktsz, - PCI_DMA_FROMDEVICE); - dev_kfree_skb(dm->skb); - } - } -} - -/* bdx_rx_free - release all Rx resources - * @priv - NIC private structure - * It assumes that Rx is desabled in HW - */ -static void bdx_rx_free(struct bdx_priv *priv) -{ - ENTER; - if (priv->rxdb) { - bdx_rx_free_skbs(priv, &priv->rxf_fifo0); - bdx_rxdb_destroy(priv->rxdb); - priv->rxdb = NULL; - } - bdx_fifo_free(priv, &priv->rxf_fifo0.m); - bdx_fifo_free(priv, &priv->rxd_fifo0.m); - - RET(); -} - -/************************************************************************* - * Rx Engine * - *************************************************************************/ - -/* bdx_rx_alloc_skbs - fill rxf fifo with new skbs - * @priv - nic's private structure - * @f - RXF fifo that needs skbs - * It allocates skbs, build rxf descs and push it (rxf descr) into rxf fifo. - * skb's virtual and physical addresses are stored in skb db. - * To calculate free space, func uses cached values of RPTR and WPTR - * When needed, it also updates RPTR and WPTR. - */ - -/* TBD: do not update WPTR if no desc were written */ - -static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f) -{ - struct sk_buff *skb; - struct rxf_desc *rxfd; - struct rx_map *dm; - int dno, delta, idx; - struct rxdb *db = priv->rxdb; - - ENTER; - dno = bdx_rxdb_available(db) - 1; - while (dno > 0) { - skb = dev_alloc_skb(f->m.pktsz + NET_IP_ALIGN); - if (!skb) { - pr_err("NO MEM: dev_alloc_skb failed\n"); - break; - } - skb-> |