asix_common.c 14.8 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 19 20 21 22
 * 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
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

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

int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
		  u16 size, void *data)
27
{
28 29 30 31 32 33 34 35
	int ret;
	ret = usbnet_read_cmd(dev, cmd,
			       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			       value, index, data, size);

	if (ret != size && ret >= 0)
		return -EINVAL;
	return ret;
36 37
}

C
Christian Riesch 已提交
38 39
int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
		   u16 size, void *data)
40
{
41 42 43
	return usbnet_write_cmd(dev, cmd,
				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
				value, index, data, size);
44 45
}

C
Christian Riesch 已提交
46 47
void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
			  u16 size, void *data)
48
{
49 50 51
	usbnet_write_cmd_async(dev, cmd,
			       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			       value, index, data, size);
52 53
}

54 55
int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
			   struct asix_rx_fixup_info *rx)
56
{
57
	int offset = 0;
58

59 60 61
	while (offset + sizeof(u16) <= skb->len) {
		u16 remaining = 0;
		unsigned char *data;
62

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
		if (!rx->size) {
			if ((skb->len - offset == sizeof(u16)) ||
			    rx->split_head) {
				if(!rx->split_head) {
					rx->header = get_unaligned_le16(
							skb->data + offset);
					rx->split_head = true;
					offset += sizeof(u16);
					break;
				} else {
					rx->header |= (get_unaligned_le16(
							skb->data + offset)
							<< 16);
					rx->split_head = false;
					offset += sizeof(u16);
				}
			} else {
				rx->header = get_unaligned_le32(skb->data +
								offset);
				offset += sizeof(u32);
			}
84

85 86 87 88 89 90 91 92 93 94 95 96
			/* get the packet length */
			rx->size = (u16) (rx->header & 0x7ff);
			if (rx->size != ((~rx->header >> 16) & 0x7ff)) {
				netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n",
					   rx->header, offset);
				rx->size = 0;
				return 0;
			}
			rx->ax_skb = netdev_alloc_skb_ip_align(dev->net,
							       rx->size);
			if (!rx->ax_skb)
				return 0;
97 98
		}

99
		if (rx->size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) {
100
			netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
101 102
				   rx->size);
			kfree_skb(rx->ax_skb);
103 104 105
			rx->ax_skb = NULL;
			rx->size = 0U;

106 107 108
			return 0;
		}

109 110 111 112
		if (rx->size > skb->len - offset) {
			remaining = rx->size - (skb->len - offset);
			rx->size = skb->len - offset;
		}
113

114 115 116 117 118 119 120
		data = skb_put(rx->ax_skb, rx->size);
		memcpy(data, skb->data + offset, rx->size);
		if (!remaining)
			usbnet_skb_return(dev, rx->ax_skb);

		offset += (rx->size + 1) & 0xfffe;
		rx->size = remaining;
121 122
	}

123
	if (skb->len != offset) {
124 125
		netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n",
			   skb->len, offset);
126 127
		return 0;
	}
128

129 130 131
	return 1;
}

132 133 134 135 136 137 138 139
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);
}

C
Christian Riesch 已提交
140 141
struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
			      gfp_t flags)
