Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6

* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6: (37 commits)
  forcedeth bug fix: realtek phy
  forcedeth bug fix: vitesse phy
  forcedeth bug fix: cicada phy
  atl1: reorder atl1_main functions
  atl1: fix excessively indented code
  atl1: cleanup atl1_main
  atl1: header file cleanup
  atl1: remove irq_sem
  cdc-subset to support new vendor/product ID
  8139cp: implement the missing dev->tx_timeout
  myri10ge: Remove nonsensical limit in the tx done routine
  gianfar: kill unused header
  EP93XX_ETH must select MII
  macb: Add multicast capability
  macb: Use generic PHY layer
  s390: add barriers to qeth driver
  s390: scatter-gather for inbound traffic in qeth driver
  eHEA: Introducing support vor DLPAR memory add
  Fix a potential NULL pointer dereference in free_shared_mem() in drivers/net/s2io.c
  [PATCH] softmac: Fix ESSID problem
  ...
This commit is contained in:
Linus Torvalds 2007-07-16 17:48:54 -07:00
commit 1f1c2881f6
44 changed files with 2470 additions and 1870 deletions

View file

@ -26,7 +26,6 @@
TODO: TODO:
* Test Tx checksumming thoroughly * Test Tx checksumming thoroughly
* Implement dev->tx_timeout
Low priority TODO: Low priority TODO:
* Complete reset on PciErr * Complete reset on PciErr
@ -1218,6 +1217,30 @@ static int cp_close (struct net_device *dev)
return 0; return 0;
} }
static void cp_tx_timeout(struct net_device *dev)
{
struct cp_private *cp = netdev_priv(dev);
unsigned long flags;
int rc;
printk(KERN_WARNING "%s: Transmit timeout, status %2x %4x %4x %4x\n",
dev->name, cpr8(Cmd), cpr16(CpCmd),
cpr16(IntrStatus), cpr16(IntrMask));
spin_lock_irqsave(&cp->lock, flags);
cp_stop_hw(cp);
cp_clean_rings(cp);
rc = cp_init_rings(cp);
cp_start_hw(cp);
netif_wake_queue(dev);
spin_unlock_irqrestore(&cp->lock, flags);
return;
}
#ifdef BROKEN #ifdef BROKEN
static int cp_change_mtu(struct net_device *dev, int new_mtu) static int cp_change_mtu(struct net_device *dev, int new_mtu)
{ {
@ -1920,10 +1943,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
dev->change_mtu = cp_change_mtu; dev->change_mtu = cp_change_mtu;
#endif #endif
dev->ethtool_ops = &cp_ethtool_ops; dev->ethtool_ops = &cp_ethtool_ops;
#if 0
dev->tx_timeout = cp_tx_timeout; dev->tx_timeout = cp_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT; dev->watchdog_timeo = TX_TIMEOUT;
#endif
#if CP_VLAN_TAG_USED #if CP_VLAN_TAG_USED
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;

View file

@ -205,7 +205,7 @@ config MII
config MACB config MACB
tristate "Atmel MACB support" tristate "Atmel MACB support"
depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263
select MII select PHYLIB
help help
The Atmel MACB ethernet interface is found on many AT32 and AT91 The Atmel MACB ethernet interface is found on many AT32 and AT91
parts. Say Y to include support for the MACB chip. parts. Say Y to include support for the MACB chip.

View file

@ -43,6 +43,7 @@ config ARM_AT91_ETHER
config EP93XX_ETH config EP93XX_ETH
tristate "EP93xx Ethernet support" tristate "EP93xx Ethernet support"
depends on ARM && ARCH_EP93XX depends on ARM && ARCH_EP93XX
select MII
help help
This is a driver for the ethernet hardware included in EP93xx CPUs. This is a driver for the ethernet hardware included in EP93xx CPUs.
Say Y if you are building a kernel for EP93xx based devices. Say Y if you are building a kernel for EP93xx based devices.

View file

@ -43,6 +43,7 @@ extern const struct ethtool_ops atl1_ethtool_ops;
struct atl1_adapter; struct atl1_adapter;
#define ATL1_MAX_INTR 3 #define ATL1_MAX_INTR 3
#define ATL1_MAX_TX_BUF_LEN 0x3000 /* 12288 bytes */
#define ATL1_DEFAULT_TPD 256 #define ATL1_DEFAULT_TPD 256
#define ATL1_MAX_TPD 1024 #define ATL1_MAX_TPD 1024
@ -57,29 +58,45 @@ struct atl1_adapter;
#define ATL1_RRD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_return_desc) #define ATL1_RRD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_return_desc)
/* /*
* This detached comment is preserved for documentation purposes only.
* It was originally attached to some code that got deleted, but seems
* important enough to keep around...
*
* <begin detached comment>
* Some workarounds require millisecond delays and are run during interrupt * Some workarounds require millisecond delays and are run during interrupt
* context. Most notably, when establishing link, the phy may need tweaking * context. Most notably, when establishing link, the phy may need tweaking
* but cannot process phy register reads/writes faster than millisecond * but cannot process phy register reads/writes faster than millisecond
* intervals...and we establish link due to a "link status change" interrupt. * intervals...and we establish link due to a "link status change" interrupt.
* <end detached comment>
*/ */
/* /*
* wrapper around a pointer to a socket buffer, * atl1_ring_header represents a single, contiguous block of DMA space
* so a DMA handle can be stored along with the buffer * mapped for the three descriptor rings (tpd, rfd, rrd) and the two
* message blocks (cmb, smb) described below
*/
struct atl1_ring_header {
void *desc; /* virtual address */
dma_addr_t dma; /* physical address*/
unsigned int size; /* length in bytes */
};
/*
* atl1_buffer is wrapper around a pointer to a socket buffer
* so a DMA handle can be stored along with the skb
*/ */
struct atl1_buffer { struct atl1_buffer {
struct sk_buff *skb; struct sk_buff *skb; /* socket buffer */
u16 length; u16 length; /* rx buffer length */
u16 alloced; u16 alloced; /* 1 if skb allocated */
dma_addr_t dma; dma_addr_t dma;
}; };
#define MAX_TX_BUF_LEN 0x3000 /* 12KB */ /* transmit packet descriptor (tpd) ring */
struct atl1_tpd_ring { struct atl1_tpd_ring {
void *desc; /* pointer to the descriptor ring memory */ void *desc; /* descriptor ring virtual address */
dma_addr_t dma; /* physical adress of the descriptor ring */ dma_addr_t dma; /* descriptor ring physical address */
u16 size; /* length of descriptor ring in bytes */ u16 size; /* descriptor ring length in bytes */
u16 count; /* number of descriptors in the ring */ u16 count; /* number of descriptors in the ring */
u16 hw_idx; /* hardware index */ u16 hw_idx; /* hardware index */
atomic_t next_to_clean; atomic_t next_to_clean;
@ -87,36 +104,34 @@ struct atl1_tpd_ring {
struct atl1_buffer *buffer_info; struct atl1_buffer *buffer_info;
}; };
/* receive free descriptor (rfd) ring */
struct atl1_rfd_ring { struct atl1_rfd_ring {
void *desc; void *desc; /* descriptor ring virtual address */
dma_addr_t dma; dma_addr_t dma; /* descriptor ring physical address */
u16 size; u16 size; /* descriptor ring length in bytes */
u16 count; u16 count; /* number of descriptors in the ring */
atomic_t next_to_use; atomic_t next_to_use;
u16 next_to_clean; u16 next_to_clean;
struct atl1_buffer *buffer_info; struct atl1_buffer *buffer_info;
}; };
/* receive return descriptor (rrd) ring */
struct atl1_rrd_ring { struct atl1_rrd_ring {
void *desc; void *desc; /* descriptor ring virtual address */
dma_addr_t dma; dma_addr_t dma; /* descriptor ring physical address */
unsigned int size; unsigned int size; /* descriptor ring length in bytes */
u16 count; u16 count; /* number of descriptors in the ring */
u16 next_to_use; u16 next_to_use;
atomic_t next_to_clean; atomic_t next_to_clean;
}; };
struct atl1_ring_header { /* coalescing message block (cmb) */
void *desc; /* pointer to the descriptor ring memory */
dma_addr_t dma; /* physical adress of the descriptor ring */
unsigned int size; /* length of descriptor ring in bytes */
};
struct atl1_cmb { struct atl1_cmb {
struct coals_msg_block *cmb; struct coals_msg_block *cmb;
dma_addr_t dma; dma_addr_t dma;
}; };
/* statistics message block (smb) */
struct atl1_smb { struct atl1_smb {
struct stats_msg_block *smb; struct stats_msg_block *smb;
dma_addr_t dma; dma_addr_t dma;
@ -141,24 +156,26 @@ struct atl1_sft_stats {
u64 tx_aborted_errors; u64 tx_aborted_errors;
u64 tx_window_errors; u64 tx_window_errors;
u64 tx_carrier_errors; u64 tx_carrier_errors;
u64 tx_pause; /* num pause packets transmitted. */
u64 tx_pause; /* num Pause packet transmitted. */ u64 excecol; /* num tx packets w/ excessive collisions. */
u64 excecol; /* num tx packets aborted due to excessive collisions. */ u64 deffer; /* num tx packets deferred */
u64 deffer; /* num deferred tx packets */ u64 scc; /* num packets subsequently transmitted
u64 scc; /* num packets subsequently transmitted successfully w/ single prior collision. */ * successfully w/ single prior collision. */
u64 mcc; /* num packets subsequently transmitted successfully w/ multiple prior collisions. */ u64 mcc; /* num packets subsequently transmitted
* successfully w/ multiple prior collisions. */
u64 latecol; /* num tx packets w/ late collisions. */ u64 latecol; /* num tx packets w/ late collisions. */
u64 tx_underun; /* num tx packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */ u64 tx_underun; /* num tx packets aborted due to transmit
u64 tx_trunc; /* num tx packets truncated due to size exceeding MTU, regardless whether truncated by Selene or not. (The name doesn't really reflect the meaning in this case.) */ * FIFO underrun, or TRD FIFO underrun */
u64 tx_trunc; /* num tx packets truncated due to size
* exceeding MTU, regardless whether truncated
* by the chip or not. (The name doesn't really
* reflect the meaning in this case.) */
u64 rx_pause; /* num Pause packets received. */ u64 rx_pause; /* num Pause packets received. */
u64 rx_rrd_ov; u64 rx_rrd_ov;
u64 rx_trunc; u64 rx_trunc;
}; };
/* board specific private data structure */ /* hardware structure */
#define ATL1_REGS_LEN 8
/* Structure containing variables used by the shared code */
struct atl1_hw { struct atl1_hw {
u8 __iomem *hw_addr; u8 __iomem *hw_addr;
struct atl1_adapter *back; struct atl1_adapter *back;
@ -167,24 +184,35 @@ struct atl1_hw {
enum atl1_dma_req_block dmar_block; enum atl1_dma_req_block dmar_block;
enum atl1_dma_req_block dmaw_block; enum atl1_dma_req_block dmaw_block;
u8 preamble_len; u8 preamble_len;
u8 max_retry; /* Retransmission maximum, after which the packet will be discarded */ u8 max_retry; /* Retransmission maximum, after which the
u8 jam_ipg; /* IPG to start JAM for collision based flow control in half-duplex mode. In units of 8-bit time */ * packet will be discarded */
u8 ipgt; /* Desired back to back inter-packet gap. The default is 96-bit time */ u8 jam_ipg; /* IPG to start JAM for collision based flow
u8 min_ifg; /* Minimum number of IFG to enforce in between RX frames. Frame gap below such IFP is dropped */ * control in half-duplex mode. In units of
* 8-bit time */
u8 ipgt; /* Desired back to back inter-packet gap.
* The default is 96-bit time */
u8 min_ifg; /* Minimum number of IFG to enforce in between
* receive frames. Frame gap below such IFP
* is dropped */
u8 ipgr1; /* 64bit Carrier-Sense window */ u8 ipgr1; /* 64bit Carrier-Sense window */
u8 ipgr2; /* 96-bit IPG window */ u8 ipgr2; /* 96-bit IPG window */
u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned burst. Each TPD is 16 bytes long */ u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned
u8 rfd_burst; /* Number of RFD to prefetch in cache-aligned burst. Each RFD is 12 bytes long */ * burst. Each TPD is 16 bytes long */
u8 rfd_burst; /* Number of RFD to prefetch in cache-aligned
* burst. Each RFD is 12 bytes long */
u8 rfd_fetch_gap; u8 rfd_fetch_gap;
u8 rrd_burst; /* Threshold number of RRDs that can be retired in a burst. Each RRD is 16 bytes long */ u8 rrd_burst; /* Threshold number of RRDs that can be retired
* in a burst. Each RRD is 16 bytes long */
u8 tpd_fetch_th; u8 tpd_fetch_th;
u8 tpd_fetch_gap; u8 tpd_fetch_gap;
u16 tx_jumbo_task_th; u16 tx_jumbo_task_th;
u16 txf_burst; /* Number of data bytes to read in a cache-aligned burst. Each SRAM entry is u16 txf_burst; /* Number of data bytes to read in a cache-
8 bytes long */ * aligned burst. Each SRAM entry is 8 bytes */
u16 rx_jumbo_th; /* Jumbo packet size for non-VLAN packet. VLAN packets should add 4 bytes */ u16 rx_jumbo_th; /* Jumbo packet size for non-VLAN packet. VLAN
* packets should add 4 bytes */
u16 rx_jumbo_lkah; u16 rx_jumbo_lkah;
u16 rrd_ret_timer; /* RRD retirement timer. Decrement by 1 after every 512ns passes. */ u16 rrd_ret_timer; /* RRD retirement timer. Decrement by 1 after
* every 512ns passes. */
u16 lcol; /* Collision Window */ u16 lcol; /* Collision Window */
u16 cmb_tpd; u16 cmb_tpd;
@ -194,48 +222,35 @@ struct atl1_hw {
u32 smb_timer; u32 smb_timer;
u16 media_type; u16 media_type;
u16 autoneg_advertised; u16 autoneg_advertised;
u16 pci_cmd_word;
u16 mii_autoneg_adv_reg; u16 mii_autoneg_adv_reg;
u16 mii_1000t_ctrl_reg; u16 mii_1000t_ctrl_reg;
u32 mem_rang;
u32 txcw;
u32 max_frame_size; u32 max_frame_size;
u32 min_frame_size; u32 min_frame_size;
u32 mc_filter_type;
u32 num_mc_addrs;
u32 collision_delta;
u32 tx_packet_delta;
u16 phy_spd_default;
u16 dev_rev; u16 dev_rev;
/* spi flash */ /* spi flash */
u8 flash_vendor; u8 flash_vendor;
u8 dma_fairness;
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
u8 perm_mac_addr[ETH_ALEN]; u8 perm_mac_addr[ETH_ALEN];
/* bool phy_preamble_sup; */
bool phy_configured; bool phy_configured;
}; };
struct atl1_adapter { struct atl1_adapter {
/* OS defined structs */
struct net_device *netdev; struct net_device *netdev;
struct pci_dev *pdev; struct pci_dev *pdev;
struct net_device_stats net_stats; struct net_device_stats net_stats;
struct atl1_sft_stats soft_stats; struct atl1_sft_stats soft_stats;
struct vlan_group *vlgrp; struct vlan_group *vlgrp;
u32 rx_buffer_len; u32 rx_buffer_len;
u32 wol; u32 wol;
u16 link_speed; u16 link_speed;
u16 link_duplex; u16 link_duplex;
spinlock_t lock; spinlock_t lock;
atomic_t irq_sem;
struct work_struct tx_timeout_task; struct work_struct tx_timeout_task;
struct work_struct link_chg_task; struct work_struct link_chg_task;
struct work_struct pcie_dma_to_rst_task; struct work_struct pcie_dma_to_rst_task;
@ -243,9 +258,7 @@ struct atl1_adapter {
struct timer_list phy_config_timer; struct timer_list phy_config_timer;
bool phy_timer_pending; bool phy_timer_pending;
bool mac_disabled; /* all descriptor rings' memory */
/* All descriptor rings' memory */
struct atl1_ring_header ring_header; struct atl1_ring_header ring_header;
/* TX */ /* TX */
@ -258,25 +271,16 @@ struct atl1_adapter {
u64 hw_csum_err; u64 hw_csum_err;
u64 hw_csum_good; u64 hw_csum_good;
u32 gorcl; u16 imt; /* interrupt moderator timer (2us resolution */
u64 gorcl_old; u16 ict; /* interrupt clear timer (2us resolution */
struct mii_if_info mii; /* MII interface info */
/* Interrupt Moderator timer ( 2us resolution) */
u16 imt;
/* Interrupt Clear timer (2us resolution) */
u16 ict;
/* MII interface info */
struct mii_if_info mii;
/* structs defined in atl1_hw.h */ /* structs defined in atl1_hw.h */
u32 bd_number; /* board number */ u32 bd_number; /* board number */
bool pci_using_64; bool pci_using_64;
struct atl1_hw hw; struct atl1_hw hw;
struct atl1_smb smb; struct atl1_smb smb;
struct atl1_cmb cmb; struct atl1_cmb cmb;
u32 pci_state[16];
}; };
#endif /* _ATL1_H_ */ #endif /* _ATL1_H_ */

File diff suppressed because it is too large Load diff

View file

@ -39,13 +39,13 @@
#include <asm/io.h> #include <asm/io.h>
#define DRV_NAME "ehea" #define DRV_NAME "ehea"
#define DRV_VERSION "EHEA_0067" #define DRV_VERSION "EHEA_0070"
/* EHEA capability flags */ /* eHEA capability flags */
#define DLPAR_PORT_ADD_REM 1 #define DLPAR_PORT_ADD_REM 1
#define DLPAR_MEM_ADD 2 #define DLPAR_MEM_ADD 2
#define DLPAR_MEM_REM 4 #define DLPAR_MEM_REM 4
#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM) #define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM)
#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
@ -113,6 +113,8 @@
/* Memory Regions */ /* Memory Regions */
#define EHEA_MR_ACC_CTRL 0x00800000 #define EHEA_MR_ACC_CTRL 0x00800000
#define EHEA_BUSMAP_START 0x8000000000000000ULL
#define EHEA_WATCH_DOG_TIMEOUT 10*HZ #define EHEA_WATCH_DOG_TIMEOUT 10*HZ
/* utility functions */ /* utility functions */
@ -186,6 +188,12 @@ struct h_epas {
set to 0 if unused */ set to 0 if unused */
}; };
struct ehea_busmap {
unsigned int entries; /* total number of entries */
unsigned int valid_sections; /* number of valid sections */
u64 *vaddr;
};
struct ehea_qp; struct ehea_qp;
struct ehea_cq; struct ehea_cq;
struct ehea_eq; struct ehea_eq;
@ -382,6 +390,8 @@ struct ehea_adapter {
struct ehea_mr mr; struct ehea_mr mr;
u32 pd; /* protection domain */ u32 pd; /* protection domain */
u64 max_mc_mac; /* max number of multicast mac addresses */ u64 max_mc_mac; /* max number of multicast mac addresses */
int active_ports;
struct list_head list;
}; };
@ -431,6 +441,9 @@ struct port_res_cfg {
int max_entries_rq3; int max_entries_rq3;
}; };
enum ehea_flag_bits {
__EHEA_STOP_XFER
};
void ehea_set_ethtool_ops(struct net_device *netdev); void ehea_set_ethtool_ops(struct net_device *netdev);
int ehea_sense_port_attr(struct ehea_port *port); int ehea_sense_port_attr(struct ehea_port *port);

View file

@ -79,6 +79,11 @@ MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue "
MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 "); MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 ");
static int port_name_cnt = 0; static int port_name_cnt = 0;
static LIST_HEAD(adapter_list);
u64 ehea_driver_flags = 0;
struct workqueue_struct *ehea_driver_wq;
struct work_struct ehea_rereg_mr_task;
static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
const struct of_device_id *id); const struct of_device_id *id);
@ -238,13 +243,17 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type) rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type)
| EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index); | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
rwqe->sg_list[0].l_key = pr->recv_mr.lkey; rwqe->sg_list[0].l_key = pr->recv_mr.lkey;
rwqe->sg_list[0].vaddr = (u64)skb->data; rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data);
rwqe->sg_list[0].len = packet_size; rwqe->sg_list[0].len = packet_size;
rwqe->data_segments = 1; rwqe->data_segments = 1;
index++; index++;
index &= max_index_mask; index &= max_index_mask;
if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)))
goto out;
} }
q_skba->index = index; q_skba->index = index;
/* Ring doorbell */ /* Ring doorbell */
@ -253,7 +262,7 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
ehea_update_rq2a(pr->qp, i); ehea_update_rq2a(pr->qp, i);
else else
ehea_update_rq3a(pr->qp, i); ehea_update_rq3a(pr->qp, i);
out:
return ret; return ret;
} }
@ -1321,7 +1330,7 @@ static void write_swqe2_TSO(struct sk_buff *skb,
sg1entry->len = skb_data_size - headersize; sg1entry->len = skb_data_size - headersize;
tmp_addr = (u64)(skb->data + headersize); tmp_addr = (u64)(skb->data + headersize);
sg1entry->vaddr = tmp_addr; sg1entry->vaddr = ehea_map_vaddr(tmp_addr);
swqe->descriptors++; swqe->descriptors++;
} }
} else } else
@ -1352,7 +1361,7 @@ static void write_swqe2_nonTSO(struct sk_buff *skb,
sg1entry->l_key = lkey; sg1entry->l_key = lkey;
sg1entry->len = skb_data_size - SWQE2_MAX_IMM; sg1entry->len = skb_data_size - SWQE2_MAX_IMM;
tmp_addr = (u64)(skb->data + SWQE2_MAX_IMM); tmp_addr = (u64)(skb->data + SWQE2_MAX_IMM);
sg1entry->vaddr = tmp_addr; sg1entry->vaddr = ehea_map_vaddr(tmp_addr);
swqe->descriptors++; swqe->descriptors++;
} }
} else { } else {
@ -1391,7 +1400,7 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
sg1entry->len = frag->size; sg1entry->len = frag->size;
tmp_addr = (u64)(page_address(frag->page) tmp_addr = (u64)(page_address(frag->page)
+ frag->page_offset); + frag->page_offset);
sg1entry->vaddr = tmp_addr; sg1entry->vaddr = ehea_map_vaddr(tmp_addr);
swqe->descriptors++; swqe->descriptors++;
sg1entry_contains_frag_data = 1; sg1entry_contains_frag_data = 1;
} }
@ -1406,7 +1415,7 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
tmp_addr = (u64)(page_address(frag->page) tmp_addr = (u64)(page_address(frag->page)
+ frag->page_offset); + frag->page_offset);
sgentry->vaddr = tmp_addr; sgentry->vaddr = ehea_map_vaddr(tmp_addr);
swqe->descriptors++; swqe->descriptors++;
} }
} }
@ -1878,6 +1887,9 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
ehea_dump(swqe, 512, "swqe"); ehea_dump(swqe, 512, "swqe");
} }
if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)))
goto out;
ehea_post_swqe(pr->qp, swqe); ehea_post_swqe(pr->qp, swqe);
pr->tx_packets++; pr->tx_packets++;
@ -1892,7 +1904,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
} }
dev->trans_start = jiffies; dev->trans_start = jiffies;
spin_unlock(&pr->xmit_lock); spin_unlock(&pr->xmit_lock);
out:
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
@ -2220,6 +2232,9 @@ out_dereg_bc:
out_clean_pr: out_clean_pr:
ehea_clean_all_portres(port); ehea_clean_all_portres(port);
out: out:
if (ret)
ehea_info("Failed starting %s. ret=%i", dev->name, ret);
return ret; return ret;
} }
@ -2259,8 +2274,13 @@ static int ehea_down(struct net_device *dev)
msleep(1); msleep(1);
ehea_broadcast_reg_helper(port, H_DEREG_BCMC); ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
ret = ehea_clean_all_portres(port);
port->state = EHEA_PORT_DOWN; port->state = EHEA_PORT_DOWN;
ret = ehea_clean_all_portres(port);
if (ret)
ehea_info("Failed freeing resources for %s. ret=%i",
dev->name, ret);
return ret; return ret;
} }
@ -2292,15 +2312,11 @@ static void ehea_reset_port(struct work_struct *work)
netif_stop_queue(dev); netif_stop_queue(dev);
netif_poll_disable(dev); netif_poll_disable(dev);
ret = ehea_down(dev); ehea_down(dev);
if (ret)
ehea_error("ehea_down failed. not all resources are freed");
ret = ehea_up(dev); ret = ehea_up(dev);
if (ret) { if (ret)
ehea_error("Reset device %s failed: ret=%d", dev->name, ret);
goto out; goto out;
}
if (netif_msg_timer(port)) if (netif_msg_timer(port))
ehea_info("Device %s resetted successfully", dev->name); ehea_info("Device %s resetted successfully", dev->name);
@ -2312,6 +2328,88 @@ out:
return; return;
} }
static void ehea_rereg_mrs(struct work_struct *work)
{
int ret, i;
struct ehea_adapter *adapter;
ehea_info("LPAR memory enlarged - re-initializing driver");
list_for_each_entry(adapter, &adapter_list, list)
if (adapter->active_ports) {
/* Shutdown all ports */
for (i = 0; i < EHEA_MAX_PORTS; i++) {
struct ehea_port *port = adapter->port[i];
if (port) {
struct net_device *dev = port->netdev;
if (dev->flags & IFF_UP) {
ehea_info("stopping %s",
dev->name);
down(&port->port_lock);
netif_stop_queue(dev);
netif_poll_disable(dev);
ehea_down(dev);
up(&port->port_lock);
}
}
}
/* Unregister old memory region */
ret = ehea_rem_mr(&adapter->mr);
if (ret) {
ehea_error("unregister MR failed - driver"
" inoperable!");
goto out;
}
}
ehea_destroy_busmap();
ret = ehea_create_busmap();
if (ret)
goto out;
clear_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
list_for_each_entry(adapter, &adapter_list, list)
if (adapter->active_ports) {
/* Register new memory region */
ret = ehea_reg_kernel_mr(adapter, &adapter->mr);
if (ret) {
ehea_error("register MR failed - driver"
" inoperable!");
goto out;
}
/* Restart all ports */
for (i = 0; i < EHEA_MAX_PORTS; i++) {
struct ehea_port *port = adapter->port[i];
if (port) {
struct net_device *dev = port->netdev;
if (dev->flags & IFF_UP) {
ehea_info("restarting %s",
dev->name);
down(&port->port_lock);
ret = ehea_up(dev);
if (!ret) {
netif_poll_enable(dev);
netif_wake_queue(dev);
}
up(&port->port_lock);
}
}
}
}
out:
return;
}
static void ehea_tx_watchdog(struct net_device *dev) static void ehea_tx_watchdog(struct net_device *dev)
{ {
struct ehea_port *port = netdev_priv(dev); struct ehea_port *port = netdev_priv(dev);
@ -2573,6 +2671,8 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
ehea_info("%s: Jumbo frames are %sabled", dev->name, ehea_info("%s: Jumbo frames are %sabled", dev->name,
jumbo == 1 ? "en" : "dis"); jumbo == 1 ? "en" : "dis");
adapter->active_ports++;
return port; return port;
out_unreg_port: out_unreg_port:
@ -2596,6 +2696,7 @@ static void ehea_shutdown_single_port(struct ehea_port *port)
ehea_unregister_port(port); ehea_unregister_port(port);
kfree(port->mc_list); kfree(port->mc_list);
free_netdev(port->netdev); free_netdev(port->netdev);
port->adapter->active_ports--;
} }
static int ehea_setup_ports(struct ehea_adapter *adapter) static int ehea_setup_ports(struct ehea_adapter *adapter)
@ -2788,6 +2889,8 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
goto out; goto out;
} }
list_add(&adapter->list, &adapter_list);
adapter->ebus_dev = dev; adapter->ebus_dev = dev;
adapter_handle = of_get_property(dev->ofdev.node, "ibm,hea-handle", adapter_handle = of_get_property(dev->ofdev.node, "ibm,hea-handle",
@ -2891,7 +2994,10 @@ static int __devexit ehea_remove(struct ibmebus_dev *dev)
ehea_destroy_eq(adapter->neq); ehea_destroy_eq(adapter->neq);
ehea_remove_adapter_mr(adapter); ehea_remove_adapter_mr(adapter);
list_del(&adapter->list);
kfree(adapter); kfree(adapter);
return 0; return 0;
} }
@ -2939,9 +3045,18 @@ int __init ehea_module_init(void)
printk(KERN_INFO "IBM eHEA ethernet device driver (Release %s)\n", printk(KERN_INFO "IBM eHEA ethernet device driver (Release %s)\n",
DRV_VERSION); DRV_VERSION);
ehea_driver_wq = create_workqueue("ehea_driver_wq");
INIT_WORK(&ehea_rereg_mr_task, ehea_rereg_mrs);
ret = check_module_parm(); ret = check_module_parm();
if (ret) if (ret)
goto out; goto out;
ret = ehea_create_busmap();
if (ret)
goto out;
ret = ibmebus_register_driver(&ehea_driver); ret = ibmebus_register_driver(&ehea_driver);
if (ret) { if (ret) {
ehea_error("failed registering eHEA device driver on ebus"); ehea_error("failed registering eHEA device driver on ebus");
@ -2965,6 +3080,7 @@ static void __exit ehea_module_exit(void)
{ {
driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities); driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities);
ibmebus_unregister_driver(&ehea_driver); ibmebus_unregister_driver(&ehea_driver);
ehea_destroy_busmap();
} }
module_init(ehea_module_init); module_init(ehea_module_init);

