Commit 5bcaa155 authored by Linus Torvalds's avatar Linus Torvalds

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

parents 1e231efe 3a48c4c2
......@@ -397,7 +397,7 @@ config SUN3LANCE
If you're not building a kernel for a Sun 3, say N.
config SUN3_82586
tristate "Sun3 on-board Intel 82586 support"
bool "Sun3 on-board Intel 82586 support"
depends on NET_ETHERNET && SUN3
help
This driver enables support for the on-board Intel 82586 based
......@@ -1924,12 +1924,15 @@ config R8169_VLAN
If in doubt, say Y.
config SIS190
tristate "SiS190 gigabit ethernet support"
tristate "SiS190/SiS191 gigabit ethernet support"
depends on PCI
select CRC32
select MII
---help---
Say Y here if you have a SiS 190 PCI Gigabit Ethernet adapter.
Say Y here if you have a SiS 190 PCI Fast Ethernet adapter or
a SiS 191 PCI Gigabit Ethernet adapter. Both are expected to
appear in lan on motherboard designs which are based on SiS 965
and SiS 966 south bridge.
To compile this driver as a module, choose M here: the module
will be called sis190. This is recommended.
......
......@@ -88,7 +88,7 @@ struct t1_rx_mode {
static inline u8 *t1_get_next_mcaddr(struct t1_rx_mode *rm)
{
u8 *addr = 0;
u8 *addr = NULL;
if (rm->idx++ < rm->dev->mc_count) {
addr = rm->list->dmi_addr;
......@@ -190,7 +190,7 @@ struct sge;
struct peespi;
struct adapter {
u8 *regs;
u8 __iomem *regs;
struct pci_dev *pdev;
unsigned long registered_device_map;
unsigned long open_device_map;
......
......@@ -824,7 +824,7 @@ static void cxgb_proc_cleanup(struct adapter *adapter,
static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
{
struct adapter *adapter = dev->priv;
struct mii_ioctl_data *data = (struct mii_ioctl_data *)&req->ifr_data;
struct mii_ioctl_data *data = if_mii(req);
switch (cmd) {
case SIOCGMIIPHY:
......
......@@ -1270,7 +1270,7 @@ struct e1000_hw_stats {
/* Structure containing variables used by the shared code (e1000_hw.c) */
struct e1000_hw {
uint8_t *hw_addr;
uint8_t __iomem *hw_addr;
uint8_t *flash_address;
e1000_mac_type mac_type;
e1000_phy_type phy_type;
......
......@@ -58,11 +58,10 @@
#define INT_CAUSE_UNMASK_ALL 0x0007ffff
#define INT_CAUSE_UNMASK_ALL_EXT 0x0011ffff
#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK
#define INT_CAUSE_MASK_ALL 0x00000000
#define INT_CAUSE_MASK_ALL_EXT 0x00000000
#define INT_CAUSE_CHECK_BITS INT_CAUSE_UNMASK_ALL
#define INT_CAUSE_CHECK_BITS_EXT INT_CAUSE_UNMASK_ALL_EXT
#endif
#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
#define MAX_DESCS_PER_SKB (MAX_SKB_FRAGS + 1)
......@@ -259,14 +258,13 @@ static void mv643xx_eth_update_mac_address(struct net_device *dev)
static void mv643xx_eth_set_rx_mode(struct net_device *dev)
{
struct mv643xx_private *mp = netdev_priv(dev);
u32 config_reg;
config_reg = ethernet_get_config_reg(mp->port_num);
if (dev->flags & IFF_PROMISC)
config_reg |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
mp->port_config |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
else
config_reg &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
ethernet_set_config_reg(mp->port_num, config_reg);
mp->port_config &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
mv_write(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num), mp->port_config);
}
/*
......@@ -369,15 +367,6 @@ static int mv643xx_eth_free_tx_queue(struct net_device *dev,
dev_kfree_skb_irq(pkt_info.return_info);
released = 0;
/*
* Decrement the number of outstanding skbs counter on
* the TX queue.
*/
if (mp->tx_ring_skbs == 0)
panic("ERROR - TX outstanding SKBs"
" counter is corrupted");
mp->tx_ring_skbs--;
} else
dma_unmap_page(NULL, pkt_info.buf_ptr,
pkt_info.byte_cnt, DMA_TO_DEVICE);
......@@ -412,15 +401,13 @@ static int mv643xx_eth_receive_queue(struct net_device *dev)
struct pkt_info pkt_info;
#ifdef MV643XX_NAPI
while (eth_port_receive(mp, &pkt_info) == ETH_OK && budget > 0) {
while (budget-- > 0 && eth_port_receive(mp, &pkt_info) == ETH_OK) {
#else
while (eth_port_receive(mp, &pkt_info) == ETH_OK) {
#endif
mp->rx_ring_skbs--;
received_packets++;
#ifdef MV643XX_NAPI
budget--;
#endif
/* Update statistics. Note byte count includes 4 byte CRC count */
stats->rx_packets++;
stats->rx_bytes += pkt_info.byte_cnt;
......@@ -1044,9 +1031,6 @@ static void mv643xx_tx(struct net_device *dev)
DMA_TO_DEVICE);
dev_kfree_skb_irq(pkt_info.return_info);
if (mp->tx_ring_skbs)
mp->tx_ring_skbs--;
} else
dma_unmap_page(NULL, pkt_info.buf_ptr,
pkt_info.byte_cnt, DMA_TO_DEVICE);
......@@ -1189,7 +1173,6 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len,
DMA_TO_DEVICE);
pkt_info.return_info = skb;
mp->tx_ring_skbs++;
status = eth_port_send(mp, &pkt_info);
if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
printk(KERN_ERR "%s: Error on transmitting packet\n",
......@@ -1274,7 +1257,6 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT |
ETH_TX_LAST_DESC;
pkt_info.return_info = skb;
mp->tx_ring_skbs++;
} else {
pkt_info.return_info = 0;
}
......@@ -1311,7 +1293,6 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len,
DMA_TO_DEVICE);
pkt_info.return_info = skb;
mp->tx_ring_skbs++;
status = eth_port_send(mp, &pkt_info);
if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
printk(KERN_ERR "%s: Error on transmitting packet\n",
......@@ -1356,6 +1337,43 @@ static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev)
return &mp->stats;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
static inline void mv643xx_enable_irq(struct mv643xx_private *mp)
{
int port_num = mp->port_num;
unsigned long flags;
spin_lock_irqsave(&mp->lock, flags);
mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
INT_CAUSE_UNMASK_ALL);
mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
INT_CAUSE_UNMASK_ALL_EXT);
spin_unlock_irqrestore(&mp->lock, flags);
}
static inline void mv643xx_disable_irq(struct mv643xx_private *mp)
{
int port_num = mp->port_num;
unsigned long flags;
spin_lock_irqsave(&mp->lock, flags);
mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
INT_CAUSE_MASK_ALL);
mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
INT_CAUSE_MASK_ALL_EXT);
spin_unlock_irqrestore(&mp->lock, flags);
}
static void mv643xx_netpoll(struct net_device *netdev)
{
struct mv643xx_private *mp = netdev_priv(netdev);
mv643xx_disable_irq(mp);
mv643xx_eth_int_handler(netdev->irq, netdev, NULL);
mv643xx_enable_irq(mp);
}
#endif
/*/
* mv643xx_eth_probe
*
......@@ -1406,6 +1424,10 @@ static int mv643xx_eth_probe(struct device *ddev)
dev->weight = 64;
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = mv643xx_netpoll;
#endif
dev->watchdog_timeo = 2 * HZ;
dev->tx_queue_len = mp->tx_ring_size;
dev->base_addr = 0;
......@@ -1883,6 +1905,9 @@ static void eth_port_start(struct mv643xx_private *mp)
/* Enable port Rx. */
mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
mp->port_rx_queue_command);
/* Disable port bandwidth limits by clearing MTU register */
mv_write(MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port_num), 0);
}
/*
......@@ -2292,34 +2317,6 @@ static void eth_port_reset(unsigned int port_num)
mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), reg_data);
}
/*
* ethernet_set_config_reg - Set specified bits in configuration register.
*
* DESCRIPTION:
* This function sets specified bits in the given ethernet
* configuration register.
*
* INPUT:
* unsigned int eth_port_num Ethernet Port number.
* unsigned int value 32 bit value.
*
* OUTPUT:
* The set bits in the value parameter are set in the configuration
* register.
*
* RETURN:
* None.
*
*/
static void ethernet_set_config_reg(unsigned int eth_port_num,
unsigned int value)
{
unsigned int eth_config_reg;
eth_config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_REG(eth_port_num));
eth_config_reg |= value;
mv_write(MV643XX_ETH_PORT_CONFIG_REG(eth_port_num), eth_config_reg);
}
static int eth_port_autoneg_supported(unsigned int eth_port_num)
{
......@@ -2345,31 +2342,6 @@ static int eth_port_link_is_up(unsigned int eth_port_num)
return 0;
}
/*
* ethernet_get_config_reg - Get the port configuration register
*
* DESCRIPTION:
* This function returns the configuration register value of the given
* ethernet port.
*
* INPUT:
* unsigned int eth_port_num Ethernet Port number.
*
* OUTPUT:
* None.
*
* RETURN:
* Port configuration register value.
*/
static unsigned int ethernet_get_config_reg(unsigned int eth_port_num)
{
unsigned int eth_config_reg;
eth_config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_EXTEND_REG
(eth_port_num));
return eth_config_reg;
}
/*
* eth_port_read_smi_reg - Read PHY registers
*
......@@ -2528,6 +2500,9 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
return ETH_ERROR;
}
mp->tx_ring_skbs++;
BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size);
/* Get the Tx Desc ring indexes */
tx_desc_curr = mp->tx_curr_desc_q;
tx_desc_used = mp->tx_used_desc_q;
......@@ -2594,6 +2569,9 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
if (mp->tx_resource_err)
return ETH_QUEUE_FULL;
mp->tx_ring_skbs++;
BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size);
/* Get the Tx Desc ring indexes */
tx_desc_curr = mp->tx_curr_desc_q;
tx_desc_used = mp->tx_used_desc_q;
......@@ -2694,6 +2672,9 @@ static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp,
/* Any Tx return cancels the Tx resource error status */
mp->tx_resource_err = 0;
BUG_ON(mp->tx_ring_skbs == 0);
mp->tx_ring_skbs--;
return ETH_OK;
}
......
......@@ -408,10 +408,6 @@ static void eth_port_init(struct mv643xx_private *mp);
static void eth_port_reset(unsigned int eth_port_num);
static void eth_port_start(struct mv643xx_private *mp);
static void ethernet_set_config_reg(unsigned int eth_port_num,
unsigned int value);
static unsigned int ethernet_get_config_reg(unsigned int eth_port_num);
/* Port MAC address routines */
static void eth_port_uc_addr_set(unsigned int eth_port_num,
unsigned char *p_addr);
......
......@@ -26,9 +26,6 @@
Updated to EISA probing API 5/2003 by Marc Zyngier.
*/
static const char *version =
"ne3210.c: Driver revision v0.03, 30/09/98\n";
#include <linux/module.h>
#include <linux/eisa.h>
#include <linux/kernel.h>
......@@ -197,7 +194,7 @@ static int __init ne3210_eisa_probe (struct device *device)
ei_status.priv = phys_mem;
if (ei_debug > 0)
printk(version);
printk("ne3210 loaded.\n");
ei_status.reset_8390 = &ne3210_reset_8390;
ei_status.block_input = &ne3210_block_input;
......@@ -360,12 +357,12 @@ MODULE_DESCRIPTION("NE3210 EISA Ethernet driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(eisa, ne3210_ids);
int ne3210_init(void)
static int ne3210_init(void)
{
return eisa_driver_register (&ne3210_eisa_driver);
}
void ne3210_cleanup(void)
static void ne3210_cleanup(void)
{
eisa_driver_unregister (&ne3210_eisa_driver);
}
......
......@@ -6,7 +6,7 @@ menu "PHY device support"
config PHYLIB
tristate "PHY Device support and infrastructure"
depends on NET_ETHERNET
depends on NET_ETHERNET && (BROKEN || !ARCH_S390)
help
Ethernet controllers are usually attached to PHY
devices. This option provides infrastructure for
......
......@@ -170,7 +170,7 @@ int __init mdio_bus_init(void)
return bus_register(&mdio_bus_type);
}
void __exit mdio_bus_exit(void)
void mdio_bus_exit(void)
{
bus_unregister(&mdio_bus_type);
}
......@@ -686,7 +686,7 @@ static void free_shared_mem(struct s2io_nic *nic)
static int s2io_verify_pci_mode(nic_t *nic)
{
XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
XENA_dev_config_t __iomem *bar0 = nic->bar0;
register u64 val64 = 0;
int mode;
......@@ -704,7 +704,7 @@ static int s2io_verify_pci_mode(nic_t *nic)
*/
static int s2io_print_pci_mode(nic_t *nic)
{
XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
XENA_dev_config_t __iomem *bar0 = nic->bar0;
register u64 val64 = 0;
int mode;
struct config_param *config = &nic->config;
......@@ -1403,7 +1403,7 @@ static int init_nic(struct s2io_nic *nic)
writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7);
/* Disable RMAC PAD STRIPPING */
add = (void *) &bar0->mac_cfg;
add = &bar0->mac_cfg;
val64 = readq(&bar0->mac_cfg);
val64 &= ~(MAC_CFG_RMAC_STRIP_PAD);
writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
......@@ -1934,7 +1934,7 @@ static int start_nic(struct s2io_nic *nic)
val64 |= 0x0000800000000000ULL;
writeq(val64, &bar0->gpio_control);
val64 = 0x0411040400000000ULL;
writeq(val64, (void __iomem *) ((u8 *) bar0 + 0x2700));
writeq(val64, (void __iomem *)bar0 + 0x2700);
}
/*
......@@ -2395,7 +2395,7 @@ static int s2io_poll(struct net_device *dev, int *budget)
int pkt_cnt = 0, org_pkts_to_process;
mac_info_t *mac_control;
struct config_param *config;
XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
XENA_dev_config_t __iomem *bar0 = nic->bar0;
u64 val64;
int i;
......@@ -2831,7 +2831,7 @@ void s2io_reset(nic_t * sp)
val64 |= 0x0000800000000000ULL;
writeq(val64, &bar0->gpio_control);
val64 = 0x0411040400000000ULL;
writeq(val64, (void __iomem *) ((u8 *) bar0 + 0x2700));
writeq(val64, (void __iomem *)bar0 + 0x2700);
}
/*
......@@ -3234,7 +3234,7 @@ s2io_alarm_handle(unsigned long data)
static void s2io_txpic_intr_handle(nic_t *sp)
{
XENA_dev_config_t *bar0 = (XENA_dev_config_t *) sp->bar0;
XENA_dev_config_t __iomem *bar0 = sp->bar0;
u64 val64;
val64 = readq(&bar0->pic_int_status);
......
......@@ -179,14 +179,6 @@ enum sis190_register_content {
TxInterFrameGapShift = 24,
TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
/* StationControl */
_1000bpsF = 0x1c00,
_1000bpsH = 0x0c00,
_100bpsF = 0x1800,
_100bpsH = 0x0800,
_10bpsF = 0x1400,
_10bpsH = 0x0400,
LinkStatus = 0x02, // unused
FullDup = 0x01, // unused
......@@ -279,6 +271,12 @@ enum sis190_eeprom_address {
EEPROMMACAddr = 0x03
};
enum sis190_feature {
F_HAS_RGMII = 1,
F_PHY_88E1111 = 2,
F_PHY_BCM5461 = 4
};
struct sis190_private {
void __iomem *mmio_addr;
struct pci_dev *pci_dev;
......@@ -300,6 +298,7 @@ struct sis190_private {
u32 msg_enable;
struct mii_if_info mii_if;
struct list_head first_phy;
u32 features;
};
struct sis190_phy {
......@@ -321,24 +320,25 @@ static struct mii_chip_info {
const char *name;
u16 id[2];
unsigned int type;
u32 feature;
} mii_chip_table[] = {
{ "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN },
{ "Agere PHY ET1101B", { 0x0282, 0xf010 }, LAN },
{ "Marvell PHY 88E1111", { 0x0141, 0x0cc0 }, LAN },
{ "Realtek PHY RTL8201", { 0x0000, 0x8200 }, LAN },
{ "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN, F_PHY_BCM5461 },
{ "Agere PHY ET1101B", { 0x0282, 0xf010 }, LAN, 0 },
{ "Marvell PHY 88E1111", { 0x0141, 0x0cc0 }, LAN, F_PHY_88E1111 },
{ "Realtek PHY RTL8201", { 0x0000, 0x8200 }, LAN, 0 },
{ NULL, }
};
const static struct {
const char *name;
u8 version; /* depend on docs */
u32 RxConfigMask; /* clear the bits supported by this chip */
} sis_chip_info[] = {
{ DRV_NAME, 0x00, 0xff7e1880, },
{ "SiS 190 PCI Fast Ethernet adapter" },
{ "SiS 191 PCI Gigabit Ethernet adapter" },
};
static struct pci_device_id sis190_pci_tbl[] __devinitdata = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0190), 0, 0, 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0191), 0, 0, 1 },
{ 0, },
};
......@@ -360,7 +360,7 @@ MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
static const u32 sis190_intr_mask =
RxQEmpty | RxQInt | TxQ1Int | TxQ0Int | RxHalt | TxHalt;
RxQEmpty | RxQInt | TxQ1Int | TxQ0Int | RxHalt | TxHalt | LinkChange;
/*
* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
......@@ -879,11 +879,6 @@ static void sis190_hw_start(struct net_device *dev)
SIS_W32(IntrStatus, 0xffffffff);
SIS_W32(IntrMask, 0x0);
/*
* Default is 100Mbps.
* A bit strange: 100Mbps is 0x1801 elsewhere -- FR 2005/06/09
*/
SIS_W16(StationControl, 0x1901);
SIS_W32(GMIIControl, 0x0);
SIS_W32(TxMacControl, 0x60);
SIS_W16(RxMacControl, 0x02);
......@@ -923,35 +918,30 @@ static void sis190_phy_task(void * data)
BMSR_ANEGCOMPLETE)) {
net_link(tp, KERN_WARNING "%s: PHY reset until link up.\n",
dev->name);
netif_carrier_off(dev);
mdio_write(ioaddr, phy_id, MII_BMCR, val | BMCR_RESET);
mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT);
} else {
/* Rejoice ! */
struct {
int val;
u32 ctl;
const char *msg;
u16 ctl;
} reg31[] = {
{ LPA_1000XFULL | LPA_SLCT,
"1000 Mbps Full Duplex",
0x01 | _1000bpsF },
{ LPA_1000XHALF | LPA_SLCT,
"1000 Mbps Half Duplex",
0x01 | _1000bpsH },
{ LPA_100FULL,
"100 Mbps Full Duplex",
0x01 | _100bpsF },
{ LPA_100HALF,
"100 Mbps Half Duplex",
0x01 | _100bpsH },
{ LPA_10FULL,
"10 Mbps Full Duplex",
0x01 | _10bpsF },
{ LPA_10HALF,
"10 Mbps Half Duplex",
0x01 | _10bpsH },
{ 0, "unknown", 0x0000 }
}, *p;
{ LPA_1000XFULL | LPA_SLCT, 0x07000c00 | 0x00001000,
"1000 Mbps Full Duplex" },
{ LPA_1000XHALF | LPA_SLCT, 0x07000c00,
"1000 Mbps Half Duplex" },
{ LPA_100FULL, 0x04000800 | 0x00001000,
"100 Mbps Full Duplex" },
{ LPA_100HALF, 0x04000800,
"100 Mbps Half Duplex" },
{ LPA_10FULL, 0x04000400 | 0x00001000,
"10 Mbps Full Duplex" },
{ LPA_10HALF, 0x04000400,
"10 Mbps Half Duplex" },
{ 0, 0x04000400, "unknown" }
}, *p;
u16 adv;
val = mdio_read(ioaddr, phy_id, 0x1f);
......@@ -964,12 +954,29 @@ static void sis190_phy_task(void * data)
val &= adv;
for (p = reg31; p->ctl; p++) {
for (p = reg31; p->val; p++) {
if ((val & p->val) == p->val)
break;
}
if (p->ctl)
SIS_W16(StationControl, p->ctl);
p->ctl |= SIS_R32(StationControl) & ~0x0f001c00;
if ((tp->features & F_HAS_RGMII) &&
(tp->features & F_PHY_BCM5461)) {
// Set Tx Delay in RGMII mode.
mdio_write(ioaddr, phy_id, 0x18, 0xf1c7);
udelay(200);
mdio_write(ioaddr, phy_id, 0x1c, 0x8c00);
p->ctl |= 0x03000000;
}
SIS_W32(StationControl, p->ctl);
if (tp->features & F_HAS_RGMII) {
SIS_W32(RGDelay, 0x0441);
SIS_W32(RGDelay, 0x0440);
}
net_link(tp, KERN_INFO "%s: link on %s mode.\n", dev->name,
p->msg);
netif_carrier_on(dev);
......@@ -1308,6 +1315,7 @@ static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp,
phy->type = (p->type == MIX) ?
((mii_status & (BMSR_100FULL | BMSR_100HALF)) ?
LAN : HOME) : p->type;
tp->features |= p->feature;
} else
phy->type = UNKNOWN;
......@@ -1316,6 +1324,25 @@ static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp,
(phy->type == UNKNOWN) ? "Unknown PHY" : p->name, phy_id);
}
static void sis190_mii_probe_88e1111_fixup(struct sis190_private *tp)
{
if (tp->features & F_PHY_88E1111) {
void __iomem *ioaddr = tp->mmio_addr;
int phy_id = tp->mii_if.phy_id;
u16 reg[2][2] = {
{ 0x808b, 0x0ce1 },
{ 0x808f, 0x0c60 }
}, *p;
p = (tp->features & F_HAS_RGMII) ? reg[0] : reg[1];
mdio_write(ioaddr, phy_id, 0x1b, p[0]);
udelay(200);
mdio_write(ioaddr, phy_id, 0x14, p[1]);
udelay(200);
}
}
/**
* sis190_mii_probe - Probe MII PHY for sis190
* @dev: the net device to probe for
......@@ -1366,6 +1393,8 @@ static int __devinit sis190_mii_probe(struct net_device *dev)
/* Select default PHY for mac */
sis190_default_phy(dev);
sis190_mii_probe_88e1111_fixup(tp);
mii_if->dev = dev;
mii_if->mdio_read = __mdio_read;
mii_if->mdio_write = __mdio_write;
......@@ -1505,6 +1534,11 @@ static void sis190_tx_timeout(struct net_device *dev)
netif_wake_queue(dev);
}
static void sis190_set_rgmii(struct sis190_private *tp, u8 reg)
{
tp->features |= (reg & 0x80) ? F_HAS_RGMII : 0;
}
static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev,
struct net_device *dev)
{
......@@ -1532,6 +1566,8 @@ static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev,
((u16 *)dev->dev_addr)[0] = le16_to_cpu(w);
}
sis190_set_rgmii(tp, sis190_read_eeprom(ioaddr, EEPROMInfo));
return 0;
}
......@@ -1577,6 +1613,8 @@ static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev,
outb(0x12, 0x78);
reg = inb(0x79);
sis190_set_rgmii(tp, reg);
/* Restore the value to ISA Bridge */
pci_write_config_byte(isa_bridge, 0x48, tmp8);
pci_dev_put(isa_bridge);
......@@ -1799,6 +1837,9 @@ static int __devinit sis190_init_one(struct pci_dev *pdev,
dev->dev_addr[2], dev->dev_addr[3],
dev->dev_addr[4], dev->dev_addr[5]);
net_probe(tp, KERN_INFO "%s: %s mode.\n", dev->name,
(tp->features & F_HAS_RGMII) ? "RGMII" : "GMII");
netif_carrier_off(dev);
sis190_set_speed_auto(dev);
......
......@@ -21,7 +21,6 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
......@@ -34,6 +33,7 @@
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
#include <asm/processor.h>
#include <asm/bitops.h>
......
......@@ -289,8 +289,8 @@ config APPLE_AIRPORT
a non-standard interface
config PLX_HERMES
tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.) (EXPERIMENTAL)"
depends on PCI && HERMES && EXPERIMENTAL
tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)"
depends on PCI && HERMES
help
Enable support for PCMCIA cards supported by the "Hermes" (aka
orinoco) driver when used in PLX9052 based PCI adaptors. These
......@@ -299,12 +299,9 @@ config PLX_HERMES
802.11b PCMCIA cards can be used in desktop machines. The Netgear
MA301 is such an adaptor.
Support for these adaptors is so far still incomplete and buggy.
You have been warned.
config TMD_HERMES
tristate "Hermes in TMD7160 based PCI adaptor support (EXPERIMENTAL)"
depends on PCI && HERMES && EXPERIMENTAL
tristate "Hermes in TMD7160 based PCI adaptor support"
depends on PCI && HERMES
help
Enable support for PCMCIA cards supported by the "Hermes" (aka
orinoco) driver when used in TMD7160 based PCI adaptors. These
......@@ -312,12 +309,18 @@ config TMD_HERMES
PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
802.11b PCMCIA cards can be used in desktop machines.
Support for these adaptors is so far still incomplete and buggy.
You have been warned.
config NORTEL_HERMES
tristate "Nortel emobility PCI adaptor support"
depends on PCI && HERMES
help
Enable support for PCMCIA cards supported by the "Hermes" (aka
orinoco) driver when used in Nortel emobility PCI adaptors. These
adaptors are not full PCMCIA controllers, but act as a more limited
PCI <-> PCMCIA bridge.
config PCI_HERMES
tristate "Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)"
depends on PCI && HERMES && EXPERIMENTAL
tristate "Prism 2.5 PCI 802.11b adaptor support"
depends on PCI && HERMES
help
Enable support for PCI and mini-PCI 802.11b wireless NICs based on
the Prism 2.5 chipset. These are true PCI cards, not the 802.11b
......@@ -372,6 +375,19 @@ config PCMCIA_HERMES
configure your card and that /etc/pcmcia/wireless.opts works:
<http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
config PCMCIA_SPECTRUM
tristate "Symbol Spectrum24 Trilogy PCMCIA card support"
depends on NET_RADIO && PCMCIA && HERMES
---help---
This is a driver for 802.11b cards using RAM-loadable Symbol
firmware, such as Symbol Wireless Networker LA4100, CompactFlash
cards by Socket Communications and Intel PRO/Wireless 2011B.
This driver requires firmware download on startup. Utilities
for downloading Symbol firmware are available at
<http://sourceforge.net/projects/orinoco/>
config AIRO_CS
tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
depends on NET_RADIO && PCMCIA && (BROKEN || !M32R)
......
......@@ -22,6 +22,8 @@ obj-$(CONFIG_APPLE_AIRPORT) += airport.o
obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o
obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o
obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o
obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o
obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o
obj-$(CONFIG_AIRO) += airo.o
obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o
......
......@@ -327,38 +327,38 @@ static struct iw_handler_def ipw2100_wx_handler_def;
static inline void read_register(struct net_device *dev, u32 reg, u32 *val)
{
*val = readl((void *)(dev->base_addr + reg));
*val = readl((void __iomem *)(dev->base_addr + reg));
IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val);
}
static inline void write_register(struct net_device *dev, u32 reg, u32 val)
{
writel(val, (void *)(dev->base_addr + reg));
writel(val, (void __iomem *)(dev->base_addr + reg));
IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val);
}
static inline void read_register_word(struct net_device *dev, u32 reg, u16 *val)
{
*val = readw((void *)(dev->base_addr + reg));
*val = readw((void __iomem *)(dev->base_addr + reg));
IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val);
}
static inline void read_register_byte(struct net_device *dev, u32 reg, u8 *val)
{
*val = readb((void *)(dev->base_addr + reg));
*val = readb((void __iomem *)(dev->base_addr + reg));
IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val);
}
static inline void write_register_word(struct net_device *dev, u32 reg, u16 val)
{
writew(val, (void *)(dev->base_addr + reg));
writew(val, (void __iomem *)(dev->base_addr + reg));
IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val);
}
static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val)
{
writeb(val, (void *)(dev->base_addr + reg));
writeb(val, (void __iomem *)(dev->base_addr + reg));
IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val);
}
......@@ -498,7 +498,7 @@ static inline void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev)
{
return (dev->base_addr &&
(readl((void *)(dev->base_addr + IPW_REG_DOA_DEBUG_AREA_START))
(readl((void __iomem *)(dev->base_addr + IPW_REG_DOA_DEBUG_AREA_START))
== IPW_DATA_DOA_DEBUG_VALUE));
}
......@@ -2125,19 +2125,19 @@ static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status)
}
static const struct ipw2100_status_indicator status_handlers[] = {
IPW2100_HANDLER(IPW_STATE_INITIALIZED, 0),
IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, 0),
IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL),
IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL),
IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated),
IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost),
IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, 0),
IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL),
IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete),
IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, 0),
IPW2100_HANDLER(IPW_STATE_LEFT_PSP, 0),
IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL),
IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL),
IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill),
IPW2100_HANDLER(IPW_STATE_DISABLED, 0),
IPW2100_HANDLER(IPW_STATE_POWER_DOWN, 0),
IPW2100_HANDLER(IPW_STATE_DISABLED, NULL),
IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL),
IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning),
IPW2100_HANDLER(-1, 0)
IPW2100_HANDLER(-1, NULL)
};
......@@ -6327,7 +6327,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv);
static struct net_device *ipw2100_alloc_device(
struct pci_dev *pci_dev,
char *base_addr,
void __iomem *base_addr,
unsigned long mem_start,
unsigned long mem_len)
{
......@@ -6474,7 +6474,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
const struct pci_device_id *ent)
{
unsigned long mem_start, mem_len, mem_flags;
char *base_addr = NULL;
void __iomem *base_addr = NULL;
struct net_device *dev = NULL;
struct ipw2100_priv *priv = NULL;
int err = 0;
......@@ -6664,7 +6664,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
}
if (base_addr)
iounmap((char*)base_addr);
iounmap(base_addr);
pci_release_regions(pci_dev);
pci_disable_device(pci_dev);
......@@ -6714,7 +6714,7 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
free_irq(dev->irq, priv);
if (dev->base_addr)
iounmap((unsigned char *)dev->base_addr);
iounmap((void __iomem *)dev->base_addr);
free_ieee80211(dev);
}
......@@ -8574,6 +8574,7 @@ static int ipw2100_ucode_download(struct ipw2100_priv *priv,
struct net_device *dev = priv->net_dev;
const unsigned char *microcode_data = fw->uc.data;
unsigned int microcode_data_left = fw->uc.size;
void __iomem *reg = (void __iomem *)dev->base_addr;
struct symbol_alive_response response;
int i, j;
......@@ -8581,23 +8582,23 @@ static int ipw2100_ucode_download(struct ipw2100_priv *priv,
/* Symbol control */
write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
readl((void *)(dev->base_addr));
readl(reg);
write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
readl((void *)(dev->base_addr));
readl(reg);
/* HW config */
write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
readl((void *)(dev->base_addr));
readl(reg);
write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
readl((void *)(dev->base_addr));
readl(reg);
/* EN_CS_ACCESS bit to reset control store pointer */
write_nic_byte(dev, 0x210000, 0x40);
readl((void *)(dev->base_addr));
readl(reg);
write_nic_byte(dev, 0x210000, 0x0);
readl((void *)(dev->base_addr));
readl(reg);
write_nic_byte(dev, 0x210000, 0x40);
readl((void *)(dev->base_addr));
readl(reg);
/* copy microcode from buffer into Symbol */
......@@ -8609,31 +8610,31 @@ static int ipw2100_ucode_download(struct ipw2100_priv *priv,
/* EN_CS_ACCESS bit to reset the control store pointer */
write_nic_byte(dev, 0x210000, 0x0);
readl((void *)(dev->base_addr));
readl(reg);
/* Enable System (Reg 0)
* first enable causes garbage in RX FIFO */
write_nic_byte(dev, 0x210000, 0x0);
readl((void *)(dev->base_addr));
readl(reg);
write_nic_byte(dev, 0x210000, 0x80);
readl((void *)(dev->base_addr));
readl(reg);
/* Reset External Baseband Reg */
write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
readl((void *)(dev->base_addr));
readl(reg);
write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
readl((void *)(dev->base_addr));
readl(reg);
/* HW Config (Reg 5) */
write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
readl((void *)(dev->base_addr));
readl(reg);
write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
readl((void *)(dev->base_addr));
readl(reg);
/* Enable System (Reg 0)
* second enable should be OK */
write_nic_byte(dev, 0x210000, 0x00); // clear enable system
readl((void *)(dev->base_addr));
readl(reg);
write_nic_byte(dev, 0x210000, 0x80); // set enable system
/* check Symbol is enabled - upped this from 5 as it wasn't always
......
......@@ -42,6 +42,7 @@
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/random.h>
#include <linux/dma-mapping.h>
#include <linux/firmware.h>
#include <linux/wireless.h>
......
......@@ -1053,8 +1053,9 @@ static void orinoco_join_ap(struct net_device *dev)
u16 channel;
} __attribute__ ((packed)) req;
const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
struct prism2_scan_apinfo *atom;
struct prism2_scan_apinfo *atom = NULL;
int offset = 4;
int found = 0;
u8 *buf;
u16 len;
......@@ -1089,15 +1090,18 @@ static void orinoco_join_ap(struct net_device *dev)
* we were requested to join */
for (; offset + atom_len <= len; offset += atom_len) {
atom = (struct prism2_scan_apinfo *) (buf + offset);
if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0)
goto found;
if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {
found = 1;
break;
}
}
DEBUG(1, "%s: Requested AP not found in scan results\n",
dev->name);
goto out;
if (! found) {
DEBUG(1, "%s: Requested AP not found in scan results\n",
dev->name);
goto out;
}
found:
memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
req.channel = atom->channel; /* both are little-endian */
err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
......@@ -1284,8 +1288,10 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
/* Read scan data */
err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
infofid, sizeof(info));
if (err)
if (err) {
kfree(buf);
break;
}
#ifdef ORINOCO_DEBUG
{
......@@ -4021,7 +4027,8 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
}
/* Translate scan data returned from the card to a card independant
* format that the Wireless Tools will understand - Jean II */
* format that the Wireless Tools will understand - Jean II
* Return message length or -errno for fatal errors */
static inline int orinoco_translate_scan(struct net_device *dev,
char *buffer,
char *scan,
......@@ -4061,13 +4068,19 @@ static inline int orinoco_translate_scan(struct net_device *dev,
break;
case FIRMWARE_TYPE_INTERSIL:
offset = 4;
if (priv->has_hostscan)
atom_len = scan[0] + (scan[1] << 8);
else
if (priv->has_hostscan) {
atom_len = le16_to_cpup((u16 *)scan);
/* Sanity check for atom_len */
if (atom_len < sizeof(struct prism2_scan_apinfo)) {
printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n",
dev->name, atom_len);
return -EIO;
}
} else
atom_len = offsetof(struct prism2_scan_apinfo, atim);
break;
default:
return 0;
return -EOPNOTSUPP;
}
/* Check that we got an whole number of atoms */
......@@ -4075,7 +4088,7 @@ static inline int orinoco_translate_scan(struct net_device *dev,
printk(KERN_ERR "%s: Unexpected scan data length %d, "
"atom_len %d, offset %d\n", dev->name, scan_len,
atom_len, offset);
return 0;
return -EIO;
}
/* Read the entries one by one */
......@@ -4210,33 +4223,41 @@ static int orinoco_ioctl_getscan(struct net_device *dev,
/* We have some results to push back to user space */
/* Translate to WE format */
srq->length = orinoco_translate_scan(dev, extra,
priv->scan_result,
priv->scan_len);
/* Return flags */
srq->flags = (__u16) priv->scan_mode;
int ret = orinoco_translate_scan(dev, extra,
priv->scan_result,
priv->scan_len);
if (ret < 0) {
err = ret;
kfree(priv->scan_result);
priv->scan_result = NULL;
} else {
srq->length = ret;
/* Results are here, so scan no longer in progress */
priv->scan_inprogress = 0;
/* Return flags */
srq->flags = (__u16) priv->scan_mode;
/* In any case, Scan results will be cleaned up in the
* reset function and when exiting the driver.
* The person triggering the scanning may never come to
* pick the results, so we need to do it in those places.
* Jean II */
/* In any case, Scan results will be cleaned up in the
* reset function and when exiting the driver.
* The person triggering the scanning may never come to
* pick the results, so we need to do it in those places.
* Jean II */
#ifdef SCAN_SINGLE_READ
/* If you enable this option, only one client (the first
* one) will be able to read the result (and only one
* time). If there is multiple concurent clients that
* want to read scan results, this behavior is not
* advisable - Jean II */
kfree(priv->scan_result);
priv->scan_result = NULL;
/* If you enable this option, only one client (the first
* one) will be able to read the result (and only one
* time). If there is multiple concurent clients that
* want to read scan results, this behavior is not
* advisable - Jean II */
kfree(priv->scan_result);
priv->scan_result = NULL;
#endif /* SCAN_SINGLE_READ */
/* Here, if too much time has elapsed since last scan,
* we may want to clean up scan results... - Jean II */
/* Here, if too much time has elapsed since last scan,
* we may want to clean up scan results... - Jean II */
}
/* Scan is no longer in progress */
priv->scan_inprogress = 0;
}
orinoco_unlock(priv, &flags);
......
......@@ -604,7 +604,6 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001),
PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a),
......
/* orinoco_nortel.c
*
* Driver for Prism II devices which would usually be driven by orinoco_cs,
* but are connected to the PCI bus by a Nortel PCI-PCMCIA-Adapter.
*
* Copyright (C) 2002 Tobias Hoffmann
* (C) 2003 Christoph Jungegger <disdos@traum404.de>
*
* Some of this code is borrowed from orinoco_plx.c
* Copyright (C) 2001 Daniel Barlow
* Some of this code is borrowed from orinoco_pci.c
* Copyright (C) 2001 Jean Tourrilhes
* Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
* has been copied from it. linux-wlan-ng-0.1.10 is originally :
* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License
* at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and
* limitations under the License.
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License version 2 (the "GPL"), in
* which case the provisions of the GPL are applicable instead of the
* above. If you wish to allow the use of your version of this file
* only under the terms of the GPL and not to allow others to use your
* version of this file under the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice and
* other provisions required by the GPL. If you do not delete the
* provisions above, a recipient may use your version of this file
* under either the MPL or the GPL.
*/
#define DRIVER_NAME "orinoco_nortel"
#define PFX DRIVER_NAME ": "
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/system.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/fcntl.h>
#include <pcmcia/cisreg.h>
#include "hermes.h"
#include "orinoco.h"
#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */
#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
/* Nortel specific data */
struct nortel_pci_card {
unsigned long iobase1;
unsigned long iobase2;
};
/*
* Do a soft reset of the PCI card using the Configuration Option Register
* We need this to get going...
* This is the part of the code that is strongly inspired from wlan-ng
*
* Note bis : Don't try to access HERMES_CMD during the reset phase.
* It just won't work !
*/
static int nortel_pci_cor_reset(struct orinoco_private *priv)
{
struct nortel_pci_card *card = priv->card;
/* Assert the reset until the card notice */
outw_p(8, card->iobase1 + 2);
inw(card->iobase2 + COR_OFFSET);
outw_p(0x80, card->iobase2 + COR_OFFSET);
mdelay(1);
/* Give time for the card to recover from this hard effort */
outw_p(0, card->iobase2 + COR_OFFSET);
outw_p(0, card->iobase2 + COR_OFFSET);
mdelay(1);
/* set COR as usual */
outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
mdelay(1);
outw_p(0x228, card->iobase1 + 2);
return 0;
}
int nortel_pci_hw_init(struct nortel_pci_card *card)
{
int i;
u32 reg;
/* setup bridge */
if (inw(card->iobase1) & 1) {
printk(KERN_ERR PFX "brg1 answer1 wrong\n");
return -EBUSY;
}
outw_p(0x118, card->iobase1 + 2);
outw_p(0x108, card->iobase1 + 2);
mdelay(30);
outw_p(0x8, card->iobase1 + 2);
for (i = 0; i < 30; i++) {
mdelay(30);
if (inw(card->iobase1) & 0x10) {
break;
}
}
if (i == 30) {
printk(KERN_ERR PFX "brg1 timed out\n");
return -EBUSY;
}
if (inw(card->iobase2 + 0xe0) & 1) {
printk(KERN_ERR PFX "brg2 answer1 wrong\n");
return -EBUSY;
}
if (inw(card->iobase2 + 0xe2) & 1) {
printk(KERN_ERR PFX "brg2 answer2 wrong\n");
return -EBUSY;
}
if (inw(card->iobase2 + 0xe4) & 1) {
printk(KERN_ERR PFX "brg2 answer3 wrong\n");
return -EBUSY;
}
/* set the PCMCIA COR-Register */
outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
mdelay(1);
reg = inw(card->iobase2 + COR_OFFSET);
if (reg != COR_VALUE) {
printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n",
reg);
return -EBUSY;
}
/* set leds */
outw_p(1, card->iobase1 + 10);
return 0;
}
static int nortel_pci_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int err;
struct orinoco_private *priv;
struct nortel_pci_card *card;
struct net_device *dev;
void __iomem *iomem;
err = pci_enable_device(pdev);
if (err) {
printk(KERN_ERR PFX "Cannot enable PCI device\n");
return err;
}
err = pci_request_regions(pdev, DRIVER_NAME);
if (err != 0) {
printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
goto fail_resources;
}
iomem = pci_iomap(pdev, 3, 0);
if (!iomem) {
err = -ENOMEM;
goto fail_map_io;
}
/* Allocate network device */
dev = alloc_orinocodev(sizeof(*card), nortel_pci_cor_reset);
if (!dev) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
priv = netdev_priv(dev);
card = priv->card;
card->iobase1 = pci_resource_start(pdev, 0);
card->iobase2 = pci_resource_start(pdev, 1);
dev->base_addr = pci_resource_start(pdev, 2);
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, iomem, HERMES_16BIT_REGSPACING);
printk(KERN_DEBUG PFX "Detected Nortel PCI device at %s irq:%d, "
"io addr:0x%lx\n", pci_name(pdev), pdev->irq, dev->base_addr);
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
dev->name, dev);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
goto fail_irq;
}
dev->irq = pdev->irq;
err = nortel_pci_hw_init(card);
if (err) {
printk(KERN_ERR PFX "Hardware initialization failed\n");
goto fail;
}
err = nortel_pci_cor_reset(priv);
if (err) {
printk(KERN_ERR PFX "Initial reset failed\n");
goto fail;
}
err = register_netdev(dev);
if (err) {
printk(KERN_ERR PFX "Cannot register network device\n");
goto fail;
}
pci_set_drvdata(pdev, dev);
return 0;
fail:
free_irq(pdev->irq, dev);
fail_irq:
pci_set_drvdata(pdev, NULL);
free_orinocodev(dev);
fail_alloc:
pci_iounmap(pdev, iomem);
fail_map_io:
pci_release_regions(pdev);
fail_resources:
pci_disable_device(pdev);
return err;
}
static void __devexit nortel_pci_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = netdev_priv(dev);
struct nortel_pci_card *card = priv->card;
/* clear leds */
outw_p(0, card->iobase1 + 10);
unregister_netdev(dev);
free_irq(dev->irq, dev);
pci_set_drvdata(pdev, NULL);
free_orinocodev(dev);
pci_iounmap(pdev, priv->hw.iobase);
pci_release_regions(pdev);
pci_disable_device(pdev);
}
static struct pci_device_id nortel_pci_id_table[] = {
/* Nortel emobility PCI */
{0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
{0,},
};
MODULE_DEVICE_TABLE(pci, nortel_pci_id_table);
static struct pci_driver nortel_pci_driver = {
.name = DRIVER_NAME,
.id_table = nortel_pci_id_table,
.probe = nortel_pci_init_one,
.remove = __devexit_p(nortel_pci_remove_one),
};
static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
" (Tobias Hoffmann & Christoph Jungegger <disdos@traum404.de>)";
MODULE_AUTHOR("Christoph Jungegger <disdos@traum404.de>");
MODULE_DESCRIPTION
("Driver for wireless LAN cards using the Nortel PCI bridge");
MODULE_LICENSE("Dual MPL/GPL");
static int __init nortel_pci_init(void)
{
printk(KERN_DEBUG "%s\n", version);
return pci_module_init(&nortel_pci_driver);
}
static void __exit nortel_pci_exit(void)
{
pci_unregister_driver(&nortel_pci_driver);
ssleep(1);
}
module_init(nortel_pci_init);
module_exit(nortel_pci_exit);
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* tab-width: 8
* End:
*/
This diff is collapsed.
......@@ -695,7 +695,7 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
return ret;
}
static int ethtool_get_perm_addr(struct net_device *dev, void *useraddr)
static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr)
{
struct ethtool_perm_addr epaddr;
u8 *data;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment