asix_common.c 19.5 KB
Newer Older
1 2
/*
 * ASIX AX8817X based USB 2.0 Ethernet Devices
3
 * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com>
4
 * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
5
 * Copyright (C) 2006 James Painter <jamie.painter@iname.com>
6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (c) 2002-2003 TiVo Inc.
 *
 * 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
19
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 21
 */

C
Christian Riesch 已提交
22 23 24
#include "asix.h"

int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
R
Robert Foss 已提交
25
		  u16 size, void *data, int in_pm)
26
{
27
	int ret;
R
Robert Foss 已提交
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
	int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16);

	BUG_ON(!dev);

	if (!in_pm)
		fn = usbnet_read_cmd;
	else
		fn = usbnet_read_cmd_nopm;

	ret = fn(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
		 value, index, data, size);

	if (unlikely(ret < 0))
		netdev_warn(dev->net, "Failed to read reg index 0x%04x: %d\n",
			    index, ret);
43 44

	return ret;
45 46
}

C
Christian Riesch 已提交
47
int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
R
Robert Foss 已提交
48
		   u16 size, void *data, int in_pm)
49
{
R
Robert Foss 已提交
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
	int ret;
	int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16);

	BUG_ON(!dev);

	if (!in_pm)
		fn = usbnet_write_cmd;
	else
		fn = usbnet_write_cmd_nopm;

	ret = fn(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
		 value, index, data, size);

	if (unlikely(ret < 0))
		netdev_warn(dev->net, "Failed to write reg index 0x%04x: %d\n",
			    index, ret);

	return ret;
68 69
}

C
Christian Riesch 已提交
70 71
void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
			  u16 size, void *data)
72
{
73 74 75
	usbnet_write_cmd_async(dev, cmd,
			       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			       value, index, data, size);
76 77
}

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
static void reset_asix_rx_fixup_info(struct asix_rx_fixup_info *rx)
{
	/* Reset the variables that have a lifetime outside of
	 * asix_rx_fixup_internal() so that future processing starts from a
	 * known set of initial conditions.
	 */

	if (rx->ax_skb) {
		/* Discard any incomplete Ethernet frame in the netdev buffer */
		kfree_skb(rx->ax_skb);
		rx->ax_skb = NULL;
	}

	/* Assume the Data header 32-bit word is at the start of the current
	 * or next URB socket buffer so reset all the state variables.
	 */
	rx->remaining = 0;
	rx->split_head = false;
	rx->header = 0;
}

99 100
int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
			   struct asix_rx_fixup_info *rx)
101
{
102
	int offset = 0;
103
	u16 size;
104

105 106 107 108 109 110 111 112 113 114
	/* When an Ethernet frame spans multiple URB socket buffers,
	 * do a sanity test for the Data header synchronisation.
	 * Attempt to detect the situation of the previous socket buffer having
	 * been truncated or a socket buffer was missing. These situations
	 * cause a discontinuity in the data stream and therefore need to avoid
	 * appending bad data to the end of the current netdev socket buffer.
	 * Also avoid unnecessarily discarding a good current netdev socket
	 * buffer.
	 */
	if (rx->remaining && (rx->remaining + sizeof(u32) <= skb->len)) {
115
		offset = ((rx->remaining + 1) & 0xfffe);
116 117 118 119 120 121 122
		rx->header = get_unaligned_le32(skb->data + offset);
		offset = 0;

		size = (u16)(rx->header & 0x7ff);
		if (size != ((~rx->header >> 16) & 0x7ff)) {
			netdev_err(dev->net, "asix_rx_fixup() Data Header synchronisation was lost, remaining %d\n",
				   rx->remaining);
123
			reset_asix_rx_fixup_info(rx);
124 125 126
		}
	}

127
	while (offset + sizeof(u16) <= skb->len) {
128
		u16 copy_length;
129

130
		if (!rx->remaining) {
131 132 133 134 135 136 137 138 139 140 141 142 143
			if (skb->len - offset == sizeof(u16)) {
				rx->header = get_unaligned_le16(
						skb->data + offset);
				rx->split_head = true;
				offset += sizeof(u16);
				break;
			}

			if (rx->split_head == true) {
				rx->header |= (get_unaligned_le16(
						skb->data + offset) << 16);
				rx->split_head = false;
				offset += sizeof(u16);
144 145 146 147 148
			} else {
				rx->header = get_unaligned_le32(skb->data +
								offset);
				offset += sizeof(u32);
			}
149

150 151 152
			/* take frame length from Data header 32-bit word */
			size = (u16)(rx->header & 0x7ff);
			if (size != ((~rx->header >> 16) & 0x7ff)) {
153 154
				netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n",
					   rx->header, offset);
155
				reset_asix_rx_fixup_info(rx);
156 157
				return 0;
			}
158
			if (size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) {
159
				netdev_dbg(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
160
					   size);
161
				reset_asix_rx_fixup_info(rx);
162 163 164
				return 0;
			}

165 166 167 168 169
			/* Sometimes may fail to get a netdev socket buffer but
			 * continue to process the URB socket buffer so that
			 * synchronisation of the Ethernet frame Data header
			 * word is maintained.
			 */
170
			rx->ax_skb = netdev_alloc_skb_ip_align(dev->net, size);
171

172
			rx->remaining = size;
173 174
		}

175 176 177 178 179 180
		if (rx->remaining > skb->len - offset) {
			copy_length = skb->len - offset;
			rx->remaining -= copy_length;
		} else {
			copy_length = rx->remaining;
			rx->remaining = 0;
181
		}
182

183
		if (rx->ax_skb) {
184 185
			skb_put_data(rx->ax_skb, skb->data + offset,
				     copy_length);
186
			if (!rx->remaining) {
187
				usbnet_skb_return(dev, rx->ax_skb);
188 189
				rx->ax_skb = NULL;
			}
190
		}
191

192
		offset += (copy_length + 1) & 0xfffe;
193 194
	}