View file

@ -60,6 +60,9 @@ static inline u32 get_longbusy_msecs(int long_busy_ret_code)
} }
} }
/* Number of pages which can be registered at once by H_REGISTER_HEA_RPAGES */
#define EHEA_MAX_RPAGE 512
/* Notification Event Queue (NEQ) Entry bit masks */ /* Notification Event Queue (NEQ) Entry bit masks */
#define NEQE_EVENT_CODE EHEA_BMASK_IBM(2, 7) #define NEQE_EVENT_CODE EHEA_BMASK_IBM(2, 7)
#define NEQE_PORTNUM EHEA_BMASK_IBM(32, 47) #define NEQE_PORTNUM EHEA_BMASK_IBM(32, 47)

View file

@ -31,6 +31,13 @@
#include "ehea_phyp.h" #include "ehea_phyp.h"
#include "ehea_qmr.h" #include "ehea_qmr.h"
struct ehea_busmap ehea_bmap = { 0, 0, NULL };
extern u64 ehea_driver_flags;
extern struct workqueue_struct *ehea_driver_wq;
extern struct work_struct ehea_rereg_mr_task;
static void *hw_qpageit_get_inc(struct hw_queue *queue) static void *hw_qpageit_get_inc(struct hw_queue *queue)
{ {
void *retvalue = hw_qeit_get(queue); void *retvalue = hw_qeit_get(queue);
@ -547,18 +554,84 @@ int ehea_destroy_qp(struct ehea_qp *qp)
return 0; return 0;
} }
int ehea_create_busmap( void )
{
u64 vaddr = EHEA_BUSMAP_START;
unsigned long abs_max_pfn = 0;
unsigned long sec_max_pfn;
int i;
/*
* Sections are not in ascending order -> Loop over all sections and
* find the highest PFN to compute the required map size.
*/
ehea_bmap.valid_sections = 0;
for (i = 0; i < NR_MEM_SECTIONS; i++)
if (valid_section_nr(i)) {
sec_max_pfn = section_nr_to_pfn(i);
if (sec_max_pfn > abs_max_pfn)
abs_max_pfn = sec_max_pfn;
ehea_bmap.valid_sections++;
}
ehea_bmap.entries = abs_max_pfn / EHEA_PAGES_PER_SECTION + 1;
ehea_bmap.vaddr = vmalloc(ehea_bmap.entries * sizeof(*ehea_bmap.vaddr));
if (!ehea_bmap.vaddr)
return -ENOMEM;
for (i = 0 ; i < ehea_bmap.entries; i++) {
unsigned long pfn = section_nr_to_pfn(i);
if (pfn_valid(pfn)) {
ehea_bmap.vaddr[i] = vaddr;
vaddr += EHEA_SECTSIZE;
} else
ehea_bmap.vaddr[i] = 0;
}
return 0;
}
void ehea_destroy_busmap( void )
{
vfree(ehea_bmap.vaddr);
}
u64 ehea_map_vaddr(void *caddr)
{
u64 mapped_addr;
unsigned long index = __pa(caddr) >> SECTION_SIZE_BITS;
if (likely(index < ehea_bmap.entries)) {
mapped_addr = ehea_bmap.vaddr[index];
if (likely(mapped_addr))
mapped_addr |= (((unsigned long)caddr)
& (EHEA_SECTSIZE - 1));
else
mapped_addr = -1;
} else
mapped_addr = -1;
if (unlikely(mapped_addr == -1))
if (!test_and_set_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
queue_work(ehea_driver_wq, &ehea_rereg_mr_task);
return mapped_addr;
}
int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
{ {
int i, k, ret; int ret;
u64 hret, pt_abs, start, end, nr_pages;
u32 acc_ctrl = EHEA_MR_ACC_CTRL;
u64 *pt; u64 *pt;
void *pg;
u64 hret, pt_abs, i, j, m, mr_len;
u32 acc_ctrl = EHEA_MR_ACC_CTRL;
start = KERNELBASE; mr_len = ehea_bmap.valid_sections * EHEA_SECTSIZE;
end = (u64)high_memory;
nr_pages = (end - start) / EHEA_PAGESIZE;
pt = kzalloc(PAGE_SIZE, GFP_KERNEL); pt = kzalloc(EHEA_MAX_RPAGE * sizeof(u64), GFP_KERNEL);
if (!pt) { if (!pt) {
ehea_error("no mem"); ehea_error("no mem");
ret = -ENOMEM; ret = -ENOMEM;
@ -566,7 +639,8 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
} }
pt_abs = virt_to_abs(pt); pt_abs = virt_to_abs(pt);
hret = ehea_h_alloc_resource_mr(adapter->handle, start, end - start, hret = ehea_h_alloc_resource_mr(adapter->handle,
EHEA_BUSMAP_START, mr_len,
acc_ctrl, adapter->pd, acc_ctrl, adapter->pd,
&mr->handle, &mr->lkey); &mr->handle, &mr->lkey);
if (hret != H_SUCCESS) { if (hret != H_SUCCESS) {
@ -575,49 +649,43 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
goto out; goto out;
} }
mr->vaddr = KERNELBASE; for (i = 0 ; i < ehea_bmap.entries; i++)
k = 0; if (ehea_bmap.vaddr[i]) {
void *sectbase = __va(i << SECTION_SIZE_BITS);
unsigned long k = 0;
while (nr_pages > 0) { for (j = 0; j < (PAGES_PER_SECTION / EHEA_MAX_RPAGE);
if (nr_pages > 1) { j++) {
u64 num_pages = min(nr_pages, (u64)512);
for (i = 0; i < num_pages; i++)
pt[i] = virt_to_abs((void*)(((u64)start) +
((k++) *
EHEA_PAGESIZE)));
hret = ehea_h_register_rpage_mr(adapter->handle, for (m = 0; m < EHEA_MAX_RPAGE; m++) {
mr->handle, 0, pg = sectbase + ((k++) * EHEA_PAGESIZE);
0, (u64)pt_abs, pt[m] = virt_to_abs(pg);
num_pages); }
nr_pages -= num_pages;
} else {
u64 abs_adr = virt_to_abs((void*)(((u64)start) +
(k * EHEA_PAGESIZE)));
hret = ehea_h_register_rpage_mr(adapter->handle, hret = ehea_h_register_rpage_mr(adapter->handle,
mr->handle, 0, mr->handle,
0, abs_adr,1); 0, 0, pt_abs,
nr_pages--; EHEA_MAX_RPAGE);
if ((hret != H_SUCCESS)
&& (hret != H_PAGE_REGISTERED)) {
ehea_h_free_resource(adapter->handle,
mr->handle,
FORCE_FREE);
ehea_error("register_rpage_mr failed");
ret = -EIO;
goto out;
}
}
} }
if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) {
ehea_h_free_resource(adapter->handle,
mr->handle, FORCE_FREE);
ehea_error("register_rpage_mr failed");
ret = -EIO;
goto out;
}
}
if (hret != H_SUCCESS) { if (hret != H_SUCCESS) {
ehea_h_free_resource(adapter->handle, mr->handle, ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE);
FORCE_FREE); ehea_error("registering mr failed");
ehea_error("register_rpage failed for last page");
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
mr->vaddr = EHEA_BUSMAP_START;
mr->adapter = adapter; mr->adapter = adapter;
ret = 0; ret = 0;
out: out:

View file

@ -36,8 +36,14 @@
* page size of ehea hardware queues * page size of ehea hardware queues
*/ */
#define EHEA_PAGESHIFT 12 #define EHEA_PAGESHIFT 12
#define EHEA_PAGESIZE 4096UL #define EHEA_PAGESIZE (1UL << EHEA_PAGESHIFT)
#define EHEA_SECTSIZE (1UL << 24)
#define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> PAGE_SHIFT)
#if (1UL << SECTION_SIZE_BITS) < EHEA_SECTSIZE
#error eHEA module can't work if kernel sectionsize < ehea sectionsize
#endif
/* Some abbreviations used here: /* Some abbreviations used here:
* *
@ -372,4 +378,8 @@ int ehea_rem_mr(struct ehea_mr *mr);
void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle); void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle);
int ehea_create_busmap( void );
void ehea_destroy_busmap( void );
u64 ehea_map_vaddr(void *caddr);
#endif /* __EHEA_QMR_H__ */ #endif /* __EHEA_QMR_H__ */

View file

@ -550,6 +550,8 @@ union ring_type {
/* PHY defines */ /* PHY defines */
#define PHY_OUI_MARVELL 0x5043 #define PHY_OUI_MARVELL 0x5043
#define PHY_OUI_CICADA 0x03f1 #define PHY_OUI_CICADA 0x03f1
#define PHY_OUI_VITESSE 0x01c1
#define PHY_OUI_REALTEK 0x01c1
#define PHYID1_OUI_MASK 0x03ff #define PHYID1_OUI_MASK 0x03ff
#define PHYID1_OUI_SHFT 6 #define PHYID1_OUI_SHFT 6
#define PHYID2_OUI_MASK 0xfc00 #define PHYID2_OUI_MASK 0xfc00
@ -557,12 +559,36 @@ union ring_type {
#define PHYID2_MODEL_MASK 0x03f0 #define PHYID2_MODEL_MASK 0x03f0
#define PHY_MODEL_MARVELL_E3016 0x220 #define PHY_MODEL_MARVELL_E3016 0x220
#define PHY_MARVELL_E3016_INITMASK 0x0300 #define PHY_MARVELL_E3016_INITMASK 0x0300
#define PHY_INIT1 0x0f000 #define PHY_CICADA_INIT1 0x0f000
#define PHY_INIT2 0x0e00 #define PHY_CICADA_INIT2 0x0e00
#define PHY_INIT3 0x01000 #define PHY_CICADA_INIT3 0x01000
#define PHY_INIT4 0x0200 #define PHY_CICADA_INIT4 0x0200
#define PHY_INIT5 0x0004 #define PHY_CICADA_INIT5 0x0004
#define PHY_INIT6 0x02000 #define PHY_CICADA_INIT6 0x02000
#define PHY_VITESSE_INIT_REG1 0x1f
#define PHY_VITESSE_INIT_REG2 0x10
#define PHY_VITESSE_INIT_REG3 0x11
#define PHY_VITESSE_INIT_REG4 0x12
#define PHY_VITESSE_INIT_MSK1 0xc
#define PHY_VITESSE_INIT_MSK2 0x0180
#define PHY_VITESSE_INIT1 0x52b5
#define PHY_VITESSE_INIT2 0xaf8a
#define PHY_VITESSE_INIT3 0x8
#define PHY_VITESSE_INIT4 0x8f8a
#define PHY_VITESSE_INIT5 0xaf86
#define PHY_VITESSE_INIT6 0x8f86
#define PHY_VITESSE_INIT7 0xaf82
#define PHY_VITESSE_INIT8 0x0100
#define PHY_VITESSE_INIT9 0x8f82
#define PHY_VITESSE_INIT10 0x0
#define PHY_REALTEK_INIT_REG1 0x1f
#define PHY_REALTEK_INIT_REG2 0x19
#define PHY_REALTEK_INIT_REG3 0x13
#define PHY_REALTEK_INIT1 0x0000
#define PHY_REALTEK_INIT2 0x8e00
#define PHY_REALTEK_INIT3 0x0001
#define PHY_REALTEK_INIT4 0xad17
#define PHY_GIGABIT 0x0100 #define PHY_GIGABIT 0x0100
#define PHY_TIMEOUT 0x1 #define PHY_TIMEOUT 0x1
@ -1096,6 +1122,28 @@ static int phy_init(struct net_device *dev)
return PHY_ERROR; return PHY_ERROR;
} }
} }
if (np->phy_oui == PHY_OUI_REALTEK) {
if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
}
/* set advertise register */ /* set advertise register */
reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
@ -1141,14 +1189,14 @@ static int phy_init(struct net_device *dev)
/* phy vendor specific configuration */ /* phy vendor specific configuration */
if ((np->phy_oui == PHY_OUI_CICADA) && (phyinterface & PHY_RGMII) ) { if ((np->phy_oui == PHY_OUI_CICADA) && (phyinterface & PHY_RGMII) ) {
phy_reserved = mii_rw(dev, np->phyaddr, MII_RESV1, MII_READ); phy_reserved = mii_rw(dev, np->phyaddr, MII_RESV1, MII_READ);
phy_reserved &= ~(PHY_INIT1 | PHY_INIT2); phy_reserved &= ~(PHY_CICADA_INIT1 | PHY_CICADA_INIT2);
phy_reserved |= (PHY_INIT3 | PHY_INIT4); phy_reserved |= (PHY_CICADA_INIT3 | PHY_CICADA_INIT4);
if (mii_rw(dev, np->phyaddr, MII_RESV1, phy_reserved)) { if (mii_rw(dev, np->phyaddr, MII_RESV1, phy_reserved)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR; return PHY_ERROR;
} }
phy_reserved = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ); phy_reserved = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ);
phy_reserved |= PHY_INIT5; phy_reserved |= PHY_CICADA_INIT5;
if (mii_rw(dev, np->phyaddr, MII_NCONFIG, phy_reserved)) { if (mii_rw(dev, np->phyaddr, MII_NCONFIG, phy_reserved)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR; return PHY_ERROR;
@ -1156,12 +1204,106 @@ static int phy_init(struct net_device *dev)
} }
if (np->phy_oui == PHY_OUI_CICADA) { if (np->phy_oui == PHY_OUI_CICADA) {
phy_reserved = mii_rw(dev, np->phyaddr, MII_SREVISION, MII_READ); phy_reserved = mii_rw(dev, np->phyaddr, MII_SREVISION, MII_READ);
phy_reserved |= PHY_INIT6; phy_reserved |= PHY_CICADA_INIT6;
if (mii_rw(dev, np->phyaddr, MII_SREVISION, phy_reserved)) { if (mii_rw(dev, np->phyaddr, MII_SREVISION, phy_reserved)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR; return PHY_ERROR;
} }
} }
if (np->phy_oui == PHY_OUI_VITESSE) {
if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG1, PHY_VITESSE_INIT1)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT2)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, MII_READ);
if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, MII_READ);
phy_reserved &= ~PHY_VITESSE_INIT_MSK1;
phy_reserved |= PHY_VITESSE_INIT3;
if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, phy_reserved)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT4)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT5)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, MII_READ);
phy_reserved &= ~PHY_VITESSE_INIT_MSK1;
phy_reserved |= PHY_VITESSE_INIT3;
if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, MII_READ);
if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, phy_reserved)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT6)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT7)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, MII_READ);
if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, MII_READ);
phy_reserved &= ~PHY_VITESSE_INIT_MSK2;
phy_reserved |= PHY_VITESSE_INIT8;
if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, phy_reserved)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT9)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG1, PHY_VITESSE_INIT10)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
}
if (np->phy_oui == PHY_OUI_REALTEK) {
/* reset could have cleared these out, set them back */
if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
}
/* some phys clear out pause advertisment on reset, set it back */ /* some phys clear out pause advertisment on reset, set it back */
mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg); mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg);

