1753f492093da7a40141bfe083073400f518f4c68Michael Buesch/* b44.c: Broadcom 44xx/47xx Fast Ethernet device driver. 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2002 David S. Miller (davem@redhat.com) 4753f492093da7a40141bfe083073400f518f4c68Michael Buesch * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi) 5753f492093da7a40141bfe083073400f518f4c68Michael Buesch * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) 6753f492093da7a40141bfe083073400f518f4c68Michael Buesch * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org) 78056bfafb8a845f3035e7aae5ffe405df118bc12Gary Zambrano * Copyright (C) 2006 Broadcom Corporation. 8eb032b9837a958e21ca000358a5bde5e17192ddbMichael Buesch * Copyright (C) 2007 Michael Buesch <m@bues.ch> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Distribute under GPL. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 132fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 142fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ethtool.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mii.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_ether.h> 2372f4861ef9b1c1ca6e4abb49854698e80d3b684dStephen Hemminger#include <linux/if_vlan.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 28a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h> 2989358f90ab6f6657d386e77e19c805d7ab88694fAndrew Morton#include <linux/dma-mapping.h> 30753f492093da7a40141bfe083073400f518f4c68Michael Buesch#include <linux/ssb/ssb.h> 315a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37753f492093da7a40141bfe083073400f518f4c68Michael Buesch 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "b44.h" 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRV_MODULE_NAME "b44" 41753f492093da7a40141bfe083073400f518f4c68Michael Buesch#define DRV_MODULE_VERSION "2.0" 427329f0d58de01878d9ce4f0be7a76e136f223eefJoe Perches#define DRV_DESCRIPTION "Broadcom 44xx/47xx 10/100 PCI ethernet driver" 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_DEF_MSG_ENABLE \ 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (NETIF_MSG_DRV | \ 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NETIF_MSG_PROBE | \ 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NETIF_MSG_LINK | \ 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NETIF_MSG_TIMER | \ 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NETIF_MSG_IFDOWN | \ 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NETIF_MSG_IFUP | \ 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NETIF_MSG_RX_ERR | \ 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NETIF_MSG_TX_ERR) 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* length of time before we decide the hardware is borked, 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and dev->tx_timeout() should be called to fix the problem 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_TX_TIMEOUT (5 * HZ) 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* hardware minimum and maximum for a single frame's data payload */ 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_MIN_MTU 60 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_MAX_MTU 1500 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_RX_RING_SIZE 512 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_DEF_RX_RING_PENDING 200 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_RX_RING_BYTES (sizeof(struct dma_desc) * \ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds B44_RX_RING_SIZE) 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_TX_RING_SIZE 512 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_DEF_TX_RING_PENDING (B44_TX_RING_SIZE - 1) 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_TX_RING_BYTES (sizeof(struct dma_desc) * \ 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds B44_TX_RING_SIZE) 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_GAP(BP) \ 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (B44_TX_RING_SIZE - (BP)->tx_pending) 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_BUFFS_AVAIL(BP) \ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (((BP)->tx_cons <= (BP)->tx_prod) ? \ 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (BP)->tx_cons + (BP)->tx_pending - (BP)->tx_prod : \ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (BP)->tx_cons - (BP)->tx_prod - TX_RING_GAP(BP)) 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NEXT_TX(N) (((N) + 1) & (B44_TX_RING_SIZE - 1)) 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 804ca857958c129781b46870ec1d2d13c50aafb8c5Felix Fietkau#define RX_PKT_OFFSET (RX_HEADER_LEN + 2) 814ca857958c129781b46870ec1d2d13c50aafb8c5Felix Fietkau#define RX_PKT_BUF_SZ (1536 + RX_PKT_OFFSET) 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* minimum number of free TX descriptors required to wake up TX process */ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4) 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 86725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano/* b44 internal pattern match filter info */ 87725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano#define B44_PATTERN_BASE 0x400 88725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano#define B44_PATTERN_SIZE 0x80 89725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano#define B44_PMASK_BASE 0x600 90725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano#define B44_PMASK_SIZE 0x10 91725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano#define B44_MAX_PATTERNS 16 92725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano#define B44_ETHIPV6UDP_HLEN 62 93725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano#define B44_ETHIPV4UDP_HLEN 42 94725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 95753f492093da7a40141bfe083073400f518f4c68Michael BueschMODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller"); 967329f0d58de01878d9ce4f0be7a76e136f223eefJoe PerchesMODULE_DESCRIPTION(DRV_DESCRIPTION); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION(DRV_MODULE_VERSION); 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_debug = -1; /* -1 == use B44_DEF_MSG_ENABLE as value */ 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(b44_debug, int, 0); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value"); 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105753f492093da7a40141bfe083073400f518f4c68Michael Buesch#ifdef CONFIG_B44_PCI 106a3aa18842a5303fc28fcc4d57dbd16618bd830a0Alexey Dobriyanstatic DEFINE_PCI_DEVICE_TABLE(b44_pci_tbl) = { 107753f492093da7a40141bfe083073400f518f4c68Michael Buesch { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401) }, 108753f492093da7a40141bfe083073400f518f4c68Michael Buesch { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0) }, 109753f492093da7a40141bfe083073400f518f4c68Michael Buesch { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1) }, 110753f492093da7a40141bfe083073400f518f4c68Michael Buesch { 0 } /* terminate list with empty entry */ 111753f492093da7a40141bfe083073400f518f4c68Michael Buesch}; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, b44_pci_tbl); 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 114753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic struct pci_driver b44_pci_driver = { 115753f492093da7a40141bfe083073400f518f4c68Michael Buesch .name = DRV_MODULE_NAME, 116753f492093da7a40141bfe083073400f518f4c68Michael Buesch .id_table = b44_pci_tbl, 117753f492093da7a40141bfe083073400f518f4c68Michael Buesch}; 118753f492093da7a40141bfe083073400f518f4c68Michael Buesch#endif /* CONFIG_B44_PCI */ 119753f492093da7a40141bfe083073400f518f4c68Michael Buesch 120753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic const struct ssb_device_id b44_ssb_tbl[] = { 121753f492093da7a40141bfe083073400f518f4c68Michael Buesch SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV), 122753f492093da7a40141bfe083073400f518f4c68Michael Buesch SSB_DEVTABLE_END 123753f492093da7a40141bfe083073400f518f4c68Michael Buesch}; 124753f492093da7a40141bfe083073400f518f4c68Michael BueschMODULE_DEVICE_TABLE(ssb, b44_ssb_tbl); 125753f492093da7a40141bfe083073400f518f4c68Michael Buesch 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_halt(struct b44 *); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_init_rings(struct b44 *); 1285fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan 1295fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan#define B44_FULL_RESET 1 1305fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan#define B44_FULL_RESET_SKIP_PHY 2 1315fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan#define B44_PARTIAL_RESET 3 132fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón#define B44_CHIP_RESET_FULL 4 133fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón#define B44_CHIP_RESET_PARTIAL 5 1345fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan 13500e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambranostatic void b44_init_hw(struct b44 *, int); 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1379f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linvillestatic int dma_desc_sync_size; 138753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic int instance; 1399f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 1403353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieustatic const char b44_gstrings[][ETH_GSTRING_LEN] = { 1413353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu#define _B44(x...) # x, 1423353930d9d026ca94747d0766f864b2a0a8c714bFrancois RomieuB44_STAT_REG_DECLARE 1433353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu#undef _B44 1443353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu}; 1453353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu 146753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev, 147753f492093da7a40141bfe083073400f518f4c68Michael Buesch dma_addr_t dma_base, 148753f492093da7a40141bfe083073400f518f4c68Michael Buesch unsigned long offset, 149753f492093da7a40141bfe083073400f518f4c68Michael Buesch enum dma_data_direction dir) 1509f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville{ 15139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_sync_single_for_device(sdev->dma_dev, dma_base + offset, 15239a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_desc_sync_size, dir); 1539f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville} 1549f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 155753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev, 156753f492093da7a40141bfe083073400f518f4c68Michael Buesch dma_addr_t dma_base, 157753f492093da7a40141bfe083073400f518f4c68Michael Buesch unsigned long offset, 158753f492093da7a40141bfe083073400f518f4c68Michael Buesch enum dma_data_direction dir) 1599f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville{ 16039a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_sync_single_for_cpu(sdev->dma_dev, dma_base + offset, 16139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_desc_sync_size, dir); 1629f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville} 1639f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned long br32(const struct b44 *bp, unsigned long reg) 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 166753f492093da7a40141bfe083073400f518f4c68Michael Buesch return ssb_read32(bp->sdev, reg); 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16910badc215493a435e2dbdc691386f2650a1778deJeff Garzikstatic inline void bw32(const struct b44 *bp, 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long reg, unsigned long val) 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 172753f492093da7a40141bfe083073400f518f4c68Michael Buesch ssb_write32(bp->sdev, reg, val); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_wait_bit(struct b44 *bp, unsigned long reg, 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 bit, unsigned long timeout, const int clear) 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long i; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < timeout; i++) { 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val = br32(bp, reg); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear && !(val & bit)) 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!clear && (val & bit)) 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(10); 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == timeout) { 190f6ca057f1bfe251d944505fc5ba4df3762802539Jochen Friedrich if (net_ratelimit()) 1912fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches netdev_err(bp->dev, "BUG! Timeout waiting for bit %08x of register %lx to %s\n", 1922fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches bit, reg, clear ? "clear" : "set"); 1932fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 199753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline void __b44_cam_read(struct b44 *bp, unsigned char *data, int index) 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 203753f492093da7a40141bfe083073400f518f4c68Michael Buesch bw32(bp, B44_CAM_CTRL, (CAM_CTRL_READ | 204753f492093da7a40141bfe083073400f518f4c68Michael Buesch (index << CAM_CTRL_INDEX_SHIFT))); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 206753f492093da7a40141bfe083073400f518f4c68Michael Buesch b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 208753f492093da7a40141bfe083073400f518f4c68Michael Buesch val = br32(bp, B44_CAM_DATA_LO); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 210753f492093da7a40141bfe083073400f518f4c68Michael Buesch data[2] = (val >> 24) & 0xFF; 211753f492093da7a40141bfe083073400f518f4c68Michael Buesch data[3] = (val >> 16) & 0xFF; 212753f492093da7a40141bfe083073400f518f4c68Michael Buesch data[4] = (val >> 8) & 0xFF; 213753f492093da7a40141bfe083073400f518f4c68Michael Buesch data[5] = (val >> 0) & 0xFF; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 215753f492093da7a40141bfe083073400f518f4c68Michael Buesch val = br32(bp, B44_CAM_DATA_HI); 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 217753f492093da7a40141bfe083073400f518f4c68Michael Buesch data[0] = (val >> 8) & 0xFF; 218753f492093da7a40141bfe083073400f518f4c68Michael Buesch data[1] = (val >> 0) & 0xFF; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline void __b44_cam_write(struct b44 *bp, unsigned char *data, int index) 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = ((u32) data[2]) << 24; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= ((u32) data[3]) << 16; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= ((u32) data[4]) << 8; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= ((u32) data[5]) << 0; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_CAM_DATA_LO, val); 23010badc215493a435e2dbdc691386f2650a1778deJeff Garzik val = (CAM_DATA_HI_VALID | 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (((u32) data[0]) << 8) | 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (((u32) data[1]) << 0)); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_CAM_DATA_HI, val); 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_CAM_CTRL, (CAM_CTRL_WRITE | 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (index << CAM_CTRL_INDEX_SHIFT))); 23610badc215493a435e2dbdc691386f2650a1778deJeff Garzik b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void __b44_disable_ints(struct b44 *bp) 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_IMASK, 0); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_disable_ints(struct b44 *bp) 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __b44_disable_ints(bp); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Flush posted writes. */ 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br32(bp, B44_IMASK); 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_enable_ints(struct b44 *bp) 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_IMASK, bp->imask); 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 257753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic int __b44_readphy(struct b44 *bp, int phy_addr, int reg, u32 *val) 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) | 264753f492093da7a40141bfe083073400f518f4c68Michael Buesch (phy_addr << MDIO_DATA_PMD_SHIFT) | 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (reg << MDIO_DATA_RA_SHIFT) | 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT))); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *val = br32(bp, B44_MDIO_DATA) & MDIO_DATA_DATA; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 273753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val) 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) | 278753f492093da7a40141bfe083073400f518f4c68Michael Buesch (phy_addr << MDIO_DATA_PMD_SHIFT) | 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (reg << MDIO_DATA_RA_SHIFT) | 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) | 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (val & MDIO_DATA_DATA))); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 285753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline int b44_readphy(struct b44 *bp, int reg, u32 *val) 286753f492093da7a40141bfe083073400f518f4c68Michael Buesch{ 287753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) 288753f492093da7a40141bfe083073400f518f4c68Michael Buesch return 0; 289753f492093da7a40141bfe083073400f518f4c68Michael Buesch 290753f492093da7a40141bfe083073400f518f4c68Michael Buesch return __b44_readphy(bp, bp->phy_addr, reg, val); 291753f492093da7a40141bfe083073400f518f4c68Michael Buesch} 292753f492093da7a40141bfe083073400f518f4c68Michael Buesch 293753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline int b44_writephy(struct b44 *bp, int reg, u32 val) 294753f492093da7a40141bfe083073400f518f4c68Michael Buesch{ 295753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) 296753f492093da7a40141bfe083073400f518f4c68Michael Buesch return 0; 297753f492093da7a40141bfe083073400f518f4c68Michael Buesch 298753f492093da7a40141bfe083073400f518f4c68Michael Buesch return __b44_writephy(bp, bp->phy_addr, reg, val); 299753f492093da7a40141bfe083073400f518f4c68Michael Buesch} 300753f492093da7a40141bfe083073400f518f4c68Michael Buesch 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* miilib interface */ 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_mii_read(struct net_device *dev, int phy_id, int location) 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 306753f492093da7a40141bfe083073400f518f4c68Michael Buesch int rc = __b44_readphy(bp, phy_id, location, &val); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0xffffffff; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_mii_write(struct net_device *dev, int phy_id, int location, 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int val) 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 316753f492093da7a40141bfe083073400f518f4c68Michael Buesch __b44_writephy(bp, phy_id, location, val); 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_phy_reset(struct b44 *bp) 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 324753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) 325753f492093da7a40141bfe083073400f518f4c68Michael Buesch return 0; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = b44_writephy(bp, MII_BMCR, BMCR_RESET); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(100); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = b44_readphy(bp, MII_BMCR, &val); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!err) { 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (val & BMCR_RESET) { 3332fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches netdev_err(bp->dev, "PHY Reset would not complete\n"); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENODEV; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3388850dce170b460d9e46a827a62d6d7bb7e7cfcf3Hauke Mehrtens return err; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __b44_set_flow_ctrl(struct b44 *bp, u32 pause_flags) 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags &= ~(B44_FLAG_TX_PAUSE | B44_FLAG_RX_PAUSE); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags |= pause_flags; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = br32(bp, B44_RXCONFIG); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pause_flags & B44_FLAG_RX_PAUSE) 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= RXCONFIG_FLOW; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val &= ~RXCONFIG_FLOW; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_RXCONFIG, val); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = br32(bp, B44_MAC_FLOW); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pause_flags & B44_FLAG_TX_PAUSE) 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= (MAC_FLOW_PAUSE_ENAB | 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (0xc0 & MAC_FLOW_RX_HI_WATER)); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val &= ~MAC_FLOW_PAUSE_ENAB; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_MAC_FLOW, val); 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote) 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36610badc215493a435e2dbdc691386f2650a1778deJeff Garzik u32 pause_enab = 0; 3672b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano 3682b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano /* The driver supports only rx pause by default because 36910badc215493a435e2dbdc691386f2650a1778deJeff Garzik the b44 mac tx pause mechanism generates excessive 37010badc215493a435e2dbdc691386f2650a1778deJeff Garzik pause frames. 3712b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano Use ethtool to turn on b44 tx pause if necessary. 3722b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano */ 3732b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano if ((local & ADVERTISE_PAUSE_CAP) && 37410badc215493a435e2dbdc691386f2650a1778deJeff Garzik (local & ADVERTISE_PAUSE_ASYM)){ 3752b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano if ((remote & LPA_PAUSE_ASYM) && 3762b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano !(remote & LPA_PAUSE_CAP)) 3772b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano pause_enab |= B44_FLAG_RX_PAUSE; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __b44_set_flow_ctrl(bp, pause_enab); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3836c08af030212d1a34593397bb01f262ff31c3629Hauke Mehrtens#ifdef CONFIG_BCM47XX 3846c08af030212d1a34593397bb01f262ff31c3629Hauke Mehrtens#include <asm/mach-bcm47xx/nvram.h> 385753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic void b44_wap54g10_workaround(struct b44 *bp) 386753f492093da7a40141bfe083073400f518f4c68Michael Buesch{ 3876c08af030212d1a34593397bb01f262ff31c3629Hauke Mehrtens char buf[20]; 388753f492093da7a40141bfe083073400f518f4c68Michael Buesch u32 val; 389753f492093da7a40141bfe083073400f518f4c68Michael Buesch int err; 390753f492093da7a40141bfe083073400f518f4c68Michael Buesch 391753f492093da7a40141bfe083073400f518f4c68Michael Buesch /* 392753f492093da7a40141bfe083073400f518f4c68Michael Buesch * workaround for bad hardware design in Linksys WAP54G v1.0 393753f492093da7a40141bfe083073400f518f4c68Michael Buesch * see https://dev.openwrt.org/ticket/146 394753f492093da7a40141bfe083073400f518f4c68Michael Buesch * check and reset bit "isolate" 395753f492093da7a40141bfe083073400f518f4c68Michael Buesch */ 3966c08af030212d1a34593397bb01f262ff31c3629Hauke Mehrtens if (nvram_getenv("boardnum", buf, sizeof(buf)) < 0) 397753f492093da7a40141bfe083073400f518f4c68Michael Buesch return; 3986c08af030212d1a34593397bb01f262ff31c3629Hauke Mehrtens if (simple_strtoul(buf, NULL, 0) == 2) { 399753f492093da7a40141bfe083073400f518f4c68Michael Buesch err = __b44_readphy(bp, 0, MII_BMCR, &val); 400753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (err) 401753f492093da7a40141bfe083073400f518f4c68Michael Buesch goto error; 402753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (!(val & BMCR_ISOLATE)) 403753f492093da7a40141bfe083073400f518f4c68Michael Buesch return; 404753f492093da7a40141bfe083073400f518f4c68Michael Buesch val &= ~BMCR_ISOLATE; 405753f492093da7a40141bfe083073400f518f4c68Michael Buesch err = __b44_writephy(bp, 0, MII_BMCR, val); 406753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (err) 407753f492093da7a40141bfe083073400f518f4c68Michael Buesch goto error; 408753f492093da7a40141bfe083073400f518f4c68Michael Buesch } 409753f492093da7a40141bfe083073400f518f4c68Michael Buesch return; 410753f492093da7a40141bfe083073400f518f4c68Michael Buescherror: 4112fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches pr_warning("PHY: cannot reset MII transceiver isolate bit\n"); 412753f492093da7a40141bfe083073400f518f4c68Michael Buesch} 413753f492093da7a40141bfe083073400f518f4c68Michael Buesch#else 414753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline void b44_wap54g10_workaround(struct b44 *bp) 415753f492093da7a40141bfe083073400f518f4c68Michael Buesch{ 416753f492093da7a40141bfe083073400f518f4c68Michael Buesch} 417753f492093da7a40141bfe083073400f518f4c68Michael Buesch#endif 418753f492093da7a40141bfe083073400f518f4c68Michael Buesch 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_setup_phy(struct b44 *bp) 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 424753f492093da7a40141bfe083073400f518f4c68Michael Buesch b44_wap54g10_workaround(bp); 425753f492093da7a40141bfe083073400f518f4c68Michael Buesch 426753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) 427753f492093da7a40141bfe083073400f518f4c68Michael Buesch return 0; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0) 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = b44_writephy(bp, B44_MII_ALEDCTRL, 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val & MII_ALEDCTRL_ALLMSK)) != 0) 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = b44_readphy(bp, B44_MII_TLEDCTRL, &val)) != 0) 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = b44_writephy(bp, B44_MII_TLEDCTRL, 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val | MII_TLEDCTRL_ENABLE)) != 0) 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(bp->flags & B44_FLAG_FORCE_LINK)) { 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 adv = ADVERTISE_CSMA; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_ADV_10HALF) 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adv |= ADVERTISE_10HALF; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_ADV_10FULL) 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adv |= ADVERTISE_10FULL; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_ADV_100HALF) 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adv |= ADVERTISE_100HALF; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_ADV_100FULL) 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adv |= ADVERTISE_100FULL; 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_PAUSE_AUTO) 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = b44_writephy(bp, MII_ADVERTISE, adv)) != 0) 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = b44_writephy(bp, MII_BMCR, (BMCR_ANENABLE | 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BMCR_ANRESTART))) != 0) 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 bmcr; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = b44_readphy(bp, MII_BMCR, &bmcr)) != 0) 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bmcr &= ~(BMCR_FULLDPLX | BMCR_ANENABLE | BMCR_SPEED100); 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_100_BASE_T) 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bmcr |= BMCR_SPEED100; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_FULL_DUPLEX) 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bmcr |= BMCR_FULLDPLX; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = b44_writephy(bp, MII_BMCR, bmcr)) != 0) 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Since we will not be negotiating there is no safe way 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to determine if the link partner supports flow control 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or not. So just disable it completely in this case. 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_set_flow_ctrl(bp, 0, 0); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_stats_update(struct b44 *bp) 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long reg; 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 *val; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = &bp->hw_stats.tx_good_octets; 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL) { 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *val++ += br32(bp, reg); 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4923353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu 4933353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu /* Pad */ 4943353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu reg += 8*4UL; 4953353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL) { 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *val++ += br32(bp, reg); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_link_report(struct b44 *bp) 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!netif_carrier_ok(bp->dev)) { 5042fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches netdev_info(bp->dev, "Link is down\n"); 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5062fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches netdev_info(bp->dev, "Link is up at %d Mbps, %s duplex\n", 5072fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches (bp->flags & B44_FLAG_100_BASE_T) ? 100 : 10, 5082fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches (bp->flags & B44_FLAG_FULL_DUPLEX) ? "full" : "half"); 5092fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches 5102fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches netdev_info(bp->dev, "Flow control is %s for TX and %s for RX\n", 5112fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches (bp->flags & B44_FLAG_TX_PAUSE) ? "on" : "off", 5122fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches (bp->flags & B44_FLAG_RX_PAUSE) ? "on" : "off"); 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_check_phy(struct b44 *bp) 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 bmsr, aux; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 520753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) { 521753f492093da7a40141bfe083073400f518f4c68Michael Buesch bp->flags |= B44_FLAG_100_BASE_T; 522753f492093da7a40141bfe083073400f518f4c68Michael Buesch bp->flags |= B44_FLAG_FULL_DUPLEX; 523753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (!netif_carrier_ok(bp->dev)) { 524753f492093da7a40141bfe083073400f518f4c68Michael Buesch u32 val = br32(bp, B44_TX_CTRL); 525753f492093da7a40141bfe083073400f518f4c68Michael Buesch val |= TX_CTRL_DUPLEX; 526753f492093da7a40141bfe083073400f518f4c68Michael Buesch bw32(bp, B44_TX_CTRL, val); 527753f492093da7a40141bfe083073400f518f4c68Michael Buesch netif_carrier_on(bp->dev); 528753f492093da7a40141bfe083073400f518f4c68Michael Buesch b44_link_report(bp); 529753f492093da7a40141bfe083073400f518f4c68Michael Buesch } 530753f492093da7a40141bfe083073400f518f4c68Michael Buesch return; 531753f492093da7a40141bfe083073400f518f4c68Michael Buesch } 532753f492093da7a40141bfe083073400f518f4c68Michael Buesch 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!b44_readphy(bp, MII_BMSR, &bmsr) && 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !b44_readphy(bp, B44_MII_AUXCTRL, &aux) && 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (bmsr != 0xffff)) { 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (aux & MII_AUXCTRL_SPEED) 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags |= B44_FLAG_100_BASE_T; 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags &= ~B44_FLAG_100_BASE_T; 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (aux & MII_AUXCTRL_DUPLEX) 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags |= B44_FLAG_FULL_DUPLEX; 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags &= ~B44_FLAG_FULL_DUPLEX; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!netif_carrier_ok(bp->dev) && 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (bmsr & BMSR_LSTATUS)) { 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val = br32(bp, B44_TX_CTRL); 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 local_adv, remote_adv; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_FULL_DUPLEX) 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= TX_CTRL_DUPLEX; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val &= ~TX_CTRL_DUPLEX; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_TX_CTRL, val); 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(bp->flags & B44_FLAG_FORCE_LINK) && 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !b44_readphy(bp, MII_ADVERTISE, &local_adv) && 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !b44_readphy(bp, MII_LPA, &remote_adv)) 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_set_flow_ctrl(bp, local_adv, remote_adv); 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Link now up */ 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_carrier_on(bp->dev); 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_link_report(bp); 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (netif_carrier_ok(bp->dev) && !(bmsr & BMSR_LSTATUS)) { 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Link now down */ 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_carrier_off(bp->dev); 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_link_report(bp); 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bmsr & BMSR_RFAULT) 5712fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches netdev_warn(bp->dev, "Remote fault detected in PHY\n"); 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bmsr & BMSR_JCD) 5732fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches netdev_warn(bp->dev, "Jabber detected in PHY\n"); 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_timer(unsigned long __opaque) 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = (struct b44 *) __opaque; 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&bp->lock); 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_check_phy(bp); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_stats_update(bp); 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&bp->lock); 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 589a72a8179734393ca351f6ecf8cad6841ab7e1470Stephen Hemminger mod_timer(&bp->timer, round_jiffies(jiffies + HZ)); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_tx(struct b44 *bp) 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 cur, cons; 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur = br32(bp, B44_DMATX_STAT) & DMATX_STAT_CDMASK; 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur /= sizeof(struct dma_desc); 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* XXX needs updating when NETIF_F_SG is supported */ 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (cons = bp->tx_cons; cons != cur; cons = NEXT_TX(cons)) { 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ring_info *rp = &bp->tx_buffers[cons]; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb = rp->skb; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6045d9428de1a9785f10a4339f80b717be665ba51c7Eric Sesterhenn BUG_ON(skb == NULL); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_unmap_single(bp->sdev->dma_dev, 60739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori rp->mapping, 60839a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori skb->len, 60939a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_TO_DEVICE); 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rp->skb = NULL; 61115ac2b08a2fd0f4aacbe8ae39788252fea6fbe63Xander Hover dev_kfree_skb_irq(skb); 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->tx_cons = cons; 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (netif_queue_stopped(bp->dev) && 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TX_BUFFS_AVAIL(bp) > B44_TX_WAKEUP_THRESH) 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(bp->dev); 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_GPTIMER, 0); 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Works like this. This chip writes a 'struct rx_header" 30 bytes 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * before the DMA address you give it. So we allocate 30 more bytes 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for the RX buffer, DMA map all of it, skb_reserve the 30 bytes, then 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * point the chip at 30 bytes past where the rx_header will go. 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dma_desc *dp; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ring_info *src_map, *map; 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct rx_header *rh; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t mapping; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dest_idx; 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 ctrl; 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds src_map = NULL; 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (src_idx >= 0) 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds src_map = &bp->rx_buffers[src_idx]; 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map = &bp->rx_buffers[dest_idx]; 642bf0dcbd929faf036f1a4f2918090344d0e249cf5Stephen Hemminger skb = netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ); 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb == NULL) 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori mapping = dma_map_single(bp->sdev->dma_dev, skb->data, 64739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori RX_PKT_BUF_SZ, 64839a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_FROM_DEVICE); 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Hardware bug work-around, the chip is unable to do PCI DMA 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to/from anything above 1GB :-( */ 65239a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori if (dma_mapping_error(bp->sdev->dma_dev, mapping) || 65328b767967763835d8526f6baedc25a8a86052640Yang Hongyang mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) { 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Sigh... */ 65539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori if (!dma_mapping_error(bp->sdev->dma_dev, mapping)) 65639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_unmap_single(bp->sdev->dma_dev, mapping, 657f225763a7d6c92c4932dbd528437997078496fccMichael Buesch RX_PKT_BUF_SZ, DMA_FROM_DEVICE); 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any(skb); 659bf0dcbd929faf036f1a4f2918090344d0e249cf5Stephen Hemminger skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA); 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb == NULL) 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 66239a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori mapping = dma_map_single(bp->sdev->dma_dev, skb->data, 66339a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori RX_PKT_BUF_SZ, 66439a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_FROM_DEVICE); 66539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori if (dma_mapping_error(bp->sdev->dma_dev, mapping) || 66639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) { 66739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori if (!dma_mapping_error(bp->sdev->dma_dev, mapping)) 66839a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any(skb); 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 672a58c891a53aca81c78f9cbe0572a301042470e96Eric Dumazet bp->force_copybreak = 1; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67572f4861ef9b1c1ca6e4abb49854698e80d3b684dStephen Hemminger rh = (struct rx_header *) skb->data; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rh->len = 0; 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rh->flags = 0; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map->skb = skb; 681753f492093da7a40141bfe083073400f518f4c68Michael Buesch map->mapping = mapping; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (src_map != NULL) 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds src_map->skb = NULL; 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6864ca857958c129781b46870ec1d2d13c50aafb8c5Felix Fietkau ctrl = (DESC_CTRL_LEN & RX_PKT_BUF_SZ); 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dest_idx == (B44_RX_RING_SIZE - 1)) 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl |= DESC_CTRL_EOT; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp = &bp->rx_ring[dest_idx]; 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp->ctrl = cpu_to_le32(ctrl); 6924ca857958c129781b46870ec1d2d13c50aafb8c5Felix Fietkau dp->addr = cpu_to_le32((u32) mapping + bp->dma_offset); 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6949f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville if (bp->flags & B44_FLAG_RX_RING_HACK) 695753f492093da7a40141bfe083073400f518f4c68Michael Buesch b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma, 6965d4d9e8ad6c646c4811bf0049df761dee6affc3dMichael Buesch dest_idx * sizeof(*dp), 697753f492093da7a40141bfe083073400f518f4c68Michael Buesch DMA_BIDIRECTIONAL); 6989f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return RX_PKT_BUF_SZ; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dma_desc *src_desc, *dest_desc; 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ring_info *src_map, *dest_map; 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct rx_header *rh; 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dest_idx; 708a7bed27dc69e3bc9238549a4964ea94ec318362cAl Viro __le32 ctrl; 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1); 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dest_desc = &bp->rx_ring[dest_idx]; 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dest_map = &bp->rx_buffers[dest_idx]; 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds src_desc = &bp->rx_ring[src_idx]; 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds src_map = &bp->rx_buffers[src_idx]; 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dest_map->skb = src_map->skb; 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rh = (struct rx_header *) src_map->skb->data; 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rh->len = 0; 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rh->flags = 0; 720753f492093da7a40141bfe083073400f518f4c68Michael Buesch dest_map->mapping = src_map->mapping; 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7229f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville if (bp->flags & B44_FLAG_RX_RING_HACK) 723753f492093da7a40141bfe083073400f518f4c68Michael Buesch b44_sync_dma_desc_for_cpu(bp->sdev, bp->rx_ring_dma, 7245d4d9e8ad6c646c4811bf0049df761dee6affc3dMichael Buesch src_idx * sizeof(*src_desc), 725753f492093da7a40141bfe083073400f518f4c68Michael Buesch DMA_BIDIRECTIONAL); 7269f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl = src_desc->ctrl; 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dest_idx == (B44_RX_RING_SIZE - 1)) 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl |= cpu_to_le32(DESC_CTRL_EOT); 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl &= cpu_to_le32(~DESC_CTRL_EOT); 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dest_desc->ctrl = ctrl; 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dest_desc->addr = src_desc->addr; 7359f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds src_map->skb = NULL; 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7389f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville if (bp->flags & B44_FLAG_RX_RING_HACK) 739753f492093da7a40141bfe083073400f518f4c68Michael Buesch b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma, 7405d4d9e8ad6c646c4811bf0049df761dee6affc3dMichael Buesch dest_idx * sizeof(*dest_desc), 741753f492093da7a40141bfe083073400f518f4c68Michael Buesch DMA_BIDIRECTIONAL); 7429f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 74339a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_sync_single_for_device(bp->sdev->dma_dev, dest_map->mapping, 74439a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori RX_PKT_BUF_SZ, 74539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_FROM_DEVICE); 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_rx(struct b44 *bp, int budget) 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int received; 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 cons, prod; 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds received = 0; 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prod = br32(bp, B44_DMARX_STAT) & DMARX_STAT_CDMASK; 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prod /= sizeof(struct dma_desc); 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cons = bp->rx_cons; 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (cons != prod && budget > 0) { 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ring_info *rp = &bp->rx_buffers[cons]; 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb = rp->skb; 761753f492093da7a40141bfe083073400f518f4c68Michael Buesch dma_addr_t map = rp->mapping; 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct rx_header *rh; 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 len; 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_sync_single_for_cpu(bp->sdev->dma_dev, map, 76639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori RX_PKT_BUF_SZ, 76739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_FROM_DEVICE); 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rh = (struct rx_header *) skb->data; 769a7bed27dc69e3bc9238549a4964ea94ec318362cAl Viro len = le16_to_cpu(rh->len); 77072f4861ef9b1c1ca6e4abb49854698e80d3b684dStephen Hemminger if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) || 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) { 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drop_it: 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_recycle_rx(bp, cons, bp->rx_prod); 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drop_it_no_recycle: 775553e2335625e6c96cb6d76c0d63cfc1034747614Eric Dumazet bp->dev->stats.rx_dropped++; 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto next_pkt; 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len == 0) { 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = 0; 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(2); 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds barrier(); 785a7bed27dc69e3bc9238549a4964ea94ec318362cAl Viro len = le16_to_cpu(rh->len); 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (len == 0 && i++ < 5); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len == 0) 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto drop_it; 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Omit CRC. */ 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= 4; 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 794a58c891a53aca81c78f9cbe0572a301042470e96Eric Dumazet if (!bp->force_copybreak && len > RX_COPY_THRESHOLD) { 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int skb_size; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod); 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb_size < 0) 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto drop_it; 79939a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_unmap_single(bp->sdev->dma_dev, map, 80039a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori skb_size, DMA_FROM_DEVICE); 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Leave out rx_header */ 8024ca857958c129781b46870ec1d2d13c50aafb8c5Felix Fietkau skb_put(skb, len + RX_PKT_OFFSET); 8034ca857958c129781b46870ec1d2d13c50aafb8c5Felix Fietkau skb_pull(skb, RX_PKT_OFFSET); 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *copy_skb; 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_recycle_rx(bp, cons, bp->rx_prod); 80853639207c032ec63dac3661af94447f9774cd40bHauke Mehrtens copy_skb = netdev_alloc_skb(bp->dev, len + 2); 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_skb == NULL) 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto drop_it_no_recycle; 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(copy_skb, 2); 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_put(copy_skb, len); 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* DMA sync done above, copy just the actual packet */ 81572f4861ef9b1c1ca6e4abb49854698e80d3b684dStephen Hemminger skb_copy_from_linear_data_offset(skb, RX_PKT_OFFSET, 816d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo copy_skb->data, len); 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = copy_skb; 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 819bc8acf2c8c3e43fcc192762a9f964b3e9a17748bEric Dumazet skb_checksum_none_assert(skb); 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = eth_type_trans(skb, bp->dev); 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_receive_skb(skb); 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds received++; 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds budget--; 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_pkt: 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->rx_prod = (bp->rx_prod + 1) & 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (B44_RX_RING_SIZE - 1); 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cons = (cons + 1) & (B44_RX_RING_SIZE - 1); 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->rx_cons = cons; 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_DMARX_PTR, cons * sizeof(struct dma_desc)); 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return received; 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 836bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemmingerstatic int b44_poll(struct napi_struct *napi, int budget) 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 838bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger struct b44 *bp = container_of(napi, struct b44, napi); 839bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger int work_done; 840e99b1f04d922f132ffab8310b470bcc93d3ddf80Dongdong Deng unsigned long flags; 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 842e99b1f04d922f132ffab8310b470bcc93d3ddf80Dongdong Deng spin_lock_irqsave(&bp->lock, flags); 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->istat & (ISTAT_TX | ISTAT_TO)) { 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* spin_lock(&bp->tx_lock); */ 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_tx(bp); 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* spin_unlock(&bp->tx_lock); */ 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 84932737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord if (bp->istat & ISTAT_RFO) { /* fast recovery, in ~20msec */ 85032737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord bp->istat &= ~ISTAT_RFO; 85132737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord b44_disable_ints(bp); 85232737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord ssb_device_enable(bp->sdev, 0); /* resets ISTAT_RFO */ 85332737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord b44_init_rings(bp); 85432737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY); 85532737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord netif_wake_queue(bp->dev); 85632737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord } 85732737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord 858e99b1f04d922f132ffab8310b470bcc93d3ddf80Dongdong Deng spin_unlock_irqrestore(&bp->lock, flags); 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 860bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger work_done = 0; 861bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger if (bp->istat & ISTAT_RX) 862bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger work_done += b44_rx(bp, budget); 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->istat & ISTAT_ERRORS) { 865d15e9c4d9a75702b30e00cdf95c71c88e3f3f51eFrancois Romieu spin_lock_irqsave(&bp->lock, flags); 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_halt(bp); 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_init_rings(bp); 8685fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY); 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(bp->dev); 870d15e9c4d9a75702b30e00cdf95c71c88e3f3f51eFrancois Romieu spin_unlock_irqrestore(&bp->lock, flags); 871bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger work_done = 0; 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 874bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger if (work_done < budget) { 875288379f050284087578b77e04f040b57db3db3f8Ben Hutchings napi_complete(napi); 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_enable_ints(bp); 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 879bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger return work_done; 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8827d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t b44_interrupt(int irq, void *dev_id) 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = dev_id; 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 istat, imask; 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int handled = 0; 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88965b984f26f16e97168ee29e53145055412f38a23Francois Romieu spin_lock(&bp->lock); 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds istat = br32(bp, B44_ISTAT); 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds imask = br32(bp, B44_IMASK); 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 894e78181feb0b94fb6afeaef3b28d4f5df1b847c98Johannes Berg /* The interrupt mask register controls which interrupt bits 895e78181feb0b94fb6afeaef3b28d4f5df1b847c98Johannes Berg * will actually raise an interrupt to the CPU when set by hw/firmware, 896e78181feb0b94fb6afeaef3b28d4f5df1b847c98Johannes Berg * but doesn't mask off the bits. 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds istat &= imask; 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (istat) { 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handled = 1; 901ba5eec9c55ec4be99d21a6ea614003b65d7f37d7Francois Romieu 902ba5eec9c55ec4be99d21a6ea614003b65d7f37d7Francois Romieu if (unlikely(!netif_running(dev))) { 9032fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches netdev_info(dev, "late interrupt\n"); 904ba5eec9c55ec4be99d21a6ea614003b65d7f37d7Francois Romieu goto irq_ack; 905ba5eec9c55ec4be99d21a6ea614003b65d7f37d7Francois Romieu } 906ba5eec9c55ec4be99d21a6ea614003b65d7f37d7Francois Romieu 907288379f050284087578b77e04f040b57db3db3f8Ben Hutchings if (napi_schedule_prep(&bp->napi)) { 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NOTE: These writes are posted by the readback of 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the ISTAT register below. 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->istat = istat; 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __b44_disable_ints(bp); 913288379f050284087578b77e04f040b57db3db3f8Ben Hutchings __napi_schedule(&bp->napi); 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 916ba5eec9c55ec4be99d21a6ea614003b65d7f37d7Francois Romieuirq_ack: 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_ISTAT, istat); 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br32(bp, B44_ISTAT); 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 92065b984f26f16e97168ee29e53145055412f38a23Francois Romieu spin_unlock(&bp->lock); 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_RETVAL(handled); 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_tx_timeout(struct net_device *dev) 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9282fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches netdev_err(dev, "transmit timed out, resetting\n"); 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&bp->lock); 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_halt(bp); 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_init_rings(bp); 9345fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan b44_init_hw(bp, B44_FULL_RESET); 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&bp->lock); 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_enable_ints(bp); 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(dev); 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 94361357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t b44_start_xmit(struct sk_buff *skb, struct net_device *dev) 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 946c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieu int rc = NETDEV_TX_OK; 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t mapping; 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 len, entry, ctrl; 94922580f894ac190c46beebb5c3172e450a2318f79Dongdong Deng unsigned long flags; 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = skb->len; 95222580f894ac190c46beebb5c3172e450a2318f79Dongdong Deng spin_lock_irqsave(&bp->lock, flags); 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This is a hard error, log it. */ 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(TX_BUFFS_AVAIL(bp) < 1)) { 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 9572fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches netdev_err(dev, "BUG! Tx Ring full when queue awake!\n"); 958c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieu goto err_out; 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE); 96239a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) { 963f65a71775cc3eb5d5d8ac4c349c8f48a7d5c7759Stephen Hemminger struct sk_buff *bounce_skb; 964f65a71775cc3eb5d5d8ac4c349c8f48a7d5c7759Stephen Hemminger 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Chip can't handle DMA to/from >1GB, use bounce buffer */ 96639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori if (!dma_mapping_error(bp->sdev->dma_dev, mapping)) 96739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_unmap_single(bp->sdev->dma_dev, mapping, len, 968f225763a7d6c92c4932dbd528437997078496fccMichael Buesch DMA_TO_DEVICE); 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9709034f77bad1e86c4b43e5f5739eb3b8f4878e947David S. Miller bounce_skb = __netdev_alloc_skb(dev, len, GFP_ATOMIC | GFP_DMA); 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bounce_skb) 972c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieu goto err_out; 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 97439a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori mapping = dma_map_single(bp->sdev->dma_dev, bounce_skb->data, 97539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori len, DMA_TO_DEVICE); 97639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) { 97739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori if (!dma_mapping_error(bp->sdev->dma_dev, mapping)) 97839a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_unmap_single(bp->sdev->dma_dev, mapping, 979f225763a7d6c92c4932dbd528437997078496fccMichael Buesch len, DMA_TO_DEVICE); 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any(bounce_skb); 981c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieu goto err_out; 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 984f65a71775cc3eb5d5d8ac4c349c8f48a7d5c7759Stephen Hemminger skb_copy_from_linear_data(skb, skb_put(bounce_skb, len), len); 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any(skb); 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = bounce_skb; 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = bp->tx_prod; 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->tx_buffers[entry].skb = skb; 991753f492093da7a40141bfe083073400f518f4c68Michael Buesch bp->tx_buffers[entry].mapping = mapping; 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl = (len & DESC_CTRL_LEN); 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl |= DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF; 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (entry == (B44_TX_RING_SIZE - 1)) 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl |= DESC_CTRL_EOT; 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->tx_ring[entry].ctrl = cpu_to_le32(ctrl); 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset); 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10019f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville if (bp->flags & B44_FLAG_TX_RING_HACK) 1002753f492093da7a40141bfe083073400f518f4c68Michael Buesch b44_sync_dma_desc_for_device(bp->sdev, bp->tx_ring_dma, 1003753f492093da7a40141bfe083073400f518f4c68Michael Buesch entry * sizeof(bp->tx_ring[0]), 1004753f492093da7a40141bfe083073400f518f4c68Michael Buesch DMA_TO_DEVICE); 10059f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = NEXT_TX(entry); 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->tx_prod = entry; 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wmb(); 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_DMATX_PTR, entry * sizeof(struct dma_desc)); 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_BUGGY_TXPTR) 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_DMATX_PTR, entry * sizeof(struct dma_desc)); 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_REORDER_BUG) 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br32(bp, B44_DMATX_PTR); 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (TX_BUFFS_AVAIL(bp) < 1) 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieuout_unlock: 102222580f894ac190c46beebb5c3172e450a2318f79Dongdong Deng spin_unlock_irqrestore(&bp->lock, flags); 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1024c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieu return rc; 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1026c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieuerr_out: 1027c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieu rc = NETDEV_TX_BUSY; 1028c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieu goto out_unlock; 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_change_mtu(struct net_device *dev, int new_mtu) 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_mtu < B44_MIN_MTU || new_mtu > B44_MAX_MTU) 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!netif_running(dev)) { 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We'll just catch it later when the 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device is up'd. 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mtu = new_mtu; 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&bp->lock); 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_halt(bp); 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mtu = new_mtu; 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_init_rings(bp); 10505fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan b44_init_hw(bp, B44_FULL_RESET); 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&bp->lock); 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_enable_ints(bp); 105410badc215493a435e2dbdc691386f2650a1778deJeff Garzik 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Free up pending packets in all rx/tx rings. 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The chip has been shut down and the driver detached from 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the networking, so no interrupts or new tx packets will 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * end up in the driver. bp->lock is not held and we are not 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in an interrupt context and thus may sleep. 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_free_rings(struct b44 *bp) 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ring_info *rp; 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < B44_RX_RING_SIZE; i++) { 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rp = &bp->rx_buffers[i]; 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rp->skb == NULL) 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 107539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ, 107639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_FROM_DEVICE); 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any(rp->skb); 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rp->skb = NULL; 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* XXX needs changes once NETIF_F_SG is set... */ 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < B44_TX_RING_SIZE; i++) { 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rp = &bp->tx_buffers[i]; 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rp->skb == NULL) 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 108739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len, 108839a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_TO_DEVICE); 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any(rp->skb); 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rp->skb = NULL; 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize tx/rx rings for packet processing. 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The chip has been shut down and the driver detached from 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the networking, so no interrupts or new tx packets will 1098874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu * end up in the driver. 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_init_rings(struct b44 *bp) 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_free_rings(bp); 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(bp->rx_ring, 0, B44_RX_RING_BYTES); 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(bp->tx_ring, 0, B44_TX_RING_BYTES); 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11099f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville if (bp->flags & B44_FLAG_RX_RING_HACK) 111039a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma, 111139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_TABLE_BYTES, DMA_BIDIRECTIONAL); 11129f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 11139f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville if (bp->flags & B44_FLAG_TX_RING_HACK) 111439a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma, 111539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_TABLE_BYTES, DMA_TO_DEVICE); 11169f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < bp->rx_pending; i++) { 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (b44_alloc_rx_skb(bp, -1, i) < 0) 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Must not be invoked with interrupt sources disabled and 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the hardware shutdown down. 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_free_consistent(struct b44 *bp) 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1129b4558ea93d66a43f7990d26f145fd4c54a01c9bfJesper Juhl kfree(bp->rx_buffers); 1130b4558ea93d66a43f7990d26f145fd4c54a01c9bfJesper Juhl bp->rx_buffers = NULL; 1131b4558ea93d66a43f7990d26f145fd4c54a01c9bfJesper Juhl kfree(bp->tx_buffers); 1132b4558ea93d66a43f7990d26f145fd4c54a01c9bfJesper Juhl bp->tx_buffers = NULL; 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->rx_ring) { 11349f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville if (bp->flags & B44_FLAG_RX_RING_HACK) { 113539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma, 113639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_TABLE_BYTES, DMA_BIDIRECTIONAL); 11379f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville kfree(bp->rx_ring); 11389f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville } else 113939a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES, 114039a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori bp->rx_ring, bp->rx_ring_dma); 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->rx_ring = NULL; 11429f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville bp->flags &= ~B44_FLAG_RX_RING_HACK; 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->tx_ring) { 11459f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville if (bp->flags & B44_FLAG_TX_RING_HACK) { 114639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma, 114739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_TABLE_BYTES, DMA_TO_DEVICE); 11489f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville kfree(bp->tx_ring); 11499f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville } else 115039a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES, 115139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori bp->tx_ring, bp->tx_ring_dma); 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->tx_ring = NULL; 11539f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville bp->flags &= ~B44_FLAG_TX_RING_HACK; 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Must not be invoked with interrupt sources disabled and 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the hardware shutdown down. Can sleep. 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1161753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic int b44_alloc_consistent(struct b44 *bp, gfp_t gfp) 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int size; 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = B44_RX_RING_SIZE * sizeof(struct ring_info); 1166753f492093da7a40141bfe083073400f518f4c68Michael Buesch bp->rx_buffers = kzalloc(size, gfp); 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bp->rx_buffers) 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_err; 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = B44_TX_RING_SIZE * sizeof(struct ring_info); 1171753f492093da7a40141bfe083073400f518f4c68Michael Buesch bp->tx_buffers = kzalloc(size, gfp); 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bp->tx_buffers) 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_err; 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = DMA_TABLE_BYTES; 117639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, 117739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori &bp->rx_ring_dma, gfp); 11789f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville if (!bp->rx_ring) { 11799f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville /* Allocation may have failed due to pci_alloc_consistent 11809f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville insisting on use of GFP_DMA, which is more restrictive 11819f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville than necessary... */ 11829f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville struct dma_desc *rx_ring; 11839f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville dma_addr_t rx_ring_dma; 11849f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 1185753f492093da7a40141bfe083073400f518f4c68Michael Buesch rx_ring = kzalloc(size, gfp); 1186874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu if (!rx_ring) 11879f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville goto out_err; 11889f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 118939a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring, 119039a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_TABLE_BYTES, 119139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_BIDIRECTIONAL); 11929f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 119339a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori if (dma_mapping_error(bp->sdev->dma_dev, rx_ring_dma) || 119428b767967763835d8526f6baedc25a8a86052640Yang Hongyang rx_ring_dma + size > DMA_BIT_MASK(30)) { 11959f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville kfree(rx_ring); 11969f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville goto out_err; 11979f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville } 11989f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 11999f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville bp->rx_ring = rx_ring; 12009f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville bp->rx_ring_dma = rx_ring_dma; 12019f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville bp->flags |= B44_FLAG_RX_RING_HACK; 12029f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville } 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 120439a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, 120539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori &bp->tx_ring_dma, gfp); 12069f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville if (!bp->tx_ring) { 1207f225763a7d6c92c4932dbd528437997078496fccMichael Buesch /* Allocation may have failed due to ssb_dma_alloc_consistent 12089f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville insisting on use of GFP_DMA, which is more restrictive 12099f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville than necessary... */ 12109f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville struct dma_desc *tx_ring; 12119f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville dma_addr_t tx_ring_dma; 12129f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 1213753f492093da7a40141bfe083073400f518f4c68Michael Buesch tx_ring = kzalloc(size, gfp); 1214874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu if (!tx_ring) 12159f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville goto out_err; 12169f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 121739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring, 121839a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_TABLE_BYTES, 121939a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori DMA_TO_DEVICE); 12209f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 122139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori if (dma_mapping_error(bp->sdev->dma_dev, tx_ring_dma) || 122228b767967763835d8526f6baedc25a8a86052640Yang Hongyang tx_ring_dma + size > DMA_BIT_MASK(30)) { 12239f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville kfree(tx_ring); 12249f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville goto out_err; 12259f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville } 12269f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 12279f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville bp->tx_ring = tx_ring; 12289f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville bp->tx_ring_dma = tx_ring_dma; 12299f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville bp->flags |= B44_FLAG_TX_RING_HACK; 12309f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville } 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_err: 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_free_consistent(bp); 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* bp->lock is held. */ 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_clear_stats(struct b44 *bp) 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long reg; 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL) 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br32(bp, reg); 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL) 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br32(bp, reg); 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* bp->lock is held. */ 1252fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botónstatic void b44_chip_reset(struct b44 *bp, int reset_kind) 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1254753f492093da7a40141bfe083073400f518f4c68Michael Buesch struct ssb_device *sdev = bp->sdev; 1255f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch bool was_enabled; 1256753f492093da7a40141bfe083073400f518f4c68Michael Buesch 1257f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch was_enabled = ssb_device_is_enabled(bp->sdev); 1258f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch 1259f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch ssb_device_enable(bp->sdev, 0); 1260f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch ssb_pcicore_dev_irqvecs_enable(&sdev->bus->pcicore, sdev); 1261f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch 1262f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch if (was_enabled) { 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_RCV_LAZY, 0); 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE); 126540ee8c768cbb57aac7e55f7b54572afa8a9eac5aGary Zambrano b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1); 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_DMATX_CTRL, 0); 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->tx_prod = bp->tx_cons = 0; 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (br32(bp, B44_DMARX_STAT) & DMARX_STAT_EMASK) { 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_wait_bit(bp, B44_DMARX_STAT, DMARX_STAT_SIDLE, 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100, 0); 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_DMARX_CTRL, 0); 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->rx_prod = bp->rx_cons = 0; 1274f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch } 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_clear_stats(bp); 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1278fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón /* 1279fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón * Don't enable PHY if we are doing a partial reset 1280fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón * we are probably going to power down 1281fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón */ 1282fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón if (reset_kind == B44_CHIP_RESET_PARTIAL) 1283fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón return; 1284fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón 1285753f492093da7a40141bfe083073400f518f4c68Michael Buesch switch (sdev->bus->bustype) { 1286753f492093da7a40141bfe083073400f518f4c68Michael Buesch case SSB_BUSTYPE_SSB: 1287753f492093da7a40141bfe083073400f518f4c68Michael Buesch bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | 128839506a552b4b302540e1f9c6c93a122df353e57dJulia Lawall (DIV_ROUND_CLOSEST(ssb_clockspeed(sdev->bus), 128939506a552b4b302540e1f9c6c93a122df353e57dJulia Lawall B44_MDC_RATIO) 1290753f492093da7a40141bfe083073400f518f4c68Michael Buesch & MDIO_CTRL_MAXF_MASK))); 1291753f492093da7a40141bfe083073400f518f4c68Michael Buesch break; 1292753f492093da7a40141bfe083073400f518f4c68Michael Buesch case SSB_BUSTYPE_PCI: 1293753f492093da7a40141bfe083073400f518f4c68Michael Buesch bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | 1294753f492093da7a40141bfe083073400f518f4c68Michael Buesch (0x0d & MDIO_CTRL_MAXF_MASK))); 1295753f492093da7a40141bfe083073400f518f4c68Michael Buesch break; 129698a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch case SSB_BUSTYPE_PCMCIA: 129798a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch case SSB_BUSTYPE_SDIO: 129898a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch WARN_ON(1); /* A device with this bus does not exist. */ 129998a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch break; 1300753f492093da7a40141bfe083073400f518f4c68Michael Buesch } 1301753f492093da7a40141bfe083073400f518f4c68Michael Buesch 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br32(bp, B44_MDIO_CTRL); 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) { 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_ENET_CTRL, ENET_CTRL_EPSEL); 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br32(bp, B44_ENET_CTRL); 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags &= ~B44_FLAG_INTERNAL_PHY; 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val = br32(bp, B44_DEVCTRL); 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (val & DEVCTRL_EPR) { 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_DEVCTRL, (val & ~DEVCTRL_EPR)); 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br32(bp, B44_DEVCTRL); 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(100); 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags |= B44_FLAG_INTERNAL_PHY; 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* bp->lock is held. */ 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_halt(struct b44 *bp) 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_disable_ints(bp); 1324fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón /* reset PHY */ 1325fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón b44_phy_reset(bp); 1326fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón /* power down PHY */ 13272fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches netdev_info(bp->dev, "powering down PHY\n"); 1328fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón bw32(bp, B44_MAC_CTRL, MAC_CTRL_PHY_PDOWN); 1329fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón /* now reset the chip, but without enabling the MAC&PHY 1330fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón * part of it. This has to be done _after_ we shut down the PHY */ 1331fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL); 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* bp->lock is held. */ 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __b44_set_mac_addr(struct b44 *bp) 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_CAM_CTRL, 0); 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(bp->dev->flags & IFF_PROMISC)) { 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __b44_cam_write(bp, bp->dev->dev_addr, 0); 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = br32(bp, B44_CAM_CTRL); 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE); 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_set_mac_addr(struct net_device *dev, void *p) 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sockaddr *addr = p; 1351753f492093da7a40141bfe083073400f518f4c68Michael Buesch u32 val; 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (netif_running(dev)) 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1356391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano if (!is_valid_ether_addr(addr->sa_data)) 1357391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano return -EINVAL; 1358391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&bp->lock); 1362753f492093da7a40141bfe083073400f518f4c68Michael Buesch 1363753f492093da7a40141bfe083073400f518f4c68Michael Buesch val = br32(bp, B44_RXCONFIG); 1364753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (!(val & RXCONFIG_CAM_ABSENT)) 1365753f492093da7a40141bfe083073400f518f4c68Michael Buesch __b44_set_mac_addr(bp); 1366753f492093da7a40141bfe083073400f518f4c68Michael Buesch 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&bp->lock); 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Called at device open time to get the chip ready for 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * packet processing. Invoked with bp->lock held. 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __b44_set_rx_mode(struct net_device *); 13765fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chanstatic void b44_init_hw(struct b44 *bp, int reset_kind) 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1380fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón b44_chip_reset(bp, B44_CHIP_RESET_FULL); 13815fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan if (reset_kind == B44_FULL_RESET) { 138200e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano b44_phy_reset(bp); 138300e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano b44_setup_phy(bp); 138400e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano } 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable CRC32, set proper LED modes and power on PHY */ 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL); 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT)); 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This sets the MAC address too. */ 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __b44_set_rx_mode(bp->dev); 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* MTU + eth header + possible VLAN tag + struct rx_header */ 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_RXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_TX_WMARK, 56); /* XXX magic */ 13985fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan if (reset_kind == B44_PARTIAL_RESET) { 13995fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | 140072f4861ef9b1c1ca6e4abb49854698e80d3b684dStephen Hemminger (RX_PKT_OFFSET << DMARX_CTRL_ROSHIFT))); 14015fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan } else { 140200e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE); 140300e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset); 140400e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | 140572f4861ef9b1c1ca6e4abb49854698e80d3b684dStephen Hemminger (RX_PKT_OFFSET << DMARX_CTRL_ROSHIFT))); 140600e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset); 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 140800e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano bw32(bp, B44_DMARX_PTR, bp->rx_pending); 140900e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano bp->rx_prod = bp->rx_pending; 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 141100e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); 141200e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano } 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = br32(bp, B44_ENET_CTRL); 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE)); 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_open(struct net_device *dev) 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1423753f492093da7a40141bfe083073400f518f4c68Michael Buesch err = b44_alloc_consistent(bp, GFP_KERNEL); 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 14256c2f4267833f453156f8f439cc32eb4c92f357b4Francois Romieu goto out; 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1427bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger napi_enable(&bp->napi); 1428bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_init_rings(bp); 14305fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan b44_init_hw(bp, B44_FULL_RESET); 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1432e254e9bff5283aad1af6d74d2a312ee011b84d61John W. Linville b44_check_phy(bp); 1433e254e9bff5283aad1af6d74d2a312ee011b84d61John W. Linville 14341fb9df5d3069064c037c81c0ab8bf783ffa5e373Thomas Gleixner err = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev); 14356c2f4267833f453156f8f439cc32eb4c92f357b4Francois Romieu if (unlikely(err < 0)) { 1436bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger napi_disable(&bp->napi); 1437fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL); 14386c2f4267833f453156f8f439cc32eb4c92f357b4Francois Romieu b44_free_rings(bp); 14396c2f4267833f453156f8f439cc32eb4c92f357b4Francois Romieu b44_free_consistent(bp); 14406c2f4267833f453156f8f439cc32eb4c92f357b4Francois Romieu goto out; 14416c2f4267833f453156f8f439cc32eb4c92f357b4Francois Romieu } 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer(&bp->timer); 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->timer.expires = jiffies + HZ; 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->timer.data = (unsigned long) bp; 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->timer.function = b44_timer; 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_timer(&bp->timer); 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_enable_ints(bp); 1450d9e2d185bf01e20339158f77c3fca00b02014912Mark Lord netif_start_queue(dev); 14516c2f4267833f453156f8f439cc32eb4c92f357b4Francois Romieuout: 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_POLL_CONTROLLER 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Polling receive - used by netconsole and other diagnostic tools 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to allow network i/o with interrupts disabled. 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_poll_controller(struct net_device *dev) 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disable_irq(dev->irq); 14637d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells b44_interrupt(dev->irq, dev); 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_irq(dev->irq); 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1468725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambranostatic void bwfilter_table(struct b44 *bp, u8 *pp, u32 bytes, u32 table_offset) 1469725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano{ 1470725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano u32 i; 1471725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano u32 *pattern = (u32 *) pp; 1472725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1473725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano for (i = 0; i < bytes; i += sizeof(u32)) { 1474725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano bw32(bp, B44_FILT_ADDR, table_offset + i); 1475725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano bw32(bp, B44_FILT_DATA, pattern[i / sizeof(u32)]); 1476725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano } 1477725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano} 1478725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1479725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambranostatic int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset) 1480725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano{ 1481725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano int magicsync = 6; 1482725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano int k, j, len = offset; 1483725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano int ethaddr_bytes = ETH_ALEN; 1484725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1485725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano memset(ppattern + offset, 0xff, magicsync); 1486725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano for (j = 0; j < magicsync; j++) 1487725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano set_bit(len++, (unsigned long *) pmask); 1488725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1489725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano for (j = 0; j < B44_MAX_PATTERNS; j++) { 1490725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano if ((B44_PATTERN_SIZE - len) >= ETH_ALEN) 1491725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano ethaddr_bytes = ETH_ALEN; 1492725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano else 1493725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano ethaddr_bytes = B44_PATTERN_SIZE - len; 1494725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano if (ethaddr_bytes <=0) 1495725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano break; 1496725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano for (k = 0; k< ethaddr_bytes; k++) { 1497725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano ppattern[offset + magicsync + 1498725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano (j * ETH_ALEN) + k] = macaddr[k]; 1499e0188829cb724e7d12a2d4e343b368ff1d6e1471Stanislav Brabec set_bit(len++, (unsigned long *) pmask); 1500725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano } 1501725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano } 1502725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano return len - 1; 1503725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano} 1504725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1505725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano/* Setup magic packet patterns in the b44 WOL 1506725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano * pattern matching filter. 1507725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano */ 1508725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambranostatic void b44_setup_pseudo_magicp(struct b44 *bp) 1509725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano{ 1510725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1511725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano u32 val; 1512725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano int plen0, plen1, plen2; 1513725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano u8 *pwol_pattern; 1514725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano u8 pwol_mask[B44_PMASK_SIZE]; 1515725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1516dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau pwol_pattern = kzalloc(B44_PATTERN_SIZE, GFP_KERNEL); 1517725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano if (!pwol_pattern) { 15182fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches pr_err("Memory not available for WOL\n"); 1519725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano return; 1520725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano } 1521725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1522725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano /* Ipv4 magic packet pattern - pattern 0.*/ 1523725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano memset(pwol_mask, 0, B44_PMASK_SIZE); 1524725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask, 1525725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano B44_ETHIPV4UDP_HLEN); 1526725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1527725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, B44_PATTERN_BASE); 1528725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, B44_PMASK_BASE); 1529725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1530725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano /* Raw ethernet II magic packet pattern - pattern 1 */ 1531725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano memset(pwol_pattern, 0, B44_PATTERN_SIZE); 1532725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano memset(pwol_mask, 0, B44_PMASK_SIZE); 1533725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano plen1 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask, 1534725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano ETH_HLEN); 1535725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1536725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, 1537725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano B44_PATTERN_BASE + B44_PATTERN_SIZE); 1538725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, 1539725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano B44_PMASK_BASE + B44_PMASK_SIZE); 1540725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1541725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano /* Ipv6 magic packet pattern - pattern 2 */ 1542725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano memset(pwol_pattern, 0, B44_PATTERN_SIZE); 1543725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano memset(pwol_mask, 0, B44_PMASK_SIZE); 1544725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano plen2 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask, 1545725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano B44_ETHIPV6UDP_HLEN); 1546725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1547725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, 1548725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano B44_PATTERN_BASE + B44_PATTERN_SIZE + B44_PATTERN_SIZE); 1549725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, 1550725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano B44_PMASK_BASE + B44_PMASK_SIZE + B44_PMASK_SIZE); 1551725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1552725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano kfree(pwol_pattern); 1553725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1554725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano /* set these pattern's lengths: one less than each real length */ 1555725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano val = plen0 | (plen1 << 8) | (plen2 << 16) | WKUP_LEN_ENABLE_THREE; 1556725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano bw32(bp, B44_WKUP_LEN, val); 1557725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1558725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano /* enable wakeup pattern matching */ 1559725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano val = br32(bp, B44_DEVCTRL); 1560725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano bw32(bp, B44_DEVCTRL, val | DEVCTRL_PFE); 1561725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 1562725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano} 156352cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 1564753f492093da7a40141bfe083073400f518f4c68Michael Buesch#ifdef CONFIG_B44_PCI 1565753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic void b44_setup_wol_pci(struct b44 *bp) 1566753f492093da7a40141bfe083073400f518f4c68Michael Buesch{ 1567753f492093da7a40141bfe083073400f518f4c68Michael Buesch u16 val; 1568753f492093da7a40141bfe083073400f518f4c68Michael Buesch 1569753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (bp->sdev->bus->bustype != SSB_BUSTYPE_SSB) { 1570753f492093da7a40141bfe083073400f518f4c68Michael Buesch bw32(bp, SSB_TMSLOW, br32(bp, SSB_TMSLOW) | SSB_TMSLOW_PE); 1571753f492093da7a40141bfe083073400f518f4c68Michael Buesch pci_read_config_word(bp->sdev->bus->host_pci, SSB_PMCSR, &val); 1572753f492093da7a40141bfe083073400f518f4c68Michael Buesch pci_write_config_word(bp->sdev->bus->host_pci, SSB_PMCSR, val | SSB_PE); 1573753f492093da7a40141bfe083073400f518f4c68Michael Buesch } 1574753f492093da7a40141bfe083073400f518f4c68Michael Buesch} 1575753f492093da7a40141bfe083073400f518f4c68Michael Buesch#else 1576753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline void b44_setup_wol_pci(struct b44 *bp) { } 1577753f492093da7a40141bfe083073400f518f4c68Michael Buesch#endif /* CONFIG_B44_PCI */ 1578753f492093da7a40141bfe083073400f518f4c68Michael Buesch 157952cafd965507b7a7bb962486539f6d7422552692Gary Zambranostatic void b44_setup_wol(struct b44 *bp) 158052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano{ 158152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano u32 val; 158252cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 158352cafd965507b7a7bb962486539f6d7422552692Gary Zambrano bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI); 158452cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 158552cafd965507b7a7bb962486539f6d7422552692Gary Zambrano if (bp->flags & B44_FLAG_B0_ANDLATER) { 158652cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 158752cafd965507b7a7bb962486539f6d7422552692Gary Zambrano bw32(bp, B44_WKUP_LEN, WKUP_LEN_DISABLE); 158852cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 158952cafd965507b7a7bb962486539f6d7422552692Gary Zambrano val = bp->dev->dev_addr[2] << 24 | 159052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano bp->dev->dev_addr[3] << 16 | 159152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano bp->dev->dev_addr[4] << 8 | 159252cafd965507b7a7bb962486539f6d7422552692Gary Zambrano bp->dev->dev_addr[5]; 159352cafd965507b7a7bb962486539f6d7422552692Gary Zambrano bw32(bp, B44_ADDR_LO, val); 159452cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 159552cafd965507b7a7bb962486539f6d7422552692Gary Zambrano val = bp->dev->dev_addr[0] << 8 | 159652cafd965507b7a7bb962486539f6d7422552692Gary Zambrano bp->dev->dev_addr[1]; 159752cafd965507b7a7bb962486539f6d7422552692Gary Zambrano bw32(bp, B44_ADDR_HI, val); 159852cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 159952cafd965507b7a7bb962486539f6d7422552692Gary Zambrano val = br32(bp, B44_DEVCTRL); 160052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano bw32(bp, B44_DEVCTRL, val | DEVCTRL_MPM | DEVCTRL_PFE); 160152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 1602725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano } else { 1603725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano b44_setup_pseudo_magicp(bp); 1604725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano } 1605753f492093da7a40141bfe083073400f518f4c68Michael Buesch b44_setup_wol_pci(bp); 160652cafd965507b7a7bb962486539f6d7422552692Gary Zambrano} 160752cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_close(struct net_device *dev) 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1614bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger napi_disable(&bp->napi); 1615ba5eec9c55ec4be99d21a6ea614003b65d7f37d7Francois Romieu 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer_sync(&bp->timer); 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&bp->lock); 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_halt(bp); 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_free_rings(bp); 1622c35ca399e09828f3f6b40c0007a95a6582d90347Stephen Hemminger netif_carrier_off(dev); 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&bp->lock); 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq, dev); 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 162852cafd965507b7a7bb962486539f6d7422552692Gary Zambrano if (bp->flags & B44_FLAG_WOL_ENABLE) { 16295fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan b44_init_hw(bp, B44_PARTIAL_RESET); 163052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano b44_setup_wol(bp); 163152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano } 163252cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_free_consistent(bp); 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device_stats *b44_get_stats(struct net_device *dev) 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 1641553e2335625e6c96cb6d76c0d63cfc1034747614Eric Dumazet struct net_device_stats *nstat = &dev->stats; 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44_hw_stats *hwstat = &bp->hw_stats; 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Convert HW stats into netdevice stats. */ 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nstat->rx_packets = hwstat->rx_pkts; 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nstat->tx_packets = hwstat->tx_pkts; 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nstat->rx_bytes = hwstat->rx_octets; 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nstat->tx_bytes = hwstat->tx_octets; 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nstat->tx_errors = (hwstat->tx_jabber_pkts + 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hwstat->tx_oversize_pkts + 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hwstat->tx_underruns + 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hwstat->tx_excessive_cols + 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hwstat->tx_late_cols); 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nstat->multicast = hwstat->tx_multicast_pkts; 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nstat->collisions = hwstat->tx_total_cols; 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nstat->rx_length_errors = (hwstat->rx_oversize_pkts + 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hwstat->rx_undersize); 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nstat->rx_over_errors = hwstat->rx_missed_pkts; 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nstat->rx_frame_errors = hwstat->rx_align_errs; 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nstat->rx_crc_errors = hwstat->rx_crc_errs; 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nstat->rx_errors = (hwstat->rx_jabber_pkts + 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hwstat->rx_oversize_pkts + 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hwstat->rx_missed_pkts + 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hwstat->rx_crc_align_errs + 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hwstat->rx_undersize + 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hwstat->rx_crc_errs + 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hwstat->rx_align_errs + 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hwstat->rx_symbol_errs); 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nstat->tx_aborted_errors = hwstat->tx_underruns; 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Carrier lost counter seems to be broken for some devices */ 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nstat->tx_carrier_errors = hwstat->tx_carrier_lost; 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return nstat; 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __b44_load_mcast(struct b44 *bp, struct net_device *dev) 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 168222bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, num_ents; 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16854cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko num_ents = min_t(int, netdev_mc_count(dev), B44_MCAST_TABLE_SIZE); 16860ddf477b8a9b02412a6cabd51c486998811c7dd1Jiri Pirko i = 0; 168722bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko netdev_for_each_mc_addr(ha, dev) { 16880ddf477b8a9b02412a6cabd51c486998811c7dd1Jiri Pirko if (i == num_ents) 16890ddf477b8a9b02412a6cabd51c486998811c7dd1Jiri Pirko break; 169022bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko __b44_cam_write(bp, ha->addr, i++ + 1); 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i+1; 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __b44_set_rx_mode(struct net_device *dev) 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = br32(bp, B44_RXCONFIG); 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI); 1702753f492093da7a40141bfe083073400f518f4c68Michael Buesch if ((dev->flags & IFF_PROMISC) || (val & RXCONFIG_CAM_ABSENT)) { 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= RXCONFIG_PROMISC; 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_RXCONFIG, val); 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1706874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu unsigned char zero[6] = {0, 0, 0, 0, 0, 0}; 1707cda22aa94d3fe3942476b3652b8b92c653b96ee3Bill Helfinstine int i = 1; 1708874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __b44_set_mac_addr(bp); 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17112f614fe04f4463ff22234133319067d7361f54e5Jeff Garzik if ((dev->flags & IFF_ALLMULTI) || 17124cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko (netdev_mc_count(dev) > B44_MCAST_TABLE_SIZE)) 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= RXCONFIG_ALLMULTI; 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1715874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu i = __b44_load_mcast(bp, dev); 171610badc215493a435e2dbdc691386f2650a1778deJeff Garzik 17172f614fe04f4463ff22234133319067d7361f54e5Jeff Garzik for (; i < 64; i++) 171810badc215493a435e2dbdc691386f2650a1778deJeff Garzik __b44_cam_write(bp, zero, i); 17192f614fe04f4463ff22234133319067d7361f54e5Jeff Garzik 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_RXCONFIG, val); 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = br32(bp, B44_CAM_CTRL); 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE); 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_set_rx_mode(struct net_device *dev) 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&bp->lock); 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __b44_set_rx_mode(dev); 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&bp->lock); 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 b44_get_msglevel(struct net_device *dev) 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return bp->msg_enable; 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_set_msglevel(struct net_device *dev, u32 value) 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->msg_enable = value; 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 1750753f492093da7a40141bfe083073400f518f4c68Michael Buesch struct ssb_bus *bus = bp->sdev->bus; 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 175227e0955184a70c4bd4542ee2da18c749b4f43345roel kluin strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); 175327e0955184a70c4bd4542ee2da18c749b4f43345roel kluin strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version)); 1754753f492093da7a40141bfe083073400f518f4c68Michael Buesch switch (bus->bustype) { 1755753f492093da7a40141bfe083073400f518f4c68Michael Buesch case SSB_BUSTYPE_PCI: 175627e0955184a70c4bd4542ee2da18c749b4f43345roel kluin strlcpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info)); 1757753f492093da7a40141bfe083073400f518f4c68Michael Buesch break; 1758753f492093da7a40141bfe083073400f518f4c68Michael Buesch case SSB_BUSTYPE_SSB: 175927e0955184a70c4bd4542ee2da18c749b4f43345roel kluin strlcpy(info->bus_info, "SSB", sizeof(info->bus_info)); 1760753f492093da7a40141bfe083073400f518f4c68Michael Buesch break; 176198a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch case SSB_BUSTYPE_PCMCIA: 176298a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch case SSB_BUSTYPE_SDIO: 176398a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch WARN_ON(1); /* A device with this bus does not exist. */ 176498a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch break; 1765753f492093da7a40141bfe083073400f518f4c68Michael Buesch } 17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_nway_reset(struct net_device *dev) 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 bmcr; 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int r; 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&bp->lock); 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_readphy(bp, MII_BMCR, &bmcr); 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_readphy(bp, MII_BMCR, &bmcr); 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = -EINVAL; 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bmcr & BMCR_ANENABLE) { 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_writephy(bp, MII_BMCR, 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bmcr | BMCR_ANRESTART); 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = 0; 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&bp->lock); 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return r; 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->supported = (SUPPORTED_Autoneg); 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->supported |= (SUPPORTED_100baseT_Half | 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SUPPORTED_100baseT_Full | 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SUPPORTED_10baseT_Half | 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SUPPORTED_10baseT_Full | 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SUPPORTED_MII); 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->advertising = 0; 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_ADV_10HALF) 1801adf6e00064ebcd3d82009ba6ef66f489f0885ebdMatthew Wilcox cmd->advertising |= ADVERTISED_10baseT_Half; 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_ADV_10FULL) 1803adf6e00064ebcd3d82009ba6ef66f489f0885ebdMatthew Wilcox cmd->advertising |= ADVERTISED_10baseT_Full; 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_ADV_100HALF) 1805adf6e00064ebcd3d82009ba6ef66f489f0885ebdMatthew Wilcox cmd->advertising |= ADVERTISED_100baseT_Half; 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_ADV_100FULL) 1807adf6e00064ebcd3d82009ba6ef66f489f0885ebdMatthew Wilcox cmd->advertising |= ADVERTISED_100baseT_Full; 1808adf6e00064ebcd3d82009ba6ef66f489f0885ebdMatthew Wilcox cmd->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; 1809707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny ethtool_cmd_speed_set(cmd, ((bp->flags & B44_FLAG_100_BASE_T) ? 1810707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny SPEED_100 : SPEED_10)); 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ? 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DUPLEX_FULL : DUPLEX_HALF; 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->port = 0; 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->phy_address = bp->phy_addr; 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ? 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds XCVR_INTERNAL : XCVR_EXTERNAL; 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ? 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AUTONEG_DISABLE : AUTONEG_ENABLE; 181947b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano if (cmd->autoneg == AUTONEG_ENABLE) 182047b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano cmd->advertising |= ADVERTISED_Autoneg; 182147b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano if (!netif_running(dev)){ 1822707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny ethtool_cmd_speed_set(cmd, 0); 182347b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano cmd->duplex = 0xff; 182447b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano } 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->maxtxpkt = 0; 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->maxrxpkt = 0; 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 183325db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny u32 speed = ethtool_cmd_speed(cmd); 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We do not support gigabit. */ 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd->autoneg == AUTONEG_ENABLE) { 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd->advertising & 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ADVERTISED_1000baseT_Half | 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ADVERTISED_1000baseT_Full)) 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 184125db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny } else if ((speed != SPEED_100 && 184225db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny speed != SPEED_10) || 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cmd->duplex != DUPLEX_HALF && 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->duplex != DUPLEX_FULL)) { 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&bp->lock); 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd->autoneg == AUTONEG_ENABLE) { 185147b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano bp->flags &= ~(B44_FLAG_FORCE_LINK | 185247b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano B44_FLAG_100_BASE_T | 185347b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano B44_FLAG_FULL_DUPLEX | 185447b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano B44_FLAG_ADV_10HALF | 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds B44_FLAG_ADV_10FULL | 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds B44_FLAG_ADV_100HALF | 18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds B44_FLAG_ADV_100FULL); 185847b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano if (cmd->advertising == 0) { 185947b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano bp->flags |= (B44_FLAG_ADV_10HALF | 186047b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano B44_FLAG_ADV_10FULL | 186147b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano B44_FLAG_ADV_100HALF | 186247b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano B44_FLAG_ADV_100FULL); 186347b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano } else { 186447b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano if (cmd->advertising & ADVERTISED_10baseT_Half) 186547b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano bp->flags |= B44_FLAG_ADV_10HALF; 186647b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano if (cmd->advertising & ADVERTISED_10baseT_Full) 186747b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano bp->flags |= B44_FLAG_ADV_10FULL; 186847b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano if (cmd->advertising & ADVERTISED_100baseT_Half) 186947b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano bp->flags |= B44_FLAG_ADV_100HALF; 187047b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano if (cmd->advertising & ADVERTISED_100baseT_Full) 187147b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano bp->flags |= B44_FLAG_ADV_100FULL; 187247b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano } 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags |= B44_FLAG_FORCE_LINK; 187547b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano bp->flags &= ~(B44_FLAG_100_BASE_T | B44_FLAG_FULL_DUPLEX); 187625db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny if (speed == SPEED_100) 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags |= B44_FLAG_100_BASE_T; 18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd->duplex == DUPLEX_FULL) 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags |= B44_FLAG_FULL_DUPLEX; 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 188247b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano if (netif_running(dev)) 188347b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano b44_setup_phy(bp); 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&bp->lock); 18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_get_ringparam(struct net_device *dev, 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ethtool_ringparam *ering) 18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ering->rx_max_pending = B44_RX_RING_SIZE - 1; 18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ering->rx_pending = bp->rx_pending; 18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* XXX ethtool lacks a tx_max_pending, oops... */ 18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_set_ringparam(struct net_device *dev, 19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ethtool_ringparam *ering) 19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ering->rx_pending > B44_RX_RING_SIZE - 1) || 19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ering->rx_mini_pending != 0) || 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ering->rx_jumbo_pending != 0) || 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ering->tx_pending > B44_TX_RING_SIZE - 1)) 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&bp->lock); 19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->rx_pending = ering->rx_pending; 19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->tx_pending = ering->tx_pending; 19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_halt(bp); 19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_init_rings(bp); 19195fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan b44_init_hw(bp, B44_FULL_RESET); 19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(bp->dev); 19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&bp->lock); 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_enable_ints(bp); 192410badc215493a435e2dbdc691386f2650a1778deJeff Garzik 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_get_pauseparam(struct net_device *dev, 19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ethtool_pauseparam *epause) 19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds epause->autoneg = 19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (bp->flags & B44_FLAG_PAUSE_AUTO) != 0; 19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds epause->rx_pause = 19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (bp->flags & B44_FLAG_RX_PAUSE) != 0; 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds epause->tx_pause = 19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (bp->flags & B44_FLAG_TX_PAUSE) != 0; 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_set_pauseparam(struct net_device *dev, 19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ethtool_pauseparam *epause) 19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&bp->lock); 19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (epause->autoneg) 19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags |= B44_FLAG_PAUSE_AUTO; 19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags &= ~B44_FLAG_PAUSE_AUTO; 19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (epause->rx_pause) 19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags |= B44_FLAG_RX_PAUSE; 19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags &= ~B44_FLAG_RX_PAUSE; 19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (epause->tx_pause) 19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags |= B44_FLAG_TX_PAUSE; 19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags &= ~B44_FLAG_TX_PAUSE; 19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->flags & B44_FLAG_PAUSE_AUTO) { 19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_halt(bp); 19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_init_rings(bp); 19625fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan b44_init_hw(bp, B44_FULL_RESET); 19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __b44_set_flow_ctrl(bp, bp->flags); 19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&bp->lock); 19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_enable_ints(bp); 196910badc215493a435e2dbdc691386f2650a1778deJeff Garzik 19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19733353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieustatic void b44_get_strings(struct net_device *dev, u32 stringset, u8 *data) 19743353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu{ 19753353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu switch(stringset) { 19763353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu case ETH_SS_STATS: 19773353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu memcpy(data, *b44_gstrings, sizeof(b44_gstrings)); 19783353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu break; 19793353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu } 19803353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu} 19813353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu 1982b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzikstatic int b44_get_sset_count(struct net_device *dev, int sset) 19833353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu{ 1984b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik switch (sset) { 1985b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik case ETH_SS_STATS: 1986b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik return ARRAY_SIZE(b44_gstrings); 1987b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik default: 1988b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik return -EOPNOTSUPP; 1989b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik } 19903353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu} 19913353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu 19923353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieustatic void b44_get_ethtool_stats(struct net_device *dev, 19933353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu struct ethtool_stats *stats, u64 *data) 19943353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu{ 19953353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu struct b44 *bp = netdev_priv(dev); 19963353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu u32 *val = &bp->hw_stats.tx_good_octets; 19973353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu u32 i; 19983353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu 19993353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu spin_lock_irq(&bp->lock); 20003353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu 20013353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu b44_stats_update(bp); 20023353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu 20033353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu for (i = 0; i < ARRAY_SIZE(b44_gstrings); i++) 20043353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu *data++ = *val++; 20053353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu 20063353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu spin_unlock_irq(&bp->lock); 20073353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu} 20083353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu 200952cafd965507b7a7bb962486539f6d7422552692Gary Zambranostatic void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 201052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano{ 201152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano struct b44 *bp = netdev_priv(dev); 201252cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 201352cafd965507b7a7bb962486539f6d7422552692Gary Zambrano wol->supported = WAKE_MAGIC; 201452cafd965507b7a7bb962486539f6d7422552692Gary Zambrano if (bp->flags & B44_FLAG_WOL_ENABLE) 201552cafd965507b7a7bb962486539f6d7422552692Gary Zambrano wol->wolopts = WAKE_MAGIC; 201652cafd965507b7a7bb962486539f6d7422552692Gary Zambrano else 201752cafd965507b7a7bb962486539f6d7422552692Gary Zambrano wol->wolopts = 0; 201852cafd965507b7a7bb962486539f6d7422552692Gary Zambrano memset(&wol->sopass, 0, sizeof(wol->sopass)); 201952cafd965507b7a7bb962486539f6d7422552692Gary Zambrano} 202052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 202152cafd965507b7a7bb962486539f6d7422552692Gary Zambranostatic int b44_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 202252cafd965507b7a7bb962486539f6d7422552692Gary Zambrano{ 202352cafd965507b7a7bb962486539f6d7422552692Gary Zambrano struct b44 *bp = netdev_priv(dev); 202452cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 202552cafd965507b7a7bb962486539f6d7422552692Gary Zambrano spin_lock_irq(&bp->lock); 202652cafd965507b7a7bb962486539f6d7422552692Gary Zambrano if (wol->wolopts & WAKE_MAGIC) 202752cafd965507b7a7bb962486539f6d7422552692Gary Zambrano bp->flags |= B44_FLAG_WOL_ENABLE; 202852cafd965507b7a7bb962486539f6d7422552692Gary Zambrano else 202952cafd965507b7a7bb962486539f6d7422552692Gary Zambrano bp->flags &= ~B44_FLAG_WOL_ENABLE; 203052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano spin_unlock_irq(&bp->lock); 203152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 203252cafd965507b7a7bb962486539f6d7422552692Gary Zambrano return 0; 203352cafd965507b7a7bb962486539f6d7422552692Gary Zambrano} 203452cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 20357282d491ecaee9883233a0e27283c4c79486279aJeff Garzikstatic const struct ethtool_ops b44_ethtool_ops = { 20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_drvinfo = b44_get_drvinfo, 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_settings = b44_get_settings, 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_settings = b44_set_settings, 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .nway_reset = b44_nway_reset, 20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_link = ethtool_op_get_link, 204152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano .get_wol = b44_get_wol, 204252cafd965507b7a7bb962486539f6d7422552692Gary Zambrano .set_wol = b44_set_wol, 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_ringparam = b44_get_ringparam, 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_ringparam = b44_set_ringparam, 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_pauseparam = b44_get_pauseparam, 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_pauseparam = b44_set_pauseparam, 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_msglevel = b44_get_msglevel, 20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_msglevel = b44_set_msglevel, 20493353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu .get_strings = b44_get_strings, 2050b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik .get_sset_count = b44_get_sset_count, 20513353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu .get_ethtool_stats = b44_get_ethtool_stats, 20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mii_ioctl_data *data = if_mii(ifr); 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 20583410572d519b6c68505f746f25033de97809eaa1Francois Romieu int err = -EINVAL; 20593410572d519b6c68505f746f25033de97809eaa1Francois Romieu 20603410572d519b6c68505f746f25033de97809eaa1Francois Romieu if (!netif_running(dev)) 20613410572d519b6c68505f746f25033de97809eaa1Francois Romieu goto out; 20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&bp->lock); 20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL); 20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&bp->lock); 20663410572d519b6c68505f746f25033de97809eaa1Francois Romieuout: 20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit b44_get_invariants(struct b44 *bp) 20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2072753f492093da7a40141bfe083073400f518f4c68Michael Buesch struct ssb_device *sdev = bp->sdev; 2073753f492093da7a40141bfe083073400f518f4c68Michael Buesch int err = 0; 2074753f492093da7a40141bfe083073400f518f4c68Michael Buesch u8 *addr; 20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2076753f492093da7a40141bfe083073400f518f4c68Michael Buesch bp->dma_offset = ssb_dma_translation(sdev); 20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2078753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (sdev->bus->bustype == SSB_BUSTYPE_SSB && 2079753f492093da7a40141bfe083073400f518f4c68Michael Buesch instance > 1) { 2080458414b2e3d9dd7ee4510d18c119a7ccd3b43ec5Larry Finger addr = sdev->bus->sprom.et1mac; 2081458414b2e3d9dd7ee4510d18c119a7ccd3b43ec5Larry Finger bp->phy_addr = sdev->bus->sprom.et1phyaddr; 2082753f492093da7a40141bfe083073400f518f4c68Michael Buesch } else { 2083458414b2e3d9dd7ee4510d18c119a7ccd3b43ec5Larry Finger addr = sdev->bus->sprom.et0mac; 2084458414b2e3d9dd7ee4510d18c119a7ccd3b43ec5Larry Finger bp->phy_addr = sdev->bus->sprom.et0phyaddr; 2085753f492093da7a40141bfe083073400f518f4c68Michael Buesch } 20865ea79631c0c47d28831a0635e8af9da539d449cdMichael Buesch /* Some ROMs have buggy PHY addresses with the high 20875ea79631c0c47d28831a0635e8af9da539d449cdMichael Buesch * bits set (sign extension?). Truncate them to a 20885ea79631c0c47d28831a0635e8af9da539d449cdMichael Buesch * valid PHY address. */ 20895ea79631c0c47d28831a0635e8af9da539d449cdMichael Buesch bp->phy_addr &= 0x1F; 20905ea79631c0c47d28831a0635e8af9da539d449cdMichael Buesch 2091753f492093da7a40141bfe083073400f518f4c68Michael Buesch memcpy(bp->dev->dev_addr, addr, 6); 2092391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano 2093391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){ 20942fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches pr_err("Invalid MAC address found in EEPROM\n"); 2095391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano return -EINVAL; 2096391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano } 2097391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano 20982160de53cc17a40ad07bd38bf52dd0bb72dd5183John W. Linville memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len); 20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->imask = IMASK_DEF; 21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 210210badc215493a435e2dbdc691386f2650a1778deJeff Garzik /* XXX - really required? 21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags |= B44_FLAG_BUGGY_TXPTR; 2104753f492093da7a40141bfe083073400f518f4c68Michael Buesch */ 210552cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 2106753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (bp->sdev->id.revision >= 7) 2107753f492093da7a40141bfe083073400f518f4c68Michael Buesch bp->flags |= B44_FLAG_B0_ANDLATER; 210852cafd965507b7a7bb962486539f6d7422552692Gary Zambrano 21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2112403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemmingerstatic const struct net_device_ops b44_netdev_ops = { 2113403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger .ndo_open = b44_open, 2114403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger .ndo_stop = b44_close, 2115403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger .ndo_start_xmit = b44_start_xmit, 2116403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger .ndo_get_stats = b44_get_stats, 2117afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = b44_set_rx_mode, 2118403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger .ndo_set_mac_address = b44_set_mac_addr, 2119403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger .ndo_validate_addr = eth_validate_addr, 2120403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger .ndo_do_ioctl = b44_ioctl, 2121403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger .ndo_tx_timeout = b44_tx_timeout, 2122403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger .ndo_change_mtu = b44_change_mtu, 2123403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger#ifdef CONFIG_NET_POLL_CONTROLLER 2124403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger .ndo_poll_controller = b44_poll_controller, 2125403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger#endif 2126403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger}; 2127403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger 2128753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic int __devinit b44_init_one(struct ssb_device *sdev, 2129753f492093da7a40141bfe083073400f518f4c68Michael Buesch const struct ssb_device_id *ent) 21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp; 21330795af5729b18218767fab27c44b1384f72dc9adJoe Perches int err; 21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2135753f492093da7a40141bfe083073400f518f4c68Michael Buesch instance++; 2136753f492093da7a40141bfe083073400f518f4c68Michael Buesch 21377329f0d58de01878d9ce4f0be7a76e136f223eefJoe Perches pr_info_once("%s version %s\n", DRV_DESCRIPTION, DRV_MODULE_VERSION); 21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = alloc_etherdev(sizeof(*bp)); 21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) { 21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENOMEM; 2142753f492093da7a40141bfe083073400f518f4c68Michael Buesch goto out; 21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2145753f492093da7a40141bfe083073400f518f4c68Michael Buesch SET_NETDEV_DEV(dev, sdev->dev); 21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* No interesting netdevice features in this card... */ 21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->features |= 0; 21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp = netdev_priv(dev); 2151753f492093da7a40141bfe083073400f518f4c68Michael Buesch bp->sdev = sdev; 21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->dev = dev; 2153a58c891a53aca81c78f9cbe0572a301042470e96Eric Dumazet bp->force_copybreak = 0; 2154874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu 2155874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE); 21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&bp->lock); 21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->rx_pending = B44_DEF_RX_RING_PENDING; 21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->tx_pending = B44_DEF_TX_RING_PENDING; 21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2162403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger dev->netdev_ops = &b44_netdev_ops; 2163bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger netif_napi_add(dev, &bp->napi, b44_poll, 64); 21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->watchdog_timeo = B44_TX_TIMEOUT; 2165753f492093da7a40141bfe083073400f518f4c68Michael Buesch dev->irq = sdev->irq; 21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SET_ETHTOOL_OPS(dev, &b44_ethtool_ops); 21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2168753f492093da7a40141bfe083073400f518f4c68Michael Buesch err = ssb_bus_powerup(sdev->bus, 0); 2169753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (err) { 2170753f492093da7a40141bfe083073400f518f4c68Michael Buesch dev_err(sdev->dev, 2171753f492093da7a40141bfe083073400f518f4c68Michael Buesch "Failed to powerup the bus\n"); 2172753f492093da7a40141bfe083073400f518f4c68Michael Buesch goto err_out_free_dev; 2173753f492093da7a40141bfe083073400f518f4c68Michael Buesch } 217439a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori 217539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori if (dma_set_mask(sdev->dma_dev, DMA_BIT_MASK(30)) || 217639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori dma_set_coherent_mask(sdev->dma_dev, DMA_BIT_MASK(30))) { 2177753f492093da7a40141bfe083073400f518f4c68Michael Buesch dev_err(sdev->dev, 21782fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches "Required 30BIT DMA mask unsupported by the system\n"); 2179753f492093da7a40141bfe083073400f518f4c68Michael Buesch goto err_out_powerdown; 2180753f492093da7a40141bfe083073400f518f4c68Michael Buesch } 218139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori 21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = b44_get_invariants(bp); 21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 2184753f492093da7a40141bfe083073400f518f4c68Michael Buesch dev_err(sdev->dev, 21852fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches "Problem fetching invariants of chip, aborting\n"); 2186753f492093da7a40141bfe083073400f518f4c68Michael Buesch goto err_out_powerdown; 21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->mii_if.dev = dev; 21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->mii_if.mdio_read = b44_mii_read; 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->mii_if.mdio_write = b44_mii_write; 21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->mii_if.phy_id = bp->phy_addr; 21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->mii_if.phy_id_mask = 0x1f; 21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->mii_if.reg_num_mask = 0x1f; 21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* By default, advertise all speed/duplex settings. */ 21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags |= (B44_FLAG_ADV_10HALF | B44_FLAG_ADV_10FULL | 21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds B44_FLAG_ADV_100HALF | B44_FLAG_ADV_100FULL); 21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* By default, auto-negotiate PAUSE. */ 22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->flags |= B44_FLAG_PAUSE_AUTO; 22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = register_netdev(dev); 22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 22052fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches dev_err(sdev->dev, "Cannot register net device, aborting\n"); 2206753f492093da7a40141bfe083073400f518f4c68Michael Buesch goto err_out_powerdown; 22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2209bcf64aa379fcadd074449cbf0c049da70071b06fPaul Fertser netif_carrier_off(dev); 2210bcf64aa379fcadd074449cbf0c049da70071b06fPaul Fertser 2211753f492093da7a40141bfe083073400f518f4c68Michael Buesch ssb_set_drvdata(sdev, dev); 22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221310badc215493a435e2dbdc691386f2650a1778deJeff Garzik /* Chip reset provides power to the b44 MAC & PCI cores, which 22145c5131297db57b501f371ab53c40343eac6f2af7Gary Zambrano * is necessary for MAC register access. 221510badc215493a435e2dbdc691386f2650a1778deJeff Garzik */ 2216fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón b44_chip_reset(bp, B44_CHIP_RESET_FULL); 22175c5131297db57b501f371ab53c40343eac6f2af7Gary Zambrano 22188850dce170b460d9e46a827a62d6d7bb7e7cfcf3Hauke Mehrtens /* do a phy reset to test if there is an active phy */ 22198850dce170b460d9e46a827a62d6d7bb7e7cfcf3Hauke Mehrtens if (b44_phy_reset(bp) < 0) 22208850dce170b460d9e46a827a62d6d7bb7e7cfcf3Hauke Mehrtens bp->phy_addr = B44_PHY_ADDR_NO_PHY; 22218850dce170b460d9e46a827a62d6d7bb7e7cfcf3Hauke Mehrtens 22227329f0d58de01878d9ce4f0be7a76e136f223eefJoe Perches netdev_info(dev, "%s %pM\n", DRV_DESCRIPTION, dev->dev_addr); 22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2226753f492093da7a40141bfe083073400f518f4c68Michael Buescherr_out_powerdown: 2227753f492093da7a40141bfe083073400f518f4c68Michael Buesch ssb_bus_may_powerdown(sdev->bus); 22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out_free_dev: 22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2232753f492093da7a40141bfe083073400f518f4c68Michael Bueschout: 22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2236753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic void __devexit b44_remove_one(struct ssb_device *sdev) 22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2238753f492093da7a40141bfe083073400f518f4c68Michael Buesch struct net_device *dev = ssb_get_drvdata(sdev); 22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2240874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu unregister_netdev(dev); 2241e92aa634a33739478958f4109d6bd35b36d13532Michael Buesch ssb_device_disable(sdev, 0); 2242753f492093da7a40141bfe083073400f518f4c68Michael Buesch ssb_bus_may_powerdown(sdev->bus); 2243874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu free_netdev(dev); 2244fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón ssb_pcihost_set_power_state(sdev, PCI_D3hot); 2245753f492093da7a40141bfe083073400f518f4c68Michael Buesch ssb_set_drvdata(sdev, NULL); 22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2248753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic int b44_suspend(struct ssb_device *sdev, pm_message_t state) 22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2250753f492093da7a40141bfe083073400f518f4c68Michael Buesch struct net_device *dev = ssb_get_drvdata(sdev); 22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2253753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (!netif_running(dev)) 2254753f492093da7a40141bfe083073400f518f4c68Michael Buesch return 0; 22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer_sync(&bp->timer); 22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 225810badc215493a435e2dbdc691386f2650a1778deJeff Garzik spin_lock_irq(&bp->lock); 22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_halt(bp); 226110badc215493a435e2dbdc691386f2650a1778deJeff Garzik netif_carrier_off(bp->dev); 22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_device_detach(bp->dev); 22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_free_rings(bp); 22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&bp->lock); 226646e178535836dcd7ef92f179218628d101892c59Pavel Machek 226746e178535836dcd7ef92f179218628d101892c59Pavel Machek free_irq(dev->irq, dev); 226852cafd965507b7a7bb962486539f6d7422552692Gary Zambrano if (bp->flags & B44_FLAG_WOL_ENABLE) { 22695fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan b44_init_hw(bp, B44_PARTIAL_RESET); 227052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano b44_setup_wol(bp); 227152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano } 2272753f492093da7a40141bfe083073400f518f4c68Michael Buesch 2273fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón ssb_pcihost_set_power_state(sdev, PCI_D3hot); 22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2277753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic int b44_resume(struct ssb_device *sdev) 22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2279753f492093da7a40141bfe083073400f518f4c68Michael Buesch struct net_device *dev = ssb_get_drvdata(sdev); 22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct b44 *bp = netdev_priv(dev); 228190afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov int rc = 0; 22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2283753f492093da7a40141bfe083073400f518f4c68Michael Buesch rc = ssb_bus_powerup(sdev->bus, 0); 228490afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov if (rc) { 2285753f492093da7a40141bfe083073400f518f4c68Michael Buesch dev_err(sdev->dev, 2286753f492093da7a40141bfe083073400f518f4c68Michael Buesch "Failed to powerup the bus\n"); 228790afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov return rc; 228890afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov } 228990afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!netif_running(dev)) 22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2293afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan spin_lock_irq(&bp->lock); 2294afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan b44_init_rings(bp); 2295afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan b44_init_hw(bp, B44_FULL_RESET); 2296afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan spin_unlock_irq(&bp->lock); 2297afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan 2298afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan /* 2299afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan * As a shared interrupt, the handler can be called immediately. To be 2300afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan * able to check the interrupt status the hardware must already be 2301afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan * powered back on (b44_init_hw). 2302afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan */ 230390afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev); 230490afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov if (rc) { 23052fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches netdev_err(dev, "request_irq failed\n"); 2306afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan spin_lock_irq(&bp->lock); 2307afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan b44_halt(bp); 2308afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan b44_free_rings(bp); 2309afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan spin_unlock_irq(&bp->lock); 231090afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov return rc; 231190afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov } 231246e178535836dcd7ef92f179218628d101892c59Pavel Machek 23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_device_attach(bp->dev); 23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b44_enable_ints(bp); 2316d9e2d185bf01e20339158f77c3fca00b02014912Mark Lord netif_wake_queue(dev); 2317a72a8179734393ca351f6ecf8cad6841ab7e1470Stephen Hemminger 2318a72a8179734393ca351f6ecf8cad6841ab7e1470Stephen Hemminger mod_timer(&bp->timer, jiffies + 1); 2319a72a8179734393ca351f6ecf8cad6841ab7e1470Stephen Hemminger 23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2323753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic struct ssb_driver b44_ssb_driver = { 23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = DRV_MODULE_NAME, 2325753f492093da7a40141bfe083073400f518f4c68Michael Buesch .id_table = b44_ssb_tbl, 23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = b44_init_one, 23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = __devexit_p(b44_remove_one), 2328753f492093da7a40141bfe083073400f518f4c68Michael Buesch .suspend = b44_suspend, 2329753f492093da7a40141bfe083073400f518f4c68Michael Buesch .resume = b44_resume, 23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2332cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtensstatic inline int __init b44_pci_init(void) 2333753f492093da7a40141bfe083073400f518f4c68Michael Buesch{ 2334753f492093da7a40141bfe083073400f518f4c68Michael Buesch int err = 0; 2335753f492093da7a40141bfe083073400f518f4c68Michael Buesch#ifdef CONFIG_B44_PCI 2336753f492093da7a40141bfe083073400f518f4c68Michael Buesch err = ssb_pcihost_register(&b44_pci_driver); 2337753f492093da7a40141bfe083073400f518f4c68Michael Buesch#endif 2338753f492093da7a40141bfe083073400f518f4c68Michael Buesch return err; 2339753f492093da7a40141bfe083073400f518f4c68Michael Buesch} 2340753f492093da7a40141bfe083073400f518f4c68Michael Buesch 234164f0a836f600e9c31ffd511713ab5d328aa96ac8Nikola Pajkovskystatic inline void b44_pci_exit(void) 2342753f492093da7a40141bfe083073400f518f4c68Michael Buesch{ 2343753f492093da7a40141bfe083073400f518f4c68Michael Buesch#ifdef CONFIG_B44_PCI 2344753f492093da7a40141bfe083073400f518f4c68Michael Buesch ssb_pcihost_unregister(&b44_pci_driver); 2345753f492093da7a40141bfe083073400f518f4c68Michael Buesch#endif 2346753f492093da7a40141bfe083073400f518f4c68Michael Buesch} 2347753f492093da7a40141bfe083073400f518f4c68Michael Buesch 23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init b44_init(void) 23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23509f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville unsigned int dma_desc_align_size = dma_get_cache_alignment(); 2351753f492093da7a40141bfe083073400f518f4c68Michael Buesch int err; 23529f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 23539f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville /* Setup paramaters for syncing RX/TX DMA descriptors */ 235422d4d77183f0af8b3b643544a5ae64ec6105d88bAlan Cox dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc)); 23559f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville 2356753f492093da7a40141bfe083073400f518f4c68Michael Buesch err = b44_pci_init(); 2357753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (err) 2358753f492093da7a40141bfe083073400f518f4c68Michael Buesch return err; 2359753f492093da7a40141bfe083073400f518f4c68Michael Buesch err = ssb_driver_register(&b44_ssb_driver); 2360753f492093da7a40141bfe083073400f518f4c68Michael Buesch if (err) 2361753f492093da7a40141bfe083073400f518f4c68Michael Buesch b44_pci_exit(); 2362753f492093da7a40141bfe083073400f518f4c68Michael Buesch return err; 23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit b44_cleanup(void) 23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2367753f492093da7a40141bfe083073400f518f4c68Michael Buesch ssb_driver_unregister(&b44_ssb_driver); 2368753f492093da7a40141bfe083073400f518f4c68Michael Buesch b44_pci_exit(); 23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(b44_init); 23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(b44_cleanup); 23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2374