| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.com) |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 5 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 6 | | - * published by the Free Software Foundation. |
|---|
| 7 | 4 | * |
|---|
| 8 | 5 | * ChangeLog: |
|---|
| 9 | 6 | * .... Most of the time spent on reading sources & docs. |
|---|
| .. | .. |
|---|
| 57 | 54 | #undef PEGASUS_WRITE_EEPROM |
|---|
| 58 | 55 | #define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \ |
|---|
| 59 | 56 | BMSR_100FULL | BMSR_ANEGCAPABLE) |
|---|
| 57 | +#define CARRIER_CHECK_DELAY (2 * HZ) |
|---|
| 60 | 58 | |
|---|
| 61 | 59 | static bool loopback; |
|---|
| 62 | 60 | static bool mii_mode; |
|---|
| .. | .. |
|---|
| 126 | 124 | |
|---|
| 127 | 125 | static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data) |
|---|
| 128 | 126 | { |
|---|
| 129 | | - u8 *buf; |
|---|
| 130 | | - int ret; |
|---|
| 131 | | - |
|---|
| 132 | | - buf = kmalloc(size, GFP_NOIO); |
|---|
| 133 | | - if (!buf) |
|---|
| 134 | | - return -ENOMEM; |
|---|
| 135 | | - |
|---|
| 136 | | - ret = usb_control_msg(pegasus->usb, usb_rcvctrlpipe(pegasus->usb, 0), |
|---|
| 137 | | - PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ, 0, |
|---|
| 138 | | - indx, buf, size, 1000); |
|---|
| 139 | | - if (ret < 0) |
|---|
| 140 | | - netif_dbg(pegasus, drv, pegasus->net, |
|---|
| 141 | | - "%s returned %d\n", __func__, ret); |
|---|
| 142 | | - else if (ret <= size) |
|---|
| 143 | | - memcpy(data, buf, ret); |
|---|
| 144 | | - kfree(buf); |
|---|
| 145 | | - return ret; |
|---|
| 127 | + return usb_control_msg_recv(pegasus->usb, 0, PEGASUS_REQ_GET_REGS, |
|---|
| 128 | + PEGASUS_REQT_READ, 0, indx, data, size, |
|---|
| 129 | + 1000, GFP_NOIO); |
|---|
| 146 | 130 | } |
|---|
| 147 | 131 | |
|---|
| 148 | 132 | static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, |
|---|
| 149 | 133 | const void *data) |
|---|
| 150 | 134 | { |
|---|
| 151 | | - u8 *buf; |
|---|
| 152 | 135 | int ret; |
|---|
| 153 | 136 | |
|---|
| 154 | | - buf = kmemdup(data, size, GFP_NOIO); |
|---|
| 155 | | - if (!buf) |
|---|
| 156 | | - return -ENOMEM; |
|---|
| 157 | | - |
|---|
| 158 | | - ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), |
|---|
| 159 | | - PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE, 0, |
|---|
| 160 | | - indx, buf, size, 100); |
|---|
| 137 | + ret = usb_control_msg_send(pegasus->usb, 0, PEGASUS_REQ_SET_REGS, |
|---|
| 138 | + PEGASUS_REQT_WRITE, 0, indx, data, size, |
|---|
| 139 | + 1000, GFP_NOIO); |
|---|
| 161 | 140 | if (ret < 0) |
|---|
| 162 | | - netif_dbg(pegasus, drv, pegasus->net, |
|---|
| 163 | | - "%s returned %d\n", __func__, ret); |
|---|
| 164 | | - kfree(buf); |
|---|
| 141 | + netif_dbg(pegasus, drv, pegasus->net, "%s failed with %d\n", __func__, ret); |
|---|
| 142 | + |
|---|
| 165 | 143 | return ret; |
|---|
| 166 | 144 | } |
|---|
| 167 | 145 | |
|---|
| 146 | +/* |
|---|
| 147 | + * There is only one way to write to a single ADM8511 register and this is via |
|---|
| 148 | + * specific control request. 'data' is ignored by the device, but it is here to |
|---|
| 149 | + * not break the API. |
|---|
| 150 | + */ |
|---|
| 168 | 151 | static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data) |
|---|
| 169 | 152 | { |
|---|
| 170 | | - u8 *buf; |
|---|
| 153 | + void *buf = &data; |
|---|
| 171 | 154 | int ret; |
|---|
| 172 | 155 | |
|---|
| 173 | | - buf = kmemdup(&data, 1, GFP_NOIO); |
|---|
| 174 | | - if (!buf) |
|---|
| 175 | | - return -ENOMEM; |
|---|
| 176 | | - |
|---|
| 177 | | - ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), |
|---|
| 178 | | - PEGASUS_REQ_SET_REG, PEGASUS_REQT_WRITE, data, |
|---|
| 179 | | - indx, buf, 1, 1000); |
|---|
| 156 | + ret = usb_control_msg_send(pegasus->usb, 0, PEGASUS_REQ_SET_REG, |
|---|
| 157 | + PEGASUS_REQT_WRITE, data, indx, buf, 1, |
|---|
| 158 | + 1000, GFP_NOIO); |
|---|
| 180 | 159 | if (ret < 0) |
|---|
| 181 | | - netif_dbg(pegasus, drv, pegasus->net, |
|---|
| 182 | | - "%s returned %d\n", __func__, ret); |
|---|
| 183 | | - kfree(buf); |
|---|
| 160 | + netif_dbg(pegasus, drv, pegasus->net, "%s failed with %d\n", __func__, ret); |
|---|
| 161 | + |
|---|
| 184 | 162 | return ret; |
|---|
| 185 | 163 | } |
|---|
| 186 | 164 | |
|---|
| .. | .. |
|---|
| 221 | 199 | |
|---|
| 222 | 200 | static int __mii_op(pegasus_t *p, __u8 phy, __u8 indx, __u16 *regd, __u8 cmd) |
|---|
| 223 | 201 | { |
|---|
| 224 | | - int i; |
|---|
| 225 | | - __u8 data[4] = { phy, 0, 0, indx }; |
|---|
| 202 | + int i, ret; |
|---|
| 226 | 203 | __le16 regdi; |
|---|
| 227 | | - int ret = -ETIMEDOUT; |
|---|
| 204 | + __u8 data[4] = { phy, 0, 0, indx }; |
|---|
| 228 | 205 | |
|---|
| 229 | 206 | if (cmd & PHY_WRITE) { |
|---|
| 230 | 207 | __le16 *t = (__le16 *) & data[1]; |
|---|
| .. | .. |
|---|
| 240 | 217 | if (data[0] & PHY_DONE) |
|---|
| 241 | 218 | break; |
|---|
| 242 | 219 | } |
|---|
| 243 | | - if (i >= REG_TIMEOUT) |
|---|
| 220 | + if (i >= REG_TIMEOUT) { |
|---|
| 221 | + ret = -ETIMEDOUT; |
|---|
| 244 | 222 | goto fail; |
|---|
| 223 | + } |
|---|
| 245 | 224 | if (cmd & PHY_READ) { |
|---|
| 246 | 225 | ret = get_registers(p, PhyData, 2, ®di); |
|---|
| 226 | + if (ret < 0) |
|---|
| 227 | + goto fail; |
|---|
| 247 | 228 | *regd = le16_to_cpu(regdi); |
|---|
| 248 | | - return ret; |
|---|
| 249 | 229 | } |
|---|
| 250 | 230 | return 0; |
|---|
| 251 | 231 | fail: |
|---|
| .. | .. |
|---|
| 268 | 248 | static int mdio_read(struct net_device *dev, int phy_id, int loc) |
|---|
| 269 | 249 | { |
|---|
| 270 | 250 | pegasus_t *pegasus = netdev_priv(dev); |
|---|
| 251 | + int ret; |
|---|
| 271 | 252 | u16 res; |
|---|
| 272 | 253 | |
|---|
| 273 | | - read_mii_word(pegasus, phy_id, loc, &res); |
|---|
| 254 | + ret = read_mii_word(pegasus, phy_id, loc, &res); |
|---|
| 255 | + if (ret < 0) |
|---|
| 256 | + return ret; |
|---|
| 257 | + |
|---|
| 274 | 258 | return (int)res; |
|---|
| 275 | 259 | } |
|---|
| 276 | 260 | |
|---|
| .. | .. |
|---|
| 284 | 268 | |
|---|
| 285 | 269 | static int read_eprom_word(pegasus_t *pegasus, __u8 index, __u16 *retdata) |
|---|
| 286 | 270 | { |
|---|
| 287 | | - int i; |
|---|
| 288 | | - __u8 tmp = 0; |
|---|
| 271 | + int ret, i; |
|---|
| 289 | 272 | __le16 retdatai; |
|---|
| 290 | | - int ret; |
|---|
| 273 | + __u8 tmp = 0; |
|---|
| 291 | 274 | |
|---|
| 292 | 275 | set_register(pegasus, EpromCtrl, 0); |
|---|
| 293 | 276 | set_register(pegasus, EpromOffset, index); |
|---|
| .. | .. |
|---|
| 295 | 278 | |
|---|
| 296 | 279 | for (i = 0; i < REG_TIMEOUT; i++) { |
|---|
| 297 | 280 | ret = get_registers(pegasus, EpromCtrl, 1, &tmp); |
|---|
| 281 | + if (ret < 0) |
|---|
| 282 | + goto fail; |
|---|
| 298 | 283 | if (tmp & EPROM_DONE) |
|---|
| 299 | 284 | break; |
|---|
| 300 | | - if (ret == -ESHUTDOWN) |
|---|
| 301 | | - goto fail; |
|---|
| 302 | 285 | } |
|---|
| 303 | | - if (i >= REG_TIMEOUT) |
|---|
| 286 | + if (i >= REG_TIMEOUT) { |
|---|
| 287 | + ret = -ETIMEDOUT; |
|---|
| 304 | 288 | goto fail; |
|---|
| 289 | + } |
|---|
| 305 | 290 | |
|---|
| 306 | 291 | ret = get_registers(pegasus, EpromData, 2, &retdatai); |
|---|
| 292 | + if (ret < 0) |
|---|
| 293 | + goto fail; |
|---|
| 307 | 294 | *retdata = le16_to_cpu(retdatai); |
|---|
| 308 | 295 | return ret; |
|---|
| 309 | 296 | |
|---|
| 310 | 297 | fail: |
|---|
| 311 | | - netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); |
|---|
| 312 | | - return -ETIMEDOUT; |
|---|
| 298 | + netif_dbg(pegasus, drv, pegasus->net, "%s failed\n", __func__); |
|---|
| 299 | + return ret; |
|---|
| 313 | 300 | } |
|---|
| 314 | 301 | |
|---|
| 315 | 302 | #ifdef PEGASUS_WRITE_EEPROM |
|---|
| .. | .. |
|---|
| 357 | 344 | return ret; |
|---|
| 358 | 345 | |
|---|
| 359 | 346 | fail: |
|---|
| 360 | | - netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); |
|---|
| 347 | + netif_dbg(pegasus, drv, pegasus->net, "%s failed\n", __func__); |
|---|
| 361 | 348 | return -ETIMEDOUT; |
|---|
| 362 | 349 | } |
|---|
| 363 | | -#endif /* PEGASUS_WRITE_EEPROM */ |
|---|
| 350 | +#endif /* PEGASUS_WRITE_EEPROM */ |
|---|
| 364 | 351 | |
|---|
| 365 | | -static inline void get_node_id(pegasus_t *pegasus, __u8 *id) |
|---|
| 352 | +static inline int get_node_id(pegasus_t *pegasus, u8 *id) |
|---|
| 366 | 353 | { |
|---|
| 367 | | - int i; |
|---|
| 368 | | - __u16 w16; |
|---|
| 354 | + int i, ret; |
|---|
| 355 | + u16 w16; |
|---|
| 369 | 356 | |
|---|
| 370 | 357 | for (i = 0; i < 3; i++) { |
|---|
| 371 | | - read_eprom_word(pegasus, i, &w16); |
|---|
| 358 | + ret = read_eprom_word(pegasus, i, &w16); |
|---|
| 359 | + if (ret < 0) |
|---|
| 360 | + return ret; |
|---|
| 372 | 361 | ((__le16 *) id)[i] = cpu_to_le16(w16); |
|---|
| 373 | 362 | } |
|---|
| 363 | + |
|---|
| 364 | + return 0; |
|---|
| 374 | 365 | } |
|---|
| 375 | 366 | |
|---|
| 376 | 367 | static void set_ethernet_addr(pegasus_t *pegasus) |
|---|
| 377 | 368 | { |
|---|
| 378 | | - __u8 node_id[6]; |
|---|
| 369 | + int ret; |
|---|
| 370 | + u8 node_id[6]; |
|---|
| 379 | 371 | |
|---|
| 380 | 372 | if (pegasus->features & PEGASUS_II) { |
|---|
| 381 | | - get_registers(pegasus, 0x10, sizeof(node_id), node_id); |
|---|
| 373 | + ret = get_registers(pegasus, 0x10, sizeof(node_id), node_id); |
|---|
| 374 | + if (ret < 0) |
|---|
| 375 | + goto err; |
|---|
| 382 | 376 | } else { |
|---|
| 383 | | - get_node_id(pegasus, node_id); |
|---|
| 384 | | - set_registers(pegasus, EthID, sizeof(node_id), node_id); |
|---|
| 377 | + ret = get_node_id(pegasus, node_id); |
|---|
| 378 | + if (ret < 0) |
|---|
| 379 | + goto err; |
|---|
| 380 | + ret = set_registers(pegasus, EthID, sizeof(node_id), node_id); |
|---|
| 381 | + if (ret < 0) |
|---|
| 382 | + goto err; |
|---|
| 385 | 383 | } |
|---|
| 384 | + |
|---|
| 386 | 385 | memcpy(pegasus->net->dev_addr, node_id, sizeof(node_id)); |
|---|
| 386 | + |
|---|
| 387 | + return; |
|---|
| 388 | +err: |
|---|
| 389 | + eth_hw_addr_random(pegasus->net); |
|---|
| 390 | + netif_dbg(pegasus, drv, pegasus->net, "software assigned MAC address.\n"); |
|---|
| 391 | + |
|---|
| 392 | + return; |
|---|
| 387 | 393 | } |
|---|
| 388 | 394 | |
|---|
| 389 | 395 | static inline int reset_mac(pegasus_t *pegasus) |
|---|
| 390 | 396 | { |
|---|
| 397 | + int ret, i; |
|---|
| 391 | 398 | __u8 data = 0x8; |
|---|
| 392 | | - int i; |
|---|
| 393 | 399 | |
|---|
| 394 | 400 | set_register(pegasus, EthCtrl1, data); |
|---|
| 395 | 401 | for (i = 0; i < REG_TIMEOUT; i++) { |
|---|
| 396 | | - get_registers(pegasus, EthCtrl1, 1, &data); |
|---|
| 402 | + ret = get_registers(pegasus, EthCtrl1, 1, &data); |
|---|
| 403 | + if (ret < 0) |
|---|
| 404 | + goto fail; |
|---|
| 397 | 405 | if (~data & 0x08) { |
|---|
| 398 | 406 | if (loopback) |
|---|
| 399 | 407 | break; |
|---|
| .. | .. |
|---|
| 416 | 424 | } |
|---|
| 417 | 425 | if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) { |
|---|
| 418 | 426 | __u16 auxmode; |
|---|
| 419 | | - read_mii_word(pegasus, 3, 0x1b, &auxmode); |
|---|
| 427 | + ret = read_mii_word(pegasus, 3, 0x1b, &auxmode); |
|---|
| 428 | + if (ret < 0) |
|---|
| 429 | + goto fail; |
|---|
| 420 | 430 | auxmode |= 4; |
|---|
| 421 | 431 | write_mii_word(pegasus, 3, 0x1b, &auxmode); |
|---|
| 422 | 432 | } |
|---|
| 423 | 433 | |
|---|
| 424 | 434 | return 0; |
|---|
| 435 | +fail: |
|---|
| 436 | + netif_dbg(pegasus, drv, pegasus->net, "%s failed\n", __func__); |
|---|
| 437 | + return ret; |
|---|
| 425 | 438 | } |
|---|
| 426 | 439 | |
|---|
| 427 | 440 | static int enable_net_traffic(struct net_device *dev, struct usb_device *usb) |
|---|
| 428 | 441 | { |
|---|
| 429 | | - __u16 linkpart; |
|---|
| 430 | | - __u8 data[4]; |
|---|
| 431 | 442 | pegasus_t *pegasus = netdev_priv(dev); |
|---|
| 432 | 443 | int ret; |
|---|
| 444 | + __u16 linkpart; |
|---|
| 445 | + __u8 data[4]; |
|---|
| 433 | 446 | |
|---|
| 434 | | - read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart); |
|---|
| 447 | + ret = read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart); |
|---|
| 448 | + if (ret < 0) |
|---|
| 449 | + goto fail; |
|---|
| 435 | 450 | data[0] = 0xc8; /* TX & RX enable, append status, no CRC */ |
|---|
| 436 | 451 | data[1] = 0; |
|---|
| 437 | 452 | if (linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL)) |
|---|
| .. | .. |
|---|
| 449 | 464 | usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS2 || |
|---|
| 450 | 465 | usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) { |
|---|
| 451 | 466 | u16 auxmode; |
|---|
| 452 | | - read_mii_word(pegasus, 0, 0x1b, &auxmode); |
|---|
| 467 | + ret = read_mii_word(pegasus, 0, 0x1b, &auxmode); |
|---|
| 468 | + if (ret < 0) |
|---|
| 469 | + goto fail; |
|---|
| 453 | 470 | auxmode |= 4; |
|---|
| 454 | 471 | write_mii_word(pegasus, 0, 0x1b, &auxmode); |
|---|
| 455 | 472 | } |
|---|
| 456 | 473 | |
|---|
| 474 | + return ret; |
|---|
| 475 | +fail: |
|---|
| 476 | + netif_dbg(pegasus, drv, pegasus->net, "%s failed\n", __func__); |
|---|
| 457 | 477 | return ret; |
|---|
| 458 | 478 | } |
|---|
| 459 | 479 | |
|---|
| .. | .. |
|---|
| 461 | 481 | { |
|---|
| 462 | 482 | pegasus_t *pegasus = urb->context; |
|---|
| 463 | 483 | struct net_device *net; |
|---|
| 484 | + u8 *buf = urb->transfer_buffer; |
|---|
| 464 | 485 | int rx_status, count = urb->actual_length; |
|---|
| 465 | 486 | int status = urb->status; |
|---|
| 466 | | - u8 *buf = urb->transfer_buffer; |
|---|
| 467 | 487 | __u16 pkt_len; |
|---|
| 468 | 488 | |
|---|
| 469 | 489 | if (!pegasus) |
|---|
| .. | .. |
|---|
| 631 | 651 | return; |
|---|
| 632 | 652 | default: |
|---|
| 633 | 653 | netif_info(pegasus, tx_err, net, "TX status %d\n", status); |
|---|
| 634 | | - /* FALL THROUGH */ |
|---|
| 654 | + fallthrough; |
|---|
| 635 | 655 | case 0: |
|---|
| 636 | 656 | break; |
|---|
| 637 | 657 | } |
|---|
| .. | .. |
|---|
| 696 | 716 | "can't resubmit interrupt urb, %d\n", res); |
|---|
| 697 | 717 | } |
|---|
| 698 | 718 | |
|---|
| 699 | | -static void pegasus_tx_timeout(struct net_device *net) |
|---|
| 719 | +static void pegasus_tx_timeout(struct net_device *net, unsigned int txqueue) |
|---|
| 700 | 720 | { |
|---|
| 701 | 721 | pegasus_t *pegasus = netdev_priv(net); |
|---|
| 702 | 722 | netif_warn(pegasus, timer, net, "tx timeout\n"); |
|---|
| .. | .. |
|---|
| 841 | 861 | if (!pegasus->rx_skb) |
|---|
| 842 | 862 | goto exit; |
|---|
| 843 | 863 | |
|---|
| 844 | | - res = set_registers(pegasus, EthID, 6, net->dev_addr); |
|---|
| 864 | + set_registers(pegasus, EthID, 6, net->dev_addr); |
|---|
| 845 | 865 | |
|---|
| 846 | 866 | usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, |
|---|
| 847 | 867 | usb_rcvbulkpipe(pegasus->usb, 1), |
|---|
| .. | .. |
|---|
| 1017 | 1037 | switch (cmd) { |
|---|
| 1018 | 1038 | case SIOCDEVPRIVATE: |
|---|
| 1019 | 1039 | data[0] = pegasus->phy; |
|---|
| 1040 | + fallthrough; |
|---|
| 1020 | 1041 | case SIOCDEVPRIVATE + 1: |
|---|
| 1021 | | - read_mii_word(pegasus, data[0], data[1] & 0x1f, &data[3]); |
|---|
| 1022 | | - res = 0; |
|---|
| 1042 | + res = read_mii_word(pegasus, data[0], data[1] & 0x1f, &data[3]); |
|---|
| 1023 | 1043 | break; |
|---|
| 1024 | 1044 | case SIOCDEVPRIVATE + 2: |
|---|
| 1025 | 1045 | if (!capable(CAP_NET_ADMIN)) |
|---|
| .. | .. |
|---|
| 1053 | 1073 | |
|---|
| 1054 | 1074 | static __u8 mii_phy_probe(pegasus_t *pegasus) |
|---|
| 1055 | 1075 | { |
|---|
| 1056 | | - int i; |
|---|
| 1076 | + int i, ret; |
|---|
| 1057 | 1077 | __u16 tmp; |
|---|
| 1058 | 1078 | |
|---|
| 1059 | 1079 | for (i = 0; i < 32; i++) { |
|---|
| 1060 | | - read_mii_word(pegasus, i, MII_BMSR, &tmp); |
|---|
| 1080 | + ret = read_mii_word(pegasus, i, MII_BMSR, &tmp); |
|---|
| 1081 | + if (ret < 0) |
|---|
| 1082 | + goto fail; |
|---|
| 1061 | 1083 | if (tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0) |
|---|
| 1062 | 1084 | continue; |
|---|
| 1063 | 1085 | else |
|---|
| 1064 | 1086 | return i; |
|---|
| 1065 | 1087 | } |
|---|
| 1066 | | - |
|---|
| 1088 | +fail: |
|---|
| 1067 | 1089 | return 0xff; |
|---|
| 1068 | 1090 | } |
|---|
| 1069 | 1091 | |
|---|
| 1070 | 1092 | static inline void setup_pegasus_II(pegasus_t *pegasus) |
|---|
| 1071 | 1093 | { |
|---|
| 1094 | + int ret; |
|---|
| 1072 | 1095 | __u8 data = 0xa5; |
|---|
| 1073 | 1096 | |
|---|
| 1074 | 1097 | set_register(pegasus, Reg1d, 0); |
|---|
| .. | .. |
|---|
| 1080 | 1103 | set_register(pegasus, Reg7b, 2); |
|---|
| 1081 | 1104 | |
|---|
| 1082 | 1105 | set_register(pegasus, 0x83, data); |
|---|
| 1083 | | - get_registers(pegasus, 0x83, 1, &data); |
|---|
| 1106 | + ret = get_registers(pegasus, 0x83, 1, &data); |
|---|
| 1107 | + if (ret < 0) |
|---|
| 1108 | + goto fail; |
|---|
| 1084 | 1109 | |
|---|
| 1085 | 1110 | if (data == 0xa5) |
|---|
| 1086 | 1111 | pegasus->chip = 0x8513; |
|---|
| .. | .. |
|---|
| 1095 | 1120 | set_register(pegasus, Reg81, 6); |
|---|
| 1096 | 1121 | else |
|---|
| 1097 | 1122 | set_register(pegasus, Reg81, 2); |
|---|
| 1123 | + |
|---|
| 1124 | + return; |
|---|
| 1125 | +fail: |
|---|
| 1126 | + netif_dbg(pegasus, drv, pegasus->net, "%s failed\n", __func__); |
|---|
| 1098 | 1127 | } |
|---|
| 1099 | | - |
|---|
| 1100 | | - |
|---|
| 1101 | | -static int pegasus_count; |
|---|
| 1102 | | -static struct workqueue_struct *pegasus_workqueue; |
|---|
| 1103 | | -#define CARRIER_CHECK_DELAY (2 * HZ) |
|---|
| 1104 | 1128 | |
|---|
| 1105 | 1129 | static void check_carrier(struct work_struct *work) |
|---|
| 1106 | 1130 | { |
|---|
| 1107 | 1131 | pegasus_t *pegasus = container_of(work, pegasus_t, carrier_check.work); |
|---|
| 1108 | 1132 | set_carrier(pegasus->net); |
|---|
| 1109 | 1133 | if (!(pegasus->flags & PEGASUS_UNPLUG)) { |
|---|
| 1110 | | - queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, |
|---|
| 1134 | + queue_delayed_work(system_long_wq, &pegasus->carrier_check, |
|---|
| 1111 | 1135 | CARRIER_CHECK_DELAY); |
|---|
| 1112 | 1136 | } |
|---|
| 1113 | 1137 | } |
|---|
| .. | .. |
|---|
| 1128 | 1152 | return 0; |
|---|
| 1129 | 1153 | } |
|---|
| 1130 | 1154 | |
|---|
| 1131 | | -/* we rely on probe() and remove() being serialized so we |
|---|
| 1132 | | - * don't need extra locking on pegasus_count. |
|---|
| 1133 | | - */ |
|---|
| 1134 | | -static void pegasus_dec_workqueue(void) |
|---|
| 1135 | | -{ |
|---|
| 1136 | | - pegasus_count--; |
|---|
| 1137 | | - if (pegasus_count == 0) { |
|---|
| 1138 | | - destroy_workqueue(pegasus_workqueue); |
|---|
| 1139 | | - pegasus_workqueue = NULL; |
|---|
| 1140 | | - } |
|---|
| 1141 | | -} |
|---|
| 1142 | | - |
|---|
| 1143 | 1155 | static int pegasus_probe(struct usb_interface *intf, |
|---|
| 1144 | 1156 | const struct usb_device_id *id) |
|---|
| 1145 | 1157 | { |
|---|
| .. | .. |
|---|
| 1151 | 1163 | |
|---|
| 1152 | 1164 | if (pegasus_blacklisted(dev)) |
|---|
| 1153 | 1165 | return -ENODEV; |
|---|
| 1154 | | - |
|---|
| 1155 | | - if (pegasus_count == 0) { |
|---|
| 1156 | | - pegasus_workqueue = alloc_workqueue("pegasus", WQ_MEM_RECLAIM, |
|---|
| 1157 | | - 0); |
|---|
| 1158 | | - if (!pegasus_workqueue) |
|---|
| 1159 | | - return -ENOMEM; |
|---|
| 1160 | | - } |
|---|
| 1161 | | - pegasus_count++; |
|---|
| 1162 | 1166 | |
|---|
| 1163 | 1167 | net = alloc_etherdev(sizeof(struct pegasus)); |
|---|
| 1164 | 1168 | if (!net) |
|---|
| .. | .. |
|---|
| 1219 | 1223 | res = register_netdev(net); |
|---|
| 1220 | 1224 | if (res) |
|---|
| 1221 | 1225 | goto out3; |
|---|
| 1222 | | - queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, |
|---|
| 1226 | + queue_delayed_work(system_long_wq, &pegasus->carrier_check, |
|---|
| 1223 | 1227 | CARRIER_CHECK_DELAY); |
|---|
| 1224 | 1228 | dev_info(&intf->dev, "%s, %s, %pM\n", net->name, |
|---|
| 1225 | 1229 | usb_dev_id[dev_index].name, net->dev_addr); |
|---|
| .. | .. |
|---|
| 1232 | 1236 | out1: |
|---|
| 1233 | 1237 | free_netdev(net); |
|---|
| 1234 | 1238 | out: |
|---|
| 1235 | | - pegasus_dec_workqueue(); |
|---|
| 1236 | 1239 | return res; |
|---|
| 1237 | 1240 | } |
|---|
| 1238 | 1241 | |
|---|
| .. | .. |
|---|
| 1247 | 1250 | } |
|---|
| 1248 | 1251 | |
|---|
| 1249 | 1252 | pegasus->flags |= PEGASUS_UNPLUG; |
|---|
| 1250 | | - cancel_delayed_work(&pegasus->carrier_check); |
|---|
| 1253 | + cancel_delayed_work_sync(&pegasus->carrier_check); |
|---|
| 1251 | 1254 | unregister_netdev(pegasus->net); |
|---|
| 1252 | 1255 | unlink_all_urbs(pegasus); |
|---|
| 1253 | 1256 | free_all_urbs(pegasus); |
|---|
| .. | .. |
|---|
| 1256 | 1259 | pegasus->rx_skb = NULL; |
|---|
| 1257 | 1260 | } |
|---|
| 1258 | 1261 | free_netdev(pegasus->net); |
|---|
| 1259 | | - pegasus_dec_workqueue(); |
|---|
| 1260 | 1262 | } |
|---|
| 1261 | 1263 | |
|---|
| 1262 | 1264 | static int pegasus_suspend(struct usb_interface *intf, pm_message_t message) |
|---|
| .. | .. |
|---|
| 1264 | 1266 | struct pegasus *pegasus = usb_get_intfdata(intf); |
|---|
| 1265 | 1267 | |
|---|
| 1266 | 1268 | netif_device_detach(pegasus->net); |
|---|
| 1267 | | - cancel_delayed_work(&pegasus->carrier_check); |
|---|
| 1269 | + cancel_delayed_work_sync(&pegasus->carrier_check); |
|---|
| 1268 | 1270 | if (netif_running(pegasus->net)) { |
|---|
| 1269 | 1271 | usb_kill_urb(pegasus->rx_urb); |
|---|
| 1270 | 1272 | usb_kill_urb(pegasus->intr_urb); |
|---|
| .. | .. |
|---|
| 1286 | 1288 | pegasus->intr_urb->actual_length = 0; |
|---|
| 1287 | 1289 | intr_callback(pegasus->intr_urb); |
|---|
| 1288 | 1290 | } |
|---|
| 1289 | | - queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, |
|---|
| 1291 | + queue_delayed_work(system_long_wq, &pegasus->carrier_check, |
|---|
| 1290 | 1292 | CARRIER_CHECK_DELAY); |
|---|
| 1291 | 1293 | return 0; |
|---|
| 1292 | 1294 | } |
|---|