View file

@ -31,7 +31,6 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <asm/ocp.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/mii.h> #include <linux/mii.h>
#include <linux/phy.h> #include <linux/phy.h>

View file

@ -17,13 +17,12 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/mii.h>
#include <linux/mutex.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/ethtool.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/phy.h>
#include <asm/arch/board.h> #include <asm/arch/board.h>
#include <asm/arch/cpu.h>
#include "macb.h" #include "macb.h"
@ -85,172 +84,202 @@ static void __init macb_get_hwaddr(struct macb *bp)
memcpy(bp->dev->dev_addr, addr, sizeof(addr)); memcpy(bp->dev->dev_addr, addr, sizeof(addr));
} }
static void macb_enable_mdio(struct macb *bp) static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
{ {
unsigned long flags; struct macb *bp = bus->priv;
u32 reg;
spin_lock_irqsave(&bp->lock, flags);
reg = macb_readl(bp, NCR);
reg |= MACB_BIT(MPE);
macb_writel(bp, NCR, reg);
macb_writel(bp, IER, MACB_BIT(MFD));
spin_unlock_irqrestore(&bp->lock, flags);
}
static void macb_disable_mdio(struct macb *bp)
{
unsigned long flags;
u32 reg;
spin_lock_irqsave(&bp->lock, flags);
reg = macb_readl(bp, NCR);
reg &= ~MACB_BIT(MPE);
macb_writel(bp, NCR, reg);
macb_writel(bp, IDR, MACB_BIT(MFD));
spin_unlock_irqrestore(&bp->lock, flags);
}
static int macb_mdio_read(struct net_device *dev, int phy_id, int location)
{
struct macb *bp = netdev_priv(dev);
int value; int value;
mutex_lock(&bp->mdio_mutex);
macb_enable_mdio(bp);
macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
| MACB_BF(RW, MACB_MAN_READ) | MACB_BF(RW, MACB_MAN_READ)
| MACB_BF(PHYA, phy_id) | MACB_BF(PHYA, mii_id)
| MACB_BF(REGA, location) | MACB_BF(REGA, regnum)
| MACB_BF(CODE, MACB_MAN_CODE))); | MACB_BF(CODE, MACB_MAN_CODE)));
wait_for_completion(&bp->mdio_complete); /* wait for end of transfer */
while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
cpu_relax();
value = MACB_BFEXT(DATA, macb_readl(bp, MAN)); value = MACB_BFEXT(DATA, macb_readl(bp, MAN));
macb_disable_mdio(bp);
mutex_unlock(&bp->mdio_mutex);
return value; return value;
} }
static void macb_mdio_write(struct net_device *dev, int phy_id, static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
int location, int val) u16 value)
{ {
struct macb *bp = netdev_priv(dev); struct macb *bp = bus->priv;
dev_dbg(&bp->pdev->dev, "mdio_write %02x:%02x <- %04x\n",
phy_id, location, val);
mutex_lock(&bp->mdio_mutex);
macb_enable_mdio(bp);
macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
| MACB_BF(RW, MACB_MAN_WRITE) | MACB_BF(RW, MACB_MAN_WRITE)
| MACB_BF(PHYA, phy_id) | MACB_BF(PHYA, mii_id)
| MACB_BF(REGA, location) | MACB_BF(REGA, regnum)
| MACB_BF(CODE, MACB_MAN_CODE) | MACB_BF(CODE, MACB_MAN_CODE)
| MACB_BF(DATA, val))); | MACB_BF(DATA, value)));
wait_for_completion(&bp->mdio_complete); /* wait for end of transfer */
while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
cpu_relax();
macb_disable_mdio(bp);
mutex_unlock(&bp->mdio_mutex);
}
static int macb_phy_probe(struct macb *bp)
{
int phy_address;
u16 phyid1, phyid2;
for (phy_address = 0; phy_address < 32; phy_address++) {
phyid1 = macb_mdio_read(bp->dev, phy_address, MII_PHYSID1);
phyid2 = macb_mdio_read(bp->dev, phy_address, MII_PHYSID2);
if (phyid1 != 0xffff && phyid1 != 0x0000
&& phyid2 != 0xffff && phyid2 != 0x0000)
break;
}
if (phy_address == 32)
return -ENODEV;
dev_info(&bp->pdev->dev,
"detected PHY at address %d (ID %04x:%04x)\n",
phy_address, phyid1, phyid2);
bp->mii.phy_id = phy_address;
return 0; return 0;
} }
static void macb_set_media(struct macb *bp, int media) static int macb_mdio_reset(struct mii_bus *bus)
{ {
u32 reg; return 0;
spin_lock_irq(&bp->lock);
reg = macb_readl(bp, NCFGR);
reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
if (media & (ADVERTISE_100HALF | ADVERTISE_100FULL))
reg |= MACB_BIT(SPD);
if (media & ADVERTISE_FULL)
reg |= MACB_BIT(FD);
macb_writel(bp, NCFGR, reg);
spin_unlock_irq(&bp->lock);
} }
static void macb_check_media(struct macb *bp, int ok_to_print, int init_media) static void macb_handle_link_change(struct net_device *dev)
{ {
struct mii_if_info *mii = &bp->mii; struct macb *bp = netdev_priv(dev);
unsigned int old_carrier, new_carrier; struct phy_device *phydev = bp->phy_dev;
int advertise, lpa, media, duplex; unsigned long flags;
/* if forced media, go no further */ int status_change = 0;
if (mii->force_media)
return;
/* check current and old link status */ spin_lock_irqsave(&bp->lock, flags);
old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
new_carrier = (unsigned int) mii_link_ok(mii);
/* if carrier state did not change, assume nothing else did */ if (phydev->link) {
if (!init_media && old_carrier == new_carrier) if ((bp->speed != phydev->speed) ||
return; (bp->duplex != phydev->duplex)) {
u32 reg;
/* no carrier, nothing much to do */ reg = macb_readl(bp, NCFGR);
if (!new_carrier) { reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
netif_carrier_off(mii->dev);
printk(KERN_INFO "%s: link down\n", mii->dev->name); if (phydev->duplex)
return; reg |= MACB_BIT(FD);
if (phydev->speed)
reg |= MACB_BIT(SPD);
macb_writel(bp, NCFGR, reg);
bp->speed = phydev->speed;
bp->duplex = phydev->duplex;
status_change = 1;
}
} }
/* if (phydev->link != bp->link) {
* we have carrier, see who's on the other end if (phydev->link)
*/ netif_schedule(dev);
netif_carrier_on(mii->dev); else {
bp->speed = 0;
bp->duplex = -1;
}
bp->link = phydev->link;
/* get MII advertise and LPA values */ status_change = 1;
if (!init_media && mii->advertising) { }
advertise = mii->advertising;
spin_unlock_irqrestore(&bp->lock, flags);
if (status_change) {
if (phydev->link)
printk(KERN_INFO "%s: link up (%d/%s)\n",
dev->name, phydev->speed,
DUPLEX_FULL == phydev->duplex ? "Full":"Half");
else
printk(KERN_INFO "%s: link down\n", dev->name);
}
}
/* based on au1000_eth. c*/
static int macb_mii_probe(struct net_device *dev)
{
struct macb *bp = netdev_priv(dev);
struct phy_device *phydev = NULL;
struct eth_platform_data *pdata;
int phy_addr;
/* find the first phy */
for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
if (bp->mii_bus.phy_map[phy_addr]) {
phydev = bp->mii_bus.phy_map[phy_addr];
break;
}
}
if (!phydev) {
printk (KERN_ERR "%s: no PHY found\n", dev->name);
return -1;
}
pdata = bp->pdev->dev.platform_data;
/* TODO : add pin_irq */
/* attach the mac to the phy */
if (pdata && pdata->is_rmii) {
phydev = phy_connect(dev, phydev->dev.bus_id,
&macb_handle_link_change, 0, PHY_INTERFACE_MODE_RMII);
} else { } else {
advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE); phydev = phy_connect(dev, phydev->dev.bus_id,
mii->advertising = advertise; &macb_handle_link_change, 0, PHY_INTERFACE_MODE_MII);
} }
lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
/* figure out media and duplex from advertise and LPA values */ if (IS_ERR(phydev)) {
media = mii_nway_result(lpa & advertise); printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
duplex = (media & ADVERTISE_FULL) ? 1 : 0; return PTR_ERR(phydev);
}
if (ok_to_print) /* mask with MAC supported features */
printk(KERN_INFO "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n", phydev->supported &= PHY_BASIC_FEATURES;
mii->dev->name,
media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? "100" : "10",
duplex ? "full" : "half", lpa);
mii->full_duplex = duplex; phydev->advertising = phydev->supported;
/* Let the MAC know about the new link state */ bp->link = 0;
macb_set_media(bp, media); bp->speed = 0;
bp->duplex = -1;
bp->phy_dev = phydev;
return 0;
}
static int macb_mii_init(struct macb *bp)
{
struct eth_platform_data *pdata;
int err = -ENXIO, i;
/* Enable managment port */
macb_writel(bp, NCR, MACB_BIT(MPE));
bp->mii_bus.name = "MACB_mii_bus",
bp->mii_bus.read = &macb_mdio_read,
bp->mii_bus.write = &macb_mdio_write,
bp->mii_bus.reset = &macb_mdio_reset,
bp->mii_bus.id = bp->pdev->id,
bp->mii_bus.priv = bp,
bp->mii_bus.dev = &bp->dev->dev;
pdata = bp->pdev->dev.platform_data;
if (pdata)
bp->mii_bus.phy_mask = pdata->phy_mask;
bp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
if (!bp->mii_bus.irq) {
err = -ENOMEM;
goto err_out;
}
for (i = 0; i < PHY_MAX_ADDR; i++)
bp->mii_bus.irq[i] = PHY_POLL;
platform_set_drvdata(bp->dev, &bp->mii_bus);
if (mdiobus_register(&bp->mii_bus))
goto err_out_free_mdio_irq;
if (macb_mii_probe(bp->dev) != 0) {
goto err_out_unregister_bus;
}
return 0;
err_out_unregister_bus:
mdiobus_unregister(&bp->mii_bus);
err_out_free_mdio_irq:
kfree(bp->mii_bus.irq);
err_out:
return err;
} }
static void macb_update_stats(struct macb *bp) static void macb_update_stats(struct macb *bp)
@ -265,16 +294,6 @@ static void macb_update_stats(struct macb *bp)
*p += __raw_readl(reg); *p += __raw_readl(reg);
} }
static void macb_periodic_task(struct work_struct *work)
{
struct macb *bp = container_of(work, struct macb, periodic_task.work);
macb_update_stats(bp);
macb_check_media(bp, 1, 0);
schedule_delayed_work(&bp->periodic_task, HZ);
}
static void macb_tx(struct macb *bp) static void macb_tx(struct macb *bp)
{ {
unsigned int tail; unsigned int tail;
@ -519,9 +538,6 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
spin_lock(&bp->lock); spin_lock(&bp->lock);
while (status) { while (status) {
if (status & MACB_BIT(MFD))
complete(&bp->mdio_complete);
/* close possible race with dev_close */ /* close possible race with dev_close */
if (unlikely(!netif_running(dev))) { if (unlikely(!netif_running(dev))) {
macb_writel(bp, IDR, ~0UL); macb_writel(bp, IDR, ~0UL);
@ -535,7 +551,8 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
* until we have processed the buffers * until we have processed the buffers
*/ */
macb_writel(bp, IDR, MACB_RX_INT_FLAGS); macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
dev_dbg(&bp->pdev->dev, "scheduling RX softirq\n"); dev_dbg(&bp->pdev->dev,
"scheduling RX softirq\n");
__netif_rx_schedule(dev); __netif_rx_schedule(dev);
} }
} }
@ -765,7 +782,7 @@ static void macb_init_hw(struct macb *bp)
macb_writel(bp, TBQP, bp->tx_ring_dma); macb_writel(bp, TBQP, bp->tx_ring_dma);
/* Enable TX and RX */ /* Enable TX and RX */
macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE)); macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE));
/* Enable interrupts */ /* Enable interrupts */
macb_writel(bp, IER, (MACB_BIT(RCOMP) macb_writel(bp, IER, (MACB_BIT(RCOMP)
@ -776,18 +793,126 @@ static void macb_init_hw(struct macb *bp)
| MACB_BIT(TCOMP) | MACB_BIT(TCOMP)
| MACB_BIT(ISR_ROVR) | MACB_BIT(ISR_ROVR)
| MACB_BIT(HRESP))); | MACB_BIT(HRESP)));
} }
static void macb_init_phy(struct net_device *dev) /*
* The hash address register is 64 bits long and takes up two
* locations in the memory map. The least significant bits are stored
* in EMAC_HSL and the most significant bits in EMAC_HSH.
*
* The unicast hash enable and the multicast hash enable bits in the
* network configuration register enable the reception of hash matched
* frames. The destination address is reduced to a 6 bit index into
* the 64 bit hash register using the following hash function. The
* hash function is an exclusive or of every sixth bit of the
* destination address.
*
* hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47]
* hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46]
* hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45]
* hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44]
* hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43]
* hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42]
*
* da[0] represents the least significant bit of the first byte
* received, that is, the multicast/unicast indicator, and da[47]
* represents the most significant bit of the last byte received. If
* the hash index, hi[n], points to a bit that is set in the hash
* register then the frame will be matched according to whether the
* frame is multicast or unicast. A multicast match will be signalled
* if the multicast hash enable bit is set, da[0] is 1 and the hash
* index points to a bit set in the hash register. A unicast match
* will be signalled if the unicast hash enable bit is set, da[0] is 0
* and the hash index points to a bit set in the hash register. To
* receive all multicast frames, the hash register should be set with
* all ones and the multicast hash enable bit should be set in the
* network configuration register.
*/
static inline int hash_bit_value(int bitnr, __u8 *addr)
{ {
if (addr[bitnr / 8] & (1 << (bitnr % 8)))
return 1;
return 0;
}
/*
* Return the hash index value for the specified address.
*/
static int hash_get_index(__u8 *addr)
{
int i, j, bitval;
int hash_index = 0;
for (j = 0; j < 6; j++) {
for (i = 0, bitval = 0; i < 8; i++)
bitval ^= hash_bit_value(i*6 + j, addr);
hash_index |= (bitval << j);
}
return hash_index;
}
/*
* Add multicast addresses to the internal multicast-hash table.
*/
static void macb_sethashtable(struct net_device *dev)
{
struct dev_mc_list *curr;
unsigned long mc_filter[2];
unsigned int i, bitnr;
struct macb *bp = netdev_priv(dev); struct macb *bp = netdev_priv(dev);
/* Set some reasonable default settings */ mc_filter[0] = mc_filter[1] = 0;
macb_mdio_write(dev, bp->mii.phy_id, MII_ADVERTISE,
ADVERTISE_CSMA | ADVERTISE_ALL); curr = dev->mc_list;
macb_mdio_write(dev, bp->mii.phy_id, MII_BMCR, for (i = 0; i < dev->mc_count; i++, curr = curr->next) {
(BMCR_SPEED100 | BMCR_ANENABLE if (!curr) break; /* unexpected end of list */
| BMCR_ANRESTART | BMCR_FULLDPLX));
bitnr = hash_get_index(curr->dmi_addr);
mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
}
macb_writel(bp, HRB, mc_filter[0]);
macb_writel(bp, HRT, mc_filter[1]);
}
/*
* Enable/Disable promiscuous and multicast modes.
*/
static void macb_set_rx_mode(struct net_device *dev)
{
unsigned long cfg;
struct macb *bp = netdev_priv(dev);
cfg = macb_readl(bp, NCFGR);
if (dev->flags & IFF_PROMISC)
/* Enable promiscuous mode */
cfg |= MACB_BIT(CAF);
else if (dev->flags & (~IFF_PROMISC))
/* Disable promiscuous mode */
cfg &= ~MACB_BIT(CAF);
if (dev->flags & IFF_ALLMULTI) {
/* Enable all multicast mode */
macb_writel(bp, HRB, -1);
macb_writel(bp, HRT, -1);
cfg |= MACB_BIT(NCFGR_MTI);
} else if (dev->mc_count > 0) {
/* Enable specific multicasts */
macb_sethashtable(dev);
cfg |= MACB_BIT(NCFGR_MTI);
} else if (dev->flags & (~IFF_ALLMULTI)) {
/* Disable all multicast mode */
macb_writel(bp, HRB, 0);
macb_writel(bp, HRT, 0);
cfg &= ~MACB_BIT(NCFGR_MTI);
}
macb_writel(bp, NCFGR, cfg);
} }
static int macb_open(struct net_device *dev) static int macb_open(struct net_device *dev)
@ -797,6 +922,10 @@ static int macb_open(struct net_device *dev)
dev_dbg(&bp->pdev->dev, "open\n"); dev_dbg(&bp->pdev->dev, "open\n");
/* if the phy is not yet register, retry later*/
if (!bp->phy_dev)
return -EAGAIN;
if (!is_valid_ether_addr(dev->dev_addr)) if (!is_valid_ether_addr(dev->dev_addr))
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
@ -810,13 +939,12 @@ static int macb_open(struct net_device *dev)
macb_init_rings(bp); macb_init_rings(bp);
macb_init_hw(bp); macb_init_hw(bp);
macb_init_phy(dev);
macb_check_media(bp, 1, 1); /* schedule a link state check */
phy_start(bp->phy_dev);
netif_start_queue(dev); netif_start_queue(dev);
schedule_delayed_work(&bp->periodic_task, HZ);
return 0; return 0;
} }
@ -825,10 +953,11 @@ static int macb_close(struct net_device *dev)
struct macb *bp = netdev_priv(dev); struct macb *bp = netdev_priv(dev);
unsigned long flags; unsigned long flags;
cancel_rearming_delayed_work(&bp->periodic_task);
netif_stop_queue(dev); netif_stop_queue(dev);
if (bp->phy_dev)
phy_stop(bp->phy_dev);
spin_lock_irqsave(&bp->lock, flags); spin_lock_irqsave(&bp->lock, flags);
macb_reset_hw(bp); macb_reset_hw(bp);
netif_carrier_off(dev); netif_carrier_off(dev);
@ -845,6 +974,9 @@ static struct net_device_stats *macb_get_stats(struct net_device *dev)
struct net_device_stats *nstat = &bp->stats; struct net_device_stats *nstat = &bp->stats;
struct macb_stats *hwstat = &bp->hw_stats; struct macb_stats *hwstat = &bp->hw_stats;
/* read stats from hardware */
macb_update_stats(bp);
/* Convert HW stats into netdevice stats */ /* Convert HW stats into netdevice stats */
nstat->rx_errors = (hwstat->rx_fcs_errors + nstat->rx_errors = (hwstat->rx_fcs_errors +
hwstat->rx_align_errors + hwstat->rx_align_errors +
@ -882,18 +1014,27 @@ static struct net_device_stats *macb_get_stats(struct net_device *dev)
static int macb_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int macb_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{ {
struct macb *bp = netdev_priv(dev); struct macb *bp = netdev_priv(dev);
struct phy_device *phydev = bp->phy_dev;
return mii_ethtool_gset(&bp->mii, cmd); if (!phydev)
return -ENODEV;
return phy_ethtool_gset(phydev, cmd);
} }
static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{ {
struct macb *bp = netdev_priv(dev); struct macb *bp = netdev_priv(dev);
struct phy_device *phydev = bp->phy_dev;
return mii_ethtool_sset(&bp->mii, cmd); if (!phydev)
return -ENODEV;
return phy_ethtool_sset(phydev, cmd);
} }
static void macb_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) static void macb_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{ {
struct macb *bp = netdev_priv(dev); struct macb *bp = netdev_priv(dev);
@ -902,104 +1043,34 @@ static void macb_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *inf
strcpy(info->bus_info, bp->pdev->dev.bus_id); strcpy(info->bus_info, bp->pdev->dev.bus_id);
} }
static int macb_nway_reset(struct net_device *dev)
{
struct macb *bp = netdev_priv(dev);
return mii_nway_restart(&bp->mii);
}
static struct ethtool_ops macb_ethtool_ops = { static struct ethtool_ops macb_ethtool_ops = {
.get_settings = macb_get_settings, .get_settings = macb_get_settings,
.set_settings = macb_set_settings, .set_settings = macb_set_settings,
.get_drvinfo = macb_get_drvinfo, .get_drvinfo = macb_get_drvinfo,
.nway_reset = macb_nway_reset,
.get_link = ethtool_op_get_link, .get_link = ethtool_op_get_link,
}; };
static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{ {
struct macb *bp = netdev_priv(dev); struct macb *bp = netdev_priv(dev);
struct phy_device *phydev = bp->phy_dev;
if (!netif_running(dev)) if (!netif_running(dev))
return -EINVAL; return -EINVAL;
return generic_mii_ioctl(&bp->mii, if_mii(rq), cmd, NULL); if (!phydev)
return -ENODEV;
return phy_mii_ioctl(phydev, if_mii(rq), cmd);
} }
static ssize_t macb_mii_show(const struct device *_dev, char *buf,
unsigned long addr)
{
struct net_device *dev = to_net_dev(_dev);
struct macb *bp = netdev_priv(dev);
ssize_t ret = -EINVAL;
if (netif_running(dev)) {
int value;
value = macb_mdio_read(dev, bp->mii.phy_id, addr);
ret = sprintf(buf, "0x%04x\n", (uint16_t)value);
}
return ret;
}
#define MII_ENTRY(name, addr) \
static ssize_t show_##name(struct device *_dev, \
struct device_attribute *attr, \
char *buf) \
{ \
return macb_mii_show(_dev, buf, addr); \
} \
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
MII_ENTRY(bmcr, MII_BMCR);
MII_ENTRY(bmsr, MII_BMSR);
MII_ENTRY(physid1, MII_PHYSID1);
MII_ENTRY(physid2, MII_PHYSID2);
MII_ENTRY(advertise, MII_ADVERTISE);
MII_ENTRY(lpa, MII_LPA);
MII_ENTRY(expansion, MII_EXPANSION);
static struct attribute *macb_mii_attrs[] = {
&dev_attr_bmcr.attr,
&dev_attr_bmsr.attr,
&dev_attr_physid1.attr,
&dev_attr_physid2.attr,
&dev_attr_advertise.attr,
&dev_attr_lpa.attr,
&dev_attr_expansion.attr,
NULL,
};
static struct attribute_group macb_mii_group = {
.name = "mii",
.attrs = macb_mii_attrs,
};
static void macb_unregister_sysfs(struct net_device *net)
{
struct device *_dev = &net->dev;
sysfs_remove_group(&_dev->kobj, &macb_mii_group);
}
static int macb_register_sysfs(struct net_device *net)
{
struct device *_dev = &net->dev;
int ret;
ret = sysfs_create_group(&_dev->kobj, &macb_mii_group);
if (ret)
printk(KERN_WARNING
"%s: sysfs mii attribute registration failed: %d\n",
net->name, ret);
return ret;
}
static int __devinit macb_probe(struct platform_device *pdev) static int __devinit macb_probe(struct platform_device *pdev)
{ {
struct eth_platform_data *pdata; struct eth_platform_data *pdata;
struct resource *regs; struct resource *regs;
struct net_device *dev; struct net_device *dev;
struct macb *bp; struct macb *bp;
struct phy_device *phydev;
unsigned long pclk_hz; unsigned long pclk_hz;
u32 config; u32 config;
int err = -ENXIO; int err = -ENXIO;
@ -1073,6 +1144,7 @@ static int __devinit macb_probe(struct platform_device *pdev)
dev->stop = macb_close; dev->stop = macb_close;
dev->hard_start_xmit = macb_start_xmit; dev->hard_start_xmit = macb_start_xmit;
dev->get_stats = macb_get_stats; dev->get_stats = macb_get_stats;
dev->set_multicast_list = macb_set_rx_mode;
dev->do_ioctl = macb_ioctl; dev->do_ioctl = macb_ioctl;
dev->poll = macb_poll; dev->poll = macb_poll;
dev->weight = 64; dev->weight = 64;
@ -1080,10 +1152,6 @@ static int __devinit macb_probe(struct platform_device *pdev)
dev->base_addr = regs->start; dev->base_addr = regs->start;
INIT_DELAYED_WORK(&bp->periodic_task, macb_periodic_task);
mutex_init(&bp->mdio_mutex);
init_completion(&bp->mdio_complete);
/* Set MII management clock divider */ /* Set MII management clock divider */
pclk_hz = clk_get_rate(bp->pclk); pclk_hz = clk_get_rate(bp->pclk);
if (pclk_hz <= 20000000) if (pclk_hz <= 20000000)
@ -1096,20 +1164,9 @@ static int __devinit macb_probe(struct platform_device *pdev)
config = MACB_BF(CLK, MACB_CLK_DIV64); config = MACB_BF(CLK, MACB_CLK_DIV64);
macb_writel(bp, NCFGR, config); macb_writel(bp, NCFGR, config);
bp->mii.dev = dev;
bp->mii.mdio_read = macb_mdio_read;
bp->mii.mdio_write = macb_mdio_write;
bp->mii.phy_id_mask = 0x1f;
bp->mii.reg_num_mask = 0x1f;
macb_get_hwaddr(bp); macb_get_hwaddr(bp);
err = macb_phy_probe(bp);
if (err) {
dev_err(&pdev->dev, "Failed to detect PHY, aborting.\n");
goto err_out_free_irq;
}
pdata = pdev->dev.platform_data; pdata = pdev->dev.platform_data;
if (pdata && pdata->is_rmii) if (pdata && pdata->is_rmii)
#if defined(CONFIG_ARCH_AT91) #if defined(CONFIG_ARCH_AT91)
macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) ); macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) );
@ -1131,9 +1188,11 @@ static int __devinit macb_probe(struct platform_device *pdev)
goto err_out_free_irq; goto err_out_free_irq;
} }
platform_set_drvdata(pdev, dev); if (macb_mii_init(bp) != 0) {
goto err_out_unregister_netdev;
}
macb_register_sysfs(dev); platform_set_drvdata(pdev, dev);
printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d " printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d "
"(%02x:%02x:%02x:%02x:%02x:%02x)\n", "(%02x:%02x:%02x:%02x:%02x:%02x)\n",
@ -1141,8 +1200,15 @@ static int __devinit macb_probe(struct platform_device *pdev)
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
phydev = bp->phy_dev;
printk(KERN_INFO "%s: attached PHY driver [%s] "
"(mii_bus:phy_addr=%s, irq=%d)\n",
dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
return 0; return 0;
err_out_unregister_netdev:
unregister_netdev(dev);
err_out_free_irq: err_out_free_irq:
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
err_out_iounmap: err_out_iounmap:
@ -1153,7 +1219,9 @@ err_out_disable_clocks:
clk_put(bp->hclk); clk_put(bp->hclk);
#endif #endif
clk_disable(bp->pclk); clk_disable(bp->pclk);
#ifndef CONFIG_ARCH_AT91
err_out_put_pclk: err_out_put_pclk:
#endif
clk_put(bp->pclk); clk_put(bp->pclk);
err_out_free_dev: err_out_free_dev:
free_netdev(dev); free_netdev(dev);
@ -1171,7 +1239,8 @@ static int __devexit macb_remove(struct platform_device *pdev)
if (dev) { if (dev) {
bp = netdev_priv(dev); bp = netdev_priv(dev);
macb_unregister_sysfs(dev); mdiobus_unregister(&bp->mii_bus);
kfree(bp->mii_bus.irq);
unregister_netdev(dev); unregister_netdev(dev);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
iounmap(bp->regs); iounmap(bp->regs);

View file

@ -383,11 +383,11 @@ struct macb {
unsigned int rx_pending, tx_pending; unsigned int rx_pending, tx_pending;
struct delayed_work periodic_task; struct mii_bus mii_bus;
struct phy_device *phy_dev;
struct mutex mdio_mutex; unsigned int link;
struct completion mdio_complete; unsigned int speed;
struct mii_if_info mii; unsigned int duplex;
}; };
#endif /* _MACB_H */ #endif /* _MACB_H */

View file

@ -1060,7 +1060,6 @@ static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index)
struct myri10ge_tx_buf *tx = &mgp->tx; struct myri10ge_tx_buf *tx = &mgp->tx;
struct sk_buff *skb; struct sk_buff *skb;
int idx, len; int idx, len;
int limit = 0;
while (tx->pkt_done != mcp_index) { while (tx->pkt_done != mcp_index) {
idx = tx->done & tx->mask; idx = tx->done & tx->mask;
@ -1091,11 +1090,6 @@ static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index)
bus), len, bus), len,
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
} }
/* limit potential for livelock by only handling
* 2 full tx rings per call */
if (unlikely(++limit > 2 * tx->mask))
break;
} }
/* start the queue if we've stopped it */ /* start the queue if we've stopped it */
if (netif_queue_stopped(mgp->dev) if (netif_queue_stopped(mgp->dev)

View file

@ -796,12 +796,14 @@ static void free_shared_mem(struct s2io_nic *nic)
struct mac_info *mac_control; struct mac_info *mac_control;
struct config_param *config; struct config_param *config;
int lst_size, lst_per_page; int lst_size, lst_per_page;
struct net_device *dev = nic->dev; struct net_device *dev;
int page_num = 0; int page_num = 0;
if (!nic) if (!nic)
return; return;
dev = nic->dev;
mac_control = &nic->mac_control; mac_control = &nic->mac_control;
config = &nic->config; config = &nic->config;

View file

@ -304,6 +304,9 @@ static const struct usb_device_id products [] = {
}, { }, {
USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader
.driver_info = (unsigned long) &blob_info, .driver_info = (unsigned long) &blob_info,
}, {
USB_DEVICE (0x1286, 0x8001), // "blob" bootloader
.driver_info = (unsigned long) &blob_info,
}, { }, {
// Linux Ethernet/RNDIS gadget on pxa210/25x/26x, second config // Linux Ethernet/RNDIS gadget on pxa210/25x/26x, second config
// e.g. Gumstix, current OpenZaurus, ... // e.g. Gumstix, current OpenZaurus, ...

View file

@ -52,6 +52,8 @@
#include "airo.h" #include "airo.h"
#define DRV_NAME "airo"
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
static struct pci_device_id card_ids[] = { static struct pci_device_id card_ids[] = {
{ 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, },
@ -71,7 +73,7 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state);
static int airo_pci_resume(struct pci_dev *pdev); static int airo_pci_resume(struct pci_dev *pdev);
static struct pci_driver airo_driver = { static struct pci_driver airo_driver = {
.name = "airo", .name = DRV_NAME,
.id_table = card_ids, .id_table = card_ids,
.probe = airo_pci_probe, .probe = airo_pci_probe,
.remove = __devexit_p(airo_pci_remove), .remove = __devexit_p(airo_pci_remove),
@ -1092,7 +1094,7 @@ static int get_dec_u16( char *buffer, int *start, int limit );
static void OUT4500( struct airo_info *, u16 register, u16 value ); static void OUT4500( struct airo_info *, u16 register, u16 value );
static unsigned short IN4500( struct airo_info *, u16 register ); static unsigned short IN4500( struct airo_info *, u16 register );
static u16 setup_card(struct airo_info*, u8 *mac, int lock); static u16 setup_card(struct airo_info*, u8 *mac, int lock);
static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ); static int enable_MAC(struct airo_info *ai, int lock);
static void disable_MAC(struct airo_info *ai, int lock); static void disable_MAC(struct airo_info *ai, int lock);
static void enable_interrupts(struct airo_info*); static void enable_interrupts(struct airo_info*);
static void disable_interrupts(struct airo_info*); static void disable_interrupts(struct airo_info*);
@ -1250,7 +1252,7 @@ static int flashputbuf(struct airo_info *ai);
static int flashrestart(struct airo_info *ai,struct net_device *dev); static int flashrestart(struct airo_info *ai,struct net_device *dev);
#define airo_print(type, name, fmt, args...) \ #define airo_print(type, name, fmt, args...) \
{ printk(type "airo(%s): " fmt "\n", name, ##args); } printk(type DRV_NAME "(%s): " fmt "\n", name, ##args)
#define airo_print_info(name, fmt, args...) \ #define airo_print_info(name, fmt, args...) \
airo_print(KERN_INFO, name, fmt, ##args) airo_print(KERN_INFO, name, fmt, ##args)
@ -1926,28 +1928,54 @@ static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) {
return rc; return rc;
} }
static int airo_open(struct net_device *dev) { static void try_auto_wep(struct airo_info *ai)
struct airo_info *info = dev->priv; {
Resp rsp; if (auto_wep && !(ai->flags & FLAG_RADIO_DOWN)) {
ai->expires = RUN_AT(3*HZ);
wake_up_interruptible(&ai->thr_wait);
}
}
if (test_bit(FLAG_FLASHING, &info->flags)) static int airo_open(struct net_device *dev) {
struct airo_info *ai = dev->priv;
int rc = 0;
if (test_bit(FLAG_FLASHING, &ai->flags))
return -EIO; return -EIO;
/* Make sure the card is configured. /* Make sure the card is configured.
* Wireless Extensions may postpone config changes until the card * Wireless Extensions may postpone config changes until the card
* is open (to pipeline changes and speed-up card setup). If * is open (to pipeline changes and speed-up card setup). If
* those changes are not yet commited, do it now - Jean II */ * those changes are not yet commited, do it now - Jean II */
if (test_bit (FLAG_COMMIT, &info->flags)) { if (test_bit(FLAG_COMMIT, &ai->flags)) {
disable_MAC(info, 1); disable_MAC(ai, 1);
writeConfigRid(info, 1); writeConfigRid(ai, 1);
} }
if (info->wifidev != dev) { if (ai->wifidev != dev) {
clear_bit(JOB_DIE, &ai->jobs);
ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name);
if (IS_ERR(ai->airo_thread_task))
return (int)PTR_ERR(ai->airo_thread_task);
rc = request_irq(dev->irq, airo_interrupt, IRQF_SHARED,
dev->name, dev);
if (rc) {
airo_print_err(dev->name,
"register interrupt %d failed, rc %d",
dev->irq, rc);
set_bit(JOB_DIE, &ai->jobs);
kthread_stop(ai->airo_thread_task);
return rc;
}
/* Power on the MAC controller (which may have been disabled) */ /* Power on the MAC controller (which may have been disabled) */
clear_bit(FLAG_RADIO_DOWN, &info->flags); clear_bit(FLAG_RADIO_DOWN, &ai->flags);
enable_interrupts(info); enable_interrupts(ai);
try_auto_wep(ai);
} }
enable_MAC(info, &rsp, 1); enable_MAC(ai, 1);
netif_start_queue(dev); netif_start_queue(dev);
return 0; return 0;
@ -2338,14 +2366,13 @@ static int airo_set_mac_address(struct net_device *dev, void *p)
{ {
struct airo_info *ai = dev->priv; struct airo_info *ai = dev->priv;
struct sockaddr *addr = p; struct sockaddr *addr = p;
Resp rsp;
readConfigRid(ai, 1); readConfigRid(ai, 1);
memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len); memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
set_bit (FLAG_COMMIT, &ai->flags); set_bit (FLAG_COMMIT, &ai->flags);
disable_MAC(ai, 1); disable_MAC(ai, 1);
writeConfigRid (ai, 1); writeConfigRid (ai, 1);
enable_MAC(ai, &rsp, 1); enable_MAC(ai, 1);
memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len); memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len);
if (ai->wifidev) if (ai->wifidev)
memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len); memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len);
@ -2392,6 +2419,11 @@ static int airo_close(struct net_device *dev) {
disable_MAC(ai, 1); disable_MAC(ai, 1);
#endif #endif
disable_interrupts( ai ); disable_interrupts( ai );
free_irq(dev->irq, dev);
set_bit(JOB_DIE, &ai->jobs);
kthread_stop(ai->airo_thread_task);
} }
return 0; return 0;
} }
@ -2403,7 +2435,6 @@ void stop_airo_card( struct net_device *dev, int freeres )
set_bit(FLAG_RADIO_DOWN, &ai->flags); set_bit(FLAG_RADIO_DOWN, &ai->flags);
disable_MAC(ai, 1); disable_MAC(ai, 1);
disable_interrupts(ai); disable_interrupts(ai);
free_irq( dev->irq, dev );
takedown_proc_entry( dev, ai ); takedown_proc_entry( dev, ai );
if (test_bit(FLAG_REGISTERED, &ai->flags)) { if (test_bit(FLAG_REGISTERED, &ai->flags)) {
unregister_netdev( dev ); unregister_netdev( dev );
@ -2414,9 +2445,6 @@ void stop_airo_card( struct net_device *dev, int freeres )
} }
clear_bit(FLAG_REGISTERED, &ai->flags); clear_bit(FLAG_REGISTERED, &ai->flags);
} }
set_bit(JOB_DIE, &ai->jobs);
kthread_stop(ai->airo_thread_task);
/* /*
* Clean out tx queue * Clean out tx queue
*/ */
@ -2554,8 +2582,7 @@ static int mpi_init_descriptors (struct airo_info *ai)
* 2) Map PCI memory for issueing commands. * 2) Map PCI memory for issueing commands.
* 3) Allocate memory (shared) to send and receive ethernet frames. * 3) Allocate memory (shared) to send and receive ethernet frames.
*/ */
static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci)
const char *name)
{ {
unsigned long mem_start, mem_len, aux_start, aux_len; unsigned long mem_start, mem_len, aux_start, aux_len;
int rc = -1; int rc = -1;
@ -2569,35 +2596,35 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
aux_start = pci_resource_start(pci, 2); aux_start = pci_resource_start(pci, 2);
aux_len = AUXMEMSIZE; aux_len = AUXMEMSIZE;
if (!request_mem_region(mem_start, mem_len, name)) { if (!request_mem_region(mem_start, mem_len, DRV_NAME)) {
airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s", airo_print_err("", "Couldn't get region %x[%x]",
(int)mem_start, (int)mem_len, name); (int)mem_start, (int)mem_len);
goto out; goto out;
} }
if (!request_mem_region(aux_start, aux_len, name)) { if (!request_mem_region(aux_start, aux_len, DRV_NAME)) {
airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s", airo_print_err("", "Couldn't get region %x[%x]",
(int)aux_start, (int)aux_len, name); (int)aux_start, (int)aux_len);
goto free_region1; goto free_region1;
} }
ai->pcimem = ioremap(mem_start, mem_len); ai->pcimem = ioremap(mem_start, mem_len);
if (!ai->pcimem) { if (!ai->pcimem) {
airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s", airo_print_err("", "Couldn't map region %x[%x]",
(int)mem_start, (int)mem_len, name); (int)mem_start, (int)mem_len);
goto free_region2; goto free_region2;
} }
ai->pciaux = ioremap(aux_start, aux_len); ai->pciaux = ioremap(aux_start, aux_len);
if (!ai->pciaux) { if (!ai->pciaux) {
airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s", airo_print_err("", "Couldn't map region %x[%x]",
(int)aux_start, (int)aux_len, name); (int)aux_start, (int)aux_len);
goto free_memmap; goto free_memmap;
} }
/* Reserve PKTSIZE for each fid and 2K for the Rids */ /* Reserve PKTSIZE for each fid and 2K for the Rids */
ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma); ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma);
if (!ai->shared) { if (!ai->shared) {
airo_print_err(ai->dev->name, "Couldn't alloc_consistent %d", airo_print_err("", "Couldn't alloc_consistent %d",
PCI_SHARED_LEN); PCI_SHARED_LEN);
goto free_auxmap; goto free_auxmap;
} }
@ -2742,7 +2769,7 @@ static int airo_networks_allocate(struct airo_info *ai)
kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement), kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement),
GFP_KERNEL); GFP_KERNEL);
if (!ai->networks) { if (!ai->networks) {
airo_print_warn(ai->dev->name, "Out of memory allocating beacons"); airo_print_warn("", "Out of memory allocating beacons");
return -ENOMEM; return -ENOMEM;
} }
@ -2770,7 +2797,6 @@ static int airo_test_wpa_capable(struct airo_info *ai)
{ {
int status; int status;
CapabilityRid cap_rid; CapabilityRid cap_rid;
const char *name = ai->dev->name;
status = readCapabilityRid(ai, &cap_rid, 1); status = readCapabilityRid(ai, &cap_rid, 1);
if (status != SUCCESS) return 0; if (status != SUCCESS) return 0;
@ -2778,12 +2804,12 @@ static int airo_test_wpa_capable(struct airo_info *ai)
/* Only firmware versions 5.30.17 or better can do WPA */ /* Only firmware versions 5.30.17 or better can do WPA */
if ((cap_rid.softVer > 0x530) if ((cap_rid.softVer > 0x530)
|| ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 17))) { || ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 17))) {
airo_print_info(name, "WPA is supported."); airo_print_info("", "WPA is supported.");
return 1; return 1;
} }
/* No WPA support */ /* No WPA support */
airo_print_info(name, "WPA unsupported (only firmware versions 5.30.17" airo_print_info("", "WPA unsupported (only firmware versions 5.30.17"
" and greater support WPA. Detected %s)", cap_rid.prodVer); " and greater support WPA. Detected %s)", cap_rid.prodVer);
return 0; return 0;
} }
@ -2797,23 +2823,19 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
int i, rc; int i, rc;
/* Create the network device object. */ /* Create the network device object. */
dev = alloc_etherdev(sizeof(*ai)); dev = alloc_netdev(sizeof(*ai), "", ether_setup);
if (!dev) { if (!dev) {
airo_print_err("", "Couldn't alloc_etherdev"); airo_print_err("", "Couldn't alloc_etherdev");
return NULL; return NULL;
}
if (dev_alloc_name(dev, dev->name) < 0) {
airo_print_err("", "Couldn't get name!");
goto err_out_free;
} }
ai = dev->priv; ai = dev->priv;
ai->wifidev = NULL; ai->wifidev = NULL;
ai->flags = 0; ai->flags = 1 << FLAG_RADIO_DOWN;
ai->jobs = 0; ai->jobs = 0;
ai->dev = dev; ai->dev = dev;
if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) { if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
airo_print_dbg(dev->name, "Found an MPI350 card"); airo_print_dbg("", "Found an MPI350 card");
set_bit(FLAG_MPI, &ai->flags); set_bit(FLAG_MPI, &ai->flags);
} }
spin_lock_init(&ai->aux_lock); spin_lock_init(&ai->aux_lock);
@ -2821,14 +2843,11 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
ai->config.len = 0; ai->config.len = 0;
ai->pci = pci; ai->pci = pci;
init_waitqueue_head (&ai->thr_wait); init_waitqueue_head (&ai->thr_wait);
ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name);
if (IS_ERR(ai->airo_thread_task))
goto err_out_free;
ai->tfm = NULL; ai->tfm = NULL;
add_airo_dev(ai); add_airo_dev(ai);
if (airo_networks_allocate (ai)) if (airo_networks_allocate (ai))
goto err_out_thr; goto err_out_free;
airo_networks_initialize (ai); airo_networks_initialize (ai);
/* The Airo-specific entries in the device structure. */ /* The Airo-specific entries in the device structure. */
@ -2851,27 +2870,22 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
dev->base_addr = port; dev->base_addr = port;
SET_NETDEV_DEV(dev, dmdev); SET_NETDEV_DEV(dev, dmdev);
SET_MODULE_OWNER(dev);
reset_card (dev, 1); reset_card (dev, 1);
msleep(400); msleep(400);
rc = request_irq( dev->irq, airo_interrupt, IRQF_SHARED, dev->name, dev );
if (rc) {
airo_print_err(dev->name, "register interrupt %d failed, rc %d",
irq, rc);
goto err_out_nets;
}
if (!is_pcmcia) { if (!is_pcmcia) {
if (!request_region( dev->base_addr, 64, dev->name )) { if (!request_region(dev->base_addr, 64, DRV_NAME)) {
rc = -EBUSY; rc = -EBUSY;
airo_print_err(dev->name, "Couldn't request region"); airo_print_err(dev->name, "Couldn't request region");
goto err_out_irq; goto err_out_nets;
} }
} }
if (test_bit(FLAG_MPI,&ai->flags)) { if (test_bit(FLAG_MPI,&ai->flags)) {
if (mpi_map_card(ai, pci, dev->name)) { if (mpi_map_card(ai, pci)) {
airo_print_err(dev->name, "Could not map memory"); airo_print_err("", "Could not map memory");
goto err_out_res; goto err_out_res;
} }
} }
@ -2899,6 +2913,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra); ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra);
} }
strcpy(dev->name, "eth%d");
rc = register_netdev(dev); rc = register_netdev(dev);
if (rc) { if (rc) {
airo_print_err(dev->name, "Couldn't register_netdev"); airo_print_err(dev->name, "Couldn't register_netdev");
@ -2921,8 +2936,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
if (setup_proc_entry(dev, dev->priv) < 0) if (setup_proc_entry(dev, dev->priv) < 0)
goto err_out_wifi; goto err_out_wifi;
netif_start_queue(dev);
SET_MODULE_OWNER(dev);
return dev; return dev;
err_out_wifi: err_out_wifi:
@ -2940,14 +2953,9 @@ err_out_map:
err_out_res: err_out_res:
if (!is_pcmcia) if (!is_pcmcia)
release_region( dev->base_addr, 64 ); release_region( dev->base_addr, 64 );
err_out_irq:
free_irq(dev->irq, dev);
err_out_nets: err_out_nets:
airo_networks_free(ai); airo_networks_free(ai);
err_out_thr:
del_airo_dev(ai); del_airo_dev(ai);
set_bit(JOB_DIE, &ai->jobs);
kthread_stop(ai->airo_thread_task);
err_out_free: err_out_free:
free_netdev(dev); free_netdev(dev);
return NULL; return NULL;
@ -3529,9 +3537,11 @@ static u16 IN4500( struct airo_info *ai, u16 reg ) {
return rc; return rc;
} }
static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) { static int enable_MAC(struct airo_info *ai, int lock)
{
int rc; int rc;
Cmd cmd; Cmd cmd;
Resp rsp;
/* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions
* FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down" * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down"
@ -3547,7 +3557,7 @@ static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) {
if (!test_bit(FLAG_ENABLED, &ai->flags)) { if (!test_bit(FLAG_ENABLED, &ai->flags)) {
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_ENABLE; cmd.cmd = MAC_ENABLE;
rc = issuecommand(ai, &cmd, rsp); rc = issuecommand(ai, &cmd, &rsp);
if (rc == SUCCESS) if (rc == SUCCESS)
set_bit(FLAG_ENABLED, &ai->flags); set_bit(FLAG_ENABLED, &ai->flags);
} else } else
@ -3557,8 +3567,12 @@ static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) {
up(&ai->sem); up(&ai->sem);
if (rc) if (rc)
airo_print_err(ai->dev->name, "%s: Cannot enable MAC, err=%d", airo_print_err(ai->dev->name, "Cannot enable MAC");
__FUNCTION__, rc); else if ((rsp.status & 0xFF00) != 0) {
airo_print_err(ai->dev->name, "Bad MAC enable reason=%x, "
"rid=%x, offset=%d", rsp.rsp0, rsp.rsp1, rsp.rsp2);
rc = ERROR;
}
return rc; return rc;
} }
@ -3902,12 +3916,9 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
if ( status != SUCCESS ) return ERROR; if ( status != SUCCESS ) return ERROR;
} }
status = enable_MAC(ai, &rsp, lock); status = enable_MAC(ai, lock);
if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) { if (status != SUCCESS)
airo_print_err(ai->dev->name, "Bad MAC enable reason = %x, rid = %x,"
" offset = %d", rsp.rsp0, rsp.rsp1, rsp.rsp2 );
return ERROR; return ERROR;
}
/* Grab the initial wep key, we gotta save it for auto_wep */ /* Grab the initial wep key, we gotta save it for auto_wep */
rc = readWepKeyRid(ai, &wkr, 1, lock); rc = readWepKeyRid(ai, &wkr, 1, lock);
@ -3919,10 +3930,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
rc = readWepKeyRid(ai, &wkr, 0, lock); rc = readWepKeyRid(ai, &wkr, 0, lock);
} while(lastindex != wkr.kindex); } while(lastindex != wkr.kindex);
if (auto_wep) { try_auto_wep(ai);
ai->expires = RUN_AT(3*HZ);
wake_up_interruptible(&ai->thr_wait);
}
return SUCCESS; return SUCCESS;
} }
@ -4004,7 +4012,7 @@ static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap )
} }
if ( !(max_tries--) ) { if ( !(max_tries--) ) {
airo_print_err(ai->dev->name, airo_print_err(ai->dev->name,
"airo: BAP setup error too many retries\n"); "BAP setup error too many retries\n");
return ERROR; return ERROR;
} }
// -- PC4500 missed it, try again // -- PC4500 missed it, try again
@ -5152,7 +5160,6 @@ static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
struct net_device *dev = dp->data; struct net_device *dev = dp->data;
struct airo_info *ai = dev->priv; struct airo_info *ai = dev->priv;
SsidRid SSID_rid; SsidRid SSID_rid;
Resp rsp;
int i; int i;
int offset = 0; int offset = 0;
@ -5177,7 +5184,7 @@ static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
SSID_rid.len = sizeof(SSID_rid); SSID_rid.len = sizeof(SSID_rid);
disable_MAC(ai, 1); disable_MAC(ai, 1);
writeSsidRid(ai, &SSID_rid, 1); writeSsidRid(ai, &SSID_rid, 1);
enable_MAC(ai, &rsp, 1); enable_MAC(ai, 1);
} }
static inline u8 hexVal(char c) { static inline u8 hexVal(char c) {
@ -5193,7 +5200,6 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) {
struct net_device *dev = dp->data; struct net_device *dev = dp->data;
struct airo_info *ai = dev->priv; struct airo_info *ai = dev->priv;
APListRid APList_rid; APListRid APList_rid;
Resp rsp;
int i; int i;
if ( !data->writelen ) return; if ( !data->writelen ) return;
@ -5218,18 +5224,17 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) {
} }
disable_MAC(ai, 1); disable_MAC(ai, 1);
writeAPListRid(ai, &APList_rid, 1); writeAPListRid(ai, &APList_rid, 1);
enable_MAC(ai, &rsp, 1); enable_MAC(ai, 1);
} }
/* This function wraps PC4500_writerid with a MAC disable */ /* This function wraps PC4500_writerid with a MAC disable */
static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data, static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
int len, int dummy ) { int len, int dummy ) {
int rc; int rc;
Resp rsp;
disable_MAC(ai, 1); disable_MAC(ai, 1);
rc = PC4500_writerid(ai, rid, rid_data, len, 1); rc = PC4500_writerid(ai, rid, rid_data, len, 1);
enable_MAC(ai, &rsp, 1); enable_MAC(ai, 1);
return rc; return rc;
} }
@ -5260,7 +5265,6 @@ static int set_wep_key(struct airo_info *ai, u16 index,
const char *key, u16 keylen, int perm, int lock ) { const char *key, u16 keylen, int perm, int lock ) {
static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
WepKeyRid wkr; WepKeyRid wkr;
Resp rsp;
memset(&wkr, 0, sizeof(wkr)); memset(&wkr, 0, sizeof(wkr));
if (keylen == 0) { if (keylen == 0) {
@ -5280,7 +5284,7 @@ static int set_wep_key(struct airo_info *ai, u16 index,
if (perm) disable_MAC(ai, lock); if (perm) disable_MAC(ai, lock);
writeWepKeyRid(ai, &wkr, perm, lock); writeWepKeyRid(ai, &wkr, perm, lock);
if (perm) enable_MAC(ai, &rsp, lock); if (perm) enable_MAC(ai, lock);
return 0; return 0;
} }
@ -5548,7 +5552,6 @@ static int proc_close( struct inode *inode, struct file *file )
changed. */ changed. */
static void timer_func( struct net_device *dev ) { static void timer_func( struct net_device *dev ) {
struct airo_info *apriv = dev->priv; struct airo_info *apriv = dev->priv;
Resp rsp;
/* We don't have a link so try changing the authtype */ /* We don't have a link so try changing the authtype */
readConfigRid(apriv, 0); readConfigRid(apriv, 0);
@ -5575,7 +5578,7 @@ static void timer_func( struct net_device *dev ) {
} }
set_bit (FLAG_COMMIT, &apriv->flags); set_bit (FLAG_COMMIT, &apriv->flags);
writeConfigRid(apriv, 0); writeConfigRid(apriv, 0);
enable_MAC(apriv, &rsp, 0); enable_MAC(apriv, 0);
up(&apriv->sem); up(&apriv->sem);
/* Schedule check to see if the change worked */ /* Schedule check to see if the change worked */
@ -5597,8 +5600,10 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev,
dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev); dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev);
else else
dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev); dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev);
if (!dev) if (!dev) {
pci_disable_device(pdev);
return -ENODEV; return -ENODEV;
}
pci_set_drvdata(pdev, dev); pci_set_drvdata(pdev, dev);
return 0; return 0;
@ -5610,6 +5615,8 @@ static void __devexit airo_pci_remove(struct pci_dev *pdev)
airo_print_info(dev->name, "Unregistering..."); airo_print_info(dev->name, "Unregistering...");
stop_airo_card(dev, 1); stop_airo_card(dev, 1);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
} }
static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
@ -5646,7 +5653,6 @@ static int airo_pci_resume(struct pci_dev *pdev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct net_device *dev = pci_get_drvdata(pdev);
struct airo_info *ai = dev->priv; struct airo_info *ai = dev->priv;
Resp rsp;
pci_power_t prev_state = pdev->current_state; pci_power_t prev_state = pdev->current_state;
pci_set_power_state(pdev, PCI_D0); pci_set_power_state(pdev, PCI_D0);
@ -5679,7 +5685,7 @@ static int airo_pci_resume(struct pci_dev *pdev)
ai->APList = NULL; ai->APList = NULL;
} }
writeConfigRid(ai, 0); writeConfigRid(ai, 0);
enable_MAC(ai, &rsp, 0); enable_MAC(ai, 0);
ai->power = PMSG_ON; ai->power = PMSG_ON;
netif_device_attach(dev); netif_device_attach(dev);
netif_wake_queue(dev); netif_wake_queue(dev);
@ -5903,7 +5909,6 @@ static int airo_set_essid(struct net_device *dev,
char *extra) char *extra)
{ {
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
Resp rsp;
SsidRid SSID_rid; /* SSIDs */ SsidRid SSID_rid; /* SSIDs */
/* Reload the list of current SSID */ /* Reload the list of current SSID */
@ -5935,7 +5940,7 @@ static int airo_set_essid(struct net_device *dev,
/* Write it to the card */ /* Write it to the card */
disable_MAC(local, 1); disable_MAC(local, 1);
writeSsidRid(local, &SSID_rid, 1); writeSsidRid(local, &SSID_rid, 1);
enable_MAC(local, &rsp, 1); enable_MAC(local, 1);
return 0; return 0;
} }
@ -6000,7 +6005,7 @@ static int airo_set_wap(struct net_device *dev,
memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN); memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN);
disable_MAC(local, 1); disable_MAC(local, 1);
writeAPListRid(local, &APList_rid, 1); writeAPListRid(local, &APList_rid, 1);
enable_MAC(local, &rsp, 1); enable_MAC(local, 1);
} }
return 0; return 0;
} }
@ -7454,7 +7459,6 @@ static int airo_config_commit(struct net_device *dev,
char *extra) /* NULL */ char *extra) /* NULL */
{ {
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
Resp rsp;
if (!test_bit (FLAG_COMMIT, &local->flags)) if (!test_bit (FLAG_COMMIT, &local->flags))
return 0; return 0;
@ -7479,7 +7483,7 @@ static int airo_config_commit(struct net_device *dev,
if (down_interruptible(&local->sem)) if (down_interruptible(&local->sem))
return -ERESTARTSYS; return -ERESTARTSYS;
writeConfigRid(local, 0); writeConfigRid(local, 0);
enable_MAC(local, &rsp, 0); enable_MAC(local, 0);
if (test_bit (FLAG_RESET, &local->flags)) if (test_bit (FLAG_RESET, &local->flags))
airo_set_promisc(local); airo_set_promisc(local);
else else
@ -7746,7 +7750,6 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
unsigned char *iobuf; unsigned char *iobuf;
int len; int len;
struct airo_info *ai = dev->priv; struct airo_info *ai = dev->priv;
Resp rsp;
if (test_bit(FLAG_FLASHING, &ai->flags)) if (test_bit(FLAG_FLASHING, &ai->flags))
return -EIO; return -EIO;
@ -7758,7 +7761,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
if (test_bit(FLAG_COMMIT, &ai->flags)) { if (test_bit(FLAG_COMMIT, &ai->flags)) {
disable_MAC (ai, 1); disable_MAC (ai, 1);
writeConfigRid (ai, 1); writeConfigRid (ai, 1);
enable_MAC (ai, &rsp, 1); enable_MAC(ai, 1);
} }
break; break;
case AIROGSLIST: ridcode = RID_SSID; break; case AIROGSLIST: ridcode = RID_SSID; break;
@ -7815,7 +7818,6 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
struct airo_info *ai = dev->priv; struct airo_info *ai = dev->priv;
int ridcode; int ridcode;
int enabled; int enabled;
Resp rsp;
static int (* writer)(struct airo_info *, u16 rid, const void *, int, int); static int (* writer)(struct airo_info *, u16 rid, const void *, int, int);
unsigned char *iobuf; unsigned char *iobuf;
@ -7849,7 +7851,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
* same with MAC off * same with MAC off
*/ */
case AIROPMACON: case AIROPMACON:
if (enable_MAC(ai, &rsp, 1) != 0) if (enable_MAC(ai, 1) != 0)
return -EIO; return -EIO;
return 0; return 0;

View file

@ -1768,7 +1768,8 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
if (priv->stop_rf_kill) { if (priv->stop_rf_kill) {
priv->stop_rf_kill = 0; priv->stop_rf_kill = 0;
queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ); queue_delayed_work(priv->workqueue, &priv->rf_kill,
round_jiffies(HZ));
} }
deferred = 1; deferred = 1;
@ -2098,7 +2099,7 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
/* Make sure the RF Kill check timer is running */ /* Make sure the RF Kill check timer is running */
priv->stop_rf_kill = 0; priv->stop_rf_kill = 0;
cancel_delayed_work(&priv->rf_kill); cancel_delayed_work(&priv->rf_kill);
queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ); queue_delayed_work(priv->workqueue, &priv->rf_kill, round_jiffies(HZ));
} }
static void isr_scan_complete(struct ipw2100_priv *priv, u32 status) static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
@ -4233,7 +4234,8 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
/* Make sure the RF_KILL check timer is running */ /* Make sure the RF_KILL check timer is running */
priv->stop_rf_kill = 0; priv->stop_rf_kill = 0;
cancel_delayed_work(&priv->rf_kill); cancel_delayed_work(&priv->rf_kill);
queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ); queue_delayed_work(priv->workqueue, &priv->rf_kill,
round_jiffies(HZ));
} else } else
schedule_reset(priv); schedule_reset(priv);
} }
@ -5969,7 +5971,8 @@ static void ipw2100_rf_kill(struct work_struct *work)
if (rf_kill_active(priv)) { if (rf_kill_active(priv)) {
IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n"); IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
if (!priv->stop_rf_kill) if (!priv->stop_rf_kill)
queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ); queue_delayed_work(priv->workqueue, &priv->rf_kill,
round_jiffies(HZ));
goto exit_unlock; goto exit_unlock;
} }

