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

sr9700.c (13273B)


      1/*
      2 * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
      3 *
      4 * Author : Liu Junliang <liujunliang_ljl@163.com>
      5 *
      6 * Based on dm9601.c
      7 *
      8 * This file is licensed under the terms of the GNU General Public License
      9 * version 2.  This program is licensed "as is" without any warranty of any
     10 * kind, whether express or implied.
     11 */
     12
     13#include <linux/module.h>
     14#include <linux/sched.h>
     15#include <linux/stddef.h>
     16#include <linux/netdevice.h>
     17#include <linux/etherdevice.h>
     18#include <linux/ethtool.h>
     19#include <linux/mii.h>
     20#include <linux/usb.h>
     21#include <linux/crc32.h>
     22#include <linux/usb/usbnet.h>
     23
     24#include "sr9700.h"
     25
     26static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
     27{
     28	int err;
     29
     30	err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG, 0, reg, data,
     31			      length);
     32	if ((err != length) && (err >= 0))
     33		err = -EINVAL;
     34	return err;
     35}
     36
     37static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
     38{
     39	int err;
     40
     41	err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG, 0, reg, data,
     42			       length);
     43	if ((err >= 0) && (err < length))
     44		err = -EINVAL;
     45	return err;
     46}
     47
     48static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
     49{
     50	return sr_read(dev, reg, 1, value);
     51}
     52
     53static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
     54{
     55	return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
     56				value, reg, NULL, 0);
     57}
     58
     59static void sr_write_async(struct usbnet *dev, u8 reg, u16 length,
     60			   const void *data)
     61{
     62	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
     63			       0, reg, data, length);
     64}
     65
     66static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
     67{
     68	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
     69			       value, reg, NULL, 0);
     70}
     71
     72static int wait_phy_eeprom_ready(struct usbnet *dev, int phy)
     73{
     74	int i;
     75
     76	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
     77		u8 tmp = 0;
     78		int ret;
     79
     80		udelay(1);
     81		ret = sr_read_reg(dev, SR_EPCR, &tmp);
     82		if (ret < 0)
     83			return ret;
     84
     85		/* ready */
     86		if (!(tmp & EPCR_ERRE))
     87			return 0;
     88	}
     89
     90	netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom");
     91
     92	return -EIO;
     93}
     94
     95static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg,
     96			      __le16 *value)
     97{
     98	int ret;
     99
    100	mutex_lock(&dev->phy_mutex);
    101
    102	sr_write_reg(dev, SR_EPAR, phy ? (reg | EPAR_PHY_ADR) : reg);
    103	sr_write_reg(dev, SR_EPCR, phy ? (EPCR_EPOS | EPCR_ERPRR) : EPCR_ERPRR);
    104
    105	ret = wait_phy_eeprom_ready(dev, phy);
    106	if (ret < 0)
    107		goto out_unlock;
    108
    109	sr_write_reg(dev, SR_EPCR, 0x0);
    110	ret = sr_read(dev, SR_EPDR, 2, value);
    111
    112	netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
    113		   phy, reg, *value, ret);
    114
    115out_unlock:
    116	mutex_unlock(&dev->phy_mutex);
    117	return ret;
    118}
    119
    120static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg,
    121			       __le16 value)
    122{
    123	int ret;
    124
    125	mutex_lock(&dev->phy_mutex);
    126
    127	ret = sr_write(dev, SR_EPDR, 2, &value);
    128	if (ret < 0)
    129		goto out_unlock;
    130
    131	sr_write_reg(dev, SR_EPAR, phy ? (reg | EPAR_PHY_ADR) : reg);
    132	sr_write_reg(dev, SR_EPCR, phy ? (EPCR_WEP | EPCR_EPOS | EPCR_ERPRW) :
    133		    (EPCR_WEP | EPCR_ERPRW));
    134
    135	ret = wait_phy_eeprom_ready(dev, phy);
    136	if (ret < 0)
    137		goto out_unlock;
    138
    139	sr_write_reg(dev, SR_EPCR, 0x0);
    140
    141out_unlock:
    142	mutex_unlock(&dev->phy_mutex);
    143	return ret;
    144}
    145
    146static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
    147{
    148	return sr_share_read_word(dev, 0, offset, value);
    149}
    150
    151static int sr9700_get_eeprom_len(struct net_device *netdev)
    152{
    153	return SR_EEPROM_LEN;
    154}
    155
    156static int sr9700_get_eeprom(struct net_device *netdev,
    157			     struct ethtool_eeprom *eeprom, u8 *data)
    158{
    159	struct usbnet *dev = netdev_priv(netdev);
    160	__le16 *buf = (__le16 *)data;
    161	int ret = 0;
    162	int i;
    163
    164	/* access is 16bit */
    165	if ((eeprom->offset & 0x01) || (eeprom->len & 0x01))
    166		return -EINVAL;
    167
    168	for (i = 0; i < eeprom->len / 2; i++) {
    169		ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, buf + i);
    170		if (ret < 0)
    171			break;
    172	}
    173
    174	return ret;
    175}
    176
    177static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
    178{
    179	struct usbnet *dev = netdev_priv(netdev);
    180	__le16 res;
    181	int rc = 0;
    182
    183	if (phy_id) {
    184		netdev_dbg(netdev, "Only internal phy supported\n");
    185		return 0;
    186	}
    187
    188	/* Access NSR_LINKST bit for link status instead of MII_BMSR */
    189	if (loc == MII_BMSR) {
    190		u8 value;
    191
    192		sr_read_reg(dev, SR_NSR, &value);
    193		if (value & NSR_LINKST)
    194			rc = 1;
    195	}
    196	sr_share_read_word(dev, 1, loc, &res);
    197	if (rc == 1)
    198		res = le16_to_cpu(res) | BMSR_LSTATUS;
    199	else
    200		res = le16_to_cpu(res) & ~BMSR_LSTATUS;
    201
    202	netdev_dbg(netdev, "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
    203		   phy_id, loc, res);
    204
    205	return res;
    206}
    207
    208static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc,
    209			  int val)
    210{
    211	struct usbnet *dev = netdev_priv(netdev);
    212	__le16 res = cpu_to_le16(val);
    213
    214	if (phy_id) {
    215		netdev_dbg(netdev, "Only internal phy supported\n");
    216		return;
    217	}
    218
    219	netdev_dbg(netdev, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
    220		   phy_id, loc, val);
    221
    222	sr_share_write_word(dev, 1, loc, res);
    223}
    224
    225static u32 sr9700_get_link(struct net_device *netdev)
    226{
    227	struct usbnet *dev = netdev_priv(netdev);
    228	u8 value = 0;
    229	int rc = 0;
    230
    231	/* Get the Link Status directly */
    232	sr_read_reg(dev, SR_NSR, &value);
    233	if (value & NSR_LINKST)
    234		rc = 1;
    235
    236	return rc;
    237}
    238
    239static int sr9700_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
    240{
    241	struct usbnet *dev = netdev_priv(netdev);
    242
    243	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
    244}
    245
    246static const struct ethtool_ops sr9700_ethtool_ops = {
    247	.get_drvinfo	= usbnet_get_drvinfo,
    248	.get_link	= sr9700_get_link,
    249	.get_msglevel	= usbnet_get_msglevel,
    250	.set_msglevel	= usbnet_set_msglevel,
    251	.get_eeprom_len	= sr9700_get_eeprom_len,
    252	.get_eeprom	= sr9700_get_eeprom,
    253	.nway_reset	= usbnet_nway_reset,
    254	.get_link_ksettings	= usbnet_get_link_ksettings_mii,
    255	.set_link_ksettings	= usbnet_set_link_ksettings_mii,
    256};
    257
    258static void sr9700_set_multicast(struct net_device *netdev)
    259{
    260	struct usbnet *dev = netdev_priv(netdev);
    261	/* We use the 20 byte dev->data for our 8 byte filter buffer
    262	 * to avoid allocating memory that is tricky to free later
    263	 */
    264	u8 *hashes = (u8 *)&dev->data;
    265	/* rx_ctl setting : enable, disable_long, disable_crc */
    266	u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG;
    267
    268	memset(hashes, 0x00, SR_MCAST_SIZE);
    269	/* broadcast address */
    270	hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;
    271	if (netdev->flags & IFF_PROMISC) {
    272		rx_ctl |= RCR_PRMSC;
    273	} else if (netdev->flags & IFF_ALLMULTI ||
    274		   netdev_mc_count(netdev) > SR_MCAST_MAX) {
    275		rx_ctl |= RCR_RUNT;
    276	} else if (!netdev_mc_empty(netdev)) {
    277		struct netdev_hw_addr *ha;
    278
    279		netdev_for_each_mc_addr(ha, netdev) {
    280			u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
    281			hashes[crc >> 3] |= 1 << (crc & 0x7);
    282		}
    283	}
    284
    285	sr_write_async(dev, SR_MAR, SR_MCAST_SIZE, hashes);
    286	sr_write_reg_async(dev, SR_RCR, rx_ctl);
    287}
    288
    289static int sr9700_set_mac_address(struct net_device *netdev, void *p)
    290{
    291	struct usbnet *dev = netdev_priv(netdev);
    292	struct sockaddr *addr = p;
    293
    294	if (!is_valid_ether_addr(addr->sa_data)) {
    295		netdev_err(netdev, "not setting invalid mac address %pM\n",
    296			   addr->sa_data);
    297		return -EINVAL;
    298	}
    299
    300	eth_hw_addr_set(netdev, addr->sa_data);
    301	sr_write_async(dev, SR_PAR, 6, netdev->dev_addr);
    302
    303	return 0;
    304}
    305
    306static const struct net_device_ops sr9700_netdev_ops = {
    307	.ndo_open		= usbnet_open,
    308	.ndo_stop		= usbnet_stop,
    309	.ndo_start_xmit		= usbnet_start_xmit,
    310	.ndo_tx_timeout		= usbnet_tx_timeout,
    311	.ndo_change_mtu		= usbnet_change_mtu,
    312	.ndo_get_stats64	= dev_get_tstats64,
    313	.ndo_validate_addr	= eth_validate_addr,
    314	.ndo_eth_ioctl		= sr9700_ioctl,
    315	.ndo_set_rx_mode	= sr9700_set_multicast,
    316	.ndo_set_mac_address	= sr9700_set_mac_address,
    317};
    318
    319static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
    320{
    321	struct net_device *netdev;
    322	struct mii_if_info *mii;
    323	u8 addr[ETH_ALEN];
    324	int ret;
    325
    326	ret = usbnet_get_endpoints(dev, intf);
    327	if (ret)
    328		goto out;
    329
    330	netdev = dev->net;
    331
    332	netdev->netdev_ops = &sr9700_netdev_ops;
    333	netdev->ethtool_ops = &sr9700_ethtool_ops;
    334	netdev->hard_header_len += SR_TX_OVERHEAD;
    335	dev->hard_mtu = netdev->mtu + netdev->hard_header_len;
    336	/* bulkin buffer is preferably not less than 3K */
    337	dev->rx_urb_size = 3072;
    338
    339	mii = &dev->mii;
    340	mii->dev = netdev;
    341	mii->mdio_read = sr_mdio_read;
    342	mii->mdio_write = sr_mdio_write;
    343	mii->phy_id_mask = 0x1f;
    344	mii->reg_num_mask = 0x1f;
    345
    346	sr_write_reg(dev, SR_NCR, NCR_RST);
    347	udelay(20);
    348
    349	/* read MAC
    350	 * After Chip Power on, the Chip will reload the MAC from
    351	 * EEPROM automatically to PAR. In case there is no EEPROM externally,
    352	 * a default MAC address is stored in PAR for making chip work properly.
    353	 */
    354	if (sr_read(dev, SR_PAR, ETH_ALEN, addr) < 0) {
    355		netdev_err(netdev, "Error reading MAC address\n");
    356		ret = -ENODEV;
    357		goto out;
    358	}
    359	eth_hw_addr_set(netdev, addr);
    360
    361	/* power up and reset phy */
    362	sr_write_reg(dev, SR_PRR, PRR_PHY_RST);
    363	/* at least 10ms, here 20ms for safe */
    364	msleep(20);
    365	sr_write_reg(dev, SR_PRR, 0);
    366	/* at least 1ms, here 2ms for reading right register */
    367	udelay(2 * 1000);
    368
    369	/* receive broadcast packets */
    370	sr9700_set_multicast(netdev);
    371
    372	sr_mdio_write(netdev, mii->phy_id, MII_BMCR, BMCR_RESET);
    373	sr_mdio_write(netdev, mii->phy_id, MII_ADVERTISE, ADVERTISE_ALL |
    374		      ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
    375	mii_nway_restart(mii);
    376
    377out:
    378	return ret;
    379}
    380
    381static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
    382{
    383	struct sk_buff *sr_skb;
    384	int len;
    385
    386	/* skb content (packets) format :
    387	 *                    p0            p1            p2    ......    pm
    388	 *                 /      \
    389	 *            /                \
    390	 *        /                            \
    391	 *  /                                        \
    392	 * p0b0 p0b1 p0b2 p0b3 ...... p0b(n-4) p0b(n-3)...p0bn
    393	 *
    394	 * p0 : packet 0
    395	 * p0b0 : packet 0 byte 0
    396	 *
    397	 * b0: rx status
    398	 * b1: packet length (incl crc) low
    399	 * b2: packet length (incl crc) high
    400	 * b3..n-4: packet data
    401	 * bn-3..bn: ethernet packet crc
    402	 */
    403	if (unlikely(skb->len < SR_RX_OVERHEAD)) {
    404		netdev_err(dev->net, "unexpected tiny rx frame\n");
    405		return 0;
    406	}
    407
    408	/* one skb may contains multiple packets */
    409	while (skb->len > SR_RX_OVERHEAD) {
    410		if (skb->data[0] != 0x40)
    411			return 0;
    412
    413		/* ignore the CRC length */
    414		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
    415
    416		if (len > ETH_FRAME_LEN || len > skb->len)
    417			return 0;
    418
    419		/* the last packet of current skb */
    420		if (skb->len == (len + SR_RX_OVERHEAD))	{
    421			skb_pull(skb, 3);
    422			skb->len = len;
    423			skb_set_tail_pointer(skb, len);
    424			skb->truesize = len + sizeof(struct sk_buff);
    425			return 2;
    426		}
    427
    428		/* skb_clone is used for address align */
    429		sr_skb = skb_clone(skb, GFP_ATOMIC);
    430		if (!sr_skb)
    431			return 0;
    432
    433		sr_skb->len = len;
    434		sr_skb->data = skb->data + 3;
    435		skb_set_tail_pointer(sr_skb, len);
    436		sr_skb->truesize = len + sizeof(struct sk_buff);
    437		usbnet_skb_return(dev, sr_skb);
    438
    439		skb_pull(skb, len + SR_RX_OVERHEAD);
    440	}
    441
    442	return 0;
    443}
    444
    445static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
    446				       gfp_t flags)
    447{
    448	int len;
    449
    450	/* SR9700 can only send out one ethernet packet at once.
    451	 *
    452	 * b0 b1 b2 b3 ...... b(n-4) b(n-3)...bn
    453	 *
    454	 * b0: rx status
    455	 * b1: packet length (incl crc) low
    456	 * b2: packet length (incl crc) high
    457	 * b3..n-4: packet data
    458	 * bn-3..bn: ethernet packet crc
    459	 */
    460
    461	len = skb->len;
    462
    463	if (skb_cow_head(skb, SR_TX_OVERHEAD)) {
    464		dev_kfree_skb_any(skb);
    465		return NULL;
    466	}
    467
    468	__skb_push(skb, SR_TX_OVERHEAD);
    469
    470	/* usbnet adds padding if length is a multiple of packet size
    471	 * if so, adjust length value in header
    472	 */
    473	if ((skb->len % dev->maxpacket) == 0)
    474		len++;
    475
    476	skb->data[0] = len;
    477	skb->data[1] = len >> 8;
    478
    479	return skb;
    480}
    481
    482static void sr9700_status(struct usbnet *dev, struct urb *urb)
    483{
    484	int link;
    485	u8 *buf;
    486
    487	/* format:
    488	   b0: net status
    489	   b1: tx status 1
    490	   b2: tx status 2
    491	   b3: rx status
    492	   b4: rx overflow
    493	   b5: rx count
    494	   b6: tx count
    495	   b7: gpr
    496	*/
    497
    498	if (urb->actual_length < 8)
    499		return;
    500
    501	buf = urb->transfer_buffer;
    502
    503	link = !!(buf[0] & 0x40);
    504	if (netif_carrier_ok(dev->net) != link) {
    505		usbnet_link_change(dev, link, 1);
    506		netdev_dbg(dev->net, "Link Status is: %d\n", link);
    507	}
    508}
    509
    510static int sr9700_link_reset(struct usbnet *dev)
    511{
    512	struct ethtool_cmd ecmd;
    513
    514	mii_check_media(&dev->mii, 1, 1);
    515	mii_ethtool_gset(&dev->mii, &ecmd);
    516
    517	netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
    518		   ecmd.speed, ecmd.duplex);
    519
    520	return 0;
    521}
    522
    523static const struct driver_info sr9700_driver_info = {
    524	.description	= "CoreChip SR9700 USB Ethernet",
    525	.flags		= FLAG_ETHER,
    526	.bind		= sr9700_bind,
    527	.rx_fixup	= sr9700_rx_fixup,
    528	.tx_fixup	= sr9700_tx_fixup,
    529	.status		= sr9700_status,
    530	.link_reset	= sr9700_link_reset,
    531	.reset		= sr9700_link_reset,
    532};
    533
    534static const struct usb_device_id products[] = {
    535	{
    536		USB_DEVICE(0x0fe6, 0x9700),	/* SR9700 device */
    537		.driver_info = (unsigned long)&sr9700_driver_info,
    538	},
    539	{},			/* END */
    540};
    541
    542MODULE_DEVICE_TABLE(usb, products);
    543
    544static struct usb_driver sr9700_usb_driver = {
    545	.name		= "sr9700",
    546	.id_table	= products,
    547	.probe		= usbnet_probe,
    548	.disconnect	= usbnet_disconnect,
    549	.suspend	= usbnet_suspend,
    550	.resume		= usbnet_resume,
    551	.disable_hub_initiated_lpm = 1,
    552};
    553
    554module_usb_driver(sr9700_usb_driver);
    555
    556MODULE_AUTHOR("liujl <liujunliang_ljl@163.com>");
    557MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/");
    558MODULE_LICENSE("GPL");