diff options
Diffstat (limited to 'kernel/drivers/staging/octeon/ethernet.c')
-rw-r--r-- | kernel/drivers/staging/octeon/ethernet.c | 159 |
1 files changed, 103 insertions, 56 deletions
diff --git a/kernel/drivers/staging/octeon/ethernet.c b/kernel/drivers/staging/octeon/ethernet.c index fbbe86648..f69fb5cc7 100644 --- a/kernel/drivers/staging/octeon/ethernet.c +++ b/kernel/drivers/staging/octeon/ethernet.c @@ -1,29 +1,13 @@ -/********************************************************************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK +/* + * This file is based on code from OCTEON SDK by Cavium Networks. * * Copyright (c) 2003-2007 Cavium Networks * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, Version 2, as * published by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information -**********************************************************************/ + */ + #include <linux/platform_device.h> #include <linux/kernel.h> #include <linux/module.h> @@ -102,19 +86,19 @@ int rx_napi_weight = 32; module_param(rx_napi_weight, int, 0444); MODULE_PARM_DESC(rx_napi_weight, "The NAPI WEIGHT parameter."); -/** +/* * cvm_oct_poll_queue - Workqueue for polling operations. */ struct workqueue_struct *cvm_oct_poll_queue; -/** +/* * cvm_oct_poll_queue_stopping - flag to indicate polling should stop. * * Set to one right before cvm_oct_poll_queue is destroyed. */ atomic_t cvm_oct_poll_queue_stopping = ATOMIC_INIT(0); -/** +/* * Array of every ethernet device owned by this driver indexed by * the ipd input port number. */ @@ -168,11 +152,12 @@ static void cvm_oct_configure_common_hw(void) num_packet_buffers); if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, - CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128); + CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 1024); #ifdef __LITTLE_ENDIAN { union cvmx_ipd_ctl_status ipd_ctl_status; + ipd_ctl_status.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS); ipd_ctl_status.s.pkt_lend = 1; ipd_ctl_status.s.wqe_lend = 1; @@ -180,10 +165,7 @@ static void cvm_oct_configure_common_hw(void) } #endif - if (USE_RED) - cvmx_helper_setup_red(num_packet_buffers / 4, - num_packet_buffers / 8); - + cvmx_helper_setup_red(num_packet_buffers / 4, num_packet_buffers / 8); } /** @@ -206,11 +188,10 @@ int cvm_oct_free_work(void *work_queue_entry) if (unlikely(!segment_ptr.s.i)) cvmx_fpa_free(cvm_oct_get_buffer_ptr(segment_ptr), segment_ptr.s.pool, - DONT_WRITEBACK(CVMX_FPA_PACKET_POOL_SIZE / - 128)); + CVMX_FPA_PACKET_POOL_SIZE / 128); segment_ptr = next_ptr; } - cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1)); + cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, 1); return 0; } @@ -383,13 +364,6 @@ static void cvm_oct_common_set_multicast_list(struct net_device *dev) } } -/** - * cvm_oct_common_set_mac_address - set the hardware MAC address for a device - * @dev: The device in question. - * @addr: Address structure to change it too. - - * Returns Zero on success - */ static int cvm_oct_set_mac_filter(struct net_device *dev) { struct octeon_ethernet *priv = netdev_priv(dev); @@ -401,11 +375,11 @@ static int cvm_oct_set_mac_filter(struct net_device *dev) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) { int i; - uint8_t *ptr = dev->dev_addr; - uint64_t mac = 0; + u8 *ptr = dev->dev_addr; + u64 mac = 0; for (i = 0; i < 6; i++) - mac = (mac << 8) | (uint64_t)ptr[i]; + mac = (mac << 8) | (u64)ptr[i]; gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); @@ -432,6 +406,13 @@ static int cvm_oct_set_mac_filter(struct net_device *dev) return 0; } +/** + * cvm_oct_common_set_mac_address - set the hardware MAC address for a device + * @dev: The device in question. + * @addr: Socket address. + * + * Returns Zero on success + */ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr) { int r = eth_mac_addr(dev, addr); @@ -468,11 +449,8 @@ int cvm_oct_common_init(struct net_device *dev) && (always_use_pow || strstr(pow_send_list, dev->name))) priv->queue = -1; - if (priv->queue != -1) { - dev->features |= NETIF_F_SG; - if (USE_HW_TCPUDP_CHECKSUM) - dev->features |= NETIF_F_IP_CSUM; - } + if (priv->queue != -1) + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; /* We do our own locking, Linux doesn't need to */ dev->features |= NETIF_F_LLTX; @@ -488,6 +466,9 @@ int cvm_oct_common_init(struct net_device *dev) memset(dev->netdev_ops->ndo_get_stats(dev), 0, sizeof(struct net_device_stats)); + if (dev->netdev_ops->ndo_stop) + dev->netdev_ops->ndo_stop(dev); + return 0; } @@ -499,6 +480,70 @@ void cvm_oct_common_uninit(struct net_device *dev) phy_disconnect(priv->phydev); } +int cvm_oct_common_open(struct net_device *dev, + void (*link_poll)(struct net_device *)) +{ + union cvmx_gmxx_prtx_cfg gmx_cfg; + struct octeon_ethernet *priv = netdev_priv(dev); + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); + cvmx_helper_link_info_t link_info; + int rv; + + rv = cvm_oct_phy_setup_device(dev); + if (rv) + return rv; + + gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + gmx_cfg.s.en = 1; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); + + if (octeon_is_simulation()) + return 0; + + if (priv->phydev) { + int r = phy_read_status(priv->phydev); + + if (r == 0 && priv->phydev->link == 0) + netif_carrier_off(dev); + cvm_oct_adjust_link(dev); + } else { + link_info = cvmx_helper_link_get(priv->port); + if (!link_info.s.link_up) + netif_carrier_off(dev); + priv->poll = link_poll; + link_poll(dev); + } + + return 0; +} + +void cvm_oct_link_poll(struct net_device *dev) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + cvmx_helper_link_info_t link_info; + + link_info = cvmx_helper_link_get(priv->port); + if (link_info.u64 == priv->link_info) + return; + + link_info = cvmx_helper_link_autoconf(priv->port); + priv->link_info = link_info.u64; + + if (link_info.s.link_up) { + if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); + } else if (netif_carrier_ok(dev)) { + netif_carrier_off(dev); + } + cvm_oct_note_carrier(priv, link_info); +} + +static int cvm_oct_xaui_open(struct net_device *dev) +{ + return cvm_oct_common_open(dev, cvm_oct_link_poll); +} + static const struct net_device_ops cvm_oct_npi_netdev_ops = { .ndo_init = cvm_oct_common_init, .ndo_uninit = cvm_oct_common_uninit, @@ -513,10 +558,10 @@ static const struct net_device_ops cvm_oct_npi_netdev_ops = { #endif }; static const struct net_device_ops cvm_oct_xaui_netdev_ops = { - .ndo_init = cvm_oct_xaui_init, - .ndo_uninit = cvm_oct_xaui_uninit, + .ndo_init = cvm_oct_common_init, + .ndo_uninit = cvm_oct_common_uninit, .ndo_open = cvm_oct_xaui_open, - .ndo_stop = cvm_oct_xaui_stop, + .ndo_stop = cvm_oct_common_stop, .ndo_start_xmit = cvm_oct_xmit, .ndo_set_rx_mode = cvm_oct_common_set_multicast_list, .ndo_set_mac_address = cvm_oct_common_set_mac_address, @@ -529,9 +574,9 @@ static const struct net_device_ops cvm_oct_xaui_netdev_ops = { }; static const struct net_device_ops cvm_oct_sgmii_netdev_ops = { .ndo_init = cvm_oct_sgmii_init, - .ndo_uninit = cvm_oct_sgmii_uninit, + .ndo_uninit = cvm_oct_common_uninit, .ndo_open = cvm_oct_sgmii_open, - .ndo_stop = cvm_oct_sgmii_stop, + .ndo_stop = cvm_oct_common_stop, .ndo_start_xmit = cvm_oct_xmit, .ndo_set_rx_mode = cvm_oct_common_set_multicast_list, .ndo_set_mac_address = cvm_oct_common_set_mac_address, @@ -559,7 +604,7 @@ static const struct net_device_ops cvm_oct_rgmii_netdev_ops = { .ndo_init = cvm_oct_rgmii_init, .ndo_uninit = cvm_oct_rgmii_uninit, .ndo_open = cvm_oct_rgmii_open, - .ndo_stop = cvm_oct_rgmii_stop, + .ndo_stop = cvm_oct_common_stop, .ndo_start_xmit = cvm_oct_xmit, .ndo_set_rx_mode = cvm_oct_common_set_multicast_list, .ndo_set_mac_address = cvm_oct_common_set_mac_address, @@ -625,7 +670,6 @@ static int cvm_oct_probe(struct platform_device *pdev) struct device_node *pip; octeon_mdiobus_force_mod_depencency(); - pr_notice("cavium-ethernet %s\n", OCTEON_ETHERNET_VERSION); pip = pdev->dev.of_node; if (!pip) { @@ -634,7 +678,7 @@ static int cvm_oct_probe(struct platform_device *pdev) } cvm_oct_poll_queue = create_singlethread_workqueue("octeon-ethernet"); - if (cvm_oct_poll_queue == NULL) { + if (!cvm_oct_poll_queue) { pr_err("octeon-ethernet: Cannot create workqueue"); return -ENOMEM; } @@ -795,7 +839,7 @@ static int cvm_oct_probe(struct platform_device *pdev) cvm_oct_device[priv->port] = dev; fau -= cvmx_pko_get_num_queues(priv->port) * - sizeof(uint32_t); + sizeof(u32); queue_delayed_work(cvm_oct_poll_queue, &priv->port_periodic_work, HZ); } @@ -820,7 +864,10 @@ static int cvm_oct_remove(struct platform_device *pdev) int port; /* Disable POW interrupt */ - cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0); + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + cvmx_write_csr(CVMX_SSO_WQ_INT_THRX(pow_receive_group), 0); + else + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0); cvmx_ipd_disable(); |