195
	if (skb->len != offset) {
196 197
		netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n",
			   skb->len, offset);
198
		reset_asix_rx_fixup_info(rx);
199 200
		return 0;
	}
201

202 203 204
	return 1;
}

205 206 207 208 209 210 211 212
int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb)
{
	struct asix_common_private *dp = dev->driver_priv;
	struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;

	return asix_rx_fixup_internal(dev, skb, rx);
}

213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
void asix_rx_fixup_common_free(struct asix_common_private *dp)
{
	struct asix_rx_fixup_info *rx;

	if (!dp)
		return;

	rx = &dp->rx_fixup_info;

	if (rx->ax_skb) {
		kfree_skb(rx->ax_skb);
		rx->ax_skb = NULL;
	}
}

C
Christian Riesch 已提交
228 229
struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
			      gfp_t flags)
230 231 232 233 234 235 236
{
	int padlen;
	int headroom = skb_headroom(skb);
	int tailroom = skb_tailroom(skb);
	u32 packet_len;
	u32 padbytes = 0xffff0000;

237
	padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4;
238

E
Eric Dumazet 已提交
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
	/* We need to push 4 bytes in front of frame (packet_len)
	 * and maybe add 4 bytes after the end (if padlen is 4)
	 *
	 * Avoid skb_copy_expand() expensive call, using following rules :
	 * - We are allowed to push 4 bytes in headroom if skb_header_cloned()
	 *   is false (and if we have 4 bytes of headroom)
	 * - We are allowed to put 4 bytes at tail if skb_cloned()
	 *   is false (and if we have 4 bytes of tailroom)
	 *
	 * TCP packets for example are cloned, but skb_header_release()
	 * was called in tcp stack, allowing us to use headroom for our needs.
	 */
	if (!skb_header_cloned(skb) &&
	    !(padlen && skb_cloned(skb)) &&
	    headroom + tailroom >= 4 + padlen) {
		/* following should not happen, but better be safe */
		if (headroom < 4 ||
		    tailroom < padlen) {
257
			skb->data = memmove(skb->head + 4, skb->data, skb->len);
258
			skb_set_tail_pointer(skb, skb->len);
259 260 261
		}
	} else {
		struct sk_buff *skb2;
E
Eric Dumazet 已提交
262

263 264 265 266 267 268 269
		skb2 = skb_copy_expand(skb, 4, padlen, flags);
		dev_kfree_skb_any(skb);
		skb = skb2;
		if (!skb)
			return NULL;
	}

E
Eric Dumazet 已提交
270
	packet_len = ((skb->len ^ 0x0000ffff) << 16) + skb->len;
271
	skb_push(skb, 4);
272
	cpu_to_le32s(&packet_len);
273
	skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
274

275
	if (padlen) {
276
		cpu_to_le32s(&padbytes);
277
		memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
278 279
		skb_put(skb, sizeof(padbytes));
	}
280

281
	usbnet_set_skb_tx_stats(skb, 1, 0);
282 283 284
	return skb;
}

