cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ax88172a.c (8960B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * ASIX AX88172A based USB 2.0 Ethernet Devices
      4 * Copyright (C) 2012 OMICRON electronics GmbH
      5 *
      6 * Supports external PHYs via phylib. Based on the driver for the
      7 * AX88772. Original copyrights follow:
      8 *
      9 * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com>
     10 * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
     11 * Copyright (C) 2006 James Painter <jamie.painter@iname.com>
     12 * Copyright (c) 2002-2003 TiVo Inc.
     13 */
     14
     15#include "asix.h"
     16#include <linux/phy.h>
     17
     18struct ax88172a_private {
     19	struct mii_bus *mdio;
     20	struct phy_device *phydev;
     21	char phy_name[20];
     22	u16 phy_addr;
     23	u16 oldmode;
     24	int use_embdphy;
     25	struct asix_rx_fixup_info rx_fixup_info;
     26};
     27
     28/* set MAC link settings according to information from phylib */
     29static void ax88172a_adjust_link(struct net_device *netdev)
     30{
     31	struct phy_device *phydev = netdev->phydev;
     32	struct usbnet *dev = netdev_priv(netdev);
     33	struct ax88172a_private *priv = dev->driver_priv;
     34	u16 mode = 0;
     35
     36	if (phydev->link) {
     37		mode = AX88772_MEDIUM_DEFAULT;
     38
     39		if (phydev->duplex == DUPLEX_HALF)
     40			mode &= ~AX_MEDIUM_FD;
     41
     42		if (phydev->speed != SPEED_100)
     43			mode &= ~AX_MEDIUM_PS;
     44	}
     45
     46	if (mode != priv->oldmode) {
     47		asix_write_medium_mode(dev, mode, 0);
     48		priv->oldmode = mode;
     49		netdev_dbg(netdev, "speed %u duplex %d, setting mode to 0x%04x\n",
     50			   phydev->speed, phydev->duplex, mode);
     51		phy_print_status(phydev);
     52	}
     53}
     54
     55static void ax88172a_status(struct usbnet *dev, struct urb *urb)
     56{
     57	/* link changes are detected by polling the phy */
     58}
     59
     60/* use phylib infrastructure */
     61static int ax88172a_init_mdio(struct usbnet *dev)
     62{
     63	struct ax88172a_private *priv = dev->driver_priv;
     64	int ret;
     65
     66	priv->mdio = mdiobus_alloc();
     67	if (!priv->mdio) {
     68		netdev_err(dev->net, "Could not allocate MDIO bus\n");
     69		return -ENOMEM;
     70	}
     71
     72	priv->mdio->priv = (void *)dev;
     73	priv->mdio->read = &asix_mdio_bus_read;
     74	priv->mdio->write = &asix_mdio_bus_write;
     75	priv->mdio->name = "Asix MDIO Bus";
     76	/* mii bus name is usb-<usb bus number>-<usb device number> */
     77	snprintf(priv->mdio->id, MII_BUS_ID_SIZE, "usb-%03d:%03d",
     78		 dev->udev->bus->busnum, dev->udev->devnum);
     79
     80	ret = mdiobus_register(priv->mdio);
     81	if (ret) {
     82		netdev_err(dev->net, "Could not register MDIO bus\n");
     83		goto mfree;
     84	}
     85
     86	netdev_info(dev->net, "registered mdio bus %s\n", priv->mdio->id);
     87	return 0;
     88
     89mfree:
     90	mdiobus_free(priv->mdio);
     91	return ret;
     92}
     93
     94static void ax88172a_remove_mdio(struct usbnet *dev)
     95{
     96	struct ax88172a_private *priv = dev->driver_priv;
     97
     98	netdev_info(dev->net, "deregistering mdio bus %s\n", priv->mdio->id);
     99	mdiobus_unregister(priv->mdio);
    100	mdiobus_free(priv->mdio);
    101}
    102
    103static const struct net_device_ops ax88172a_netdev_ops = {
    104	.ndo_open		= usbnet_open,
    105	.ndo_stop		= usbnet_stop,
    106	.ndo_start_xmit		= usbnet_start_xmit,
    107	.ndo_tx_timeout		= usbnet_tx_timeout,
    108	.ndo_change_mtu		= usbnet_change_mtu,
    109	.ndo_get_stats64	= dev_get_tstats64,
    110	.ndo_set_mac_address	= asix_set_mac_address,
    111	.ndo_validate_addr	= eth_validate_addr,
    112	.ndo_eth_ioctl		= phy_do_ioctl_running,
    113	.ndo_set_rx_mode        = asix_set_multicast,
    114};
    115
    116static const struct ethtool_ops ax88172a_ethtool_ops = {
    117	.get_drvinfo		= asix_get_drvinfo,
    118	.get_link		= usbnet_get_link,
    119	.get_msglevel		= usbnet_get_msglevel,
    120	.set_msglevel		= usbnet_set_msglevel,
    121	.get_wol		= asix_get_wol,
    122	.set_wol		= asix_set_wol,
    123	.get_eeprom_len		= asix_get_eeprom_len,
    124	.get_eeprom		= asix_get_eeprom,
    125	.set_eeprom		= asix_set_eeprom,
    126	.nway_reset		= phy_ethtool_nway_reset,
    127	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
    128	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
    129};
    130
    131static int ax88172a_reset_phy(struct usbnet *dev, int embd_phy)
    132{
    133	int ret;
    134
    135	ret = asix_sw_reset(dev, AX_SWRESET_IPPD, 0);
    136	if (ret < 0)
    137		goto err;
    138
    139	msleep(150);
    140	ret = asix_sw_reset(dev, AX_SWRESET_CLEAR, 0);
    141	if (ret < 0)
    142		goto err;
    143
    144	msleep(150);
    145
    146	ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_IPPD,
    147			    0);
    148	if (ret < 0)
    149		goto err;
    150
    151	return 0;
    152
    153err:
    154	return ret;
    155}
    156
    157
    158static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf)
    159{
    160	int ret;
    161	u8 buf[ETH_ALEN];
    162	struct ax88172a_private *priv;
    163
    164	usbnet_get_endpoints(dev, intf);
    165
    166	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
    167	if (!priv)
    168		return -ENOMEM;
    169
    170	dev->driver_priv = priv;
    171
    172	/* Get the MAC address */
    173	ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf, 0);
    174	if (ret < ETH_ALEN) {
    175		netdev_err(dev->net, "Failed to read MAC address: %d\n", ret);
    176		ret = -EIO;
    177		goto free;
    178	}
    179	eth_hw_addr_set(dev->net, buf);
    180
    181	dev->net->netdev_ops = &ax88172a_netdev_ops;
    182	dev->net->ethtool_ops = &ax88172a_ethtool_ops;
    183
    184	/* are we using the internal or the external phy? */
    185	ret = asix_read_cmd(dev, AX_CMD_SW_PHY_STATUS, 0, 0, 1, buf, 0);
    186	if (ret < 0) {
    187		netdev_err(dev->net, "Failed to read software interface selection register: %d\n",
    188			   ret);
    189		goto free;
    190	}
    191
    192	netdev_dbg(dev->net, "AX_CMD_SW_PHY_STATUS = 0x%02x\n", buf[0]);
    193	switch (buf[0] & AX_PHY_SELECT_MASK) {
    194	case AX_PHY_SELECT_INTERNAL:
    195		netdev_dbg(dev->net, "use internal phy\n");
    196		priv->use_embdphy = 1;
    197		break;
    198	case AX_PHY_SELECT_EXTERNAL:
    199		netdev_dbg(dev->net, "use external phy\n");
    200		priv->use_embdphy = 0;
    201		break;
    202	default:
    203		netdev_err(dev->net, "Interface mode not supported by driver\n");
    204		ret = -ENOTSUPP;
    205		goto free;
    206	}
    207
    208	ret = asix_read_phy_addr(dev, priv->use_embdphy);
    209	if (ret < 0)
    210		goto free;
    211
    212	priv->phy_addr = ret;
    213
    214	ax88172a_reset_phy(dev, priv->use_embdphy);
    215
    216	/* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
    217	if (dev->driver_info->flags & FLAG_FRAMING_AX) {
    218		/* hard_mtu  is still the default - the device does not support
    219		   jumbo eth frames */
    220		dev->rx_urb_size = 2048;
    221	}
    222
    223	/* init MDIO bus */
    224	ret = ax88172a_init_mdio(dev);
    225	if (ret)
    226		goto free;
    227
    228	return 0;
    229
    230free:
    231	kfree(priv);
    232	return ret;
    233}
    234
    235static int ax88172a_stop(struct usbnet *dev)
    236{
    237	struct ax88172a_private *priv = dev->driver_priv;
    238
    239	netdev_dbg(dev->net, "Stopping interface\n");
    240
    241	if (priv->phydev) {
    242		netdev_info(dev->net, "Disconnecting from phy %s\n",
    243			    priv->phy_name);
    244		phy_stop(priv->phydev);
    245		phy_disconnect(priv->phydev);
    246	}
    247
    248	return 0;
    249}
    250
    251static void ax88172a_unbind(struct usbnet *dev, struct usb_interface *intf)
    252{
    253	struct ax88172a_private *priv = dev->driver_priv;
    254
    255	ax88172a_remove_mdio(dev);
    256	kfree(priv);
    257}
    258
    259static int ax88172a_reset(struct usbnet *dev)
    260{
    261	struct asix_data *data = (struct asix_data *)&dev->data;
    262	struct ax88172a_private *priv = dev->driver_priv;
    263	int ret;
    264	u16 rx_ctl;
    265
    266	ax88172a_reset_phy(dev, priv->use_embdphy);
    267
    268	msleep(150);
    269	rx_ctl = asix_read_rx_ctl(dev, 0);
    270	netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl);
    271	ret = asix_write_rx_ctl(dev, 0x0000, 0);
    272	if (ret < 0)
    273		goto out;
    274
    275	rx_ctl = asix_read_rx_ctl(dev, 0);
    276	netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
    277
    278	msleep(150);
    279
    280	ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
    281			     AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
    282			     AX88772_IPG2_DEFAULT, 0, NULL, 0);
    283	if (ret < 0) {
    284		netdev_err(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret);
    285		goto out;
    286	}
    287
    288	/* Rewrite MAC address */
    289	memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
    290	ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
    291			     data->mac_addr, 0);
    292	if (ret < 0)
    293		goto out;
    294
    295	/* Set RX_CTL to default values with 2k buffer, and enable cactus */
    296	ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, 0);
    297	if (ret < 0)
    298		goto out;
    299
    300	rx_ctl = asix_read_rx_ctl(dev, 0);
    301	netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n",
    302		   rx_ctl);
    303
    304	rx_ctl = asix_read_medium_status(dev, 0);
    305	netdev_dbg(dev->net, "Medium Status is 0x%04x after all initializations\n",
    306		   rx_ctl);
    307
    308	/* Connect to PHY */
    309	snprintf(priv->phy_name, 20, PHY_ID_FMT,
    310		 priv->mdio->id, priv->phy_addr);
    311
    312	priv->phydev = phy_connect(dev->net, priv->phy_name,
    313				   &ax88172a_adjust_link,
    314				   PHY_INTERFACE_MODE_MII);
    315	if (IS_ERR(priv->phydev)) {
    316		netdev_err(dev->net, "Could not connect to PHY device %s\n",
    317			   priv->phy_name);
    318		ret = PTR_ERR(priv->phydev);
    319		goto out;
    320	}
    321
    322	netdev_info(dev->net, "Connected to phy %s\n", priv->phy_name);
    323
    324	/* During power-up, the AX88172A set the power down (BMCR_PDOWN)
    325	 * bit of the PHY. Bring the PHY up again.
    326	 */
    327	genphy_resume(priv->phydev);
    328	phy_start(priv->phydev);
    329
    330	return 0;
    331
    332out:
    333	return ret;
    334
    335}
    336
    337static int ax88172a_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
    338{
    339	struct ax88172a_private *dp = dev->driver_priv;
    340	struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;
    341
    342	return asix_rx_fixup_internal(dev, skb, rx);
    343}
    344
    345const struct driver_info ax88172a_info = {
    346	.description = "ASIX AX88172A USB 2.0 Ethernet",
    347	.bind = ax88172a_bind,
    348	.reset = ax88172a_reset,
    349	.stop = ax88172a_stop,
    350	.unbind = ax88172a_unbind,
    351	.status = ax88172a_status,
    352	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
    353		 FLAG_MULTI_PACKET,
    354	.rx_fixup = ax88172a_rx_fixup,
    355	.tx_fixup = asix_tx_fixup,
    356};