142 143 144 145 146 147 148
{
	int padlen;
	int headroom = skb_headroom(skb);
	int tailroom = skb_tailroom(skb);
	u32 packet_len;
	u32 padbytes = 0xffff0000;

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

E
Eric Dumazet 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
	/* 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) {
169
			skb->data = memmove(skb->head + 4, skb->data, skb->len);
170
			skb_set_tail_pointer(skb, skb->len);
171 172 173
		}
	} else {
		struct sk_buff *skb2;
E
Eric Dumazet 已提交
174

175 176 177 178 179 180 181
		skb2 = skb_copy_expand(skb, 4, padlen, flags);
		dev_kfree_skb_any(skb);
		skb = skb2;
		if (!skb)
			return NULL;
	}

E
Eric Dumazet 已提交
182
	packet_len = ((skb->len ^ 0x0000ffff) << 16) + skb->len;
183
	skb_push(skb, 4);
184
	cpu_to_le32s(&packet_len);
185
	skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
186

187
	if (padlen) {
188
		cpu_to_le32s(&padbytes);
189
		memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
190 191 192 193 194
		skb_put(skb, sizeof(padbytes));
	}
	return skb;
}

C
Christian Riesch 已提交
195
int asix_set_sw_mii(struct usbnet *dev)
196 197 198 199
{
	int ret;
	ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
	if (ret < 0)
200
		netdev_err(dev->net, "Failed to enable software MII access\n");
201 202 203
	return ret;
}

C
Christian Riesch 已提交
204
int asix_set_hw_mii(struct usbnet *dev)
205 206 207 208
{
	int ret;
	ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
	if (ret < 0)
209
		netdev_err(dev->net, "Failed to enable hardware MII access\n");
210 211 212
	return ret;
}

213
int asix_read_phy_addr(struct usbnet *dev, int internal)
214
{
215
	int offset = (internal ? 1 : 0);
A
Al Viro 已提交
216 217
	u8 buf[2];
	int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf);
218

219
	netdev_dbg(dev->net, "asix_get_phy_addr()\n");
220

A
Al Viro 已提交
221
	if (ret < 0) {
222
		netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret);
A
Al Viro 已提交
223
		goto out;
224
	}
225 226
	netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n",
		   *((__le16 *)buf));
227
	ret = buf[offset];
A
Al Viro 已提交
228 229

out:
230 231 232
	return ret;
}

233 234 235 236 237 238 239
int asix_get_phy_addr(struct usbnet *dev)
{
	/* return the address of the internal phy */
	return asix_read_phy_addr(dev, 1);
}


C
Christian Riesch 已提交
240
int asix_sw_reset(struct usbnet *dev, u8 flags)
241 242 243 244 245
{
	int ret;

        ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL);
	if (ret < 0)
246
		netdev_err(dev->net, "Failed to send software reset: %02x\n", ret);
247 248 249

	return ret;
}
250

C
Christian Riesch 已提交
251
u16 asix_read_rx_ctl(struct usbnet *dev)
252
{
A
Al Viro 已提交
253 254
	__le16 v;
	int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v);
255

A
Al Viro 已提交
256
	if (ret < 0) {
257
		netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret);
A
Al Viro 已提交
258
		goto out;
259
	}
A
Al Viro 已提交
260 261
	ret = le16_to_cpu(v);
out:
262 263 264
	return ret;
}

C
Christian Riesch 已提交
265
int asix_write_rx_ctl(struct usbnet *dev, u16 mode)
266 267 268
{
	int ret;

269
	netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode);
270 271
	ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
	if (ret < 0)
272 273
		netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n",
			   mode, ret);
274 275 276 277

	return ret;
}

C
Christian Riesch 已提交
278
u16 asix_read_medium_status(struct usbnet *dev)
279
{
A
Al Viro 已提交
280 281
	__le16 v;
	int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v);
282

A
Al Viro 已提交
283
	if (ret < 0) {
284 285
		netdev_err(dev->net, "Error reading Medium Status register: %02x\n",
			   ret);
286
		return ret;	/* TODO: callers not checking for error ret */
287
	}
288 289 290

	return le16_to_cpu(v);

291 292
}

C
Christian Riesch 已提交
293
int asix_write_medium_mode(struct usbnet *dev, u16 mode)
294
{
295
	int ret;
296

297
	netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode);
298 299
	ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
	if (ret < 0)
300 301
		netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n",
			   mode, ret);
302

303 304
	return ret;
}
305

C
Christian Riesch 已提交
306
int asix_write_gpio(struct usbnet *dev, u16 value, int sleep)
307 308
{
	int ret;
309

310
	netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value);
311 312
	ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);
	if (ret < 0)
313 314
		netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n",
			   value, ret);
315

316 317 318 319
	if (sleep)
		msleep(sleep);

	return ret;
320 321
}

322 323 324
/*
 * AX88772 & AX88178 have a 16-bit RX_CTL value
 */
C
Christian Riesch 已提交
325
void asix_set_multicast(struct net_device *net)
326 327
{
	struct usbnet *dev = netdev_priv(net);
328
	struct asix_data *data = (struct asix_data *)&dev->data;
329
	u16 rx_ctl = AX_DEFAULT_RX_CTL;
330 331

	if (net->flags & IFF_PROMISC) {
332
		rx_ctl |= AX_RX_CTL_PRO;
333
	} else if (net->flags & IFF_ALLMULTI ||
334
		   netdev_mc_count(net) > AX_MAX_MCAST) {
335
		rx_ctl |= AX_RX_CTL_AMALL;
336
	} else if (netdev_mc_empty(net)) {
337 338 339 340 341 342
		/* 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 */
343
		struct netdev_hw_addr *ha;
344 345 346 347 348
		u32 crc_bits;

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

		/* Build the multicast hash filter. */
349 350
		netdev_for_each_mc_addr(ha, net) {
			crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
351 352 353 354
			data->multi_filter[crc_bits >> 3] |=
			    1 << (crc_bits & 7);
		}

355
		asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
356 357
				   AX_MCAST_FILTER_SIZE, data->multi_filter);

358
		rx_ctl |= AX_RX_CTL_AM;
359 360
	}