View file

@ -1751,7 +1751,7 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
/* Make sure the RF_KILL check timer is running */ /* Make sure the RF_KILL check timer is running */
cancel_delayed_work(&priv->rf_kill); cancel_delayed_work(&priv->rf_kill);
queue_delayed_work(priv->workqueue, &priv->rf_kill, queue_delayed_work(priv->workqueue, &priv->rf_kill,
2 * HZ); round_jiffies(2 * HZ));
} else } else
queue_work(priv->workqueue, &priv->up); queue_work(priv->workqueue, &priv->up);
} }
@ -4690,7 +4690,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
else if (priv->config & CFG_BACKGROUND_SCAN else if (priv->config & CFG_BACKGROUND_SCAN
&& priv->status & STATUS_ASSOCIATED) && priv->status & STATUS_ASSOCIATED)
queue_delayed_work(priv->workqueue, queue_delayed_work(priv->workqueue,
&priv->request_scan, HZ); &priv->request_scan,
round_jiffies(HZ));
/* Send an empty event to user space. /* Send an empty event to user space.
* We don't send the received data on the event because * We don't send the received data on the event because

View file

@ -240,7 +240,7 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
if (*enable) if (*enable)
penableRSN->enable = cpu_to_le16(cmd_enable_rsn); penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
else else
penableRSN->enable = cpu_to_le16(cmd_enable_rsn); penableRSN->enable = cpu_to_le16(cmd_disable_rsn);
} }
lbs_deb_leave(LBS_DEB_CMD); lbs_deb_leave(LBS_DEB_CMD);

View file

@ -439,7 +439,6 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
ret = 0; ret = 0;
done: done:
skb->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */
lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
return ret; return ret;
} }