R
Robert Foss 已提交
285
int asix_set_sw_mii(struct usbnet *dev, int in_pm)
286 287
{
	int ret;
R
Robert Foss 已提交
288 289
	ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL, in_pm);

290
	if (ret < 0)
291
		netdev_err(dev->net, "Failed to enable software MII access\n");
292 293 294
	return ret;
}

R
Robert Foss 已提交
295
int asix_set_hw_mii(struct usbnet *dev, int in_pm)
296 297
{
	int ret;
R
Robert Foss 已提交
298
	ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL, in_pm);
299
	if (ret < 0)
300
		netdev_err(dev->net, "Failed to enable hardware MII access\n");
301 302 303
	return ret;
}

304
int asix_read_phy_addr(struct usbnet *dev, int internal)
305
{
306
	int offset = (internal ? 1 : 0);
A
Al Viro 已提交
307
	u8 buf[2];
R
Robert Foss 已提交
308
	int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf, 0);
309

310
	netdev_dbg(dev->net, "asix_get_phy_addr()\n");
311

A
Al Viro 已提交
312
	if (ret < 0) {
313
		netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret);
A
Al Viro 已提交
314
		goto out;
315
	}
316 317
	netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n",
		   *((__le16 *)buf));
318
	ret = buf[offset];
A
Al Viro 已提交
319 320

out:
321 322 323
	return ret;
}

324 325 326 327 328 329 330
int asix_get_phy_addr(struct usbnet *dev)
{
	/* return the address of the internal phy */
	return asix_read_phy_addr(dev, 1);
}


R
Robert Foss 已提交
331
int asix_sw_reset(struct usbnet *dev, u8 flags, int in_pm)
332 333 334
{
	int ret;

R
Robert Foss 已提交
335
	ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL, in_pm);
336
	if (ret < 0)
337
		netdev_err(dev->net, "Failed to send software reset: %02x\n", ret);
338 339 340

	return ret;
}
341

R
Robert Foss 已提交
342
u16 asix_read_rx_ctl(struct usbnet *dev, int in_pm)
343
{
A
Al Viro 已提交
344
	__le16 v;
R
Robert Foss 已提交
345
	int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v, in_pm);
346

A
Al Viro 已提交
347
	if (ret < 0) {
348
		netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret);
A
Al Viro 已提交
349
		goto out;
350
	}
A
Al Viro 已提交
351 352
	ret = le16_to_cpu(v);
out:
353 354 355
	return ret;
}

R
Robert Foss 已提交
356
int asix_write_rx_ctl(struct usbnet *dev, u16 mode, int in_pm)
357 358 359
{
	int ret;

360
	netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode);
R
Robert Foss 已提交
361
	ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL, in_pm);
362
	if (ret < 0)
363 364
		netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n",
			   mode, ret);
365 366 367 368

	return ret;
}

R
Robert Foss 已提交
369
u16 asix_read_medium_status(struct usbnet *dev, int in_pm)
370
{
A
Al Viro 已提交
371
	__le16 v;
R
Robert Foss 已提交
372 373
	int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS,
				0, 0, 2, &v, in_pm);
374

A
Al Viro 已提交
375
	if (ret < 0) {
376 377
		netdev_err(dev->net, "Error reading Medium Status register: %02x\n",
			   ret);
378
		return ret;	/* TODO: callers not checking for error ret */
379
	}
380 381 382

	return le16_to_cpu(v);

383 384
}

R
Robert Foss 已提交
385
int asix_write_medium_mode(struct usbnet *dev, u16 mode, int in_pm)
386
{
387
	int ret;
388

389
	netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode);
R
Robert Foss 已提交
390 391
	ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
			     mode, 0, 0, NULL, in_pm);
392
	if (ret < 0)
393 394
		netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n",
			   mode, ret);
395

396 397
	return ret;
}
398

R
Robert Foss 已提交
399
int asix_write_gpio(struct usbnet *dev, u16 value, int sleep, int in_pm)
400 401
{
	int ret;
402

403
	netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value);
R
Robert Foss 已提交
404
	ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL, in_pm);
405
	if (ret < 0)