361
	asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
362 363
}

C
Christian Riesch 已提交
364
int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
365 366
{
	struct usbnet *dev = netdev_priv(netdev);
A
Al Viro 已提交
367
	__le16 res;
368

369
	mutex_lock(&dev->phy_mutex);
370 371
	asix_set_sw_mii(dev);
	asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
A
Al Viro 已提交
372
				(__u16)loc, 2, &res);
373
	asix_set_hw_mii(dev);
374
	mutex_unlock(&dev->phy_mutex);
375

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

A
Al Viro 已提交
379
	return le16_to_cpu(res);
380 381
}

C
Christian Riesch 已提交
382
void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
383 384
{
	struct usbnet *dev = netdev_priv(netdev);
A
Al Viro 已提交
385
	__le16 res = cpu_to_le16(val);
386

387 388
	netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
		   phy_id, loc, val);
389
	mutex_lock(&dev->phy_mutex);
390
	asix_set_sw_mii(dev);
A
Al Viro 已提交
391
	asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res);
392
	asix_set_hw_mii(dev);
393
	mutex_unlock(&dev->phy_mutex);
394 395
}

C
Christian Riesch 已提交
396
void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
397 398 399 400
{
	struct usbnet *dev = netdev_priv(net);
	u8 opt;

401
	if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) {
402 403 404 405 406 407
		wolinfo->supported = 0;
		wolinfo->wolopts = 0;
		return;
	}
	wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
	wolinfo->wolopts = 0;
408 409 410 411
	if (opt & AX_MONITOR_LINK)
		wolinfo->wolopts |= WAKE_PHY;
	if (opt & AX_MONITOR_MAGIC)
		wolinfo->wolopts |= WAKE_MAGIC;
412 413
}

C
Christian Riesch 已提交
414
int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
415 416 417 418 419 420 421 422 423
{
	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;

424
	if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE,
A
Al Viro 已提交
425
			      opt, 0, 0, NULL) < 0)
426 427 428 429 430
		return -EINVAL;

	return 0;
}

C
Christian Riesch 已提交
431
int asix_get_eeprom_len(struct net_device *net)
432
{
433
	return AX_EEPROM_LEN;
434 435
}

C
Christian Riesch 已提交
436 437
int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
		    u8 *data)
438 439
{
	struct usbnet *dev = netdev_priv(net);
440 441
	u16 *eeprom_buff;
	int first_word, last_word;
442 443
	int i;

444
	if (eeprom->len == 0)
445 446 447 448
		return -EINVAL;

	eeprom->magic = AX_EEPROM_MAGIC;

449 450 451 452 453 454 455 456
	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;

457
	/* ax8817x returns 2 bytes from eeprom on read */
458 459 460 461 462 463
	for (i = first_word; i <= last_word; i++) {
		if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, i, 0, 2,
				  &(eeprom_buff[i - first_word])) < 0) {
			kfree(eeprom_buff);
			return -EIO;
		}
464
	}
465 466 467

	memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
	kfree(eeprom_buff);
468 469 470
	return 0;
}

471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
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,
				    &(eeprom_buff[0]));
		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,
				    &(eeprom_buff[last_word - first_word]));
		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 */
	ret = asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0x0000, 0, 0, NULL);
	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,
				     eeprom_buff[i - first_word], 0, NULL);
		if (ret < 0) {
			netdev_err(net, "Failed to write EEPROM at offset 0x%02x.\n",
				   i);
			goto free;
		}
		msleep(20);
	}

	ret = asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0x0000, 0, 0, NULL);
	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 已提交
552
void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
553 554 555
{
	/* Inherit standard device info */
	usbnet_get_drvinfo(net, info);
556 557
	strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
	strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
558
	info->eedump_len = AX_EEPROM_LEN;
559 560
}

C
Christian Riesch 已提交
561
int asix_set_mac_address(struct net_device *net, void *p)
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
{
	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;
}