View file

@ -1 +0,0 @@

View file

@ -1719,9 +1719,6 @@ static int wlan_set_encodeext(struct net_device *dev,
pkey->type = KEY_TYPE_ID_TKIP; pkey->type = KEY_TYPE_ID_TKIP;
} else if (alg == IW_ENCODE_ALG_CCMP) { } else if (alg == IW_ENCODE_ALG_CCMP) {
pkey->type = KEY_TYPE_ID_AES; pkey->type = KEY_TYPE_ID_AES;
} else {
ret = -EINVAL;
goto out;
} }
/* If WPA isn't enabled yet, do that now */ /* If WPA isn't enabled yet, do that now */

View file

@ -1853,7 +1853,6 @@ prism54_del_mac(struct net_device *ndev, struct iw_request_info *info,
islpci_private *priv = netdev_priv(ndev); islpci_private *priv = netdev_priv(ndev);
struct islpci_acl *acl = &priv->acl; struct islpci_acl *acl = &priv->acl;
struct mac_entry *entry; struct mac_entry *entry;
struct list_head *ptr;
struct sockaddr *addr = (struct sockaddr *) extra; struct sockaddr *addr = (struct sockaddr *) extra;
if (addr->sa_family != ARPHRD_ETHER) if (addr->sa_family != ARPHRD_ETHER)
@ -1861,11 +1860,9 @@ prism54_del_mac(struct net_device *ndev, struct iw_request_info *info,
if (down_interruptible(&acl->sem)) if (down_interruptible(&acl->sem))
return -ERESTARTSYS; return -ERESTARTSYS;
for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { list_for_each_entry(entry, &acl->mac_list, _list) {
entry = list_entry(ptr, struct mac_entry, _list);
if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) { if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) {
list_del(ptr); list_del(&entry->_list);
acl->size--; acl->size--;
kfree(entry); kfree(entry);
up(&acl->sem); up(&acl->sem);
@ -1883,7 +1880,6 @@ prism54_get_mac(struct net_device *ndev, struct iw_request_info *info,
islpci_private *priv = netdev_priv(ndev); islpci_private *priv = netdev_priv(ndev);
struct islpci_acl *acl = &priv->acl; struct islpci_acl *acl = &priv->acl;
struct mac_entry *entry; struct mac_entry *entry;
struct list_head *ptr;
struct sockaddr *dst = (struct sockaddr *) extra; struct sockaddr *dst = (struct sockaddr *) extra;
dwrq->length = 0; dwrq->length = 0;
@ -1891,9 +1887,7 @@ prism54_get_mac(struct net_device *ndev, struct iw_request_info *info,
if (down_interruptible(&acl->sem)) if (down_interruptible(&acl->sem))
return -ERESTARTSYS; return -ERESTARTSYS;
for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { list_for_each_entry(entry, &acl->mac_list, _list) {
entry = list_entry(ptr, struct mac_entry, _list);
memcpy(dst->sa_data, entry->addr, ETH_ALEN); memcpy(dst->sa_data, entry->addr, ETH_ALEN);
dst->sa_family = ARPHRD_ETHER; dst->sa_family = ARPHRD_ETHER;
dwrq->length++; dwrq->length++;
@ -1960,7 +1954,6 @@ prism54_get_policy(struct net_device *ndev, struct iw_request_info *info,
static int static int
prism54_mac_accept(struct islpci_acl *acl, char *mac) prism54_mac_accept(struct islpci_acl *acl, char *mac)
{ {
struct list_head *ptr;
struct mac_entry *entry; struct mac_entry *entry;
int res = 0; int res = 0;
@ -1972,8 +1965,7 @@ prism54_mac_accept(struct islpci_acl *acl, char *mac)
return 1; return 1;
} }
for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { list_for_each_entry(entry, &acl->mac_list, _list) {
entry = list_entry(ptr, struct mac_entry, _list);
if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
res = 1; res = 1;
break; break;
@ -2216,11 +2208,9 @@ prism54_wpa_bss_ie_init(islpci_private *priv)
void void
prism54_wpa_bss_ie_clean(islpci_private *priv) prism54_wpa_bss_ie_clean(islpci_private *priv)
{ {
struct list_head *ptr, *n; struct islpci_bss_wpa_ie *bss, *n;
list_for_each_safe(ptr, n, &priv->bss_wpa_list) { list_for_each_entry_safe(bss, n, &priv->bss_wpa_list, list) {
struct islpci_bss_wpa_ie *bss;
bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
kfree(bss); kfree(bss);
} }
} }

View file

@ -67,7 +67,7 @@ static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
msleep(2); msleep(2);
} }
static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, u16 data) static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data)
{ {
struct rtl8187_priv *priv = dev->priv; struct rtl8187_priv *priv = dev->priv;
u16 reg80, reg82, reg84; u16 reg80, reg82, reg84;
@ -106,7 +106,7 @@ void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
struct rtl8187_priv *priv = dev->priv; struct rtl8187_priv *priv = dev->priv;
if (priv->asic_rev) if (priv->asic_rev)
rtl8225_write_8051(dev, addr, data); rtl8225_write_8051(dev, addr, cpu_to_le16(data));
else else
rtl8225_write_bitbang(dev, addr, data); rtl8225_write_bitbang(dev, addr, data);
} }

View file

@ -49,8 +49,9 @@ void zd_chip_clear(struct zd_chip *chip)
ZD_MEMCLEAR(chip, sizeof(*chip)); ZD_MEMCLEAR(chip, sizeof(*chip));
} }
static int scnprint_mac_oui(const u8 *addr, char *buffer, size_t size) static int scnprint_mac_oui(struct zd_chip *chip, char *buffer, size_t size)
{ {
u8 *addr = zd_usb_to_netdev(&chip->usb)->dev_addr;
return scnprintf(buffer, size, "%02x-%02x-%02x", return scnprintf(buffer, size, "%02x-%02x-%02x",
addr[0], addr[1], addr[2]); addr[0], addr[1], addr[2]);
} }
@ -61,10 +62,10 @@ static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size)
int i = 0; int i = 0;
i = scnprintf(buffer, size, "zd1211%s chip ", i = scnprintf(buffer, size, "zd1211%s chip ",
chip->is_zd1211b ? "b" : ""); zd_chip_is_zd1211b(chip) ? "b" : "");
i += zd_usb_scnprint_id(&chip->usb, buffer+i, size-i); i += zd_usb_scnprint_id(&chip->usb, buffer+i, size-i);
i += scnprintf(buffer+i, size-i, " "); i += scnprintf(buffer+i, size-i, " ");
i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i); i += scnprint_mac_oui(chip, buffer+i, size-i);
i += scnprintf(buffer+i, size-i, " "); i += scnprintf(buffer+i, size-i, " ");
i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i); i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type, i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type,
@ -366,64 +367,9 @@ error:
return r; return r;
} }
static int _read_mac_addr(struct zd_chip *chip, u8 *mac_addr,
const zd_addr_t *addr)
{
int r;
u32 parts[2];
r = zd_ioread32v_locked(chip, parts, (const zd_addr_t *)addr, 2);
if (r) {
dev_dbg_f(zd_chip_dev(chip),
"error: couldn't read e2p macs. Error number %d\n", r);
return r;
}
mac_addr[0] = parts[0];
mac_addr[1] = parts[0] >> 8;
mac_addr[2] = parts[0] >> 16;
mac_addr[3] = parts[0] >> 24;
mac_addr[4] = parts[1];
mac_addr[5] = parts[1] >> 8;
return 0;
}
static int read_e2p_mac_addr(struct zd_chip *chip)
{
static const zd_addr_t addr[2] = { E2P_MAC_ADDR_P1, E2P_MAC_ADDR_P2 };
ZD_ASSERT(mutex_is_locked(&chip->mutex));
return _read_mac_addr(chip, chip->e2p_mac, (const zd_addr_t *)addr);
}
/* MAC address: if custom mac addresses are to to be used CR_MAC_ADDR_P1 and /* MAC address: if custom mac addresses are to to be used CR_MAC_ADDR_P1 and
* CR_MAC_ADDR_P2 must be overwritten * CR_MAC_ADDR_P2 must be overwritten
*/ */
void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr)
{
mutex_lock(&chip->mutex);
memcpy(mac_addr, chip->e2p_mac, ETH_ALEN);
mutex_unlock(&chip->mutex);
}
static int read_mac_addr(struct zd_chip *chip, u8 *mac_addr)
{
static const zd_addr_t addr[2] = { CR_MAC_ADDR_P1, CR_MAC_ADDR_P2 };
return _read_mac_addr(chip, mac_addr, (const zd_addr_t *)addr);
}
int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr)
{
int r;
dev_dbg_f(zd_chip_dev(chip), "\n");
mutex_lock(&chip->mutex);
r = read_mac_addr(chip, mac_addr);
mutex_unlock(&chip->mutex);
return r;
}
int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
{ {
int r; int r;
@ -444,12 +390,6 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
mutex_lock(&chip->mutex); mutex_lock(&chip->mutex);
r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs)); r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
#ifdef DEBUG
{
u8 tmp[ETH_ALEN];
read_mac_addr(chip, tmp);
}
#endif /* DEBUG */
mutex_unlock(&chip->mutex); mutex_unlock(&chip->mutex);
return r; return r;
} }
@ -809,7 +749,7 @@ out:
static int hw_reset_phy(struct zd_chip *chip) static int hw_reset_phy(struct zd_chip *chip)
{ {
return chip->is_zd1211b ? zd1211b_hw_reset_phy(chip) : return zd_chip_is_zd1211b(chip) ? zd1211b_hw_reset_phy(chip) :
zd1211_hw_reset_phy(chip); zd1211_hw_reset_phy(chip);
} }
@ -874,7 +814,7 @@ static int hw_init_hmac(struct zd_chip *chip)
if (r) if (r)
return r; return r;
return chip->is_zd1211b ? return zd_chip_is_zd1211b(chip) ?
zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip); zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip);
} }
@ -1136,8 +1076,15 @@ static int read_fw_regs_offset(struct zd_chip *chip)
return 0; return 0;
} }
/* Read mac address using pre-firmware interface */
int zd_chip_read_mac_addr_fw(struct zd_chip *chip, u8 *addr)
{
dev_dbg_f(zd_chip_dev(chip), "\n");
return zd_usb_read_fw(&chip->usb, E2P_MAC_ADDR_P1, addr,
ETH_ALEN);
}
int zd_chip_init_hw(struct zd_chip *chip, u8 device_type) int zd_chip_init_hw(struct zd_chip *chip)
{ {
int r; int r;
u8 rf_type; u8 rf_type;
@ -1145,7 +1092,6 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
dev_dbg_f(zd_chip_dev(chip), "\n"); dev_dbg_f(zd_chip_dev(chip), "\n");
mutex_lock(&chip->mutex); mutex_lock(&chip->mutex);
chip->is_zd1211b = (device_type == DEVICE_ZD1211B) != 0;
#ifdef DEBUG #ifdef DEBUG
r = test_init(chip); r = test_init(chip);
@ -1201,10 +1147,6 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
goto out; goto out;
#endif /* DEBUG */ #endif /* DEBUG */
r = read_e2p_mac_addr(chip);
if (r)
goto out;
r = read_cal_int_tables(chip); r = read_cal_int_tables(chip);
if (r) if (r)
goto out; goto out;
@ -1259,7 +1201,7 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip,
r = update_pwr_int(chip, channel); r = update_pwr_int(chip, channel);
if (r) if (r)
return r; return r;
if (chip->is_zd1211b) { if (zd_chip_is_zd1211b(chip)) {
static const struct zd_ioreq16 ioreqs[] = { static const struct zd_ioreq16 ioreqs[] = {
{ CR69, 0x28 }, { CR69, 0x28 },
{}, {},

View file

@ -704,7 +704,6 @@ struct zd_chip {
struct mutex mutex; struct mutex mutex;
/* Base address of FW_REG_ registers */ /* Base address of FW_REG_ registers */
zd_addr_t fw_regs_base; zd_addr_t fw_regs_base;
u8 e2p_mac[ETH_ALEN];
/* EepSetPoint in the vendor driver */ /* EepSetPoint in the vendor driver */
u8 pwr_cal_values[E2P_CHANNEL_COUNT]; u8 pwr_cal_values[E2P_CHANNEL_COUNT];
/* integration values in the vendor driver */ /* integration values in the vendor driver */
@ -715,7 +714,7 @@ struct zd_chip {
unsigned int pa_type:4, unsigned int pa_type:4,
patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
new_phy_layout:1, al2230s_bit:1, new_phy_layout:1, al2230s_bit:1,
is_zd1211b:1, supports_tx_led:1; supports_tx_led:1;
}; };
static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb) static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb)
@ -734,9 +733,15 @@ void zd_chip_init(struct zd_chip *chip,
struct net_device *netdev, struct net_device *netdev,
struct usb_interface *intf); struct usb_interface *intf);
void zd_chip_clear(struct zd_chip *chip); void zd_chip_clear(struct zd_chip *chip);
int zd_chip_init_hw(struct zd_chip *chip, u8 device_type); int zd_chip_read_mac_addr_fw(struct zd_chip *chip, u8 *addr);
int zd_chip_init_hw(struct zd_chip *chip);
int zd_chip_reset(struct zd_chip *chip); int zd_chip_reset(struct zd_chip *chip);
static inline int zd_chip_is_zd1211b(struct zd_chip *chip)
{
return chip->usb.is_zd1211b;
}
static inline int zd_ioread16v_locked(struct zd_chip *chip, u16 *values, static inline int zd_ioread16v_locked(struct zd_chip *chip, u16 *values,
const zd_addr_t *addresses, const zd_addr_t *addresses,
unsigned int count) unsigned int count)
@ -825,8 +830,6 @@ static inline u8 _zd_chip_get_channel(struct zd_chip *chip)
} }
u8 zd_chip_get_channel(struct zd_chip *chip); u8 zd_chip_get_channel(struct zd_chip *chip);
int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain); int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain);
void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr);
int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr);
int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr); int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr);
int zd_chip_switch_radio_on(struct zd_chip *chip); int zd_chip_switch_radio_on(struct zd_chip *chip);
int zd_chip_switch_radio_off(struct zd_chip *chip); int zd_chip_switch_radio_off(struct zd_chip *chip);