406 407
		netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n",
			   value, ret);
408

409 410 411 412
	if (sleep)
		msleep(sleep);

	return ret;
413 414
}

415 416 417
/*
 * AX88772 & AX88178 have a 16-bit RX_CTL value
 */
C
Christian Riesch 已提交
418
void asix_set_multicast(struct net_device *net)
419 420
{
	struct usbnet *dev = netdev_priv(net);
421
	struct asix_data *data = (struct asix_data *)&dev->data;
422
	u16 rx_ctl = AX_DEFAULT_RX_CTL;
423 424

	if (net->flags & IFF_PROMISC) {
425
		rx_ctl |= AX_RX_CTL_PRO;
426
	} else if (net->flags & IFF_ALLMULTI ||
427
		   netdev_mc_count(net) > AX_MAX_MCAST) {
428
		rx_ctl |= AX_RX_CTL_AMALL;
429
	} else if (netdev_mc_empty(net)) {
430 431 432 433 434 435
		/* just broadcast and directed */
	} else {
		/* We use the 20 byte dev->data
		 * for our 8 byte filter buffer
		 * to avoid allocating memory that
		 * is tricky to free later */
436
		struct netdev_hw_addr *ha;
437 438 439 440 441
		u32 crc_bits;

		memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);

		/* Build the multicast hash filter. */
442 443
		netdev_for_each_mc_addr(ha, net) {
			crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
444 445 446 447
			data->multi_filter[crc_bits >> 3] |=
			    1 << (crc_bits & 7);
		}

448
		asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
449 450
				   AX_MCAST_FILTER_SIZE, data->multi_filter);

451
		rx_ctl |= AX_RX_CTL_AM;
452 453
	}

454
	asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
455 456
}

C
Christian Riesch 已提交
457
int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
458 459
{
	struct usbnet *dev = netdev_priv(netdev);
A
Al Viro 已提交
460
	__le16 res;
R
Robert Foss 已提交
461 462
	u8 smsr;
	int i = 0;
463
	int ret;
464

465
	mutex_lock(&dev->phy_mutex);
R
Robert Foss 已提交
466
	do {
467
		ret = asix_set_sw_mii(dev, 0);
468
		if (ret == -ENODEV || ret == -ETIMEDOUT)
469
			break;
R
Robert Foss 已提交
470
		usleep_range(1000, 1100);
471 472 473
		ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG,
				    0, 0, 1, &smsr, 0);
	} while (!(smsr & AX_HOST_EN) && (i++ < 30) && (ret != -ENODEV));
474
	if (ret == -ENODEV || ret == -ETIMEDOUT) {
475 476 477
		mutex_unlock(&dev->phy_mutex);
		return ret;
	}
R
Robert Foss 已提交
478

479
	asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
R
Robert Foss 已提交
480 481
				(__u16)loc, 2, &res, 0);
	asix_set_hw_mii(dev, 0);
482
	mutex_unlock(&dev->phy_mutex);
483

484
	netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
R
Robert Foss 已提交
485
			phy_id, loc, le16_to_cpu(res));
486

A
Al Viro 已提交
487
	return le16_to_cpu(res);
488 489
}

C
Christian Riesch 已提交
490
void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
491 492
{
	struct usbnet *dev = netdev_priv(netdev);
A
Al Viro 已提交
493
	__le16 res = cpu_to_le16(val);
R
Robert Foss 已提交
494 495
	u8 smsr;
	int i = 0;
496
	int ret;
497

498
	netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
R
Robert Foss 已提交
499 500 501 502
			phy_id, loc, val);

	mutex_lock(&dev->phy_mutex);
	do {
503 504 505
		ret = asix_set_sw_mii(dev, 0);
		if (ret == -ENODEV)
			break;
R
Robert Foss 已提交
506
		usleep_range(1000, 1100);
507 508 509 510 511 512 513
		ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG,
				    0, 0, 1, &smsr, 0);
	} while (!(smsr & AX_HOST_EN) && (i++ < 30) && (ret != -ENODEV));
	if (ret == -ENODEV) {
		mutex_unlock(&dev->phy_mutex);
		return;
	}
R
Robert Foss 已提交
514 515 516 517 518 519 520 521 522 523 524 525 526

	asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
		       (__u16)loc, 2, &res, 0);
	asix_set_hw_mii(dev, 0);
	mutex_unlock(&dev->phy_mutex);
}

