[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20180214011132.GA12307@lunn.ch>
Date: Wed, 14 Feb 2018 02:11:32 +0100
From: Andrew Lunn <andrew@...n.ch>
To: Bryan Whitehead <Bryan.Whitehead@...rochip.com>
Cc: davem@...emloft.net, UNGLinuxDriver@...rochip.com,
netdev@...r.kernel.org
Subject: Re: [PATCH v1 net-next 1/3] lan743x: Add main source file for new
lan743x driver
On Tue, Feb 13, 2018 at 06:26:48PM -0500, Bryan Whitehead wrote:
> Add main source files for new lan743x driver
>
> Signed-off-by: Bryan Whitehead <Bryan.Whitehead@...rochip.com>
> ---
> drivers/net/ethernet/microchip/lan743x_main.c | 2964 +++++++++++++++++++++++++
> drivers/net/ethernet/microchip/lan743x_main.h | 1331 +++++++++++
> 2 files changed, 4295 insertions(+)
> create mode 100644 drivers/net/ethernet/microchip/lan743x_main.c
> create mode 100644 drivers/net/ethernet/microchip/lan743x_main.h
>
> diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
> new file mode 100644
> index 0000000..6cfb439
> --- /dev/null
> +++ b/drivers/net/ethernet/microchip/lan743x_main.c
> @@ -0,0 +1,2964 @@
> +/*
> + * Copyright (C) 2018 Microchip Technology
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "lan743x_main.h"
> +
> +#define LAN743X_COMPONENT_FLAG_PCI BIT(0)
> +#define LAN743X_COMPONENT_FLAG_CSR BIT(1)
> +#define LAN743X_COMPONENT_FLAG_INTR BIT(2)
> +#define LAN743X_COMPONENT_FLAG_DP BIT(3)
> +#define LAN743X_COMPONENT_FLAG_MAC BIT(4)
> +#define LAN743X_COMPONENT_FLAG_PHY BIT(5)
> +#define LAN743X_COMPONENT_FLAG_RFE BIT(6)
> +#define LAN743X_COMPONENT_FLAG_FCT BIT(7)
> +#define LAN743X_COMPONENT_FLAG_TX(channel) BIT(16 + (channel))
> +#define LAN743X_COMPONENT_FLAG_RX(channel) BIT(20 + (channel))
> +
> +#define LAN743X_INIT_FLAG_NETDEV_REGISTERED BIT(24)
> +#define LAN743X_INIT_FLAG_MDIOBUS_ALLOCATED BIT(25)
> +#define LAN743X_INIT_FLAG_MDIOBUS_REGISTERED BIT(26)
Hi Bryan
It seems odd to have some defines in lan743x_main.h and some inline.
It is probably better to have them all in one place.
> +static int lan743x_csr_light_reset(struct lan743x_adapter *adapter)
> +{
> + unsigned long timeout;
> + u32 data;
> +
> + data = lan743x_csr_read(adapter, HW_CFG);
> + data |= HW_CFG_LRST_;
> + lan743x_csr_write(adapter, HW_CFG, data);
> + timeout = jiffies + (10 * HZ);
> + do {
> + if (time_after(jiffies, timeout))
> + return -EIO;
> + msleep(100);
> + data = lan743x_csr_read(adapter, HW_CFG);
> + } while (data & HW_CFG_LRST_);
You could probably use readx_poll_timeout() here.
> +
> + return 0;
> +}
> +
> +static int lan743x_csr_wait_for_bit(struct lan743x_adapter *adapter,
> + int offset, u32 bit_mask,
> + int target_value, int usleep_min,
> + int usleep_max, int count)
> +{
> + int timeout = count;
> + int current_value;
> + int ret = -EIO;
> +
> + while (timeout) {
> + current_value = (lan743x_csr_read(adapter, offset) & bit_mask)
> + ? 1 : 0;
> + if (target_value == current_value) {
> + ret = 0;
> + break;
> + }
> + usleep_range(usleep_min, usleep_max);
> + timeout--;
> + }
And here as well.
> + return ret;
> +}
> +
> +static int lan743x_csr_init(struct lan743x_adapter *adapter)
> +{
> + struct lan743x_csr *csr = &adapter->csr;
> + resource_size_t bar_start, bar_length;
> + int result;
> +
> + bar_start = pci_resource_start(adapter->pci.pdev, 0);
> + bar_length = pci_resource_len(adapter->pci.pdev, 0);
> + csr->csr_address = ioremap(bar_start, bar_length);
devm_ioremap() will make your cleanup code simpler.
> + if (!csr->csr_address) {
> + result = -ENOMEM;
> + goto clean_up;
> + }
> +
> + csr->id_rev = lan743x_csr_read(adapter, ID_REV);
> + csr->fpga_rev = lan743x_csr_read(adapter, FPGA_REV);
> + netif_info(adapter, probe, adapter->netdev,
> + "ID_REV = 0x%08X, FPGA_REV = %d.%d\n",
> + csr->id_rev, (csr->fpga_rev) & 0x000000FF,
> + ((csr->fpga_rev) >> 8) & 0x000000FF);
> + if ((csr->id_rev & 0xFFF00000) != 0x74300000) {
> + result = -ENODEV;
> + goto clean_up;
> + }
You have:
define ID_REV_CHIP_ID_MASK_ (0xFFFF0000)
#define ID_REV_CHIP_ID_7430_ (0x7430)
#define ID_REV_CHIP_REV_MASK_ (0x0000FFFF)
#define ID_REV_CHIP_REV_A0_ (0x00000000)
#define ID_REV_CHIP_REV_B0_ (0x00000010)
#define FPGA_REV (0x04)
#define FPGA_REV_MINOR_MASK_ (0x0000FF00)
#define FPGA_REV_MAJOR_MASK_ (0x000000FF)
Why not use them.
> + csr->flags = LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR;
> + switch (csr->id_rev & ID_REV_CHIP_REV_MASK_) {
> + case ID_REV_CHIP_REV_A0_:
> + csr->flags |= LAN743X_CSR_FLAG_IS_A0;
> + csr->flags &= ~LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR;
> + break;
> + case ID_REV_CHIP_REV_B0_:
> + csr->flags |= LAN743X_CSR_FLAG_IS_B0;
> + break;
> + }
> +
> + result = lan743x_csr_light_reset(adapter);
> + if (result)
> + goto clean_up;
> + return 0;
> +clean_up:
> + if (csr->csr_address)
> + iounmap(csr->csr_address);
> + return result;
> +}
> +static int lan743x_intr_register_isr(struct lan743x_adapter *adapter,
> + int vector_index, u32 flags,
> + u32 int_mask,
> + lan743x_vector_handler handler,
> + void *context)
> +{
> + struct lan743x_vector *vector = &adapter->intr.vector_list
> + [vector_index];
> + int ret;
> +
> + vector->adapter = adapter;
> + vector->flags = flags;
> + vector->vector_index = vector_index;
> + vector->int_mask = int_mask;
> + vector->handler = handler;
> + vector->context = context;
> + ret = request_irq(vector->irq,
> + lan743x_intr_entry_isr,
> + (flags & LAN743X_VECTOR_FLAG_IRQ_SHARED) ?
> + IRQF_SHARED : 0,
> + DRIVER_NAME,
> + vector);
devm_request_irq()?
> +static int lan743x_intr_open(struct lan743x_adapter *adapter)
> +{
> +#if LAN743X_TRY_MSIX
> + struct msix_entry msix_entries[LAN743X_MAX_VECTOR_COUNT];
> +#endif
> + struct lan743x_intr *intr = &adapter->intr;
> + u32 int_vec_en_auto_clr = 0;
> + u32 int_vec_map0 = 0;
> + u32 int_vec_map1 = 0;
> + int ret = -ENODEV;
> + int index = 0;
> + u32 flags = 0;
> +
> + intr->number_of_vectors = 0;
> +#if LAN743X_TRY_MSIX
It is better to use
if (IS_ENABLED(CONFIG_LAN743X_TRY_MSIX)) {
The compiler will then detect problems in the code, even when it is
disabled, and still optimize it out. In general, we don't like #ifdefs.
> + memset(&msix_entries[0], 0,
> + sizeof(struct msix_entry) * LAN743X_MAX_VECTOR_COUNT);
> + for (index = 0; index < LAN743X_MAX_VECTOR_COUNT; index++)
> + msix_entries[index].entry = index;
> + ret = pci_enable_msix_range(adapter->pci.pdev,
> + msix_entries, 1,
> + 1 + LAN743X_USED_TX_CHANNELS +
> + LAN743X_USED_RX_CHANNELS);
> + if (ret > 0) {
> + intr->flags |= INTR_FLAG_MSIX_ENABLED;
> + intr->number_of_vectors = ret;
> + intr->using_vectors = true;
> + for (index = 0; index < intr->number_of_vectors; index++)
> + intr->vector_list[index].irq = msix_entries
> + [index].vector;
> + netif_info(adapter, ifup, adapter->netdev,
> + "using MSIX interrupts, number of vectors = %d\n",
> + intr->number_of_vectors);
> + }
> +#endif
> +#if LAN743X_TRY_MSI
> + if (!intr->number_of_vectors) {
> + if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) {
> + if (!pci_enable_msi(adapter->pci.pdev)) {
> + intr->flags |= INTR_FLAG_MSI_ENABLED;
> + intr->number_of_vectors = 1;
> + intr->using_vectors = true;
> + intr->vector_list[0].irq =
> + adapter->pci.pdev->irq;
> + netif_info(adapter, ifup, adapter->netdev,
> + "using MSI interrupts, number of vectors = %d\n",
> + intr->number_of_vectors);
> + }
> + }
> + }
> +#endif
> +static int lan743x_mac_mii_wait_till_not_busy(struct lan743x_adapter *adapter)
> +{
> + unsigned long start_time = jiffies;
> + u32 data;
> +
> + do {
> + data = lan743x_csr_read(adapter, MAC_MII_ACC);
> + if (!(data & MAC_MII_ACC_MII_BUSY_))
> + return 0;
> + } while (!time_after(jiffies, start_time + HZ));
Another possible use of readx_poll_timeout.
> +static void lan743x_mac_set_address(struct lan743x_adapter *adapter,
> + u8 *addr)
> +{
> + u32 addr_lo, addr_hi;
> +
> + addr_lo = addr[0] |
> + addr[1] << 8 |
> + addr[2] << 16 |
> + addr[3] << 24;
> + addr_hi = addr[4] |
> + addr[5] << 8;
> + lan743x_csr_write(adapter, MAC_RX_ADDRL, addr_lo);
> + lan743x_csr_write(adapter, MAC_RX_ADDRH, addr_hi);
> + ether_addr_copy(adapter->mac.mac_address, addr);
> + netif_info(adapter, drv, adapter->netdev,
> + "MAC address set to %02X:%02X:%02X:%02X:%02X:%02X\n",
%pM ?
> + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
> +}
> +
> +static int lan743x_mac_init(struct lan743x_adapter *adapter)
> +{
> + struct lan743x_mac *mac = &adapter->mac;
> + bool mac_address_valid = true;
> + struct net_device *netdev;
> + u32 mac_addr_hi = 0;
> + u32 mac_addr_lo = 0;
> + u32 data;
> + int ret;
> +
> + netdev = adapter->netdev;
> + lan743x_csr_write(adapter, MAC_CR, MAC_CR_RST_);
> + ret = lan743x_csr_wait_for_bit(adapter, MAC_CR, MAC_CR_RST_,
> + 0, 1000, 20000, 100);
> + if (ret)
> + return ret;
> +
> + /* setup auto duplex, and speed detection */
> + data = lan743x_csr_read(adapter, MAC_CR);
> + data |= MAC_CR_ADD_ | MAC_CR_ASD_;
> + data |= MAC_CR_CNTR_RST_;
> + lan743x_csr_write(adapter, MAC_CR, data);
> + mac_addr_hi = lan743x_csr_read(adapter, MAC_RX_ADDRH);
> + mac_addr_lo = lan743x_csr_read(adapter, MAC_RX_ADDRL);
> + mac->mac_address[0] = mac_addr_lo & 0xFF;
> + mac->mac_address[1] = (mac_addr_lo >> 8) & 0xFF;
> + mac->mac_address[2] = (mac_addr_lo >> 16) & 0xFF;
> + mac->mac_address[3] = (mac_addr_lo >> 24) & 0xFF;
> + mac->mac_address[4] = mac_addr_hi & 0xFF;
> + mac->mac_address[5] = (mac_addr_hi >> 8) & 0xFF;
> + if (((mac_addr_hi & 0x0000FFFF) == 0x0000FFFF) &&
> + mac_addr_lo == 0xFFFFFFFF) {
> + mac_address_valid = false;
> + } else if (!is_valid_ether_addr(mac->mac_address)) {
> + mac_address_valid = false;
> + }
> + if (!mac_address_valid)
> + random_ether_addr(mac->mac_address);
> + lan743x_mac_set_address(adapter, mac->mac_address);
> + netif_info(adapter, probe, adapter->netdev,
> + "MAC Address = %02X:%02X:%02X:%02X:%02X:%02X\n",
> + mac->mac_address[0], mac->mac_address[1],
> + mac->mac_address[2], mac->mac_address[3],
> + mac->mac_address[4], mac->mac_address[5]);
lan743x_mac_set_address() prints it. Why print it again?
> + ether_addr_copy(netdev->dev_addr, mac->mac_address);
> + return 0;
> +}
> +
> +
> +/* PHY */
> +#define PHY_FLAG_OPENED BIT(0)
> +#define PHY_FLAG_ATTACHED BIT(1)
> +static int lan743x_phy_reset(struct lan743x_adapter *adapter)
> +{
> + unsigned long timeout;
> + u32 data;
> +
> + data = lan743x_csr_read(adapter, PMT_CTL);
> + data |= PMT_CTL_ETH_PHY_RST_;
> + lan743x_csr_write(adapter, PMT_CTL, data);
> + timeout = jiffies + HZ;
> + do {
> + if (time_after(jiffies, timeout))
> + return -EIO;
> + msleep(50);
> + data = lan743x_csr_read(adapter, PMT_CTL);
> + } while ((data & PMT_CTL_ETH_PHY_RST_) || !(data & PMT_CTL_READY_));
readx_poll_timeout()
> + return 0;
> +}
> +
> +static void lan743x_phy_link_status_change(struct net_device *netdev)
> +{
> + struct lan743x_adapter *adapter = netdev_priv(netdev);
> + struct phy_device *phydev = netdev->phydev;
> +
> + if (phydev) {
> + if (phydev->state == PHY_RUNNING) {
> + struct ethtool_link_ksettings ksettings;
> + struct lan743x_phy *phy = NULL;
> + int remote_advertisement = 0;
> + int local_advertisement = 0;
> +
> + phy = &adapter->phy;
> + memset(&ksettings, 0, sizeof(ksettings));
> + phy_ethtool_get_link_ksettings(netdev, &ksettings);
> + local_advertisement = phy_read(phydev, MII_ADVERTISE);
> + if (local_advertisement < 0)
> + goto done;
A bit unusual to use a goto here, since this is not error handling, or
dealing with a mutex. Maybe just return;
> + remote_advertisement = phy_read(phydev, MII_LPA);
> + if (remote_advertisement < 0)
> + goto done;
> + netif_info(adapter, link, adapter->netdev,
> + "link UP: speed: %u duplex: %d anadv: 0x%04x anlpa: 0x%04x\n",
> + ksettings.base.speed, ksettings.base.duplex,
> + local_advertisement, remote_advertisement);
phy_print_status()
> + lan743x_phy_update_flowcontrol(adapter,
> + ksettings.base.duplex,
> + local_advertisement,
> + remote_advertisement);
> + } else if (phydev->state == PHY_NOLINK) {
> + netif_info(adapter, link, adapter->netdev,
> + "link DOWN\n");
Here too.
> + }
> + }
> +done:
> + return;
> +}
> +
> +static int lan743x_phy_open(struct lan743x_adapter *adapter)
> +{
> + struct lan743x_phy *phy = &adapter->phy;
> + struct phy_device *phydev;
> + struct net_device *netdev;
> + int ret = -EIO;
> + u32 mii_adv;
> +
> + netdev = adapter->netdev;
> + phydev = phy_find_first(adapter->mdiobus);
> + if (!phydev) {
> + ret = -EIO;
> + goto clean_up;
> + }
> + ret = phy_connect_direct(netdev, phydev,
> + lan743x_phy_link_status_change,
> + PHY_INTERFACE_MODE_GMII);
> + if (ret) {
> + ret = -EIO;
Why change the error code phy_connect_direct() returned?
> + goto clean_up;
> + }
> + phy->flags |= PHY_FLAG_ATTACHED;
> +
> + /* MAC doesn't support 1000T Half */
> + phydev->supported &= ~SUPPORTED_1000baseT_Half;
> + /* support both flow controls */
> + phy->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX);
> + phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
> + mii_adv = (u32)mii_advertise_flowctrl(phy->fc_request_control);
> + phydev->advertising |= mii_adv_to_ethtool_adv_t(mii_adv);
> + phy->fc_autoneg = phydev->autoneg;
> +
> + /* PHY interrupt enabled here */
> + phy_start(phydev);
> + phy_start_aneg(phydev);
> + phy->flags |= PHY_FLAG_OPENED;
> + return 0;
> +clean_up:
> + lan743x_phy_close(adapter);
> + return ret;
> +}
> +
> +static int lan743x_mdiobus_init(struct lan743x_adapter *adapter)
> +{
> + int ret;
> +
> + adapter->mdiobus = mdiobus_alloc();
devm_mdiobus_alloc() ?
> + if (!(adapter->mdiobus)) {
> + ret = -ENOMEM;
> + goto clean_up;
> + }
> + adapter->init_flags |= LAN743X_INIT_FLAG_MDIOBUS_ALLOCATED;
> + adapter->mdiobus->priv = (void *)adapter;
> + adapter->mdiobus->read = lan743x_mdiobus_read;
> + adapter->mdiobus->write = lan743x_mdiobus_write;
> + adapter->mdiobus->name = "lan743x-mdiobus";
> + snprintf(adapter->mdiobus->id, MII_BUS_ID_SIZE,
> + "pci-%s", pci_name(adapter->pci.pdev));
> +
> + /* set to internal PHY id */
> + adapter->mdiobus->phy_mask = ~(int)BIT(1);
phy_mask is a u32.
> +
> + /* register mdiobus */
> + ret = mdiobus_register(adapter->mdiobus);
> + if (ret < 0)
> + goto clean_up;
> + adapter->init_flags |= LAN743X_INIT_FLAG_MDIOBUS_REGISTERED;
> + return 0;
> +clean_up:
> + if (adapter->mdiobus)
> + mdiobus_free(adapter->mdiobus);
> + adapter->init_flags &= ~(LAN743X_INIT_FLAG_MDIOBUS_REGISTERED |
> + LAN743X_INIT_FLAG_MDIOBUS_ALLOCATED);
> + return ret;
> +}
> +
> +/* lan743x_pcidev_probe - Device Initialization Routine
> + * @pdev: PCI device information struct
> + * @id: entry in lan743x_pci_tbl
> + *
> + * Returns 0 on success, negative on failure
> + *
> + * initializes an adapter identified by a pci_dev structure.
> + * The OS initialization, configuring of the adapter private structure,
> + * and a hardware reset occur.
> + **/
> +static int lan743x_pcidev_probe(struct pci_dev *pdev,
> + const struct pci_device_id *id)
> +{
> + struct lan743x_adapter *adapter = NULL;
> + struct net_device *netdev = NULL;
> + int ret = -ENODEV;
> +
> + netdev = alloc_etherdev(sizeof(struct lan743x_adapter));
devm_alloc_etherdev() ?
> + if (!netdev)
> + goto clean_up;
> + SET_NETDEV_DEV(netdev, &pdev->dev);
> + pci_set_drvdata(pdev, netdev);
> + adapter = netdev_priv(netdev);
> + adapter->netdev = netdev;
> + adapter->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE |
> + NETIF_MSG_LINK | NETIF_MSG_IFUP |
> + NETIF_MSG_IFDOWN | NETIF_MSG_TX_QUEUED;
> + netdev->max_mtu = LAN743X_MAX_FRAME_SIZE;
> + ret = lan743x_pci_init(adapter, pdev);
> + if (ret)
> + goto clean_up;
> + adapter->init_flags |= LAN743X_COMPONENT_FLAG_PCI;
> + ret = lan743x_csr_init(adapter);
> + if (ret)
> + goto clean_up;
> + adapter->init_flags |= LAN743X_COMPONENT_FLAG_CSR;
> + ret = lan743x_hardware_init(adapter, pdev);
> + if (ret)
> + goto clean_up;
> + ret = lan743x_mdiobus_init(adapter);
> + if (ret)
> + goto clean_up;
> + adapter->netdev->netdev_ops = &lan743x_netdev_ops;
> + adapter->netdev->features = NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_CSUM;
> + adapter->netdev->hw_features = adapter->netdev->features;
> + ret = register_netdev(adapter->netdev);
> + if (ret < 0)
> + goto clean_up;
> + adapter->init_flags |= LAN743X_INIT_FLAG_NETDEV_REGISTERED;
> + netif_info(adapter, probe, adapter->netdev, "Probe succeeded\n");
> + return 0;
> +
> +clean_up:
> + if (adapter) {
> + netif_warn(adapter, probe, adapter->netdev,
> + "Incomplete initialization, performing clean up\n");
> + lan743x_full_cleanup(adapter);
> + }
> + return ret;
> +}
> +++ b/drivers/net/ethernet/microchip/lan743x_main.h
> +u32 lan743x_csr_read(struct lan743x_adapter *adapter, int offset);
> +void lan743x_csr_write(struct lan743x_adapter *adapter, int offset, u32 data);
Why are these needed?
> +
> +/* INTERRUPTS */
> +typedef void(*lan743x_vector_handler)(void *context, u32 int_sts, u32 flags);
And this.
Andrew
Powered by blists - more mailing lists