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

mdio-mvusb.c (2918B)


      1// SPDX-License-Identifier: GPL-2.0
      2
      3#include <linux/kernel.h>
      4#include <linux/module.h>
      5#include <linux/of_mdio.h>
      6#include <linux/phy.h>
      7#include <linux/usb.h>
      8
      9#define USB_MARVELL_VID	0x1286
     10
     11static const struct usb_device_id mvusb_mdio_table[] = {
     12	{ USB_DEVICE(USB_MARVELL_VID, 0x1fa4) },
     13
     14	{}
     15};
     16MODULE_DEVICE_TABLE(usb, mvusb_mdio_table);
     17
     18enum {
     19	MVUSB_CMD_PREAMBLE0,
     20	MVUSB_CMD_PREAMBLE1,
     21	MVUSB_CMD_ADDR,
     22	MVUSB_CMD_VAL,
     23};
     24
     25struct mvusb_mdio {
     26	struct usb_device *udev;
     27	struct mii_bus *mdio;
     28
     29	__le16 buf[4];
     30};
     31
     32static int mvusb_mdio_read(struct mii_bus *mdio, int dev, int reg)
     33{
     34	struct mvusb_mdio *mvusb = mdio->priv;
     35	int err, alen;
     36
     37	if (dev & MII_ADDR_C45)
     38		return -EOPNOTSUPP;
     39
     40	mvusb->buf[MVUSB_CMD_ADDR] = cpu_to_le16(0xa400 | (dev << 5) | reg);
     41
     42	err = usb_bulk_msg(mvusb->udev, usb_sndbulkpipe(mvusb->udev, 2),
     43			   mvusb->buf, 6, &alen, 100);
     44	if (err)
     45		return err;
     46
     47	err = usb_bulk_msg(mvusb->udev, usb_rcvbulkpipe(mvusb->udev, 6),
     48			   &mvusb->buf[MVUSB_CMD_VAL], 2, &alen, 100);
     49	if (err)
     50		return err;
     51
     52	return le16_to_cpu(mvusb->buf[MVUSB_CMD_VAL]);
     53}
     54
     55static int mvusb_mdio_write(struct mii_bus *mdio, int dev, int reg, u16 val)
     56{
     57	struct mvusb_mdio *mvusb = mdio->priv;
     58	int alen;
     59
     60	if (dev & MII_ADDR_C45)
     61		return -EOPNOTSUPP;
     62
     63	mvusb->buf[MVUSB_CMD_ADDR] = cpu_to_le16(0x8000 | (dev << 5) | reg);
     64	mvusb->buf[MVUSB_CMD_VAL]  = cpu_to_le16(val);
     65
     66	return usb_bulk_msg(mvusb->udev, usb_sndbulkpipe(mvusb->udev, 2),
     67			    mvusb->buf, 8, &alen, 100);
     68}
     69
     70static int mvusb_mdio_probe(struct usb_interface *interface,
     71			    const struct usb_device_id *id)
     72{
     73	struct device *dev = &interface->dev;
     74	struct mvusb_mdio *mvusb;
     75	struct mii_bus *mdio;
     76
     77	mdio = devm_mdiobus_alloc_size(dev, sizeof(*mvusb));
     78	if (!mdio)
     79		return -ENOMEM;
     80
     81	mvusb = mdio->priv;
     82	mvusb->mdio = mdio;
     83	mvusb->udev = usb_get_dev(interface_to_usbdev(interface));
     84
     85	/* Reversed from USB PCAPs, no idea what these mean. */
     86	mvusb->buf[MVUSB_CMD_PREAMBLE0] = cpu_to_le16(0xe800);
     87	mvusb->buf[MVUSB_CMD_PREAMBLE1] = cpu_to_le16(0x0001);
     88
     89	snprintf(mdio->id, MII_BUS_ID_SIZE, "mvusb-%s", dev_name(dev));
     90	mdio->name = mdio->id;
     91	mdio->parent = dev;
     92	mdio->read = mvusb_mdio_read;
     93	mdio->write = mvusb_mdio_write;
     94
     95	usb_set_intfdata(interface, mvusb);
     96	return of_mdiobus_register(mdio, dev->of_node);
     97}
     98
     99static void mvusb_mdio_disconnect(struct usb_interface *interface)
    100{
    101	struct mvusb_mdio *mvusb = usb_get_intfdata(interface);
    102	struct usb_device *udev = mvusb->udev;
    103
    104	mdiobus_unregister(mvusb->mdio);
    105	usb_set_intfdata(interface, NULL);
    106	usb_put_dev(udev);
    107}
    108
    109static struct usb_driver mvusb_mdio_driver = {
    110	.name       = "mvusb_mdio",
    111	.id_table   = mvusb_mdio_table,
    112	.probe      = mvusb_mdio_probe,
    113	.disconnect = mvusb_mdio_disconnect,
    114};
    115
    116module_usb_driver(mvusb_mdio_driver);
    117
    118MODULE_AUTHOR("Tobias Waldekranz <tobias@waldekranz.com>");
    119MODULE_DESCRIPTION("Marvell USB MDIO Adapter");
    120MODULE_LICENSE("GPL");