int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc)
{
	struct usbnet *dev = netdev_priv(netdev);
	__le16 res;
	u8 smsr;
	int i = 0;
527
	int ret;
R
Robert Foss 已提交
528 529 530

	mutex_lock(&dev->phy_mutex);
	do {
531
		ret = asix_set_sw_mii(dev, 1);
532
		if (ret == -ENODEV || ret == -ETIMEDOUT)
533
			break;
R
Robert Foss 已提交
534
		usleep_range(1000, 1100);
535 536 537
		ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG,
				    0, 0, 1, &smsr, 1);
	} while (!(smsr & AX_HOST_EN) && (i++ < 30) && (ret != -ENODEV));
538
	if (ret == -ENODEV || ret == -ETIMEDOUT) {
539 540 541
		mutex_unlock(&dev->phy_mutex);
		return ret;
	}
R
Robert Foss 已提交
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560

	asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
		      (__u16)loc, 2, &res, 1);
	asix_set_hw_mii(dev, 1);
	mutex_unlock(&dev->phy_mutex);

	netdev_dbg(dev->net, "asix_mdio_read_nopm() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
			phy_id, loc, le16_to_cpu(res));

	return le16_to_cpu(res);
}

void
asix_mdio_write_nopm(struct net_device *netdev, int phy_id, int loc, int val)
{
	struct usbnet *dev = netdev_priv(netdev);
	__le16 res = cpu_to_le16(val);
	u8 smsr;
	int i = 0;
561
	int ret;
R
Robert Foss 已提交
562 563 564 565

	netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
			phy_id, loc, val);

566
	mutex_lock(&dev->phy_mutex);
R
Robert Foss 已提交
567
	do {
568 569 570
		ret = asix_set_sw_mii(dev, 1);
		if (ret == -ENODEV)
			break;
R
Robert Foss 已提交
571
		usleep_range(1000, 1100);
572 573 574 575 576 577 578
		ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG,
				    0, 0, 1, &smsr, 1);
	} while (!(smsr & AX_HOST_EN) && (i++ < 30) && (ret != -ENODEV));
	if (ret == -ENODEV) {
		mutex_unlock(&dev->phy_mutex);
		return;
	}
R
Robert Foss 已提交
579 580 581 582

	asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
		       (__u16)loc, 2, &res, 1);
	asix_set_hw_mii(dev, 1);
583
	mutex_unlock(&dev->phy_mutex);
584 585
}

C
Christian Riesch 已提交
586
void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
587 588 589 590
{
	struct usbnet *dev = netdev_priv(net);
	u8 opt;

R
Robert Foss 已提交
591 592
	if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE,
			  0, 0, 1, &opt, 0) < 0) {
593 594 595 596 597 598
		wolinfo->supported = 0;
		wolinfo->wolopts = 0;
		return;
	}
	wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
	wolinfo->wolopts = 0;
599 600 601 602
	if (opt & AX_MONITOR_LINK)
		wolinfo->wolopts |= WAKE_PHY;
	if (opt & AX_MONITOR_MAGIC)
		wolinfo->wolopts |= WAKE_MAGIC;
603 604
}

C
Christian Riesch 已提交
605
int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
606 607 608 609 610 611 612 613 614
{
	struct usbnet *dev = netdev_priv(net);
	u8 opt = 0;

	if (wolinfo->wolopts & WAKE_PHY)
		opt |= AX_MONITOR_LINK;
	if (wolinfo->wolopts & WAKE_MAGIC)
		opt |= AX_MONITOR_MAGIC;

615
	if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE,
R
Robert Foss 已提交
616
			      opt, 0, 0, NULL, 0) < 0)
617 618 619 620 621
		return -EINVAL;

	return 0;
}

C
Christian Riesch 已提交
622
int asix_get_eeprom_len(struct net_device *net)
623
{
624
	return AX_EEPROM_LEN;
625 626
}

C
Christian Riesch 已提交
627 628
int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
		    u8 *data)
629 630
{
	struct usbnet *dev = netdev_priv(net);
631 632
	u16 *eeprom_buff;
	int first_word, last_word;
633 634
	int i;

635
	if (eeprom->len == 0)
636 637 638 639
		return -EINVAL;

	eeprom->magic = AX_EEPROM_MAGIC;

640 641 642 643 644 645 646 647
	first_word = eeprom->offset >> 1;
	last_word = (eeprom->offset + eeprom->len - 1) >> 1;

	eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1),
			      GFP_KERNEL);
	if (!eeprom_buff)
		return -ENOMEM;