View file

@ -86,38 +86,46 @@ out:
return r; return r;
} }
int zd_mac_init_hw(struct zd_mac *mac, u8 device_type) int zd_mac_preinit_hw(struct zd_mac *mac)
{
int r;
u8 addr[ETH_ALEN];
r = zd_chip_read_mac_addr_fw(&mac->chip, addr);
if (r)
return r;
memcpy(mac->netdev->dev_addr, addr, ETH_ALEN);
return 0;
}
int zd_mac_init_hw(struct zd_mac *mac)
{ {
int r; int r;
struct zd_chip *chip = &mac->chip; struct zd_chip *chip = &mac->chip;
u8 addr[ETH_ALEN];
u8 default_regdomain; u8 default_regdomain;
r = zd_chip_enable_int(chip); r = zd_chip_enable_int(chip);
if (r) if (r)
goto out; goto out;
r = zd_chip_init_hw(chip, device_type); r = zd_chip_init_hw(chip);
if (r) if (r)
goto disable_int; goto disable_int;
zd_get_e2p_mac_addr(chip, addr);
r = zd_write_mac_addr(chip, addr);
if (r)
goto disable_int;
ZD_ASSERT(!irqs_disabled()); ZD_ASSERT(!irqs_disabled());
spin_lock_irq(&mac->lock);
memcpy(mac->netdev->dev_addr, addr, ETH_ALEN);
spin_unlock_irq(&mac->lock);
r = zd_read_regdomain(chip, &default_regdomain); r = zd_read_regdomain(chip, &default_regdomain);
if (r) if (r)
goto disable_int; goto disable_int;
if (!zd_regdomain_supported(default_regdomain)) { if (!zd_regdomain_supported(default_regdomain)) {
dev_dbg_f(zd_mac_dev(mac), /* The vendor driver overrides the regulatory domain and
"Regulatory Domain %#04x is not supported.\n", * allowed channel registers and unconditionally restricts
default_regdomain); * available channels to 1-11 everywhere. Match their
r = -EINVAL; * questionable behaviour only for regdomains which we don't
goto disable_int; * recognise. */
dev_warn(zd_mac_dev(mac), "Unrecognised regulatory domain: "
"%#04x. Defaulting to FCC.\n", default_regdomain);
default_regdomain = ZD_REGDOMAIN_FCC;
} }
spin_lock_irq(&mac->lock); spin_lock_irq(&mac->lock);
mac->regdomain = mac->default_regdomain = default_regdomain; mac->regdomain = mac->default_regdomain = default_regdomain;
@ -164,14 +172,25 @@ int zd_mac_open(struct net_device *netdev)
{ {
struct zd_mac *mac = zd_netdev_mac(netdev); struct zd_mac *mac = zd_netdev_mac(netdev);
struct zd_chip *chip = &mac->chip; struct zd_chip *chip = &mac->chip;
struct zd_usb *usb = &chip->usb;
int r; int r;
if (!usb->initialized) {
r = zd_usb_init_hw(usb);
if (r)
goto out;
}
tasklet_enable(&mac->rx_tasklet); tasklet_enable(&mac->rx_tasklet);
r = zd_chip_enable_int(chip); r = zd_chip_enable_int(chip);
if (r < 0) if (r < 0)
goto out; goto out;
r = zd_write_mac_addr(chip, netdev->dev_addr);
if (r)
goto disable_int;
r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G); r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G);
if (r < 0) if (r < 0)
goto disable_int; goto disable_int;
@ -251,9 +270,11 @@ int zd_mac_set_mac_address(struct net_device *netdev, void *p)
dev_dbg_f(zd_mac_dev(mac), dev_dbg_f(zd_mac_dev(mac),
"Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data)); "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data));
r = zd_write_mac_addr(chip, addr->sa_data); if (netdev->flags & IFF_UP) {
if (r) r = zd_write_mac_addr(chip, addr->sa_data);
return r; if (r)
return r;
}
spin_lock_irqsave(&mac->lock, flags); spin_lock_irqsave(&mac->lock, flags);
memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN); memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN);
@ -855,7 +876,7 @@ static int fill_ctrlset(struct zd_mac *mac,
/* ZD1211B: Computing the length difference this way, gives us /* ZD1211B: Computing the length difference this way, gives us
* flexibility to compute the packet length. * flexibility to compute the packet length.
*/ */
cs->packet_length = cpu_to_le16(mac->chip.is_zd1211b ? cs->packet_length = cpu_to_le16(zd_chip_is_zd1211b(&mac->chip) ?
packet_length - frag_len : packet_length); packet_length - frag_len : packet_length);
/* /*

View file

@ -189,7 +189,8 @@ int zd_mac_init(struct zd_mac *mac,
struct usb_interface *intf); struct usb_interface *intf);
void zd_mac_clear(struct zd_mac *mac); void zd_mac_clear(struct zd_mac *mac);
int zd_mac_init_hw(struct zd_mac *mac, u8 device_type); int zd_mac_preinit_hw(struct zd_mac *mac);
int zd_mac_init_hw(struct zd_mac *mac);
int zd_mac_open(struct net_device *netdev); int zd_mac_open(struct net_device *netdev);
int zd_mac_stop(struct net_device *netdev); int zd_mac_stop(struct net_device *netdev);

View file

@ -34,7 +34,7 @@ static const char * const rfs[] = {
[AL2210_RF] = "AL2210_RF", [AL2210_RF] = "AL2210_RF",
[MAXIM_NEW_RF] = "MAXIM_NEW_RF", [MAXIM_NEW_RF] = "MAXIM_NEW_RF",
[UW2453_RF] = "UW2453_RF", [UW2453_RF] = "UW2453_RF",
[UNKNOWN_A_RF] = "UNKNOWN_A_RF", [AL2230S_RF] = "AL2230S_RF",
[RALINK_RF] = "RALINK_RF", [RALINK_RF] = "RALINK_RF",
[INTERSIL_RF] = "INTERSIL_RF", [INTERSIL_RF] = "INTERSIL_RF",
[RF2959_RF] = "RF2959_RF", [RF2959_RF] = "RF2959_RF",
@ -77,6 +77,7 @@ int zd_rf_init_hw(struct zd_rf *rf, u8 type)
r = zd_rf_init_rf2959(rf); r = zd_rf_init_rf2959(rf);
break; break;
case AL2230_RF: case AL2230_RF:
case AL2230S_RF:
r = zd_rf_init_al2230(rf); r = zd_rf_init_al2230(rf);
break; break;
case AL7230B_RF: case AL7230B_RF:

View file

@ -26,7 +26,7 @@
#define AL2210_RF 0x7 #define AL2210_RF 0x7
#define MAXIM_NEW_RF 0x8 #define MAXIM_NEW_RF 0x8
#define UW2453_RF 0x9 #define UW2453_RF 0x9
#define UNKNOWN_A_RF 0xa #define AL2230S_RF 0xa
#define RALINK_RF 0xb #define RALINK_RF 0xb
#define INTERSIL_RF 0xc #define INTERSIL_RF 0xc
#define RF2959_RF 0xd #define RF2959_RF 0xd

View file

@ -21,6 +21,8 @@
#include "zd_usb.h" #include "zd_usb.h"
#include "zd_chip.h" #include "zd_chip.h"
#define IS_AL2230S(chip) ((chip)->al2230s_bit || (chip)->rf.type == AL2230S_RF)
static const u32 zd1211_al2230_table[][3] = { static const u32 zd1211_al2230_table[][3] = {
RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, }, RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, },
RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, }, RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, },
@ -176,7 +178,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
if (r) if (r)
return r; return r;
if (chip->al2230s_bit) { if (IS_AL2230S(chip)) {
r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s, r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s,
ARRAY_SIZE(ioreqs_init_al2230s)); ARRAY_SIZE(ioreqs_init_al2230s));
if (r) if (r)
@ -188,7 +190,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
return r; return r;
/* improve band edge for AL2230S */ /* improve band edge for AL2230S */
if (chip->al2230s_bit) if (IS_AL2230S(chip))
r = zd_rfwrite_locked(chip, 0x000824, RF_RV_BITS); r = zd_rfwrite_locked(chip, 0x000824, RF_RV_BITS);
else else
r = zd_rfwrite_locked(chip, 0x0005a4, RF_RV_BITS); r = zd_rfwrite_locked(chip, 0x0005a4, RF_RV_BITS);
@ -314,7 +316,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
if (r) if (r)
return r; return r;
if (chip->al2230s_bit) { if (IS_AL2230S(chip)) {
r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s, r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s,
ARRAY_SIZE(ioreqs_init_al2230s)); ARRAY_SIZE(ioreqs_init_al2230s));
if (r) if (r)
@ -328,7 +330,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
if (r) if (r)
return r; return r;
if (chip->al2230s_bit) if (IS_AL2230S(chip))
r = zd_rfwrite_locked(chip, 0x241000, RF_RV_BITS); r = zd_rfwrite_locked(chip, 0x241000, RF_RV_BITS);
else else
r = zd_rfwrite_locked(chip, 0x25a000, RF_RV_BITS); r = zd_rfwrite_locked(chip, 0x25a000, RF_RV_BITS);
@ -422,7 +424,7 @@ int zd_rf_init_al2230(struct zd_rf *rf)
struct zd_chip *chip = zd_rf_to_chip(rf); struct zd_chip *chip = zd_rf_to_chip(rf);
rf->switch_radio_off = al2230_switch_radio_off; rf->switch_radio_off = al2230_switch_radio_off;
if (chip->is_zd1211b) { if (zd_chip_is_zd1211b(chip)) {
rf->init_hw = zd1211b_al2230_init_hw; rf->init_hw = zd1211b_al2230_init_hw;
rf->set_channel = zd1211b_al2230_set_channel; rf->set_channel = zd1211b_al2230_set_channel;
rf->switch_radio_on = zd1211b_al2230_switch_radio_on; rf->switch_radio_on = zd1211b_al2230_switch_radio_on;

View file

@ -473,7 +473,7 @@ int zd_rf_init_al7230b(struct zd_rf *rf)
{ {
struct zd_chip *chip = zd_rf_to_chip(rf); struct zd_chip *chip = zd_rf_to_chip(rf);
if (chip->is_zd1211b) { if (zd_chip_is_zd1211b(chip)) {
rf->init_hw = zd1211b_al7230b_init_hw; rf->init_hw = zd1211b_al7230b_init_hw;
rf->switch_radio_on = zd1211b_al7230b_switch_radio_on; rf->switch_radio_on = zd1211b_al7230b_switch_radio_on;
rf->set_channel = zd1211b_al7230b_set_channel; rf->set_channel = zd1211b_al7230b_set_channel;

View file

@ -265,7 +265,7 @@ int zd_rf_init_rf2959(struct zd_rf *rf)
{ {
struct zd_chip *chip = zd_rf_to_chip(rf); struct zd_chip *chip = zd_rf_to_chip(rf);
if (chip->is_zd1211b) { if (zd_chip_is_zd1211b(chip)) {
dev_err(zd_chip_dev(chip), dev_err(zd_chip_dev(chip),
"RF2959 is currently not supported for ZD1211B" "RF2959 is currently not supported for ZD1211B"
" devices\n"); " devices\n");

View file

@ -486,7 +486,7 @@ static int uw2453_switch_radio_on(struct zd_rf *rf)
if (r) if (r)
return r; return r;
if (chip->is_zd1211b) if (zd_chip_is_zd1211b(chip))
ioreqs[1].value = 0x7f; ioreqs[1].value = 0x7f;
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));

View file

@ -71,6 +71,7 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
/* "Driverless" devices that need ejecting */ /* "Driverless" devices that need ejecting */
{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
@ -195,26 +196,27 @@ static u16 get_word(const void *data, u16 offset)
return le16_to_cpu(p[offset]); return le16_to_cpu(p[offset]);
} }
static char *get_fw_name(char *buffer, size_t size, u8 device_type, static char *get_fw_name(struct zd_usb *usb, char *buffer, size_t size,
const char* postfix) const char* postfix)
{ {
scnprintf(buffer, size, "%s%s", scnprintf(buffer, size, "%s%s",
device_type == DEVICE_ZD1211B ? usb->is_zd1211b ?
FW_ZD1211B_PREFIX : FW_ZD1211_PREFIX, FW_ZD1211B_PREFIX : FW_ZD1211_PREFIX,
postfix); postfix);
return buffer; return buffer;
} }
static int handle_version_mismatch(struct usb_device *udev, u8 device_type, static int handle_version_mismatch(struct zd_usb *usb,
const struct firmware *ub_fw) const struct firmware *ub_fw)
{ {
struct usb_device *udev = zd_usb_to_usbdev(usb);
const struct firmware *ur_fw = NULL; const struct firmware *ur_fw = NULL;
int offset; int offset;
int r = 0; int r = 0;
char fw_name[128]; char fw_name[128];
r = request_fw_file(&ur_fw, r = request_fw_file(&ur_fw,
get_fw_name(fw_name, sizeof(fw_name), device_type, "ur"), get_fw_name(usb, fw_name, sizeof(fw_name), "ur"),
&udev->dev); &udev->dev);
if (r) if (r)
goto error; goto error;
@ -237,11 +239,12 @@ error:
return r; return r;
} }
static int upload_firmware(struct usb_device *udev, u8 device_type) static int upload_firmware(struct zd_usb *usb)
{ {
int r; int r;
u16 fw_bcdDevice; u16 fw_bcdDevice;
u16 bcdDevice; u16 bcdDevice;
struct usb_device *udev = zd_usb_to_usbdev(usb);
const struct firmware *ub_fw = NULL; const struct firmware *ub_fw = NULL;
const struct firmware *uph_fw = NULL; const struct firmware *uph_fw = NULL;
char fw_name[128]; char fw_name[128];
@ -249,7 +252,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
bcdDevice = get_bcdDevice(udev); bcdDevice = get_bcdDevice(udev);
r = request_fw_file(&ub_fw, r = request_fw_file(&ub_fw,
get_fw_name(fw_name, sizeof(fw_name), device_type, "ub"), get_fw_name(usb, fw_name, sizeof(fw_name), "ub"),
&udev->dev); &udev->dev);
if (r) if (r)
goto error; goto error;
@ -264,7 +267,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
dev_warn(&udev->dev, "device has old bootcode, please " dev_warn(&udev->dev, "device has old bootcode, please "
"report success or failure\n"); "report success or failure\n");
r = handle_version_mismatch(udev, device_type, ub_fw); r = handle_version_mismatch(usb, ub_fw);
if (r) if (r)
goto error; goto error;
} else { } else {
@ -275,7 +278,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
r = request_fw_file(&uph_fw, r = request_fw_file(&uph_fw,
get_fw_name(fw_name, sizeof(fw_name), device_type, "uphr"), get_fw_name(usb, fw_name, sizeof(fw_name), "uphr"),
&udev->dev); &udev->dev);
if (r) if (r)
goto error; goto error;
@ -294,6 +297,30 @@ error:
return r; return r;
} }
/* Read data from device address space using "firmware interface" which does
* not require firmware to be loaded. */
int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len)
{
int r;
struct usb_device *udev = zd_usb_to_usbdev(usb);
r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0,
data, len, 5000);
if (r < 0) {
dev_err(&udev->dev,
"read over firmware interface failed: %d\n", r);
return r;
} else if (r != len) {
dev_err(&udev->dev,
"incomplete read over firmware interface: %d/%d\n",
r, len);
return -EIO;
}
return 0;
}
#define urb_dev(urb) (&(urb)->dev->dev) #define urb_dev(urb) (&(urb)->dev->dev)
static inline void handle_regs_int(struct urb *urb) static inline void handle_regs_int(struct urb *urb)
@ -920,9 +947,42 @@ static int eject_installer(struct usb_interface *intf)
return 0; return 0;
} }
int zd_usb_init_hw(struct zd_usb *usb)
{
int r;
struct zd_mac *mac = zd_usb_to_mac(usb);
dev_dbg_f(zd_usb_dev(usb), "\n");
r = upload_firmware(usb);
if (r) {
dev_err(zd_usb_dev(usb),
"couldn't load firmware. Error number %d\n", r);
return r;
}
r = usb_reset_configuration(zd_usb_to_usbdev(usb));
if (r) {
dev_dbg_f(zd_usb_dev(usb),
"couldn't reset configuration. Error number %d\n", r);
return r;
}
r = zd_mac_init_hw(mac);
if (r) {
dev_dbg_f(zd_usb_dev(usb),
"couldn't initialize mac. Error number %d\n", r);
return r;
}
usb->initialized = 1;
return 0;
}
static int probe(struct usb_interface *intf, const struct usb_device_id *id) static int probe(struct usb_interface *intf, const struct usb_device_id *id)
{ {
int r; int r;
struct zd_usb *usb;
struct usb_device *udev = interface_to_usbdev(intf); struct usb_device *udev = interface_to_usbdev(intf);
struct net_device *netdev = NULL; struct net_device *netdev = NULL;
@ -950,26 +1010,10 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
goto error; goto error;
} }
r = upload_firmware(udev, id->driver_info); usb = &zd_netdev_mac(netdev)->chip.usb;
if (r) { usb->is_zd1211b = (id->driver_info == DEVICE_ZD1211B) != 0;
dev_err(&intf->dev,
"couldn't load firmware. Error number %d\n", r);
goto error;
}
r = usb_reset_configuration(udev); r = zd_mac_preinit_hw(zd_netdev_mac(netdev));
if (r) {
dev_dbg_f(&intf->dev,
"couldn't reset configuration. Error number %d\n", r);
goto error;
}
/* At this point the interrupt endpoint is not generally enabled. We
* save the USB bandwidth until the network device is opened. But
* notify that the initialization of the MAC will require the
* interrupts to be temporary enabled.
*/
r = zd_mac_init_hw(zd_netdev_mac(netdev), id->driver_info);
if (r) { if (r) {
dev_dbg_f(&intf->dev, dev_dbg_f(&intf->dev,
"couldn't initialize mac. Error number %d\n", r); "couldn't initialize mac. Error number %d\n", r);

View file

@ -188,6 +188,7 @@ struct zd_usb {
struct zd_usb_rx rx; struct zd_usb_rx rx;
struct zd_usb_tx tx; struct zd_usb_tx tx;
struct usb_interface *intf; struct usb_interface *intf;
u8 is_zd1211b:1, initialized:1;
}; };
#define zd_usb_dev(usb) (&usb->intf->dev) #define zd_usb_dev(usb) (&usb->intf->dev)
@ -236,6 +237,8 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits); int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits);
int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len);
extern struct workqueue_struct *zd_workqueue; extern struct workqueue_struct *zd_workqueue;
#endif /* _ZD_USB_H */ #endif /* _ZD_USB_H */

View file

@ -211,6 +211,10 @@ struct qeth_perf_stats {
/* initial values when measuring starts */ /* initial values when measuring starts */
unsigned long initial_rx_packets; unsigned long initial_rx_packets;
unsigned long initial_tx_packets; unsigned long initial_tx_packets;
/* inbound scatter gather data */
unsigned int sg_skbs_rx;
unsigned int sg_frags_rx;
unsigned int sg_alloc_page_rx;
}; };
/* Routing stuff */ /* Routing stuff */
@ -341,6 +345,9 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
#define QETH_IP_HEADER_SIZE 40 #define QETH_IP_HEADER_SIZE 40
/* large receive scatter gather copy break */
#define QETH_RX_SG_CB (PAGE_SIZE >> 1)
struct qeth_hdr_layer3 { struct qeth_hdr_layer3 {
__u8 id; __u8 id;
__u8 flags; __u8 flags;
@ -771,6 +778,7 @@ struct qeth_card_options {
int layer2; int layer2;
enum qeth_large_send_types large_send; enum qeth_large_send_types large_send;
int performance_stats; int performance_stats;
int rx_sg_cb;
}; };
/* /*
@ -828,6 +836,7 @@ struct qeth_card {
int (*orig_hard_header)(struct sk_buff *,struct net_device *, int (*orig_hard_header)(struct sk_buff *,struct net_device *,
unsigned short,void *,void *,unsigned); unsigned short,void *,void *,unsigned);
struct qeth_osn_info osn_info; struct qeth_osn_info osn_info;
atomic_t force_alloc_skb;
}; };
struct qeth_card_list_struct { struct qeth_card_list_struct {

View file

@ -1054,6 +1054,7 @@ qeth_set_intial_options(struct qeth_card *card)
else else
card->options.layer2 = 0; card->options.layer2 = 0;
card->options.performance_stats = 0; card->options.performance_stats = 0;
card->options.rx_sg_cb = QETH_RX_SG_CB;
} }
/** /**
@ -1934,6 +1935,7 @@ qeth_send_control_data(struct qeth_card *card, int len,
atomic_inc(&reply->received); atomic_inc(&reply->received);
wake_up(&reply->wait_q); wake_up(&reply->wait_q);
} }
cpu_relax();
}; };
rc = reply->rc; rc = reply->rc;
qeth_put_reply(reply); qeth_put_reply(reply);
@ -2258,6 +2260,89 @@ qeth_get_skb(unsigned int length, struct qeth_hdr *hdr)
return skb; return skb;
} }
static inline int
qeth_create_skb_frag(struct qdio_buffer_element *element,
struct sk_buff **pskb,
int offset, int *pfrag, int data_len)
{
struct page *page = virt_to_page(element->addr);
if (*pfrag == 0) {
/* the upper protocol layers assume that there is data in the
* skb itself. Copy a small amount (64 bytes) to make them
* happy. */
*pskb = dev_alloc_skb(64 + QETH_FAKE_LL_LEN_ETH);
if (!(*pskb))
return -ENOMEM;
skb_reserve(*pskb, QETH_FAKE_LL_LEN_ETH);
if (data_len <= 64) {
memcpy(skb_put(*pskb, data_len), element->addr + offset,
data_len);
} else {
get_page(page);
memcpy(skb_put(*pskb, 64), element->addr + offset, 64);
skb_fill_page_desc(*pskb, *pfrag, page, offset + 64,
data_len - 64);
(*pskb)->data_len += data_len - 64;
(*pskb)->len += data_len - 64;
(*pskb)->truesize += data_len - 64;
}
} else {
get_page(page);
skb_fill_page_desc(*pskb, *pfrag, page, offset, data_len);
(*pskb)->data_len += data_len;
(*pskb)->len += data_len;
(*pskb)->truesize += data_len;
}
(*pfrag)++;
return 0;
}
static inline struct qeth_buffer_pool_entry *
qeth_find_free_buffer_pool_entry(struct qeth_card *card)
{
struct list_head *plh;
struct qeth_buffer_pool_entry *entry;
int i, free;
struct page *page;
if (list_empty(&card->qdio.in_buf_pool.entry_list))
return NULL;
list_for_each(plh, &card->qdio.in_buf_pool.entry_list) {
entry = list_entry(plh, struct qeth_buffer_pool_entry, list);
free = 1;
for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) {
if (page_count(virt_to_page(entry->elements[i])) > 1) {
free = 0;
break;
}
}
if (free) {
list_del_init(&entry->list);
return entry;
}
}
/* no free buffer in pool so take first one and swap pages */
entry = list_entry(card->qdio.in_buf_pool.entry_list.next,
struct qeth_buffer_pool_entry, list);
for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) {
if (page_count(virt_to_page(entry->elements[i])) > 1) {
page = alloc_page(GFP_ATOMIC|GFP_DMA);
if (!page) {
return NULL;
} else {
free_page((unsigned long)entry->elements[i]);
entry->elements[i] = page_address(page);
if (card->options.performance_stats)
card->perf_stats.sg_alloc_page_rx++;
}
}
}
list_del_init(&entry->list);
return entry;
}
static struct sk_buff * static struct sk_buff *
qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
struct qdio_buffer_element **__element, int *__offset, struct qdio_buffer_element **__element, int *__offset,
@ -2269,6 +2354,8 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
int skb_len; int skb_len;
void *data_ptr; void *data_ptr;
int data_len; int data_len;
int use_rx_sg = 0;
int frag = 0;
QETH_DBF_TEXT(trace,6,"nextskb"); QETH_DBF_TEXT(trace,6,"nextskb");
/* qeth_hdr must not cross element boundaries */ /* qeth_hdr must not cross element boundaries */
@ -2293,23 +2380,43 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
if (!skb_len) if (!skb_len)
return NULL; return NULL;
if (card->options.fake_ll){ if ((skb_len >= card->options.rx_sg_cb) &&
if(card->dev->type == ARPHRD_IEEE802_TR){ (!(card->info.type == QETH_CARD_TYPE_OSN)) &&
if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR, *hdr))) (!atomic_read(&card->force_alloc_skb))) {
goto no_mem; use_rx_sg = 1;
skb_reserve(skb,QETH_FAKE_LL_LEN_TR); } else {
if (card->options.fake_ll) {
if (card->dev->type == ARPHRD_IEEE802_TR) {
if (!(skb = qeth_get_skb(skb_len +
QETH_FAKE_LL_LEN_TR, *hdr)))
goto no_mem;
skb_reserve(skb, QETH_FAKE_LL_LEN_TR);
} else {
if (!(skb = qeth_get_skb(skb_len +
QETH_FAKE_LL_LEN_ETH, *hdr)))
goto no_mem;
skb_reserve(skb, QETH_FAKE_LL_LEN_ETH);
}
} else { } else {
if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH, *hdr))) skb = qeth_get_skb(skb_len, *hdr);
if (!skb)
goto no_mem; goto no_mem;
skb_reserve(skb,QETH_FAKE_LL_LEN_ETH);
} }
} else if (!(skb = qeth_get_skb(skb_len, *hdr))) }
goto no_mem;
data_ptr = element->addr + offset; data_ptr = element->addr + offset;
while (skb_len) { while (skb_len) {
data_len = min(skb_len, (int)(element->length - offset)); data_len = min(skb_len, (int)(element->length - offset));
if (data_len) if (data_len) {
memcpy(skb_put(skb, data_len), data_ptr, data_len); if (use_rx_sg) {
if (qeth_create_skb_frag(element, &skb, offset,
&frag, data_len))
goto no_mem;
} else {
memcpy(skb_put(skb, data_len), data_ptr,
data_len);
}
}
skb_len -= data_len; skb_len -= data_len;
if (skb_len){ if (skb_len){
if (qeth_is_last_sbale(element)){ if (qeth_is_last_sbale(element)){
@ -2331,6 +2438,10 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
} }
*__element = element; *__element = element;
*__offset = offset; *__offset = offset;
if (use_rx_sg && card->options.performance_stats) {
card->perf_stats.sg_skbs_rx++;
card->perf_stats.sg_frags_rx += skb_shinfo(skb)->nr_frags;
}
return skb; return skb;
no_mem: no_mem:
if (net_ratelimit()){ if (net_ratelimit()){
@ -2608,28 +2719,15 @@ qeth_process_inbound_buffer(struct qeth_card *card,
} }
} }
static struct qeth_buffer_pool_entry * static int
qeth_get_buffer_pool_entry(struct qeth_card *card)
{
struct qeth_buffer_pool_entry *entry;
QETH_DBF_TEXT(trace, 6, "gtbfplen");
if (!list_empty(&card->qdio.in_buf_pool.entry_list)) {
entry = list_entry(card->qdio.in_buf_pool.entry_list.next,
struct qeth_buffer_pool_entry, list);
list_del_init(&entry->list);
return entry;
}
return NULL;
}
static void
qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
{ {
struct qeth_buffer_pool_entry *pool_entry; struct qeth_buffer_pool_entry *pool_entry;
int i; int i;
pool_entry = qeth_get_buffer_pool_entry(card); pool_entry = qeth_find_free_buffer_pool_entry(card);
if (!pool_entry)
return 1;
/* /*
* since the buffer is accessed only from the input_tasklet * since the buffer is accessed only from the input_tasklet
* there shouldn't be a need to synchronize; also, since we use * there shouldn't be a need to synchronize; also, since we use
@ -2648,6 +2746,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
buf->buffer->element[i].flags = 0; buf->buffer->element[i].flags = 0;
} }
buf->state = QETH_QDIO_BUF_EMPTY; buf->state = QETH_QDIO_BUF_EMPTY;
return 0;
} }
static void static void
@ -2682,6 +2781,7 @@ qeth_queue_input_buffer(struct qeth_card *card, int index)
int count; int count;
int i; int i;
int rc; int rc;
int newcount = 0;
QETH_DBF_TEXT(trace,6,"queinbuf"); QETH_DBF_TEXT(trace,6,"queinbuf");
count = (index < queue->next_buf_to_init)? count = (index < queue->next_buf_to_init)?
@ -2692,9 +2792,27 @@ qeth_queue_input_buffer(struct qeth_card *card, int index)
/* only requeue at a certain threshold to avoid SIGAs */ /* only requeue at a certain threshold to avoid SIGAs */
if (count >= QETH_IN_BUF_REQUEUE_THRESHOLD(card)){ if (count >= QETH_IN_BUF_REQUEUE_THRESHOLD(card)){
for (i = queue->next_buf_to_init; for (i = queue->next_buf_to_init;
i < queue->next_buf_to_init + count; ++i) i < queue->next_buf_to_init + count; ++i) {
qeth_init_input_buffer(card, if (qeth_init_input_buffer(card,
&queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]); &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q])) {
break;
} else {
newcount++;
}
}
if (newcount < count) {
/* we are in memory shortage so we switch back to
traditional skb allocation and drop packages */
if (atomic_cmpxchg(&card->force_alloc_skb, 0, 1))
printk(KERN_WARNING
"qeth: switch to alloc skb\n");
count = newcount;
} else {
if (atomic_cmpxchg(&card->force_alloc_skb, 1, 0))
printk(KERN_WARNING "qeth: switch to sg\n");
}
/* /*
* according to old code it should be avoided to requeue all * according to old code it should be avoided to requeue all
* 128 buffers in order to benefit from PCI avoidance. * 128 buffers in order to benefit from PCI avoidance.
@ -6494,6 +6612,7 @@ qeth_hardsetup_card(struct qeth_card *card)
QETH_DBF_TEXT(setup, 2, "hrdsetup"); QETH_DBF_TEXT(setup, 2, "hrdsetup");
atomic_set(&card->force_alloc_skb, 0);
retry: retry:
if (retries < 3){ if (retries < 3){
PRINT_WARN("Retrying to do IDX activates.\n"); PRINT_WARN("Retrying to do IDX activates.\n");

View file

@ -212,6 +212,12 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
" Skb fragments sent in SG mode : %u\n\n", " Skb fragments sent in SG mode : %u\n\n",
card->perf_stats.sg_skbs_sent, card->perf_stats.sg_skbs_sent,
card->perf_stats.sg_frags_sent); card->perf_stats.sg_frags_sent);
seq_printf(s, " Skbs received in SG mode : %u\n"
" Skb fragments received in SG mode : %u\n"
" Page allocations for rx SG mode : %u\n\n",
card->perf_stats.sg_skbs_rx,
card->perf_stats.sg_frags_rx,
card->perf_stats.sg_alloc_page_rx);
seq_printf(s, " large_send tx (in Kbytes) : %u\n" seq_printf(s, " large_send tx (in Kbytes) : %u\n"
" large_send count : %u\n\n", " large_send count : %u\n\n",
card->perf_stats.large_send_bytes >> 10, card->perf_stats.large_send_bytes >> 10,

View file

@ -64,6 +64,7 @@ extern void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
/* Ethernet (EMAC & MACB) */ /* Ethernet (EMAC & MACB) */
struct at91_eth_data { struct at91_eth_data {
u32 phy_mask;
u8 phy_irq_pin; /* PHY IRQ */ u8 phy_irq_pin; /* PHY IRQ */
u8 is_rmii; /* using RMII interface? */ u8 is_rmii; /* using RMII interface? */
}; };

View file

@ -21,6 +21,7 @@ void at32_map_usart(unsigned int hw_id, unsigned int line);
struct platform_device *at32_add_device_usart(unsigned int id); struct platform_device *at32_add_device_usart(unsigned int id);
struct eth_platform_data { struct eth_platform_data {
u32 phy_mask;
u8 is_rmii; u8 is_rmii;
}; };
struct platform_device * struct platform_device *

View file

@ -271,8 +271,11 @@ ieee80211softmac_assoc_work(struct work_struct *work)
*/ */
dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n"); dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n");
ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL); ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL);
if (ieee80211softmac_start_scan(mac)) if (ieee80211softmac_start_scan(mac)) {
dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n"); dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n");
mac->associnfo.associating = 0;
mac->associnfo.associated = 0;
}
goto out; goto out;
} else { } else {
mac->associnfo.associating = 0; mac->associnfo.associating = 0;