648
	/* ax8817x returns 2 bytes from eeprom on read */
649 650
	for (i = first_word; i <= last_word; i++) {
		if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, i, 0, 2,
R
Robert Foss 已提交
651
				  &eeprom_buff[i - first_word], 0) < 0) {
652 653 654
			kfree(eeprom_buff);
			return -EIO;
		}
655
	}
656 657 658

	memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
	kfree(eeprom_buff);
659 660 661
	return 0;
}

662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
		    u8 *data)
{
	struct usbnet *dev = netdev_priv(net);
	u16 *eeprom_buff;
	int first_word, last_word;
	int i;
	int ret;

	netdev_dbg(net, "write EEPROM len %d, offset %d, magic 0x%x\n",
		   eeprom->len, eeprom->offset, eeprom->magic);

	if (eeprom->len == 0)
		return -EINVAL;

	if (eeprom->magic != AX_EEPROM_MAGIC)
		return -EINVAL;

	first_word = eeprom->offset >> 1;
	last_word = (eeprom->offset + eeprom->len - 1) >> 1;

	eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1),
			      GFP_KERNEL);
	if (!eeprom_buff)
		return -ENOMEM;

	/* align data to 16 bit boundaries, read the missing data from
	   the EEPROM */
	if (eeprom->offset & 1) {
		ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, first_word, 0, 2,
R
Robert Foss 已提交
692
				    &eeprom_buff[0], 0);
693 694 695 696 697 698 699 700
		if (ret < 0) {
			netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", first_word);
			goto free;
		}
	}

	if ((eeprom->offset + eeprom->len) & 1) {
		ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, last_word, 0, 2,
R
Robert Foss 已提交
701
				    &eeprom_buff[last_word - first_word], 0);
702 703 704 705 706 707 708 709 710
		if (ret < 0) {
			netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", last_word);
			goto free;
		}
	}

	memcpy((u8 *)eeprom_buff + (eeprom->offset & 1), data, eeprom->len);

	/* write data to EEPROM */
R
Robert Foss 已提交
711
	ret = asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0x0000, 0, 0, NULL, 0);
712 713 714 715 716 717 718 719 720 721
	if (ret < 0) {
		netdev_err(net, "Failed to enable EEPROM write\n");
		goto free;
	}
	msleep(20);

	for (i = first_word; i <= last_word; i++) {
		netdev_dbg(net, "write to EEPROM at offset 0x%02x, data 0x%04x\n",
			   i, eeprom_buff[i - first_word]);
		ret = asix_write_cmd(dev, AX_CMD_WRITE_EEPROM, i,
R
Robert Foss 已提交
722
				     eeprom_buff[i - first_word], 0, NULL, 0);
723 724 725 726 727 728 729 730
		if (ret < 0) {
			netdev_err(net, "Failed to write EEPROM at offset 0x%02x.\n",
				   i);
			goto free;
		}
		msleep(20);
	}

R
Robert Foss 已提交
731
	ret = asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0x0000, 0, 0, NULL, 0);
732 733 734 735 736 737 738 739 740 741 742
	if (ret < 0) {
		netdev_err(net, "Failed to disable EEPROM write\n");
		goto free;
	}

	ret = 0;
free:
	kfree(eeprom_buff);
	return ret;
}

C
Christian Riesch 已提交
743
void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
744 745 746
{
	/* Inherit standard device info */
	usbnet_get_drvinfo(net, info);
747 748
	strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
	strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
749 750
}

C
Christian Riesch 已提交
751
int asix_set_mac_address(struct net_device *net, void *p)
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773
{
	struct usbnet *dev = netdev_priv(net);
	struct asix_data *data = (struct asix_data *)&dev->data;
	struct sockaddr *addr = p;

	if (netif_running(net))
		return -EBUSY;
	if (!is_valid_ether_addr(addr->sa_data))
		return -EADDRNOTAVAIL;

	memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);

	/* We use the 20 byte dev->data
	 * for our 6 byte mac buffer
	 * to avoid allocating memory that
	 * is tricky to free later */
	memcpy(data->mac_addr, addr->sa_data, ETH_ALEN);
	asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
							data->mac_addr);

	return 0;
}