Commit 48a97054 authored by Jeff Garzik's avatar Jeff Garzik

Merge redhat.com:/spare/repo/netdev-2.6/misc

into redhat.com:/spare/repo/net-drivers-2.5
parents 2b65a560 627f8b57
......@@ -40,7 +40,7 @@ config IEEE1394_OUI_DB
help
If you say Y here, then an OUI list (vendor unique ID's) will be
compiled into the ieee1394 module. This doesn't really do much
accept being able to display the vendor of a hardware node. The
except being able to display the vendor of a hardware node. The
downside is that it adds about 300k to the size of the module,
or kernel (depending on whether you compile ieee1394 as a
module, or static in the kernel).
......
......@@ -82,6 +82,7 @@
#include <linux/poll.h>
#include <linux/ioctl32.h>
#include <linux/compat.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
......@@ -1196,6 +1197,7 @@ static int amdtp_release(struct inode *inode, struct file *file)
return 0;
}
static struct cdev amdtp_cdev;
static struct file_operations amdtp_fops =
{
.owner = THIS_MODULE,
......@@ -1262,12 +1264,11 @@ MODULE_LICENSE("GPL");
static int __init amdtp_init_module (void)
{
int ret;
ret = ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_AMDTP,
THIS_MODULE, &amdtp_fops);
if (ret) {
HPSB_ERR("amdtp: unable to get minor device block");
cdev_init(&amdtp_cdev, &amdtp_fops);
amdtp_cdev.owner = THIS_MODULE;
kobject_set_name(&amdtp_cdev.kobj, "amdtp");
if (cdev_add(&amdtp_cdev, IEEE1394_AMDTP_DEV, 16)) {
HPSB_ERR("amdtp: unable to add char device");
return -EIO;
}
......@@ -1276,12 +1277,15 @@ static int __init amdtp_init_module (void)
hpsb_register_highlevel(&amdtp_highlevel);
#ifdef CONFIG_COMPAT
ret = register_ioctl32_conversion(AMDTP_IOC_CHANNEL, NULL);
ret |= register_ioctl32_conversion(AMDTP_IOC_PLUG, NULL);
ret |= register_ioctl32_conversion(AMDTP_IOC_PING, NULL);
ret |= register_ioctl32_conversion(AMDTP_IOC_ZAP, NULL);
if (ret)
HPSB_ERR("amdtp: Error registering ioctl32 translations");
{
int ret;
ret = register_ioctl32_conversion(AMDTP_IOC_CHANNEL, NULL);
ret |= register_ioctl32_conversion(AMDTP_IOC_PLUG, NULL);
ret |= register_ioctl32_conversion(AMDTP_IOC_PING, NULL);
ret |= register_ioctl32_conversion(AMDTP_IOC_ZAP, NULL);
if (ret)
HPSB_ERR("amdtp: Error registering ioctl32 translations");
}
#endif
HPSB_INFO("Loaded AMDTP driver");
......@@ -1304,10 +1308,12 @@ static void __exit amdtp_exit_module (void)
hpsb_unregister_highlevel(&amdtp_highlevel);
devfs_remove("amdtp");
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP);
cdev_unmap(IEEE1394_AMDTP_DEV, 16);
cdev_del(&amdtp_cdev);
HPSB_INFO("Unloaded AMDTP driver");
}
module_init(amdtp_init_module);
module_exit(amdtp_exit_module);
MODULE_ALIAS_CHARDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_AMDTP * 16);
......@@ -77,6 +77,25 @@ enum {
static struct hpsb_highlevel cmp_highlevel;
static void cmp_add_host(struct hpsb_host *host);
static void cmp_host_reset(struct hpsb_host *host);
static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
u64 addr, size_t length, u16 flags);
static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 flags);
static struct hpsb_highlevel cmp_highlevel = {
.name = "cmp",
.add_host = cmp_add_host,
.host_reset = cmp_host_reset,
};
static struct hpsb_address_ops pcr_ops = {
.read = pcr_read,
.lock = pcr_lock,
};
struct cmp_pcr *
cmp_register_opcr(struct hpsb_host *host, int opcr_number, int payload,
void (*update)(struct cmp_pcr *pcr, void *data),
......@@ -137,6 +156,10 @@ static void cmp_add_host(struct hpsb_host *host)
return;
}
hpsb_register_addrspace(&cmp_highlevel, host, &pcr_ops,
CSR_REGISTER_BASE + CSR_PCR_MAP,
CSR_REGISTER_BASE + CSR_PCR_MAP_END);
ch->host = host;
ch->u.ompr.rate = IEEE1394_SPEED_100;
ch->u.ompr.bcast_channel_base = 63;
......@@ -258,17 +281,6 @@ static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
}
static struct hpsb_highlevel cmp_highlevel = {
.name = "cmp",
.add_host = cmp_add_host,
.host_reset = cmp_host_reset,
};
static struct hpsb_address_ops pcr_ops = {
.read = pcr_read,
.lock = pcr_lock,
};
/* Module interface */
MODULE_AUTHOR("Kristian Hogsberg <hogsberg@users.sf.net>");
......@@ -283,10 +295,6 @@ static int __init cmp_init_module (void)
{
hpsb_register_highlevel (&cmp_highlevel);
hpsb_register_addrspace(&cmp_highlevel, &pcr_ops,
CSR_REGISTER_BASE + CSR_PCR_MAP,
CSR_REGISTER_BASE + CSR_PCR_MAP_END);
HPSB_INFO("Loaded CMP driver");
return 0;
......
......@@ -35,6 +35,43 @@ static int fcp = 1;
module_param(fcp, int, 0444);
MODULE_PARM_DESC(fcp, "Map FCP registers (default = 1, disable = 0).");
static void add_host(struct hpsb_host *host);
static void host_reset(struct hpsb_host *host);
static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
u64 addr, size_t length, u16 fl);
static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
quadlet_t *data, u64 addr, size_t length, u16 flags);
static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
u64 addr, size_t length, u16 flags);
static int write_regs(struct hpsb_host *host, int nodeid, int destid,
quadlet_t *data, u64 addr, size_t length, u16 flags);
static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl);
static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl);
static struct hpsb_highlevel csr_highlevel = {
.name = "standard registers",
.add_host = add_host,
.host_reset = host_reset,
};
static struct hpsb_address_ops map_ops = {
.read = read_maps,
};
static struct hpsb_address_ops fcp_ops = {
.write = write_fcp,
};
static struct hpsb_address_ops reg_ops = {
.read = read_regs,
.write = write_regs,
.lock = lock_regs,
.lock64 = lock64_regs,
};
static u16 csr_crc16(unsigned *data, int length)
{
int check=0, i;
......@@ -125,6 +162,24 @@ static inline void calculate_expire(struct csr_control *csr)
static void add_host(struct hpsb_host *host)
{
hpsb_register_addrspace(&csr_highlevel, host, &reg_ops,
CSR_REGISTER_BASE,
CSR_REGISTER_BASE + CSR_CONFIG_ROM);
hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
CSR_REGISTER_BASE + CSR_CONFIG_ROM,
CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
if (fcp) {
hpsb_register_addrspace(&csr_highlevel, host, &fcp_ops,
CSR_REGISTER_BASE + CSR_FCP_COMMAND,
CSR_REGISTER_BASE + CSR_FCP_END);
}
hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
CSR_REGISTER_BASE + CSR_SPEED_MAP,
CSR_REGISTER_BASE + CSR_SPEED_MAP_END);
host->csr.lock = SPIN_LOCK_UNLOCKED;
host->csr.rom_size = host->driver->get_rom(host, &host->csr.rom);
......@@ -684,48 +739,10 @@ static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
}
static struct hpsb_highlevel csr_highlevel = {
.name = "standard registers",
.add_host = add_host,
.host_reset = host_reset,
};
static struct hpsb_address_ops map_ops = {
.read = read_maps,
};
static struct hpsb_address_ops fcp_ops = {
.write = write_fcp,
};
static struct hpsb_address_ops reg_ops = {
.read = read_regs,
.write = write_regs,
.lock = lock_regs,
.lock64 = lock64_regs,
};
void init_csr(void)
{
hpsb_register_highlevel(&csr_highlevel);
hpsb_register_addrspace(&csr_highlevel, &reg_ops, CSR_REGISTER_BASE,
CSR_REGISTER_BASE + CSR_CONFIG_ROM);
hpsb_register_addrspace(&csr_highlevel, &map_ops,
CSR_REGISTER_BASE + CSR_CONFIG_ROM,
CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
if (fcp) {
hpsb_register_addrspace(&csr_highlevel, &fcp_ops,
CSR_REGISTER_BASE + CSR_FCP_COMMAND,
CSR_REGISTER_BASE + CSR_FCP_END);
}
hpsb_register_addrspace(&csr_highlevel, &map_ops,
CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
hpsb_register_addrspace(&csr_highlevel, &map_ops,
CSR_REGISTER_BASE + CSR_SPEED_MAP,
CSR_REGISTER_BASE + CSR_SPEED_MAP_END);
}
void cleanup_csr(void)
......
......@@ -110,6 +110,7 @@
#include <linux/string.h>
#include <linux/ioctl32.h>
#include <linux/compat.h>
#include <linux/cdev.h>
#include "ieee1394.h"
#include "ieee1394_types.h"
......@@ -2165,6 +2166,7 @@ static void ir_tasklet_func(unsigned long data)
spin_unlock(&video->spinlock);
}
static struct cdev dv1394_cdev;
static struct file_operations dv1394_fops=
{
.owner = THIS_MODULE,
......@@ -2607,17 +2609,17 @@ static void __exit dv1394_exit_module(void)
hpsb_unregister_protocol(&dv1394_driver);
hpsb_unregister_highlevel(&dv1394_highlevel);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
cdev_unmap(IEEE1394_DV1394_DEV, 16);
cdev_del(&dv1394_cdev);
devfs_remove("ieee1394/dv");
}
static int __init dv1394_init_module(void)
{
int ret;
ret = ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_DV1394,
THIS_MODULE, &dv1394_fops);
if (ret) {
cdev_init(&dv1394_cdev, &dv1394_fops);
dv1394_cdev.owner = THIS_MODULE;
kobject_set_name(&dv1394_cdev.kobj, "dv1394");
if (cdev_add(&dv1394_cdev, IEEE1394_DV1394_DEV, 16)) {
printk(KERN_ERR "dv1394: unable to register character device\n");
return -EIO;
}
......@@ -2629,18 +2631,22 @@ static int __init dv1394_init_module(void)
hpsb_register_protocol(&dv1394_driver);
#ifdef CONFIG_COMPAT
/* First compatible ones */
ret = register_ioctl32_conversion(DV1394_IOC_SHUTDOWN, NULL);
ret |= register_ioctl32_conversion(DV1394_IOC_SUBMIT_FRAMES, NULL);
ret |= register_ioctl32_conversion(DV1394_IOC_WAIT_FRAMES, NULL);
ret |= register_ioctl32_conversion(DV1394_IOC_RECEIVE_FRAMES, NULL);
ret |= register_ioctl32_conversion(DV1394_IOC_START_RECEIVE, NULL);
/* These need to be handled by translation */
ret |= register_ioctl32_conversion(DV1394_IOC32_INIT, handle_dv1394_init);
ret |= register_ioctl32_conversion(DV1394_IOC32_GET_STATUS, handle_dv1394_get_status);
if (ret)
printk(KERN_ERR "dv1394: Error registering ioctl32 translations\n");
{
int ret;
/* First compatible ones */
ret = register_ioctl32_conversion(DV1394_IOC_SHUTDOWN, NULL);
ret |= register_ioctl32_conversion(DV1394_IOC_SUBMIT_FRAMES, NULL);
ret |= register_ioctl32_conversion(DV1394_IOC_WAIT_FRAMES, NULL);
ret |= register_ioctl32_conversion(DV1394_IOC_RECEIVE_FRAMES, NULL);
ret |= register_ioctl32_conversion(DV1394_IOC_START_RECEIVE, NULL);
/* These need to be handled by translation */
ret |= register_ioctl32_conversion(DV1394_IOC32_INIT, handle_dv1394_init);
ret |= register_ioctl32_conversion(DV1394_IOC32_GET_STATUS, handle_dv1394_get_status);
if (ret)
printk(KERN_ERR "dv1394: Error registering ioctl32 translations\n");
}
#endif
return 0;
......@@ -2648,3 +2654,4 @@ static int __init dv1394_init_module(void)
module_init(dv1394_init_module);
module_exit(dv1394_exit_module);
MODULE_ALIAS_CHARDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16);
......@@ -89,7 +89,7 @@
#define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__)
static char version[] __devinitdata =
"$Rev: 1079 $ Ben Collins <bcollins@debian.org>";
"$Rev: 1096 $ Ben Collins <bcollins@debian.org>";
struct fragment_info {
struct list_head list;
......@@ -168,6 +168,26 @@ static void ether1394_iso(struct hpsb_iso *iso);
static int ether1394_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static int ether1394_ethtool_ioctl(struct net_device *dev, void *useraddr);
static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
quadlet_t *data, u64 addr, size_t len, u16 flags);
static void ether1394_add_host (struct hpsb_host *host);
static void ether1394_remove_host (struct hpsb_host *host);
static void ether1394_host_reset (struct hpsb_host *host);
/* Function for incoming 1394 packets */
static struct hpsb_address_ops addr_ops = {
.write = ether1394_write,
};
/* Ieee1394 highlevel driver functions */
static struct hpsb_highlevel eth1394_highlevel = {
.name = driver_name,
.add_host = ether1394_add_host,
.remove_host = ether1394_remove_host,
.host_reset = ether1394_host_reset,
};
static void eth1394_iso_shutdown(struct eth1394_priv *priv)
{
priv->bc_state = ETHER1394_BC_CLOSED;
......@@ -420,6 +440,10 @@ static void ether1394_add_host (struct hpsb_host *host)
struct eth1394_priv *priv;
static int version_printed = 0;
hpsb_register_addrspace(&eth1394_highlevel, host, &addr_ops,
ETHER1394_REGION_ADDR,
ETHER1394_REGION_ADDR_END);
if (version_printed++ == 0)
ETH1394_PRINT_G (KERN_INFO, "%s\n", version);
......@@ -1599,7 +1623,7 @@ static int ether1394_ethtool_ioctl(struct net_device *dev, void *useraddr)
case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
strcpy (info.driver, driver_name);
strcpy (info.version, "$Rev: 1079 $");
strcpy (info.version, "$Rev: 1096 $");
/* FIXME XXX provide sane businfo */
strcpy (info.bus_info, "ieee1394");
if (copy_to_user (useraddr, &info, sizeof (info)))
......@@ -1619,18 +1643,6 @@ static int ether1394_ethtool_ioctl(struct net_device *dev, void *useraddr)
return 0;
}
/* Function for incoming 1394 packets */
static struct hpsb_address_ops addr_ops = {
.write = ether1394_write,
};
/* Ieee1394 highlevel driver functions */
static struct hpsb_highlevel eth1394_highlevel = {
.name = driver_name,
.add_host = ether1394_add_host,
.remove_host = ether1394_remove_host,
.host_reset = ether1394_host_reset,
};
static int __init ether1394_init_module (void)
{
......@@ -1640,9 +1652,6 @@ static int __init ether1394_init_module (void)
/* Register ourselves as a highlevel driver */
hpsb_register_highlevel(&eth1394_highlevel);
hpsb_register_addrspace(&eth1394_highlevel, &addr_ops, ETHER1394_REGION_ADDR,
ETHER1394_REGION_ADDR_END);
return 0;
}
......
......@@ -39,7 +39,10 @@ struct hl_host_info {
static LIST_HEAD(hl_drivers);
static rwlock_t hl_drivers_lock = RW_LOCK_UNLOCKED;
static DECLARE_RWSEM(hl_drivers_sem);
static LIST_HEAD(hl_irqs);
static rwlock_t hl_irqs_lock = RW_LOCK_UNLOCKED;
static LIST_HEAD(addr_space);
static rwlock_t addr_space_lock = RW_LOCK_UNLOCKED;
......@@ -239,20 +242,22 @@ static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
void hpsb_register_highlevel(struct hpsb_highlevel *hl)
{
unsigned long flags;
INIT_LIST_HEAD(&hl->addr_list);
INIT_LIST_HEAD(&hl->host_info_list);
rwlock_init(&hl->host_info_lock);
write_lock_irqsave(&hl_drivers_lock, flags);
down_write(&hl_drivers_sem);
list_add_tail(&hl->hl_list, &hl_drivers);
write_unlock_irqrestore(&hl_drivers_lock, flags);
up_write(&hl_drivers_sem);
if (hl->add_host)
nodemgr_for_each_host(hl, highlevel_for_each_host_reg);
write_lock(&hl_irqs_lock);
list_add_tail(&hl->irq_list, &hl_irqs);
write_unlock(&hl_irqs_lock);
return;
}
......@@ -280,15 +285,19 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
}
write_unlock_irqrestore(&addr_space_lock, flags);
write_lock_irqsave(&hl_drivers_lock, flags);
write_lock(&hl_irqs_lock);
list_del(&hl->irq_list);
write_unlock(&hl_irqs_lock);
down_write(&hl_drivers_sem);
list_del(&hl->hl_list);
write_unlock_irqrestore(&hl_drivers_lock, flags);
up_write(&hl_drivers_sem);
if (hl->remove_host)
nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
}
int hpsb_register_addrspace(struct hpsb_highlevel *hl,
int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
struct hpsb_address_ops *ops, u64 start, u64 end)
{
struct hpsb_address_serve *as;
......@@ -314,7 +323,7 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl,
as->end = end;
write_lock_irqsave(&addr_space_lock, flags);
entry = addr_space.next;
entry = host->addr_space.next;
while (list_entry(entry, struct hpsb_address_serve, as_list)->end
<= start) {
......@@ -336,7 +345,8 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl,
return retval;
}
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start)
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
u64 start)
{
int retval = 0;
struct hpsb_address_serve *as;
......@@ -350,7 +360,7 @@ int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start)
while (entry != &hl->addr_list) {
as = list_entry(entry, struct hpsb_address_serve, addr_list);
entry = entry->next;
if (as->start == start) {
if (as->start == start && as->host == host) {
list_del(&as->as_list);
list_del(&as->addr_list);
kfree(as);
......@@ -395,89 +405,82 @@ void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
void highlevel_add_host(struct hpsb_host *host)
{
struct list_head *entry;
struct hpsb_highlevel *hl;
read_lock(&hl_drivers_lock);
list_for_each(entry, &hl_drivers) {
hl = list_entry(entry, struct hpsb_highlevel, hl_list);
down_read(&hl_drivers_sem);
list_for_each_entry(hl, &hl_drivers, hl_list) {
if (hl->add_host)
hl->add_host(host);
}
read_unlock(&hl_drivers_lock);
up_read(&hl_drivers_sem);
}
void highlevel_remove_host(struct hpsb_host *host)
{
struct list_head *entry;
struct hpsb_highlevel *hl;
struct list_head *lh, *next;
struct hpsb_address_serve *as;
unsigned long flags;
read_lock(&hl_drivers_lock);
list_for_each(entry, &hl_drivers) {
hl = list_entry(entry, struct hpsb_highlevel, hl_list);
down_read(&hl_drivers_sem);
list_for_each_entry(hl, &hl_drivers, hl_list) {
if (hl->remove_host) {
hl->remove_host(host);
hpsb_destroy_hostinfo(hl, host);
}
}
read_unlock(&hl_drivers_lock);
up_read(&hl_drivers_sem);
/* Free up 1394 address space left behind by high level drivers. */
write_lock_irqsave(&addr_space_lock, flags);
list_for_each_safe (lh, next, &host->addr_space) {
as = list_entry(lh, struct hpsb_address_serve, as_list);
if (!list_empty(&as->addr_list)) {
list_del(&as->addr_list);
kfree(as);
}
}
write_unlock_irqrestore(&addr_space_lock, flags);
}
void highlevel_host_reset(struct hpsb_host *host)
{
struct list_head *entry;
struct hpsb_highlevel *hl;
read_lock(&hl_drivers_lock);
list_for_each(entry, &hl_drivers) {
hl = list_entry(entry, struct hpsb_highlevel, hl_list);
read_lock(&hl_irqs_lock);
list_for_each_entry(hl, &hl_irqs, hl_list) {
if (hl->host_reset)
hl->host_reset(host);
}
read_unlock(&hl_drivers_lock);
read_unlock(&hl_irqs_lock);
}
void highlevel_iso_receive(struct hpsb_host *host, void *data,
size_t length)
void highlevel_iso_receive(struct hpsb_host *host, void *data, size_t length)
{
struct list_head *entry;
struct hpsb_highlevel *hl;
int channel = (((quadlet_t *)data)[0] >> 8) & 0x3f;
read_lock(&hl_drivers_lock);
entry = hl_drivers.next;
while (entry != &hl_drivers) {
hl = list_entry(entry, struct hpsb_highlevel, hl_list);
if (hl->iso_receive) {
read_lock(&hl_irqs_lock);
list_for_each_entry(hl, &hl_irqs, irq_list) {
if (hl->iso_receive)
hl->iso_receive(host, channel, data, length);
}
entry = entry->next;
}
read_unlock(&hl_drivers_lock);
read_unlock(&hl_irqs_lock);
}
void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
void *data, size_t length)
{
struct list_head *entry;
struct hpsb_highlevel *hl;
int cts = ((quadlet_t *)data)[0] >> 4;
read_lock(&hl_drivers_lock);
entry = hl_drivers.next;
while (entry != &hl_drivers) {
hl = list_entry(entry, struct hpsb_highlevel, hl_list);
if (hl->fcp_request) {
read_lock(&hl_irqs_lock);
list_for_each_entry(hl, &hl_irqs, irq_list) {
if (hl->fcp_request)
hl->fcp_request(host, nodeid, direction, cts, data,
length);
}
entry = entry->next;
length);
}
read_unlock(&hl_drivers_lock);
read_unlock(&hl_irqs_lock);
}
int highlevel_read(struct hpsb_host *host, int nodeid, void *data,
......@@ -490,7 +493,7 @@ int highlevel_read(struct hpsb_host *host, int nodeid, void *data,
read_lock(&addr_space_lock);
entry = addr_space.next;
entry = host->addr_space.next;
as = list_entry(entry, struct hpsb_address_serve, as_list);
while (as->start <= addr) {
......@@ -536,7 +539,7 @@ int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
read_lock(&addr_space_lock);
entry = addr_space.next;
entry = host->addr_space.next;
as = list_entry(entry, struct hpsb_address_serve, as_list);
while (as->start <= addr) {
......@@ -582,7 +585,7 @@ int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
read_lock(&addr_space_lock);
entry = addr_space.next;
entry = host->addr_space.next;
as = list_entry(entry, struct hpsb_address_serve, as_list);
while (as->start <= addr) {
......@@ -615,7 +618,7 @@ int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
read_lock(&addr_space_lock);
entry = addr_space.next;
entry = host->addr_space.next;
as = list_entry(entry, struct hpsb_address_serve, as_list);
while (as->start <= addr) {
......@@ -640,7 +643,7 @@ int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
return rcode;
}
void init_hpsb_highlevel(void)
void init_hpsb_highlevel(struct hpsb_host *host)
{
INIT_LIST_HEAD(&dummy_zero_addr.as_list);
INIT_LIST_HEAD(&dummy_zero_addr.addr_list);
......@@ -652,6 +655,6 @@ void init_hpsb_highlevel(void)
dummy_zero_addr.start = dummy_zero_addr.end = 0;
dummy_max_addr.start = dummy_max_addr.end = ((u64) 1) << 48;
list_add_tail(&dummy_zero_addr.as_list, &addr_space);
list_add_tail(&dummy_max_addr.as_list, &addr_space);
list_add_tail(&dummy_zero_addr.as_list, &host->addr_space);
list_add_tail(&dummy_max_addr.as_list, &host->addr_space);
}
......@@ -10,6 +10,8 @@ struct hpsb_address_serve {
struct hpsb_address_ops *op;
struct hpsb_host *host;
/* first address handled and first address behind, quadlet aligned */
u64 start, end;
};
......@@ -36,9 +38,9 @@ struct hpsb_highlevel {
* hpsb_unregister_highlevel once for each host. */
void (*remove_host) (struct hpsb_host *host);
/* Host experienced bus reset with possible configuration changes. Note
* that this one may occur during interrupt/bottom half handling. You
* can not expect to be able to do stock hpsb_reads. */
/* Host experienced bus reset with possible configuration changes.
* Note that this one may occur during interrupt/bottom half handling.
* You can not expect to be able to do stock hpsb_reads. */
void (*host_reset) (struct hpsb_host *host);
/* An isochronous packet was received. Channel contains the channel
......@@ -50,13 +52,14 @@ struct hpsb_highlevel {
/* A write request was received on either the FCP_COMMAND (direction =
* 0) or the FCP_RESPONSE (direction = 1) register. The cts arg
* contains the cts field (first byte of data).
*/
* contains the cts field (first byte of data). */
void (*fcp_request) (struct hpsb_host *host, int nodeid, int direction,
int cts, u8 *data, size_t length);
/* These are initialized by the subsystem when the
* hpsb_higlevel is registered. */
struct list_head hl_list;
struct list_head irq_list;
struct list_head addr_list;
struct list_head host_info_list;
......@@ -137,10 +140,11 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
* It returns true for successful allocation. There is no unregister function,
* all address spaces are deallocated together with the hpsb_highlevel.
*/
int hpsb_register_addrspace(struct hpsb_highlevel *hl,
int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
struct hpsb_address_ops *ops, u64 start, u64 end);
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start);
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
u64 start);
/*
* Enable or disable receving a certain isochronous channel through the
......@@ -179,6 +183,6 @@ int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, void *d
struct hpsb_host *hpsb_get_host_bykey(struct hpsb_highlevel *hl, unsigned long key);
/* Initialize the highlevel system */
void init_hpsb_highlevel(void);
void init_hpsb_highlevel(struct hpsb_host *host);
#endif /* IEEE1394_HIGHLEVEL_H */
......@@ -89,6 +89,8 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
INIT_LIST_HEAD(&h->pending_packets);
spin_lock_init(&h->pending_pkt_lock);
INIT_LIST_HEAD(&h->addr_space);
for (i = 0; i < ARRAY_SIZE(h->tpool); i++)
HPSB_TPOOL_INIT(&h->tpool[i]);
......
......@@ -69,6 +69,8 @@ struct hpsb_host {
int id;
struct device device;
struct list_head addr_space;
};
......
......@@ -993,186 +993,11 @@ void abort_timedouts(unsigned long __opaque)
}
/*
* character device dispatching (see ieee1394_core.h)
* Dan Maas <dmaas@dcine.com>
*/
static struct {
struct file_operations *file_ops;
struct module *module;
} ieee1394_chardevs[16];
static rwlock_t ieee1394_chardevs_lock = RW_LOCK_UNLOCKED;
static int ieee1394_dispatch_open(struct inode *inode, struct file *file);
static struct file_operations ieee1394_chardev_ops = {
.owner =THIS_MODULE,
.open = ieee1394_dispatch_open,
};
/* claim a block of minor numbers */
int ieee1394_register_chardev(int blocknum,
struct module *module,
struct file_operations *file_ops)
{
int retval;
if ( (blocknum < 0) || (blocknum > 15) )
return -EINVAL;
write_lock(&ieee1394_chardevs_lock);
if (ieee1394_chardevs[blocknum].file_ops == NULL) {
/* grab the minor block */
ieee1394_chardevs[blocknum].file_ops = file_ops;
ieee1394_chardevs[blocknum].module = module;
retval = 0;
} else {
/* block already taken */
retval = -EBUSY;
}
write_unlock(&ieee1394_chardevs_lock);
return retval;
}
/* release a block of minor numbers */
void ieee1394_unregister_chardev(int blocknum)
{
if ( (blocknum < 0) || (blocknum > 15) )
return;
write_lock(&ieee1394_chardevs_lock);
if (ieee1394_chardevs[blocknum].file_ops) {
ieee1394_chardevs[blocknum].file_ops = NULL;
ieee1394_chardevs[blocknum].module = NULL;
}
write_unlock(&ieee1394_chardevs_lock);
}
/*
ieee1394_get_chardev() - look up and acquire a character device
driver that has previously registered using ieee1394_register_chardev()
On success, returns 1 and sets module and file_ops to the driver.
The module will have an incremented reference count.
On failure, returns 0.
The module will NOT have an incremented reference count.
*/
static int ieee1394_get_chardev(int blocknum,
struct module **module,
struct file_operations **file_ops)
{
int ret = 0;
if ((blocknum < 0) || (blocknum > 15))
return ret;
read_lock(&ieee1394_chardevs_lock);
*module = ieee1394_chardevs[blocknum].module;
*file_ops = ieee1394_chardevs[blocknum].file_ops;
if (*file_ops == NULL)
goto out;
if (!try_module_get(*module))
goto out;
/* success! */
ret = 1;
out:
read_unlock(&ieee1394_chardevs_lock);
return ret;
}
/* the point of entry for open() on any ieee1394 character device */
static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
{
struct file_operations *file_ops;
struct module *module;
int blocknum;
int retval;
/*
Maintaining correct module reference counts is tricky here!
The key thing to remember is that the VFS increments the
reference count of ieee1394 before it calls
ieee1394_dispatch_open().
If the open() succeeds, then we need to transfer this extra
reference to the task-specific driver module (e.g. raw1394).
The VFS will deref the driver module automatically when the
file is later released.
If the open() fails, then the VFS will drop the
reference count of whatever module file->f_op->owner points
to, immediately after this function returns.
*/
/* shift away lower four bits of the minor
to get the index of the ieee1394_driver
we want */
blocknum = (iminor(inode) >> 4) & 0xF;
/* look up the driver */
if (ieee1394_get_chardev(blocknum, &module, &file_ops) == 0)
return -ENODEV;
/* redirect all subsequent requests to the driver's
own file_operations */
file->f_op = file_ops;
/* at this point BOTH ieee1394 and the task-specific driver have
an extra reference */
/* follow through with the open() */
retval = file_ops->open(inode, file);
if (retval == 0) {
/* If the open() succeeded, then ieee1394 will be left
* with an extra module reference, so we discard it here.
*
* The task-specific driver still has the extra reference
* given to it by ieee1394_get_chardev(). This extra
* reference prevents the module from unloading while the
* file is open, and will be dropped by the VFS when the
* file is released. */
module_put(THIS_MODULE);
} else {
/* point the file's f_ops back to ieee1394. The VFS will then
decrement ieee1394's reference count immediately after this
function returns. */
file->f_op = &ieee1394_chardev_ops;
/* If the open() failed, then we need to drop the extra
* reference we gave to the task-specific driver. */
module_put(module);
}
return retval;
}
static int __init ieee1394_init(void)
{
devfs_mk_dir("ieee1394");
if (register_chrdev(IEEE1394_MAJOR, "ieee1394", &ieee1394_chardev_ops)) {
if (register_chrdev_region(IEEE1394_CORE_DEV, 256, "ieee1394")) {
HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
return -ENODEV;
}
......@@ -1184,7 +1009,6 @@ static int __init ieee1394_init(void)
bus_register(&ieee1394_bus_type);
init_hpsb_highlevel();
init_csr();
if (!disable_nodemgr)
......@@ -1206,7 +1030,7 @@ static void __exit ieee1394_cleanup(void)
kmem_cache_destroy(hpsb_packet_cache);
unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
devfs_remove("ieee1394");
}
......@@ -1234,8 +1058,6 @@ EXPORT_SYMBOL(hpsb_selfid_received);
EXPORT_SYMBOL(hpsb_selfid_complete);
EXPORT_SYMBOL(hpsb_packet_sent);
EXPORT_SYMBOL(hpsb_packet_received);
EXPORT_SYMBOL(ieee1394_register_chardev);
EXPORT_SYMBOL(ieee1394_unregister_chardev);
/** ieee1394_transactions.c **/
EXPORT_SYMBOL(hpsb_get_tlabel);
......
......@@ -176,9 +176,9 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
* task-specific interfaces (raw1394, video1394, dv1394, etc) in
* blocks of 16.
*
* The core ieee1394.o modules handles the initial open() for all
* character devices on major 171; it then dispatches to the
* appropriate task-specific driver.
* The core ieee1394.o module allocates the device number region
* 171:0-255, the various drivers must then cdev_add() their cdev
* objects to handle their respective sub-regions.
*
* Minor device number block allocations:
*
......@@ -199,29 +199,19 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
#define IEEE1394_MINOR_BLOCK_AMDTP 3
#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
#define IEEE1394_CORE_DEV MKDEV(IEEE1394_MAJOR, 0)
#define IEEE1394_RAW1394_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16)
#define IEEE1394_VIDEO1394_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_VIDEO1394 * 16)
#define IEEE1394_DV1394_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16)
#define IEEE1394_AMDTP_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_AMDTP * 16)
#define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
/* return the index (within a minor number block) of a file */
static inline unsigned char ieee1394_file_to_instance(struct file *file)
{
unsigned char minor = iminor(file->f_dentry->d_inode);
/* return lower 4 bits */
return minor & 0xF;
return file->f_dentry->d_inode->i_cindex;
}
/*
* Task-specific drivers should call ieee1394_register_chardev() to
* request a block of 16 minor numbers.
*
* Returns 0 if the request was successful, -EBUSY if the block was
* already taken.
*/
int ieee1394_register_chardev(int blocknum, /* 0-15 */
struct module *module, /* THIS_MODULE */
struct file_operations *file_ops);
/* release a block of minor numbers */
void ieee1394_unregister_chardev(int blocknum);
/* Our sysfs bus entry */
extern struct bus_type ieee1394_bus_type;
......
......@@ -161,7 +161,7 @@ printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
static char version[] __devinitdata =
"$Rev: 1087 $ Ben Collins <bcollins@debian.org>";
"$Rev: 1097 $ Ben Collins <bcollins@debian.org>";
/* Module Parameters */
static int phys_dma = 1;
......@@ -174,6 +174,7 @@ static void dma_trm_reset(struct dma_trm_ctx *d);
static int alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
enum context_type type, int ctx, int num_desc,
int buf_size, int split_buf_size, int context_base);
static void stop_dma_rcv_ctx(struct dma_rcv_ctx *d);
static void free_dma_rcv_ctx(struct dma_rcv_ctx *d);
static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
......@@ -358,7 +359,7 @@ static void ohci_soft_reset(struct ti_ohci *ohci) {
reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
for (i = 0; i < OHCI_LOOP_COUNT; i++) {
if (!reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_softReset)
if (!(reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_softReset))
break;
mdelay(1);
}
......@@ -1077,6 +1078,7 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
DBGMSG(ohci->id, "Listening disabled on channel %d", arg);
if (ohci->ir_legacy_channels == 0) {
stop_dma_rcv_ctx(&ohci->ir_legacy_context);
free_dma_rcv_ctx(&ohci->ir_legacy_context);
DBGMSG(ohci->id, "ISO receive legacy context deactivated");
}
......@@ -2249,6 +2251,14 @@ static irqreturn_t ohci_irq_handler(int irq, void *dev_id,
if (!event)
return IRQ_NONE;
/* If event is ~(u32)0 cardbus card was ejected. In this case
* we just return, and clean up in the ohci1394_pci_remove
* function. */
if (event == ~(u32) 0) {
DBGMSG(ohci->id, "Device removed.");
return IRQ_NONE;
}
DBGMSG(ohci->id, "IntEvent: %08x", event);
if (event & OHCI1394_unrecoverableError) {
......@@ -2811,15 +2821,8 @@ static void dma_trm_tasklet (unsigned long data)
spin_unlock_irqrestore(&d->lock, flags);
}
static void free_dma_rcv_ctx(struct dma_rcv_ctx *d)
static void stop_dma_rcv_ctx(struct dma_rcv_ctx *d)
{
int i;
if (d->ohci == NULL)
return;
DBGMSG(d->ohci->id, "Freeing dma_rcv_ctx %d", d->ctx);
if (d->ctrlClear) {
ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
......@@ -2831,6 +2834,17 @@ static void free_dma_rcv_ctx(struct dma_rcv_ctx *d)
tasklet_kill(&d->task);
}
}
}
static void free_dma_rcv_ctx(struct dma_rcv_ctx *d)
{
int i;
if (d->ohci == NULL)
return;
DBGMSG(d->ohci->id, "Freeing dma_rcv_ctx %d", d->ctx);
if (d->buf_cpu) {
for (i=0; i<d->num_desc; i++)
......@@ -2982,19 +2996,6 @@ static void free_dma_trm_ctx(struct dma_trm_ctx *d)
DBGMSG(d->ohci->id, "Freeing dma_trm_ctx %d", d->ctx);
if (d->ctrlClear) {
ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
if (d->type == DMA_CTX_ISO) {
/* disable interrupts */
reg_write(d->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << d->ctx);
ohci1394_unregister_iso_tasklet(d->ohci,
&d->ohci->it_legacy_tasklet);
} else {
tasklet_kill(&d->task);
}
}
if (d->prg_cpu) {
for (i=0; i<d->num_desc; i++)
if (d->prg_cpu[i] && d->prg_bus[i]) {
......@@ -3511,6 +3512,8 @@ static void ohci1394_pci_remove(struct pci_dev *pdev)
free_irq(ohci->dev->irq, ohci);
case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE:
/* The ohci_soft_reset() stops all DMA contexts, so we
* dont need to do this. */
/* Free AR dma */
free_dma_rcv_ctx(&ohci->ar_req_context);
free_dma_rcv_ctx(&ohci->ar_resp_context);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -38,6 +38,7 @@
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/devfs_fs_kernel.h>
......@@ -1695,7 +1696,7 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
spin_unlock_irqrestore(&host_info_lock, flags);
return sizeof(struct raw1394_request);
}
retval = hpsb_register_addrspace(&raw1394_highlevel, &arm_ops, req->req.address,
retval = hpsb_register_addrspace(&raw1394_highlevel, fi->host, &arm_ops, req->req.address,
req->req.address + req->req.length);
if (retval) {
/* INSERT ENTRY */
......@@ -1782,7 +1783,7 @@ static int arm_unregister(struct file_info *fi, struct pending_request *req)
spin_unlock_irqrestore(&host_info_lock, flags);
return sizeof(struct raw1394_request);
}
retval = hpsb_unregister_addrspace(&raw1394_highlevel, addr->start);
retval = hpsb_unregister_addrspace(&raw1394_highlevel, fi->host, addr->start);
if (!retval) {
printk(KERN_ERR "raw1394: arm_Unregister failed -> EINVAL\n");
spin_unlock_irqrestore(&host_info_lock, flags);
......@@ -2464,10 +2465,6 @@ static int raw1394_open(struct inode *inode, struct file *file)
{
struct file_info *fi;
if (ieee1394_file_to_instance(file) > 0) {
return -ENXIO;
}
fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL);
if (fi == NULL)
return -ENOMEM;
......@@ -2554,7 +2551,7 @@ static int raw1394_release(struct inode *inode, struct file *file)
}
if (!another_host) {
DBGMSG("raw1394_release: call hpsb_arm_unregister");
retval = hpsb_unregister_addrspace(&raw1394_highlevel, addr->start);
retval = hpsb_unregister_addrspace(&raw1394_highlevel, fi->host, addr->start);
if (!retval) {
++fail;
printk(KERN_ERR "raw1394_release arm_Unregister failed\n");
......@@ -2646,7 +2643,8 @@ static struct hpsb_highlevel raw1394_highlevel = {
.fcp_request = fcp_request,
};
static struct file_operations file_ops = {
static struct cdev raw1394_cdev;
static struct file_operations raw1394_fops = {
.owner = THIS_MODULE,
.read = raw1394_read,
.write = raw1394_write,
......@@ -2664,8 +2662,10 @@ static int __init init_raw1394(void)
devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16),
S_IFCHR | S_IRUSR | S_IWUSR, RAW1394_DEVICE_NAME);
if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394,
THIS_MODULE, &file_ops)) {
cdev_init(&raw1394_cdev, &raw1394_fops);
raw1394_cdev.owner = THIS_MODULE;
kobject_set_name(&raw1394_cdev.kobj, RAW1394_DEVICE_NAME);
if (cdev_add(&raw1394_cdev, IEEE1394_RAW1394_DEV, 1)) {
HPSB_ERR("raw1394 failed to register minor device block");
devfs_remove(RAW1394_DEVICE_NAME);
hpsb_unregister_highlevel(&raw1394_highlevel);
......@@ -2682,7 +2682,8 @@ static int __init init_raw1394(void)
static void __exit cleanup_raw1394(void)
{
hpsb_unregister_protocol(&raw1394_driver);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394);
cdev_unmap(IEEE1394_RAW1394_DEV, 1);
cdev_del(&raw1394_cdev);
devfs_remove(RAW1394_DEVICE_NAME);
hpsb_unregister_highlevel(&raw1394_highlevel);
}
......@@ -2690,3 +2691,4 @@ static void __exit cleanup_raw1394(void)
module_init(init_raw1394);
module_exit(cleanup_raw1394);
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16);
......@@ -77,7 +77,7 @@
#include "sbp2.h"
static char version[] __devinitdata =
"$Rev: 1082 $ Ben Collins <bcollins@debian.org>";
"$Rev: 1096 $ Ben Collins <bcollins@debian.org>";
/*
* Module load parameter definitions
......@@ -712,6 +712,18 @@ static struct sbp2scsi_host_info *sbp2_add_host(struct hpsb_host *host)
return NULL;
}
/* Register our sbp2 status address space... */
hpsb_register_addrspace(&sbp2_highlevel, host, &sbp2_ops,
SBP2_STATUS_FIFO_ADDRESS,
SBP2_STATUS_FIFO_ADDRESS +
SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2SCSI_MAX_SCSI_IDS+1));
/* Handle data movement if physical dma is not enabled/supported
* on host controller */
#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
hpsb_register_addrspace(&sbp2_highlevel, host, &sbp2_physdma_ops, 0x0ULL, 0xfffffffcULL);
#endif
hi = hpsb_create_hostinfo(&sbp2_highlevel, host, sizeof(*hi));
if (!hi) {
SBP2_ERR("failed to allocate hostinfo");
......@@ -2881,17 +2893,6 @@ static int sbp2_module_init(void)
/* Register our high level driver with 1394 stack */
hpsb_register_highlevel(&sbp2_highlevel);
/* Register our sbp2 status address space... */
hpsb_register_addrspace(&sbp2_highlevel, &sbp2_ops, SBP2_STATUS_FIFO_ADDRESS,
SBP2_STATUS_FIFO_ADDRESS +
SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2SCSI_MAX_SCSI_IDS+1));
/* Handle data movement if physical dma is not enabled/supported
* on host controller */
#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
hpsb_register_addrspace(&sbp2_highlevel, &sbp2_physdma_ops, 0x0ULL, 0xfffffffcULL);
#endif
hpsb_register_protocol(&sbp2_driver);
return 0;
......
......@@ -46,6 +46,7 @@
#include <linux/mm.h>
#include <linux/ioctl32.h>
#include <linux/compat.h>
#include <linux/cdev.h>
#include "ieee1394.h"
#include "ieee1394_types.h"
......@@ -1231,6 +1232,7 @@ static int video1394_release(struct inode *inode, struct file *file)
return 0;
}
static struct cdev video1394_cdev;
static struct file_operations video1394_fops=
{
.owner = THIS_MODULE,
......@@ -1445,18 +1447,18 @@ static void __exit video1394_exit_module (void)
hpsb_unregister_highlevel(&video1394_highlevel);
devfs_remove(VIDEO1394_DRIVER_NAME);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394);
cdev_unmap(IEEE1394_VIDEO1394_DEV, 16);
cdev_del(&video1394_cdev);
PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
}
static int __init video1394_init_module (void)
{
int ret;
ret = ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394,
THIS_MODULE, &video1394_fops);
if (ret) {
cdev_init(&video1394_cdev, &video1394_fops);
video1394_cdev.owner = THIS_MODULE;
kobject_set_name(&video1394_cdev.kobj, VIDEO1394_DRIVER_NAME);
if (cdev_add(&video1394_cdev, IEEE1394_VIDEO1394_DEV, 16)) {
PRINT_G(KERN_ERR, "video1394: unable to get minor device block");
return -EIO;
}
......@@ -1468,25 +1470,29 @@ static int __init video1394_init_module (void)
hpsb_register_protocol(&video1394_driver);
#ifdef CONFIG_COMPAT
/* First the compatible ones */
ret = register_ioctl32_conversion(VIDEO1394_IOC_LISTEN_CHANNEL, NULL);
ret |= register_ioctl32_conversion(VIDEO1394_IOC_UNLISTEN_CHANNEL, NULL);
ret |= register_ioctl32_conversion(VIDEO1394_IOC_TALK_CHANNEL, NULL);
ret |= register_ioctl32_conversion(VIDEO1394_IOC_UNTALK_CHANNEL, NULL);
/* These need translation */
ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER,
video1394_w_wait32);
ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_WAIT_BUFFER,
video1394_wr_wait32);
ret |= register_ioctl32_conversion(VIDEO1394_IOC_TALK_QUEUE_BUFFER,
video1394_queue_buf32);
ret |= register_ioctl32_conversion(VIDEO1394_IOC32_TALK_WAIT_BUFFER,
video1394_w_wait32);
ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_POLL_BUFFER,
video1394_wr_wait32);
if (ret)
PRINT_G(KERN_INFO, "Error registering ioctl32 translations");
{
int ret;
/* First the compatible ones */
ret = register_ioctl32_conversion(VIDEO1394_IOC_LISTEN_CHANNEL, NULL);
ret |= register_ioctl32_conversion(VIDEO1394_IOC_UNLISTEN_CHANNEL, NULL);
ret |= register_ioctl32_conversion(VIDEO1394_IOC_TALK_CHANNEL, NULL);
ret |= register_ioctl32_conversion(VIDEO1394_IOC_UNTALK_CHANNEL, NULL);
/* These need translation */
ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER,
video1394_w_wait32);
ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_WAIT_BUFFER,
video1394_wr_wait32);
ret |= register_ioctl32_conversion(VIDEO1394_IOC_TALK_QUEUE_BUFFER,
video1394_queue_buf32);
ret |= register_ioctl32_conversion(VIDEO1394_IOC32_TALK_WAIT_BUFFER,
video1394_w_wait32);
ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_POLL_BUFFER,
video1394_wr_wait32);
if (ret)
PRINT_G(KERN_INFO, "Error registering ioctl32 translations");
}
#endif
PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module");
......@@ -1496,3 +1502,4 @@ static int __init video1394_init_module (void)
module_init(video1394_init_module);
module_exit(video1394_exit_module);
MODULE_ALIAS_CHARDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_VIDEO1394 * 16);
......@@ -1283,6 +1283,19 @@ config B44
<file:Documentation/networking/net-modules.txt>. The module will be
called b44.
config FORCEDETH
tristate "Reverse Engineered nForce Ethernet support (EXPERIMENTAL)"
depends on NET_PCI && PCI && EXPERIMENTAL
help
If you have a network (Ethernet) controller of this type, say Y and
read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here and read
<file:Documentation/networking/net-modules.txt>. The module will be
called forcedeth.
config CS89x0
tristate "CS89x0 support"
depends on NET_PCI && ISA
......
......@@ -95,6 +95,7 @@ obj-$(CONFIG_LNE390) += lne390.o 8390.o
obj-$(CONFIG_NE3210) += ne3210.o 8390.o
obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o
obj-$(CONFIG_B44) += b44.o
obj-$(CONFIG_FORCEDETH) += forcedeth.o
obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
......
/*
* forcedeth: Ethernet driver for NVIDIA nForce media access controllers.
*
* Note: This driver is a cleanroom reimplementation based on reverse
* engineered documentation written by Carl-Daniel Hailfinger
* and Andrew de Quincey. It's neither supported nor endorsed
* by NVIDIA Corp. Use at your own risk.
*
* NVIDIA, nForce and other NVIDIA marks are trademarks or registered
* trademarks of NVIDIA Corporation in the United States and other
* countries.
*
* Copyright (C) 2003 Manfred Spraul
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Changelog:
* 0.01: 05 Oct 2003: First release that compiles without warnings.
* 0.02: 05 Oct 2003: Fix bug for drain_tx: do not try to free NULL skbs.
* Check all PCI BARs for the register window.
* udelay added to mii_rw.
* 0.03: 06 Oct 2003: Initialize dev->irq.
* 0.04: 07 Oct 2003: Initialize np->lock, reduce handled irqs, add printks.
* 0.05: 09 Oct 2003: printk removed again, irq status print tx_timeout.
* 0.06: 10 Oct 2003: MAC Address read updated, pff flag generation updated,
* irq mask updated
* 0.07: 14 Oct 2003: Further irq mask updates.
* 0.08: 20 Oct 2003: rx_desc.Length initialization added, alloc_rx refill
* added into irq handler, NULL check for drain_ring.
* 0.09: 20 Oct 2003: Basic link speed irq implementation. Only handle the
* requested interrupt sources.
* 0.10: 20 Oct 2003: First cleanup for release.
* 0.11: 21 Oct 2003: hexdump for tx added, rx buffer sizes increased.
* MAC Address init fix, set_multicast cleanup.
* 0.12: 23 Oct 2003: Cleanups for release.
* 0.13: 25 Oct 2003: Limit for concurrent tx packets increased to 10.
* Set link speed correctly. start rx before starting
* tx (start_rx sets the link speed).
* 0.14: 25 Oct 2003: Nic dependant irq mask.
* 0.15: 08 Nov 2003: fix smp deadlock with set_multicast_list during
* open.
* 0.16: 15 Nov 2003: include file cleanup for ppc64, rx buffer size
* increased to 1628 bytes.
* 0.17: 16 Nov 2003: undo rx buffer size increase. Substract 1 from
* the tx length.
* 0.18: 17 Nov 2003: fix oops due to late initialization of dev_stats
* 0.19: 29 Nov 2003: Handle RxNoBuf, detect & handle invalid mac
* addresses, really stop rx if already running
* in start_rx, clean up a bit.
* (C) Carl-Daniel Hailfinger
* 0.20: 07 Dev 2003: alloc fixes
*
* Known bugs:
* The irq handling is wrong - no tx done interrupts are generated.
* This means recovery from netif_stop_queue only happens in the hw timer
* interrupt (1/2 second on nForce2, 1/100 second on nForce3), or if an
* rx packet arrives by chance.
*/
#define FORCEDETH_VERSION "0.19"
#include <linux/module.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/timer.h>
#include <linux/skbuff.h>
#include <linux/mii.h>
#include <linux/random.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#if 0
#define dprintk printk
#else
#define dprintk(x...) do { } while (0)
#endif
/*
* Hardware access:
*/
#define DEV_NEED_LASTPACKET1 0x0001
#define DEV_IRQMASK_1 0x0002
#define DEV_IRQMASK_2 0x0004
enum {
NvRegIrqStatus = 0x000,
#define NVREG_IRQSTAT_MIIEVENT 0x040
#define NVREG_IRQSTAT_MASK 0x1ff
NvRegIrqMask = 0x004,
#define NVREG_IRQ_RX 0x0002
#define NVREG_IRQ_RX_NOBUF 0x0004
#define NVREG_IRQ_TX_ERR 0x0008
#define NVREG_IRQ_TX2 0x0010
#define NVREG_IRQ_TIMER 0x0020
#define NVREG_IRQ_LINK 0x0040
#define NVREG_IRQ_TX1 0x0100
#define NVREG_IRQMASK_WANTED_1 0x005f
#define NVREG_IRQMASK_WANTED_2 0x0147
#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1))
NvRegUnknownSetupReg6 = 0x008,
#define NVREG_UNKSETUP6_VAL 3
NvRegPollingInterval = 0x00c,
NvRegMisc1 = 0x080,
#define NVREG_MISC1_HD 0x02
#define NVREG_MISC1_FORCE 0x3b0f3c
NvRegTransmitterControl = 0x084,
#define NVREG_XMITCTL_START 0x01
NvRegTransmitterStatus = 0x088,
#define NVREG_XMITSTAT_BUSY 0x01
NvRegPacketFilterFlags = 0x8c,
#define NVREG_PFF_ALWAYS 0x7F0008
#define NVREG_PFF_PROMISC 0x80
#define NVREG_PFF_MYADDR 0x20
NvRegOffloadConfig = 0x90,
#define NVREG_OFFLOAD_HOMEPHY 0x601
#define NVREG_OFFLOAD_NORMAL 0x5ee
NvRegReceiverControl = 0x094,
#define NVREG_RCVCTL_START 0x01
NvRegReceiverStatus = 0x98,
#define NVREG_RCVSTAT_BUSY 0x01
NvRegRandomSeed = 0x9c,
#define NVREG_RNDSEED_MASK 0x00ff
#define NVREG_RNDSEED_FORCE 0x7f00
NvRegUnknownSetupReg1 = 0xA0,
#define NVREG_UNKSETUP1_VAL 0x16070f
NvRegUnknownSetupReg2 = 0xA4,
#define NVREG_UNKSETUP2_VAL 0x16
NvRegMacAddrA = 0xA8,
NvRegMacAddrB = 0xAC,
NvRegMulticastAddrA = 0xB0,
#define NVREG_MCASTADDRA_FORCE 0x01
NvRegMulticastAddrB = 0xB4,
NvRegMulticastMaskA = 0xB8,
NvRegMulticastMaskB = 0xBC,
NvRegTxRingPhysAddr = 0x100,
NvRegRxRingPhysAddr = 0x104,
NvRegRingSizes = 0x108,
#define NVREG_RINGSZ_TXSHIFT 0
#define NVREG_RINGSZ_RXSHIFT 16
NvRegUnknownTransmitterReg = 0x10c,
NvRegLinkSpeed = 0x110,
#define NVREG_LINKSPEED_FORCE 0x10000
#define NVREG_LINKSPEED_10 10
#define NVREG_LINKSPEED_100 100
#define NVREG_LINKSPEED_1000 1000
NvRegUnknownSetupReg5 = 0x130,
#define NVREG_UNKSETUP5_BIT31 (1<<31)
NvRegUnknownSetupReg3 = 0x134,
#define NVREG_UNKSETUP3_VAL1 0x200010
NvRegTxRxControl = 0x144,
#define NVREG_TXRXCTL_KICK 0x0001
#define NVREG_TXRXCTL_BIT1 0x0002
#define NVREG_TXRXCTL_BIT2 0x0004
#define NVREG_TXRXCTL_IDLE 0x0008
#define NVREG_TXRXCTL_RESET 0x0010
NvRegMIIStatus = 0x180,
#define NVREG_MIISTAT_ERROR 0x0001
#define NVREG_MIISTAT_LINKCHANGE 0x0008
#define NVREG_MIISTAT_MASK 0x000f
#define NVREG_MIISTAT_MASK2 0x000f
NvRegUnknownSetupReg4 = 0x184,
#define NVREG_UNKSETUP4_VAL 8
NvRegAdapterControl = 0x188,
#define NVREG_ADAPTCTL_START 0x02
#define NVREG_ADAPTCTL_LINKUP 0x04
#define NVREG_ADAPTCTL_PHYVALID 0x4000
#define NVREG_ADAPTCTL_RUNNING 0x100000
#define NVREG_ADAPTCTL_PHYSHIFT 24
NvRegMIISpeed = 0x18c,
#define NVREG_MIISPEED_BIT8 (1<<8)
#define NVREG_MIIDELAY 5
NvRegMIIControl = 0x190,
#define NVREG_MIICTL_INUSE 0x10000
#define NVREG_MIICTL_WRITE 0x08000
#define NVREG_MIICTL_ADDRSHIFT 5
NvRegMIIData = 0x194,
NvRegWakeUpFlags = 0x200,
#define NVREG_WAKEUPFLAGS_VAL 0x7770
#define NVREG_WAKEUPFLAGS_BUSYSHIFT 24
#define NVREG_WAKEUPFLAGS_ENABLESHIFT 16
#define NVREG_WAKEUPFLAGS_D3SHIFT 12
#define NVREG_WAKEUPFLAGS_D2SHIFT 8
#define NVREG_WAKEUPFLAGS_D1SHIFT 4
#define NVREG_WAKEUPFLAGS_D0SHIFT 0
#define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01
#define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02
#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04
NvRegPatternCRC = 0x204,
NvRegPatternMask = 0x208,
NvRegPowerCap = 0x268,
#define NVREG_POWERCAP_D3SUPP (1<<30)
#define NVREG_POWERCAP_D2SUPP (1<<26)
#define NVREG_POWERCAP_D1SUPP (1<<25)
NvRegPowerState = 0x26c,
#define NVREG_POWERSTATE_POWEREDUP 0x8000
#define NVREG_POWERSTATE_VALID 0x0100
#define NVREG_POWERSTATE_MASK 0x0003
#define NVREG_POWERSTATE_D0 0x0000
#define NVREG_POWERSTATE_D1 0x0001
#define NVREG_POWERSTATE_D2 0x0002
#define NVREG_POWERSTATE_D3 0x0003
};
struct ring_desc {
u32 PacketBuffer;
u16 Length;
u16 Flags;
};
#define NV_TX_LASTPACKET (1<<0)
#define NV_TX_RETRYERROR (1<<3)
#define NV_TX_LASTPACKET1 (1<<8)
#define NV_TX_DEFERRED (1<<10)
#define NV_TX_CARRIERLOST (1<<11)
#define NV_TX_LATECOLLISION (1<<12)
#define NV_TX_UNDERFLOW (1<<13)
#define NV_TX_ERROR (1<<14)
#define NV_TX_VALID (1<<15)
#define NV_RX_DESCRIPTORVALID (1<<0)
#define NV_RX_MISSEDFRAME (1<<1)
#define NV_RX_SUBSTRACT1 (1<<3)
#define NV_RX_ERROR1 (1<<7)
#define NV_RX_ERROR2 (1<<8)
#define NV_RX_ERROR3 (1<<9)
#define NV_RX_ERROR4 (1<<10)
#define NV_RX_CRCERR (1<<11)
#define NV_RX_OVERFLOW (1<<12)
#define NV_RX_FRAMINGERR (1<<13)
#define NV_RX_ERROR (1<<14)
#define NV_RX_AVAIL (1<<15)
/* Miscelaneous hardware related defines: */
#define NV_PCI_REGSZ 0x270
/* various timeout delays: all in usec */
#define NV_TXRX_RESET_DELAY 4
#define NV_TXSTOP_DELAY1 10
#define NV_TXSTOP_DELAY1MAX 500000
#define NV_TXSTOP_DELAY2 100
#define NV_RXSTOP_DELAY1 10
#define NV_RXSTOP_DELAY1MAX 500000
#define NV_RXSTOP_DELAY2 100
#define NV_SETUP5_DELAY 5
#define NV_SETUP5_DELAYMAX 50000
#define NV_POWERUP_DELAY 5
#define NV_POWERUP_DELAYMAX 5000
#define NV_MIIBUSY_DELAY 50
#define NV_MIIPHY_DELAY 10
#define NV_MIIPHY_DELAYMAX 10000
#define NV_WAKEUPPATTERNS 5
#define NV_WAKEUPMASKENTRIES 4
/* General driver defaults */
#define NV_WATCHDOG_TIMEO (2*HZ)
#define DEFAULT_MTU 1500 /* also maximum supported, at least for now */
#define RX_RING 128
#define TX_RING 16
/* limited to 1 packet until we understand NV_TX_LASTPACKET */
#define TX_LIMIT_STOP 10
#define TX_LIMIT_START 5
/* rx/tx mac addr + type + vlan + align + slack*/
#define RX_NIC_BUFSIZE (DEFAULT_MTU + 64)
/* even more slack */
#define RX_ALLOC_BUFSIZE (DEFAULT_MTU + 128)
#define OOM_REFILL (1+HZ/20)
#define POLL_WAIT (1+HZ/100)
/*
* SMP locking:
* All hardware access under dev->priv->lock, except the performance
* critical parts:
* - rx is (pseudo-) lockless: it relies on the single-threading provided
* by the arch code for interrupts.
* - tx setup is lockless: it relies on dev->xmit_lock. Actual submission
* needs dev->priv->lock :-(
* - set_multicast_list: preparation lockless, relies on dev->xmit_lock.
*/
/* in dev: base, irq */
struct fe_priv {
spinlock_t lock;
/* General data:
* Locking: spin_lock(&np->lock); */
struct net_device_stats stats;
int in_shutdown;
u32 linkspeed;
int duplex;
int phyaddr;
/* General data: RO fields */
dma_addr_t ring_addr;
struct pci_dev *pci_dev;
u32 orig_mac[2];
u32 irqmask;
/* rx specific fields.
* Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
*/
struct ring_desc *rx_ring;
unsigned int cur_rx, refill_rx;
struct sk_buff *rx_skbuff[RX_RING];
dma_addr_t rx_dma[RX_RING];
unsigned int rx_buf_sz;
struct timer_list oom_kick;
struct timer_list nic_poll;
/*
* tx specific fields.
*/
struct ring_desc *tx_ring;
unsigned int next_tx, nic_tx;
struct sk_buff *tx_skbuff[TX_RING];
dma_addr_t tx_dma[TX_RING];
u16 tx_flags;
};
/*
* Maximum number of loops until we assume that a bit in the irq mask
* is stuck. Overridable with module param.
*/
static int max_interrupt_work = 5;
static inline struct fe_priv *get_nvpriv(struct net_device *dev)
{
return (struct fe_priv *) dev->priv;
}
static inline u8 *get_hwbase(struct net_device *dev)
{
return (u8 *) dev->base_addr;
}
static inline void pci_push(u8 * base)
{
/* force out pending posted writes */
readl(base);
}
static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
int delay, int delaymax, const char *msg)
{
u8 *base = get_hwbase(dev);
pci_push(base);
do {
udelay(delay);
delaymax -= delay;
if (delaymax < 0) {
if (msg)
printk(msg);
return 1;
}
} while ((readl(base + offset) & mask) != target);
return 0;
}
#define MII_READ (-1)
/* mii_rw: read/write a register on the PHY.
*
* Caller must guarantee serialization
*/
static int mii_rw(struct net_device *dev, int addr, int miireg, int value)
{
u8 *base = get_hwbase(dev);
int was_running;
u32 reg;
int retval;
writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
was_running = 0;
reg = readl(base + NvRegAdapterControl);
if (reg & NVREG_ADAPTCTL_RUNNING) {
was_running = 1;
writel(reg & ~NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl);
}
reg = readl(base + NvRegMIIControl);
if (reg & NVREG_MIICTL_INUSE) {
writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl);
udelay(NV_MIIBUSY_DELAY);
}
reg = NVREG_MIICTL_INUSE | (addr << NVREG_MIICTL_ADDRSHIFT) | miireg;
if (value != MII_READ) {
writel(value, base + NvRegMIIData);
reg |= NVREG_MIICTL_WRITE;
}
writel(reg, base + NvRegMIIControl);
if (reg_delay(dev, NvRegMIIControl, NVREG_MIICTL_INUSE, 0,
NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, NULL)) {
dprintk(KERN_DEBUG "%s: mii_rw of reg %d at PHY %d timed out.\n",
dev->name, miireg, addr);
retval = -1;
} else if (value != MII_READ) {
/* it was a write operation - fewer failures are detectable */
dprintk(KERN_DEBUG "%s: mii_rw wrote 0x%x to reg %d at PHY %d\n",
dev->name, value, miireg, addr);
retval = 0;
} else if (readl(base + NvRegMIIStatus) & NVREG_MIISTAT_ERROR) {
dprintk(KERN_DEBUG "%s: mii_rw of reg %d at PHY %d failed.\n",
dev->name, miireg, addr);
retval = -1;
} else {
/* FIXME: why is that required? */
udelay(50);
retval = readl(base + NvRegMIIData);
dprintk(KERN_DEBUG "%s: mii_rw read from reg %d at PHY %d: 0x%x.\n",
dev->name, miireg, addr, retval);
}
if (was_running) {
reg = readl(base + NvRegAdapterControl);
writel(reg | NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl);
}
return retval;
}
static void start_rx(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
u8 *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: start_rx\n", dev->name);
/* Already running? Stop it. */
if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) {
writel(0, base + NvRegReceiverControl);
pci_push(base);
}
writel(np->linkspeed, base + NvRegLinkSpeed);
pci_push(base);
writel(NVREG_RCVCTL_START, base + NvRegReceiverControl);
pci_push(base);
}
static void stop_rx(struct net_device *dev)
{
u8 *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: stop_rx\n", dev->name);
writel(0, base + NvRegReceiverControl);
reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0,
NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX,
KERN_INFO "stop_rx: ReceiverStatus remained busy");
udelay(NV_RXSTOP_DELAY2);
writel(0, base + NvRegLinkSpeed);
}
static void start_tx(struct net_device *dev)
{
u8 *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: start_tx\n", dev->name);
writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl);
pci_push(base);
}
static void stop_tx(struct net_device *dev)
{
u8 *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: stop_tx\n", dev->name);
writel(0, base + NvRegTransmitterControl);
reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0,
NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX,
KERN_INFO "stop_tx: TransmitterStatus remained busy");
udelay(NV_TXSTOP_DELAY2);
writel(0, base + NvRegUnknownTransmitterReg);
}
static void txrx_reset(struct net_device *dev)
{
u8 *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: txrx_reset\n", dev->name);
writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET, base + NvRegTxRxControl);
pci_push(base);
udelay(NV_TXRX_RESET_DELAY);
writel(NVREG_TXRXCTL_BIT2, base + NvRegTxRxControl);
pci_push(base);
}
/*
* get_stats: dev->get_stats function
* Get latest stats value from the nic.
* Called with read_lock(&dev_base_lock) held for read -
* only synchronized against unregister_netdevice.
*/
static struct net_device_stats *get_stats(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
/* It seems that the nic always generates interrupts and doesn't
* accumulate errors internally. Thus the current values in np->stats
* are already up to date.
*/
return &np->stats;
}
/*
* nic_ioctl: dev->do_ioctl function
* Called with rtnl_lock held.
*/
static int nic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
return -EOPNOTSUPP;
}
/*
* alloc_rx: fill rx ring entries.
* Return 1 if the allocations for the skbs failed and the
* rx engine is without Available descriptors
*/
static int alloc_rx(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
unsigned int refill_rx = np->refill_rx;
while (np->cur_rx != refill_rx) {
int nr = refill_rx % RX_RING;
struct sk_buff *skb;
if (np->rx_skbuff[nr] == NULL) {
skb = dev_alloc_skb(RX_ALLOC_BUFSIZE);
if (!skb)
break;
skb->dev = dev;
np->rx_skbuff[nr] = skb;
} else {
skb = np->rx_skbuff[nr];
}
np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len,
PCI_DMA_FROMDEVICE);
np->rx_ring[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
np->rx_ring[nr].Length = cpu_to_le16(RX_NIC_BUFSIZE);
wmb();
np->rx_ring[nr].Flags = cpu_to_le16(NV_RX_AVAIL);
dprintk(KERN_DEBUG "%s: alloc_rx: Packet %d marked as Available\n",
dev->name, refill_rx);
refill_rx++;
}
np->refill_rx = refill_rx;
if (np->cur_rx - refill_rx == RX_RING)
return 1;
return 0;
}
static void do_rx_refill(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = get_nvpriv(dev);
disable_irq(dev->irq);
if (alloc_rx(dev)) {
spin_lock(&np->lock);
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
spin_unlock(&np->lock);
}
enable_irq(dev->irq);
}
static int init_ring(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
int i;
np->next_tx = np->nic_tx = 0;
for (i = 0; i < TX_RING; i++) {
np->tx_ring[i].Flags = 0;
}
np->cur_rx = RX_RING;
np->refill_rx = 0;
for (i = 0; i < RX_RING; i++) {
np->rx_ring[i].Flags = 0;
}
return alloc_rx(dev);
}
static void drain_tx(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
int i;
for (i = 0; i < TX_RING; i++) {
np->tx_ring[i].Flags = 0;
if (np->tx_skbuff[i]) {
pci_unmap_single(np->pci_dev, np->tx_dma[i],
np->tx_skbuff[i]->len,
PCI_DMA_TODEVICE);
dev_kfree_skb(np->tx_skbuff[i]);
np->tx_skbuff[i] = NULL;
np->stats.tx_dropped++;
}
}
}
static void drain_rx(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
int i;
for (i = 0; i < RX_RING; i++) {
np->rx_ring[i].Flags = 0;
wmb();
if (np->rx_skbuff[i]) {
pci_unmap_single(np->pci_dev, np->rx_dma[i],
np->rx_skbuff[i]->len,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(np->rx_skbuff[i]);
np->rx_skbuff[i] = NULL;
}
}
}
static void drain_ring(struct net_device *dev)
{
drain_tx(dev);
drain_rx(dev);
}
/*
* start_xmit: dev->hard_start_xmit function
* Called with dev->xmit_lock held.
*/
static int start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
int nr = np->next_tx % TX_RING;
np->tx_skbuff[nr] = skb;
np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len,
PCI_DMA_TODEVICE);
np->tx_ring[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
np->tx_ring[nr].Length = cpu_to_le16(skb->len-1);
spin_lock_irq(&np->lock);
wmb();
np->tx_ring[nr].Flags = np->tx_flags;
dprintk(KERN_DEBUG "%s: start_xmit: packet packet %d queued for transmission.\n",
dev->name, np->next_tx);
{
int j;
for (j=0; j<64; j++) {
if ((j%16) == 0)
dprintk("\n%03x:", j);
dprintk(" %02x", ((unsigned char*)skb->data)[j]);
}
dprintk("\n");
}
np->next_tx++;
dev->trans_start = jiffies;
if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP)
netif_stop_queue(dev);
spin_unlock_irq(&np->lock);
writel(NVREG_TXRXCTL_KICK, get_hwbase(dev) + NvRegTxRxControl);
return 0;
}
/*
* tx_done: check for completed packets, release the skbs.
*
* Caller must own np->lock.
*/
static void tx_done(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
while (np->nic_tx < np->next_tx) {
struct ring_desc *prd;
int i = np->nic_tx % TX_RING;
prd = &np->tx_ring[i];
dprintk(KERN_DEBUG "%s: tx_done: looking at packet %d, Flags 0x%x.\n",
dev->name, np->nic_tx, prd->Flags);
if (prd->Flags & cpu_to_le16(NV_TX_VALID))
break;
if (prd->Flags & cpu_to_le16(NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
NV_TX_UNDERFLOW|NV_TX_ERROR)) {
if (prd->Flags & cpu_to_le16(NV_TX_UNDERFLOW))
np->stats.tx_fifo_errors++;
if (prd->Flags & cpu_to_le16(NV_TX_CARRIERLOST))
np->stats.tx_carrier_errors++;
np->stats.tx_errors++;
} else {
np->stats.tx_packets++;
np->stats.tx_bytes += np->tx_skbuff[i]->len;
}
pci_unmap_single(np->pci_dev, np->tx_dma[i],
np->tx_skbuff[i]->len,
PCI_DMA_TODEVICE);
dev_kfree_skb_irq(np->tx_skbuff[i]);
np->tx_skbuff[i] = NULL;
np->nic_tx++;
}
if (np->next_tx - np->nic_tx < TX_LIMIT_START)
netif_wake_queue(dev);
}
/*
* tx_timeout: dev->tx_timeout function
* Called with dev->xmit_lock held.
*/
static void tx_timeout(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
u8 *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: Got tx_timeout. irq: %08x\n", dev->name,
readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK);
spin_lock_irq(&np->lock);
/* 1) stop tx engine */
stop_tx(dev);
/* 2) check that the packets were not sent already: */
tx_done(dev);
/* 3) if there are dead entries: clear everything */
if (np->next_tx != np->nic_tx) {
printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);
drain_tx(dev);
np->next_tx = np->nic_tx = 0;
writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
netif_wake_queue(dev);
}
/* 4) restart tx engine */
start_tx(dev);
spin_unlock_irq(&np->lock);
}
static void rx_process(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
for (;;) {
struct ring_desc *prd;
struct sk_buff *skb;
int len;
int i;
if (np->cur_rx - np->refill_rx >= RX_RING)
break; /* we scanned the whole ring - do not continue */
i = np->cur_rx % RX_RING;
prd = &np->rx_ring[i];
dprintk(KERN_DEBUG "%s: rx_process: looking at packet %d, Flags 0x%x.\n",
dev->name, np->cur_rx, prd->Flags);
if (prd->Flags & cpu_to_le16(NV_RX_AVAIL))
break; /* still owned by hardware, */
/*
* the packet is for us - immediately tear down the pci mapping, and
* prefetch the first cacheline of the packet.
*/
pci_unmap_single(np->pci_dev, np->rx_dma[i],
np->rx_skbuff[i]->len,
PCI_DMA_FROMDEVICE);
prefetch(np->rx_skbuff[i]->data);
{
int j;
dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",prd->Flags);
for (j=0; j<64; j++) {
if ((j%16) == 0)
dprintk("\n%03x:", j);
dprintk(" %02x", ((unsigned char*)np->rx_skbuff[i]->data)[j]);
}
dprintk("\n");
}
/* look at what we actually got: */
if (!(prd->Flags & cpu_to_le16(NV_RX_DESCRIPTORVALID)))
goto next_pkt;
len = le16_to_cpu(prd->Length);
if (prd->Flags & cpu_to_le16(NV_RX_MISSEDFRAME)) {
np->stats.rx_missed_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
if (prd->Flags & cpu_to_le16(NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) {
np->stats.rx_errors++;
goto next_pkt;
}
if (prd->Flags & cpu_to_le16(NV_RX_CRCERR)) {
np->stats.rx_crc_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
if (prd->Flags & cpu_to_le16(NV_RX_OVERFLOW)) {
np->stats.rx_over_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
if (prd->Flags & cpu_to_le16(NV_RX_ERROR)) {
/* framing errors are soft errors, the rest is fatal. */
if (prd->Flags & cpu_to_le16(NV_RX_FRAMINGERR)) {
if (prd->Flags & cpu_to_le16(NV_RX_SUBSTRACT1)) {
len--;
}
} else {
np->stats.rx_errors++;
goto next_pkt;
}
}
/* got a valid packet - forward it to the network core */
skb = np->rx_skbuff[i];
np->rx_skbuff[i] = NULL;
skb_put(skb, len);
skb->protocol = eth_type_trans(skb, dev);
dprintk(KERN_DEBUG "%s: rx_process: packet %d with %d bytes, proto %d accepted.\n",
dev->name, np->cur_rx, len, skb->protocol);
netif_rx(skb);
dev->last_rx = jiffies;
np->stats.rx_packets++;
np->stats.rx_bytes += len;
next_pkt:
np->cur_rx++;
}
}
/*
* change_mtu: dev->change_mtu function
* Called with dev_base_lock held for read.
*/
static int change_mtu(struct net_device *dev, int new_mtu)
{
if (new_mtu > DEFAULT_MTU)
return -EINVAL;
dev->mtu = new_mtu;
return 0;
}
/*
* change_mtu: dev->change_mtu function
* Called with dev->xmit_lock held.
*/
static void set_multicast(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
u8 *base = get_hwbase(dev);
u32 addr[2];
u32 mask[2];
u32 pff;
memset(addr, 0, sizeof(addr));
memset(mask, 0, sizeof(mask));
if (dev->flags & IFF_PROMISC) {
printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
pff = NVREG_PFF_PROMISC;
} else {
pff = NVREG_PFF_MYADDR;
if (dev->flags & IFF_ALLMULTI || dev->mc_list) {
u32 alwaysOff[2];
u32 alwaysOn[2];
alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0xffffffff;
if (dev->flags & IFF_ALLMULTI) {
alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0;
} else {
struct dev_mc_list *walk;
walk = dev->mc_list;
while (walk != NULL) {
u32 a, b;
a = le32_to_cpu(*(u32 *) walk->dmi_addr);
b = le16_to_cpu(*(u16 *) (&walk->dmi_addr[4]));
alwaysOn[0] &= a;
alwaysOff[0] &= ~a;
alwaysOn[1] &= b;
alwaysOff[1] &= ~b;
walk = walk->next;
}
}
addr[0] = alwaysOn[0];
addr[1] = alwaysOn[1];
mask[0] = alwaysOn[0] | alwaysOff[0];
mask[1] = alwaysOn[1] | alwaysOff[1];
}
}
addr[0] |= NVREG_MCASTADDRA_FORCE;
pff |= NVREG_PFF_ALWAYS;
spin_lock_irq(&np->lock);
stop_rx(dev);
writel(addr[0], base + NvRegMulticastAddrA);
writel(addr[1], base + NvRegMulticastAddrB);
writel(mask[0], base + NvRegMulticastMaskA);
writel(mask[1], base + NvRegMulticastMaskB);
writel(pff, base + NvRegPacketFilterFlags);
start_rx(dev);
spin_unlock_irq(&np->lock);
}
static int update_linkspeed(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
int adv, lpa, newls, newdup;
adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ);
dprintk(KERN_DEBUG "%s: update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n",
dev->name, adv, lpa);
/* FIXME: handle parallel detection properly, handle gigabit ethernet */
lpa = lpa & adv;
if (lpa & LPA_100FULL) {
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100;
newdup = 1;
} else if (lpa & LPA_100HALF) {
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100;
newdup = 0;
} else if (lpa & LPA_10FULL) {
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
newdup = 1;
} else if (lpa & LPA_10HALF) {
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
newdup = 0;
} else {
dprintk(KERN_DEBUG "%s: bad ability %04x - falling back to 10HD.\n", dev->name, lpa);
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
newdup = 0;
}
if (np->duplex != newdup || np->linkspeed != newls) {
np->duplex = newdup;
np->linkspeed = newls;
return 1;
}
return 0;
}
static void link_irq(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
u8 *base = get_hwbase(dev);
u32 miistat;
int miival;
miistat = readl(base + NvRegMIIStatus);
writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
printk(KERN_DEBUG "%s: link change notification, status 0x%x.\n", dev->name, miistat);
miival = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
if (miival & BMSR_ANEGCOMPLETE) {
update_linkspeed(dev);
if (netif_carrier_ok(dev)) {
stop_rx(dev);
} else {
netif_carrier_on(dev);
printk(KERN_INFO "%s: link up.\n", dev->name);
}
writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD),
base + NvRegMisc1);
start_rx(dev);
} else {
if (netif_carrier_ok(dev)) {
netif_carrier_off(dev);
printk(KERN_INFO "%s: link down.\n", dev->name);
stop_rx(dev);
}
writel(np->linkspeed, base + NvRegLinkSpeed);
pci_push(base);
}
}
static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = get_nvpriv(dev);
u8 *base = get_hwbase(dev);
u32 events;
int i;
dprintk(KERN_DEBUG "%s: nic_irq\n", dev->name);
for (i=0; ; i++) {
events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
pci_push(base);
dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) {
spin_lock(&np->lock);
tx_done(dev);
spin_unlock(&np->lock);
}
if (events & (NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) {
rx_process(dev);
if (alloc_rx(dev)) {
spin_lock(&np->lock);
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
spin_unlock(&np->lock);
}
}
if (events & NVREG_IRQ_LINK) {
spin_lock(&np->lock);
link_irq(dev);
spin_unlock(&np->lock);
}
if (events & (NVREG_IRQ_TX_ERR)) {
dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
dev->name, events);
}
if (events & (NVREG_IRQ_UNKNOWN)) {
printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
dev->name, events);
}
if (i > max_interrupt_work) {
spin_lock(&np->lock);
/* disable interrupts on the nic */
writel(0, base + NvRegIrqMask);
pci_push(base);
if (!np->in_shutdown)
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
printk(KERN_DEBUG "%s: too many iterations (%d) in nic_irq.\n", dev->name, i);
spin_unlock(&np->lock);
break;
}
}
dprintk(KERN_DEBUG "%s: nic_irq completed\n", dev->name);
return IRQ_RETVAL(i);
}
static void do_nic_poll(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = get_nvpriv(dev);
u8 *base = get_hwbase(dev);
disable_irq(dev->irq);
/*
* reenable interrupts on the nic, we have to do this before calling
* nic_irq because that may decide to do otherwise
*/
writel(np->irqmask, base + NvRegIrqMask);
pci_push(base);
nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL);
enable_irq(dev->irq);
}
static int open(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
u8 *base = get_hwbase(dev);
int ret, oom, i;
dprintk(KERN_DEBUG "forcedeth: open\n");
/* 1) erase previous misconfiguration */
/* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */
writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
writel(0, base + NvRegMulticastAddrB);
writel(0, base + NvRegMulticastMaskA);
writel(0, base + NvRegMulticastMaskB);
writel(0, base + NvRegPacketFilterFlags);
writel(0, base + NvRegAdapterControl);
writel(0, base + NvRegLinkSpeed);
writel(0, base + NvRegUnknownTransmitterReg);
txrx_reset(dev);
writel(0, base + NvRegUnknownSetupReg6);
/* 2) initialize descriptor rings */
np->in_shutdown = 0;
oom = init_ring(dev);
/* 3) set mac address */
{
u32 mac[2];
mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
(dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24);
mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8);
writel(mac[0], base + NvRegMacAddrA);
writel(mac[1], base + NvRegMacAddrB);
}
/* 4) continue setup */
np->linkspeed = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
np->duplex = 0;
writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3);
writel(0, base + NvRegTxRxControl);
pci_push(base);
writel(NVREG_TXRXCTL_BIT1, base + NvRegTxRxControl);
reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31,
NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX,
KERN_INFO "open: SetupReg5, Bit 31 remained off\n");
writel(0, base + NvRegUnknownSetupReg4);
/* 5) Find a suitable PHY */
writel(NVREG_MIISPEED_BIT8|NVREG_MIIDELAY, base + NvRegMIISpeed);
for (i = 1; i < 32; i++) {
int id1, id2;
id1 = mii_rw(dev, i, MII_PHYSID1, MII_READ);
if (id1 < 0)
continue;
id2 = mii_rw(dev, i, MII_PHYSID2, MII_READ);
if (id2 < 0)
continue;
dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n",
dev->name, id1, id2, i);
np->phyaddr = i;
update_linkspeed(dev);
break;
}
if (i == 32) {
printk(KERN_INFO "%s: open: failing due to lack of suitable PHY.\n",
dev->name);
ret = -EINVAL;
goto out_drain;
}
/* 6) continue setup */
writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD),
base + NvRegMisc1);
writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus);
writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags);
writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig);
writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus);
get_random_bytes(&i, sizeof(i));
writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed);
writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1);
writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2);
writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6);
writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT)|NVREG_ADAPTCTL_PHYVALID,
base + NvRegAdapterControl);
writel(NVREG_UNKSETUP4_VAL, base + NvRegUnknownSetupReg4);
writel(NVREG_WAKEUPFLAGS_VAL, base + NvRegWakeUpFlags);
/* 7) start packet processing */
writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr);
writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
i = readl(base + NvRegPowerState);
if ( (i & NVREG_POWERSTATE_POWEREDUP) == 0) {
writel(NVREG_POWERSTATE_POWEREDUP|i, base + NvRegPowerState);
}
pci_push(base);
udelay(10);
writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID, base + NvRegPowerState);
writel(NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl);
writel(0, base + NvRegIrqMask);
pci_push(base);
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
pci_push(base);
writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
pci_push(base);
ret = request_irq(dev->irq, &nic_irq, SA_SHIRQ, dev->name, dev);
if (ret)
goto out_drain;
writel(np->irqmask, base + NvRegIrqMask);
spin_lock_irq(&np->lock);
writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
writel(0, base + NvRegMulticastAddrB);
writel(0, base + NvRegMulticastMaskA);
writel(0, base + NvRegMulticastMaskB);
writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags);
start_rx(dev);
start_tx(dev);
netif_start_queue(dev);
if (oom)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
if (!(mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ) & BMSR_ANEGCOMPLETE)) {
printk("%s: no link during initialization.\n", dev->name);
netif_carrier_off(dev);
}
spin_unlock_irq(&np->lock);
return 0;
out_drain:
drain_ring(dev);
return ret;
}
static int close(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
spin_lock_irq(&np->lock);
np->in_shutdown = 1;
spin_unlock_irq(&np->lock);
synchronize_irq(dev->irq);
del_timer_sync(&np->oom_kick);
del_timer_sync(&np->nic_poll);
netif_stop_queue(dev);
spin_lock_irq(&np->lock);
stop_tx(dev);
stop_rx(dev);
spin_unlock_irq(&np->lock);
free_irq(dev->irq, dev);
drain_ring(dev);
/* FIXME: power down nic */
return 0;
}
static int __devinit probe_nic(struct pci_dev *pci_dev, const struct pci_device_id *id)
{
struct net_device *dev;
struct fe_priv *np;
unsigned long addr;
u8 *base;
int err, i;
dev = alloc_etherdev(sizeof(struct fe_priv));
np = get_nvpriv(dev);
err = -ENOMEM;
if (!dev)
goto out;
np->pci_dev = pci_dev;
spin_lock_init(&np->lock);
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pci_dev->dev);
init_timer(&np->oom_kick);
np->oom_kick.data = (unsigned long) dev;
np->oom_kick.function = &do_rx_refill; /* timer handler */
init_timer(&np->nic_poll);
np->nic_poll.data = (unsigned long) dev;
np->nic_poll.function = &do_nic_poll; /* timer handler */
err = pci_enable_device(pci_dev);
if (err) {
printk(KERN_INFO "forcedeth: pci_enable_dev failed (%d) for device %s\n",
err, pci_name(pci_dev));
goto out_free;
}
pci_set_master(pci_dev);
err = pci_request_regions(pci_dev, dev->name);
if (err < 0)
goto out_disable;
err = -EINVAL;
addr = 0;
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
dprintk(KERN_DEBUG "%s: resource %d start %p len %ld flags 0x%08lx.\n",
pci_name(pci_dev), i, (void*)pci_resource_start(pci_dev, i),
pci_resource_len(pci_dev, i),
pci_resource_flags(pci_dev, i));
if (pci_resource_flags(pci_dev, i) & IORESOURCE_MEM &&
pci_resource_len(pci_dev, i) >= NV_PCI_REGSZ) {
addr = pci_resource_start(pci_dev, i);
break;
}
}
if (i == DEVICE_COUNT_RESOURCE) {
printk(KERN_INFO "forcedeth: Couldn't find register window for device %s.\n",
pci_name(pci_dev));
goto out_relreg;
}
err = -ENOMEM;
dev->base_addr = (unsigned long) ioremap(addr, NV_PCI_REGSZ);
if (!dev->base_addr)
goto out_disable;
dev->irq = pci_dev->irq;
np->rx_ring = pci_alloc_consistent(pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING),
&np->ring_addr);
if (!np->rx_ring)
goto out_unmap;
np->tx_ring = &np->rx_ring[RX_RING];
dev->open = open;
dev->stop = close;
dev->hard_start_xmit = start_xmit;
dev->get_stats = get_stats;
dev->change_mtu = change_mtu;
dev->set_multicast_list = set_multicast;
dev->do_ioctl = nic_ioctl;
dev->tx_timeout = tx_timeout;
dev->watchdog_timeo = NV_WATCHDOG_TIMEO;
pci_set_drvdata(pci_dev, dev);
/* read the mac address */
base = get_hwbase(dev);
np->orig_mac[0] = readl(base + NvRegMacAddrA);
np->orig_mac[1] = readl(base + NvRegMacAddrB);
dev->dev_addr[0] = (np->orig_mac[1] >> 8) & 0xff;
dev->dev_addr[1] = (np->orig_mac[1] >> 0) & 0xff;
dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff;
dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff;
dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff;
dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff;
if (!is_valid_ether_addr(dev->dev_addr)) {
/*
* Bad mac address. At least one bios sets the mac address
* to 01:23:45:67:89:ab
*/
printk(KERN_ERR "%s: Invalid Mac address detected: %02x:%02x:%02x:%02x:%02x:%02x\n",
pci_name(pci_dev),
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
printk(KERN_ERR "Please complain to your hardware vendor. Switching to a random MAC.\n");
dev->dev_addr[0] = 0x00;
dev->dev_addr[1] = 0x00;
dev->dev_addr[2] = 0x6c;
get_random_bytes(&dev->dev_addr[3], 3);
}
dprintk(KERN_DEBUG "%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", pci_name(pci_dev),
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
np->tx_flags = cpu_to_le16(NV_TX_LASTPACKET|NV_TX_LASTPACKET1|NV_TX_VALID);
if (id->driver_data & DEV_NEED_LASTPACKET1)
np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1);
if (id->driver_data & DEV_IRQMASK_1)
np->irqmask = NVREG_IRQMASK_WANTED_1;
if (id->driver_data & DEV_IRQMASK_2)
np->irqmask = NVREG_IRQMASK_WANTED_2;
err = register_netdev(dev);
if (err) {
printk(KERN_INFO "forcedeth: unable to register netdev: %d\n", err);
goto out_freering;
}
printk(KERN_INFO "%s: forcedeth.c: subsystem: %05x:%04x bound to %s\n",
dev->name, pci_dev->subsystem_vendor, pci_dev->subsystem_device,
pci_name(pci_dev));
return 0;
out_freering:
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING),
np->rx_ring, np->ring_addr);
out_unmap:
iounmap(get_hwbase(dev));
out_relreg:
pci_release_regions(pci_dev);
out_disable:
pci_disable_device(pci_dev);
out_free:
free_netdev(dev);
pci_set_drvdata(pci_dev, NULL);
out:
return err;
}
static void __devexit remove_nic(struct pci_dev *pci_dev)
{
struct net_device *dev = pci_get_drvdata(pci_dev);
struct fe_priv *np = get_nvpriv(dev);
u8 *base = get_hwbase(dev);
unregister_netdev(dev);
/* special op: write back the misordered MAC address - otherwise
* the next probe_nic would see a wrong address.
*/
writel(np->orig_mac[0], base + NvRegMacAddrA);
writel(np->orig_mac[1], base + NvRegMacAddrB);
/* free all structures */
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring, np->ring_addr);
iounmap(get_hwbase(dev));
pci_release_regions(pci_dev);
pci_disable_device(pci_dev);
free_netdev(dev);
pci_set_drvdata(pci_dev, NULL);
}
static struct pci_device_id pci_tbl[] = {
{ /* nForce Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = 0x1C3,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_IRQMASK_1,
},
{ /* nForce2 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = 0x0066,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2,
},
{ /* nForce3 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = 0x00D6,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2,
},
{0,},
};
static struct pci_driver driver = {
.name = "forcedeth",
.id_table = pci_tbl,
.probe = probe_nic,
.remove = __devexit_p(remove_nic),
};
static int __init init_nic(void)
{
printk(KERN_INFO "forcedeth.c: Reverse Engineered nForce ethernet driver. Version %s.\n", FORCEDETH_VERSION);
return pci_module_init(&driver);
}
static void __exit exit_nic(void)
{
pci_unregister_driver(&driver);
}
MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt");
MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>");
MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, pci_tbl);
module_init(init_nic);
module_exit(exit_nic);
......@@ -325,6 +325,21 @@ config HDLC_X25
comment "X.25/LAPB support is disabled"
depends on WAN && HDLC && (LAPB!=m || HDLC!=m) && LAPB!=y
config PCI200SYN
tristate "Goramo PCI200SYN support"
depends on HDLC && PCI
help
This driver is for PCI200SYN cards made by Goramo sp. j.
If you have such a card, say Y here and see
<http://hq.pm.waw.pl/pub/hdlc/>
If you want to compile the driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called pci200syn.
If unsure, say N here.
config WANXL
tristate "SBE Inc. wanXL support"
depends on HDLC && PCI
......
......@@ -67,6 +67,7 @@ endif
obj-$(CONFIG_N2) += n2.o
obj-$(CONFIG_C101) += c101.o
obj-$(CONFIG_WANXL) += wanxl.o
obj-$(CONFIG_PCI200SYN) += pci200syn.o
ifeq ($(CONFIG_WANXL_BUILD_FIRMWARE),y)
ifeq ($(ARCH),m68k)
......
......@@ -23,8 +23,8 @@
*
*/
#ifndef _HD64572_H
#define _HD64572_H
#ifndef __HD64572_H
#define __HD64572_H
/* Illegal Access Register */
#define ILAR 0x00
......@@ -59,6 +59,9 @@
#define IR0_M(val, chan) ((val)<<(8*(chan))) /* Int MSCI */
/* MSCI Channel Registers */
#define MSCI0_OFFSET 0x00
#define MSCI1_OFFSET 0x80
#define MD0 0x138 /* Mode reg 0 */
#define MD1 0x139 /* Mode reg 1 */
#define MD2 0x13a /* Mode reg 2 */
......@@ -107,6 +110,11 @@
#define RCR 0x156 /* Rx DMA Critical Request Reg */
/* Timer Registers */
#define TIMER0RX_OFFSET 0x00
#define TIMER0TX_OFFSET 0x10
#define TIMER1RX_OFFSET 0x20
#define TIMER1TX_OFFSET 0x30
#define TCNTL 0x200 /* Timer Upcounter L */
#define TCNTH 0x201 /* Timer Upcounter H */
#define TCONRL 0x204 /* Timer Constant Register L */
......@@ -132,6 +140,11 @@
#define DCR_TX(chan) (0x59 + 2*chan) /* DMA Command Reg (Tx) */
/* DMA Channel Registers */
#define DMAC0RX_OFFSET 0x00
#define DMAC0TX_OFFSET 0x20
#define DMAC1RX_OFFSET 0x40
#define DMAC1TX_OFFSET 0x60
#define DARL 0x80 /* Dest Addr Register L (single-block, RX only) */
#define DARH 0x81 /* Dest Addr Register H (single-block, RX only) */
#define DARB 0x82 /* Dest Addr Register B (single-block, RX only) */
......@@ -166,7 +179,17 @@ typedef struct {
unsigned char filler[5]; /* alignment filler (16 bytes) */
} pcsca_bd_t;
/*
/* Block Descriptor Structure */
typedef struct {
u32 cp; /* pointer to next block descriptor */
u32 bp; /* buffer pointer */
u16 len; /* data length */
u8 stat; /* status */
u8 unused; /* pads to 4-byte boundary */
}pkt_desc;
/*
Descriptor Status definitions:
Bit Transmission Reception
......@@ -190,6 +213,23 @@ typedef struct {
#define DST_SHRT 0x40 /* Short Frame */
#define DST_EOM 0x80 /* End of Message */
/* Packet Descriptor Status bits */
#define ST_TX_EOM 0x80 /* End of frame */
#define ST_TX_UNDRRUN 0x08
#define ST_TX_OWNRSHP 0x02
#define ST_TX_EOT 0x01 /* End of transmition */
#define ST_RX_EOM 0x80 /* End of frame */
#define ST_RX_SHORT 0x40 /* Short frame */
#define ST_RX_ABORT 0x20 /* Abort */
#define ST_RX_RESBIT 0x10 /* Residual bit */
#define ST_RX_OVERRUN 0x08 /* Overrun */
#define ST_RX_CRC 0x04 /* CRC */
#define ST_RX_OWNRSHP 0x02
#define ST_ERROR_MASK 0x7C
/* Status Counter Registers */
#define CMCR 0x158 /* Counter Master Ctl Reg */
#define TECNTL 0x160 /* Tx EOM Counter L */
......@@ -246,11 +286,25 @@ typedef struct {
#define MD0_BIT_SYNC 0x80
#define MD0_TRANSP 0xc0
#define MD0_HDLC 0x80 /* Bit-sync HDLC mode */
#define MD0_CRC_NONE 0x00
#define MD0_CRC_16_0 0x04
#define MD0_CRC_16 0x05
#define MD0_CRC_ITU32 0x06
#define MD0_CRC_ITU 0x07
#define MD1_NOADDR 0x00
#define MD1_SADDR1 0x40
#define MD1_SADDR2 0x80
#define MD1_DADDR 0xc0
#define MD2_NRZI_IEEE 0x40
#define MD2_MANCHESTER 0x80
#define MD2_FM_MARK 0xA0
#define MD2_FM_SPACE 0xC0
#define MD2_LOOPBACK 0x03 /* Local data Loopback */
#define MD2_F_DUPLEX 0x00
#define MD2_AUTO_ECHO 0x01
#define MD2_LOOP_HI_Z 0x02
......@@ -274,6 +328,10 @@ typedef struct {
#define CTL_URSKP 0x40
#define CTL_URCT 0x80
#define CTL_NORTS 0x01
#define CTL_NODTR 0x02
#define CTL_IDLE 0x10
#define RXS_BR0 0x01
#define RXS_BR1 0x02
#define RXS_BR2 0x04
......@@ -302,6 +360,12 @@ typedef struct {
#define EXS_TES1 0x20
#define EXS_TES2 0x40
#define CLK_BRG_MASK 0x0F
#define CLK_PIN_OUT 0x80
#define CLK_LINE 0x00 /* clock line input */
#define CLK_BRG 0x40 /* internal baud rate generator */
#define CLK_TX_RXCLK 0x60 /* TX clock from RX clock */
#define CMD_RX_RST 0x11
#define CMD_RX_ENA 0x12
#define CMD_RX_DIS 0x13
......@@ -324,6 +388,10 @@ typedef struct {
#define CMD_SRCH_MODE 0x31
#define CMD_NOP 0x00
#define CMD_RESET 0x21
#define CMD_TX_ENABLE 0x02
#define CMD_RX_ENABLE 0x12
#define ST0_RXRDY 0x01
#define ST0_TXRDY 0x02
#define ST0_RXINTB 0x20
......@@ -374,6 +442,8 @@ typedef struct {
#define IE0_RXINTB 0x20
#define IE0_RXINTA 0x40
#define IE0_TXINT 0x80
#define IE0_UDRN 0x00008000 /* TX underrun MSCI interrupt enable */
#define IE0_CDCD 0x00000400 /* CD level change interrupt enable */
#define IE1_IDLD 0x01
#define IE1_ABTD 0x02
......@@ -424,14 +494,28 @@ typedef struct {
#define DIR_EOM 0x40
#define DIR_EOT 0x80
#define DIR_REFE 0x04
#define DIR_UDRFE 0x04
#define DIR_COAE 0x08
#define DIR_COFE 0x10
#define DIR_BOFE 0x20
#define DIR_EOME 0x40
#define DIR_EOTE 0x80
#define DMR_CNTE 0x02
#define DMR_NF 0x04
#define DMR_SEOME 0x08
#define DMR_TMOD 0x10
#define DMER_DME 0x80 /* DMA Master Enable */
#define DCR_SW_ABT 0x01
#define DCR_FCT_CLR 0x02
#define DCR_ABORT 0x01
#define DCR_CLEAR_EOF 0x02
#define PCR_COTE 0x80
#define PCR_PR0 0x01
#define PCR_PR1 0x02
#define PCR_PR2 0x04
......@@ -440,4 +524,4 @@ typedef struct {
#define PCR_OSB 0x40
#define PCR_BURST 0x80
#endif /* (_HD64572_H) */
#endif /* (__HD64572_H) */
/*
* Goramo PCI200SYN synchronous serial card driver for Linux
*
* Copyright (C) 2002-2003 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*
* For information see http://hq.pm.waw.pl/hdlc/
*
* Sources of information:
* Hitachi HD64572 SCA-II User's Manual
* PLX Technology Inc. PCI9052 Data Book
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/in.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/moduleparam.h>
#include <linux/netdevice.h>
#include <linux/hdlc.h>
#include <linux/pci.h>
#include <asm/delay.h>
#include <asm/io.h>
#include "hd64572.h"
static const char* version = "Goramo PCI200SYN driver version: 1.16";
static const char* devname = "PCI200SYN";
#undef DEBUG_PKT
#define DEBUG_RINGS
#define PCI200SYN_PLX_SIZE 0x80 /* PLX control window size (128b) */
#define PCI200SYN_SCA_SIZE 0x400 /* SCA window size (1Kb) */
#define ALL_PAGES_ALWAYS_MAPPED
#define NEED_DETECT_RAM
#define NEED_SCA_MSCI_INTR
#define MAX_TX_BUFFERS 10
static int pci_clock_freq = 33000000;
#define CLOCK_BASE pci_clock_freq
#define PCI_VENDOR_ID_GORAMO 0x10B5 /* uses PLX:9050 ID - this card */
#define PCI_DEVICE_ID_PCI200SYN 0x9050 /* doesn't have its own ID */
/*
* PLX PCI9052 local configuration and shared runtime registers.
* This structure can be used to access 9052 registers (memory mapped).
*/
typedef struct {
u32 loc_addr_range[4]; /* 00-0Ch : Local Address Ranges */
u32 loc_rom_range; /* 10h : Local ROM Range */
u32 loc_addr_base[4]; /* 14-20h : Local Address Base Addrs */
u32 loc_rom_base; /* 24h : Local ROM Base */
u32 loc_bus_descr[4]; /* 28-34h : Local Bus Descriptors */
u32 rom_bus_descr; /* 38h : ROM Bus Descriptor */
u32 cs_base[4]; /* 3C-48h : Chip Select Base Addrs */
u32 intr_ctrl_stat; /* 4Ch : Interrupt Control/Status */
u32 init_ctrl; /* 50h : EEPROM ctrl, Init Ctrl, etc */
}plx9052;
typedef struct port_s {
hdlc_device hdlc; /* HDLC device struct - must be first */
struct card_s *card;
spinlock_t lock; /* TX lock */
sync_serial_settings settings;
int rxpart; /* partial frame received, next frame invalid*/
unsigned short encoding;
unsigned short parity;
u16 rxin; /* rx ring buffer 'in' pointer */
u16 txin; /* tx ring buffer 'in' and 'last' pointers */
u16 txlast;
u8 rxs, txs, tmc; /* SCA registers */
u8 phy_node; /* physical port # - 0 or 1 */
}port_t;
typedef struct card_s {
u8* rambase; /* buffer memory base (virtual) */
u8* scabase; /* SCA memory base (virtual) */
plx9052* plxbase; /* PLX registers memory base (virtual) */
u16 rx_ring_buffers; /* number of buffers in a ring */
u16 tx_ring_buffers;
u16 buff_offset; /* offset of first buffer of first channel */
u8 irq; /* interrupt request level */
port_t ports[2];
}card_t;
#define sca_in(reg, card) readb(card->scabase + (reg))
#define sca_out(value, reg, card) writeb(value, card->scabase + (reg))
#define sca_inw(reg, card) readw(card->scabase + (reg))
#define sca_outw(value, reg, card) writew(value, card->scabase + (reg))
#define sca_inl(reg, card) readl(card->scabase + (reg))
#define sca_outl(value, reg, card) writel(value, card->scabase + (reg))
#define port_to_card(port) (port->card)
#define log_node(port) (port->phy_node)
#define phy_node(port) (port->phy_node)
#define winbase(card) (card->rambase)
#define get_port(card, port) (&card->ports[port])
#define sca_flush(card) (sca_in(IER0, card));
static inline void new_memcpy_toio(char *dest, char *src, int length)
{
int len;
do {
len = length > 256 ? 256 : length;
memcpy_toio(dest, src, len);
dest += len;
src += len;
length -= len;
readb(dest);
} while (len);
}
#undef memcpy_toio
#define memcpy_toio new_memcpy_toio
#include "hd6457x.c"
static void pci200_set_iface(port_t *port)
{
card_t *card = port->card;
u16 msci = get_msci(port);
u8 rxs = port->rxs & CLK_BRG_MASK;
u8 txs = port->txs & CLK_BRG_MASK;
sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
port_to_card(port));
switch(port->settings.clock_type) {
case CLOCK_INT:
rxs |= CLK_BRG; /* BRG output */
txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */
break;
case CLOCK_TXINT:
rxs |= CLK_LINE; /* RXC input */
txs |= CLK_PIN_OUT | CLK_BRG; /* BRG output */
break;
case CLOCK_TXFROMRX:
rxs |= CLK_LINE; /* RXC input */
txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */
break;
default: /* EXTernal clock */
rxs |= CLK_LINE; /* RXC input */
txs |= CLK_PIN_OUT | CLK_LINE; /* TXC input */
break;
}
port->rxs = rxs;
port->txs = txs;
sca_out(rxs, msci + RXS, card);
sca_out(txs, msci + TXS, card);
sca_set_port(port);
}
static int pci200_open(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
port_t *port = hdlc_to_port(hdlc);
int result = hdlc_open(hdlc);
if (result)
return result;
sca_open(hdlc);
pci200_set_iface(port);
sca_flush(port_to_card(port));
return 0;
}
static int pci200_close(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
sca_close(hdlc);
sca_flush(port_to_card(dev_to_port(dev)));
hdlc_close(hdlc);
return 0;
}
static int pci200_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
const size_t size = sizeof(sync_serial_settings);
sync_serial_settings new_line, *line = ifr->ifr_settings.ifs_ifsu.sync;
hdlc_device *hdlc = dev_to_hdlc(dev);
port_t *port = hdlc_to_port(hdlc);
#ifdef DEBUG_RINGS
if (cmd == SIOCDEVPRIVATE) {
sca_dump_rings(hdlc);
return 0;
}
#endif
if (cmd != SIOCWANDEV)
return hdlc_ioctl(dev, ifr, cmd);
switch(ifr->ifr_settings.type) {
case IF_GET_IFACE:
ifr->ifr_settings.type = IF_IFACE_V35;
if (ifr->ifr_settings.size < size) {
ifr->ifr_settings.size = size; /* data size wanted */
return -ENOBUFS;
}
if (copy_to_user(line, &port->settings, size))
return -EFAULT;
return 0;
case IF_IFACE_V35:
case IF_IFACE_SYNC_SERIAL:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(&new_line, line, size))
return -EFAULT;
if (new_line.clock_type != CLOCK_EXT &&
new_line.clock_type != CLOCK_TXFROMRX &&
new_line.clock_type != CLOCK_INT &&
new_line.clock_type != CLOCK_TXINT)
return -EINVAL; /* No such clock setting */
if (new_line.loopback != 0 && new_line.loopback != 1)
return -EINVAL;
memcpy(&port->settings, &new_line, size); /* Update settings */
pci200_set_iface(port);
sca_flush(port_to_card(port));
return 0;
default:
return hdlc_ioctl(dev, ifr, cmd);
}
}
static void pci200_pci_remove_one(struct pci_dev *pdev)
{
int i;
card_t *card = pci_get_drvdata(pdev);
for(i = 0; i < 2; i++)
if (card->ports[i].card)
unregister_hdlc_device(&card->ports[i].hdlc);
if (card->irq)
free_irq(card->irq, card);
if (card->rambase)
iounmap(card->rambase);
if (card->scabase)
iounmap(card->scabase);
if (card->plxbase)
iounmap(card->plxbase);
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
kfree(card);
}
static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
card_t *card;
u8 rev_id;
u32 *p;
int i;
u32 ramsize;
u32 ramphys; /* buffer memory base */
u32 scaphys; /* SCA memory base */
u32 plxphys; /* PLX registers memory base */
#ifndef MODULE
static int printed_version;
if (!printed_version++)
printk(KERN_INFO "%s\n", version);
#endif
i = pci_enable_device(pdev);
if (i)
return i;
i = pci_request_regions(pdev, "PCI200SYN");
if (i) {
pci_disable_device(pdev);
return i;
}
card = kmalloc(sizeof(card_t), GFP_KERNEL);
if (card == NULL) {
printk(KERN_ERR "pci200syn: unable to allocate memory\n");
pci_release_regions(pdev);
pci_disable_device(pdev);
return -ENOBUFS;
}
memset(card, 0, sizeof(card_t));
pci_set_drvdata(pdev, card);
pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
if (pci_resource_len(pdev, 0) != PCI200SYN_PLX_SIZE ||
pci_resource_len(pdev, 2) != PCI200SYN_SCA_SIZE ||
pci_resource_len(pdev, 3) < 16384) {
printk(KERN_ERR "pci200syn: invalid card EEPROM parameters\n");
pci200_pci_remove_one(pdev);
return -EFAULT;
}
plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK;
card->plxbase = ioremap(plxphys, PCI200SYN_PLX_SIZE);
scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK;
card->scabase = ioremap(scaphys, PCI200SYN_SCA_SIZE);
ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK;
card->rambase = ioremap(ramphys, pci_resource_len(pdev,3));
if (card->plxbase == NULL ||
card->scabase == NULL ||
card->rambase == NULL) {
printk(KERN_ERR "pci200syn: ioremap() failed\n");
pci200_pci_remove_one(pdev);
}
/* Reset PLX */
p = &card->plxbase->init_ctrl;
writel(readl(p) | 0x40000000, p);
readl(p); /* Flush the write - do not use sca_flush */
udelay(1);
writel(readl(p) & ~0x40000000, p);
readl(p); /* Flush the write - do not use sca_flush */
udelay(1);
ramsize = sca_detect_ram(card, card->rambase,
pci_resource_len(pdev, 3));
/* number of TX + RX buffers for one port - this is dual port card */
i = ramsize / (2 * (sizeof(pkt_desc) + HDLC_MAX_MRU));
card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS);
card->rx_ring_buffers = i - card->tx_ring_buffers;
card->buff_offset = 2 * sizeof(pkt_desc) * (card->tx_ring_buffers +
card->rx_ring_buffers);
printk(KERN_INFO "pci200syn: %u KB RAM at 0x%x, IRQ%u, using %u TX +"
" %u RX packets rings\n", ramsize / 1024, ramphys,
pdev->irq, card->tx_ring_buffers, card->rx_ring_buffers);
if (card->tx_ring_buffers < 1) {
printk(KERN_ERR "pci200syn: RAM test failed\n");
pci200_pci_remove_one(pdev);
return -EFAULT;
}
/* Enable interrupts on the PCI bridge */
p = &card->plxbase->intr_ctrl_stat;
writew(readw(p) | 0x0040, p);
/* Allocate IRQ */
if(request_irq(pdev->irq, sca_intr, SA_SHIRQ, devname, card)) {
printk(KERN_WARNING "pci200syn: could not allocate IRQ%d.\n",
pdev->irq);
pci200_pci_remove_one(pdev);
return -EBUSY;
}
card->irq = pdev->irq;
sca_init(card, 0);
for(i = 0; i < 2; i++) {
port_t *port = &card->ports[i];
struct net_device *dev = hdlc_to_dev(&port->hdlc);
port->phy_node = i;
spin_lock_init(&port->lock);
SET_MODULE_OWNER(dev);
dev->irq = card->irq;
dev->mem_start = ramphys;
dev->mem_end = ramphys + ramsize - 1;
dev->tx_queue_len = 50;
dev->do_ioctl = pci200_ioctl;
dev->open = pci200_open;
dev->stop = pci200_close;
port->hdlc.attach = sca_attach;
port->hdlc.xmit = sca_xmit;
port->settings.clock_type = CLOCK_EXT;
if(register_hdlc_device(&port->hdlc)) {
printk(KERN_ERR "pci200syn: unable to register hdlc "
"device\n");
pci200_pci_remove_one(pdev);
return -ENOBUFS;
}
port->card = card;
sca_init_sync_port(port); /* Set up SCA memory */
printk(KERN_INFO "%s: PCI200SYN node %d\n",
hdlc_to_name(&port->hdlc), port->phy_node);
}
sca_flush(card);
return 0;
}
static struct pci_device_id pci200_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_GORAMO, PCI_DEVICE_ID_PCI200SYN, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, 0 },
{ 0, }
};
static struct pci_driver pci200_pci_driver = {
name: "PCI200SYN",
id_table: pci200_pci_tbl,
probe: pci200_pci_init_one,
remove: pci200_pci_remove_one,
};
static int __init pci200_init_module(void)
{
#ifdef MODULE
printk(KERN_INFO "%s\n", version);
#endif
if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) {
printk(KERN_ERR "pci200syn: Invalid PCI clock frequency\n");
return -EINVAL;
}
return pci_module_init(&pci200_pci_driver);
}
static void __exit pci200_cleanup_module(void)
{
pci_unregister_driver(&pci200_pci_driver);
}
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("Goramo PCI200SYN serial port driver");
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(pci, pci200_pci_tbl);
module_param(pci_clock_freq, int, 0444);
MODULE_PARM_DESC(pci_clock_freq, "System PCI clock frequency in Hz");
module_init(pci200_init_module);
module_exit(pci200_cleanup_module);
......@@ -282,7 +282,7 @@ config PCMCIA_ATMEL
one of these, you will need to provide a firmware image
to be loaded into the card by the driver. The Atmel
firmware package can be downloaded from
http://www.thekelleys.org.uk/atmel/atmel_firmware.tar.gz
http://www.thekelleys.org.uk/atmel
config PCMCIA_WL3501
tristate "Planet WL3501 PCMCIA cards"
......
......@@ -1027,7 +1027,6 @@ struct airo_info {
#define FLAG_802_11 7
#define FLAG_PENDING_XMIT 9
#define FLAG_PENDING_XMIT11 10
#define FLAG_PCI 11
#define JOB_MASK 0x1ff0000
#define JOB_DIE 16
#define JOB_XMIT 17
......@@ -4623,7 +4622,6 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev,
return -ENODEV;
pci_set_drvdata(pdev, dev);
set_bit (FLAG_PCI, &((struct airo_info *)dev->priv)->flags);
return 0;
}
......@@ -4653,7 +4651,7 @@ static int __init airo_init_module( void )
#ifdef CONFIG_PCI
printk( KERN_INFO "airo: Probing for PCI adapters\n" );
pci_module_init(&airo_driver);
pci_register_driver(&airo_driver);
printk( KERN_INFO "airo: Finished probing for PCI adapters\n" );
#endif
......@@ -4665,22 +4663,15 @@ static int __init airo_init_module( void )
static void __exit airo_cleanup_module( void )
{
int is_pci = 0;
while( airo_devices ) {
printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name );
#ifdef CONFIG_PCI
if (test_bit(FLAG_PCI, &((struct airo_info *)airo_devices->dev->priv)->flags))
is_pci = 1;
#endif
stop_airo_card( airo_devices->dev, 1 );
}
remove_proc_entry("aironet", proc_root_driver);
if (is_pci) {
#ifdef CONFIG_PCI
pci_unregister_driver(&airo_driver);
pci_unregister_driver(&airo_driver);
#endif
}
}
#ifdef WIRELESS_EXT
......
......@@ -67,7 +67,7 @@
#include "ieee802_11.h"
#define DRIVER_MAJOR 0
#define DRIVER_MINOR 8
#define DRIVER_MINOR 9
MODULE_AUTHOR("Simon Kelley");
MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
......@@ -153,12 +153,15 @@ module_param(firmware, charp, 0);
#define C80211_MGMT_ElementID_ChallengeText 16
#define C80211_MGMT_CAPABILITY_ShortPreamble 0x0020
#define MIB_MAX_DATA_BYTES 212
#define MIB_HEADER_SIZE 4 /* first four fields */
struct get_set_mib {
u8 type;
u8 size;
u8 index;
u8 reserved;
u8 data[72];
u8 data[MIB_MAX_DATA_BYTES];
};
struct rx_desc {
......@@ -195,32 +198,40 @@ struct rx_desc {
struct tx_desc {
u32 NextDescriptor;
u16 TxStartOfFrame;
u16 TxLength;
u8 TxState;
u8 TxStatus;
u8 RetryCount;
u8 TxRate;
u32 TxTime;
u8 Reserved;
u8 PacketType;
u16 HostTxLength;
u32 NextDescriptor;
u16 TxStartOfFrame;
u16 TxLength;
u8 TxState;
u8 TxStatus;
u8 RetryCount;
u8 TxRate;
u8 KeyIndex;
u8 ChiperType;
u8 ChipreLength;
u8 Reserved1;
u8 Reserved;
u8 PacketType;
u16 HostTxLength;
};
#define TX_DESC_NEXT_OFFSET 0
#define TX_DESC_POS_OFFSET 4
#define TX_DESC_SIZE_OFFSET 6
#define TX_DESC_FLAGS_OFFSET 8
#define TX_DESC_STATUS_OFFSET 9
#define TX_DESC_RETRY_OFFSET 10
#define TX_DESC_RATE_OFFSET 11
#define TX_DESC_PACKET_TYPE_OFFSET 17
#define TX_DESC_HOST_LENGTH_OFFSET 18
#define TX_DESC_NEXT_OFFSET 0
#define TX_DESC_POS_OFFSET 4
#define TX_DESC_SIZE_OFFSET 6
#define TX_DESC_FLAGS_OFFSET 8
#define TX_DESC_STATUS_OFFSET 9
#define TX_DESC_RETRY_OFFSET 10
#define TX_DESC_RATE_OFFSET 11
#define TX_DESC_KEY_INDEX_OFFSET 12
#define TX_DESC_CIPHER_TYPE_OFFSET 13
#define TX_DESC_CIPHER_LENGTH_OFFSET 14
#define TX_DESC_PACKET_TYPE_OFFSET 17
#define TX_DESC_HOST_LENGTH_OFFSET 18
......@@ -324,6 +335,9 @@ struct tx_desc {
#define ACTIVE_MODE 1
#define PS_MODE 2
#define MAX_ENCRYPTION_KEYS 4
#define MAX_ENCRYPTION_KEY_SIZE 40
///////////////////////////////////////////////////////////////////////////
// 802.11 related definitions
///////////////////////////////////////////////////////////////////////////
......@@ -370,6 +384,14 @@ struct tx_desc {
#define IFACE_FUNC_CTRL_OFFSET 28
#define IFACE_MAC_STAT_OFFSET 30
#define IFACE_GENERIC_INT_TYPE_OFFSET 32
#define CIPHER_SUITE_NONE 0
#define CIPHER_SUITE_WEP_64 1
#define CIPHER_SUITE_TKIP 2
#define CIPHER_SUITE_AES 3
#define CIPHER_SUITE_CCX 4
#define CIPHER_SUITE_WEP_128 5
//
// IFACE MACROS & definitions
//
......@@ -432,6 +454,7 @@ struct atmel_private {
void *card; /* Bus dependent stucture varies for PCcard */
int (*present_callback)(void *); /* And callback which uses it */
char firmware_id[32];
char firmware_template[32];
unsigned char *firmware;
int firmware_length;
struct timer_list management_timer;
......@@ -457,20 +480,11 @@ struct atmel_private {
u16 frag_seq, frag_len, frag_no;
u8 frag_source[6];
int wep_key_len[4]; /* need to know these and not stored in Mib. */
struct { /* NB this is matched to the hardware, don't change. */
u8 wep_is_on;
u8 default_key; /* 0..3 */
u8 reserved;
u8 exclude_unencrypted;
u32 WEPICV_error_count;
u32 WEP_excluded_count;
u8 wep_keys[4][13];
u8 encryption_level; /* 0, 1, 2 */
u8 reserved2[3];
} wep;
u8 wep_is_on, default_key, exclude_unencrypted, encryption_level;
u8 group_cipher_suite, pairwise_cipher_suite;
u8 wep_keys[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE];
int wep_key_len[MAX_ENCRYPTION_KEYS];
int use_wpa;
u16 host_info_base;
struct host_info_struct {
......@@ -510,8 +524,6 @@ struct atmel_private {
STATION_STATE_ASSOCIATING,
STATION_STATE_READY,
STATION_STATE_REASSOCIATING,
STATION_STATE_FORCED_JOINNING,
STATION_STATE_FORCED_JOIN_FAILURE,
STATION_STATE_DOWN,
STATION_STATE_NO_CARD,
STATION_STATE_MGMT_ERROR
......@@ -564,6 +576,7 @@ struct atmel_private {
static u8 atmel_basic_rates[4] = {0x82,0x84,0x0b,0x16};
static void build_wpa_mib(struct atmel_private *priv);
static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void atmel_copy_to_card(struct net_device *dev, u16 dest, unsigned char *src, u16 len);
static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, u16 src, u16 len);
......@@ -717,14 +730,54 @@ static u16 find_tx_buff(struct atmel_private *priv, u16 len)
return 0;
}
static void tx_update_descriptor(struct atmel_private *priv, u16 len, u16 buff, u8 type)
static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, u16 len, u16 buff, u8 type)
{
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff);
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len);
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len);
if (!priv->use_wpa)
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len);
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type);
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate);
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0);
if (priv->use_wpa) {
int cipher_type, cipher_length;
if (is_bcast) {
cipher_type = priv->group_cipher_suite;
if (cipher_type == CIPHER_SUITE_WEP_64 ||
cipher_type == CIPHER_SUITE_WEP_128 )
cipher_length = 8;
else if (cipher_type == CIPHER_SUITE_TKIP)
cipher_length = 12;
else if (priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_64 ||
priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_128) {
cipher_type = priv->pairwise_cipher_suite;
cipher_length = 8;
} else {
cipher_type = CIPHER_SUITE_NONE;
cipher_length = 0;
}
} else {
cipher_type = priv->pairwise_cipher_suite;
if (cipher_type == CIPHER_SUITE_WEP_64 ||
cipher_type == CIPHER_SUITE_WEP_128 )
cipher_length = 8;
else if (cipher_type == CIPHER_SUITE_TKIP)
cipher_length = 12;
else if (priv->group_cipher_suite == CIPHER_SUITE_WEP_64 ||
priv->group_cipher_suite == CIPHER_SUITE_WEP_128) {
cipher_type = priv->group_cipher_suite;
cipher_length = 8;
} else {
cipher_type = CIPHER_SUITE_NONE;
cipher_length = 0;
}
}
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_TYPE_OFFSET, priv->tx_desc_tail),
cipher_type);
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_LENGTH_OFFSET, priv->tx_desc_tail),
cipher_length);
}
atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L);
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN);
if (priv->tx_desc_previous != priv->tx_desc_tail)
......@@ -745,16 +798,19 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev)
struct ieee802_11_hdr header;
unsigned long flags;
u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
if(priv->station_state != STATION_STATE_READY) {
u8 SNAP_RFC1024[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
if (priv->station_state != STATION_STATE_READY) {
priv->stats.tx_errors++;
goto done;
dev_kfree_skb(skb);
return 0;
}
if (priv->card && priv->present_callback &&
!(*priv->present_callback)(priv->card)) {
priv->stats.tx_errors++;
goto done;
dev_kfree_skb(skb);
return 0;
}
/* first ensure the timer func cannot run */
......@@ -778,7 +834,7 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev)
frame_ctl = IEEE802_11_FTYPE_DATA;
header.duration_id = 0;
header.seq_ctl = 0;
if (priv->wep.wep_is_on)
if (priv->wep_is_on)
frame_ctl |= IEEE802_11_FCTL_WEP;
if (priv->operating_mode == IW_MODE_ADHOC) {
memcpy(&header.addr1, skb->data, 6);
......@@ -791,6 +847,9 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev)
memcpy(&header.addr3, skb->data, 6);
}
if (priv->use_wpa)
memcpy(&header.addr4, SNAP_RFC1024, 6);
header.frame_ctl = cpu_to_le16(frame_ctl);
/* Copy the wireless header into the card */
atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE);
......@@ -798,14 +857,13 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev)
atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12);
priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE;
tx_update_descriptor(priv, len + 18, buff, TX_PACKET_TYPE_DATA);
/* low bit of first byte of destination tells us if broadcast */
tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA);
dev->trans_start = jiffies;
priv->stats.tx_bytes += len;
spin_unlock_irqrestore(&priv->irqlock, flags);
spin_unlock_bh(&priv->timerlock);
done:
dev_kfree_skb(skb);
return 0;
......@@ -824,7 +882,7 @@ static void atmel_transmit_management_frame(struct atmel_private *priv,
atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET);
atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len);
priv->tx_buff_tail += len;
tx_update_descriptor(priv, len, buff, TX_PACKET_TYPE_MGMT);
tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT);
}
static void fast_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header,
......@@ -1027,7 +1085,7 @@ static void rx_done_irq(struct atmel_private *priv)
/* probe for CRC use here if needed once five packets have arrived with
the same crc status, we assume we know what's happening and stop probing */
if (priv->probe_crc) {
if (!priv->wep.wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP)) {
if (!priv->wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP)) {
priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size);
} else {
priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24);
......@@ -1042,7 +1100,7 @@ static void rx_done_irq(struct atmel_private *priv)
}
/* don't CRC header when WEP in use */
if (priv->do_rx_crc && (!priv->wep.wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP))) {
if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP))) {
crc = crc32_le(0xffffffff, (unsigned char *)&header, 24);
}
msdu_size -= 24; /* header */
......@@ -1158,6 +1216,9 @@ static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs
reset_irq_status(priv, ISR_IBSS_MERGE);
atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS,
priv->CurrentBSSID, 6);
/* The WPA stuff cares about the current AP address */
if (priv->use_wpa)
build_wpa_mib(priv);
} else if (isr & ISR_GENERIC_IRQ) {
reset_irq_status(priv, ISR_GENERIC_IRQ);
printk(KERN_INFO "%s: Generic_irq recieved.\n", dev->name);
......@@ -1237,6 +1298,7 @@ static int atmel_close (struct net_device *dev)
{
struct atmel_private *priv = (struct atmel_private *) dev->priv;
netif_carrier_off(dev);
if (netif_running(dev))
netif_stop_queue(dev);
......@@ -1255,17 +1317,17 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)
p += sprintf(p, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR);
if (priv->station_state != STATION_STATE_DOWN) {
p += sprintf(p, "Firmware version:\t%d.%d build %d ",
p += sprintf(p, "Firmware version:\t%d.%d build %d\nFirmware location:\t",
priv->host_info.major_version,
priv->host_info.minor_version,
priv->host_info.build_version);
if (priv->card_type != CARD_TYPE_EEPROM)
p += sprintf(p, "[built-in]\n");
p += sprintf(p, "on card\n");
else if (priv->firmware)
p += sprintf(p, "[%s loaded by host]\n", priv->firmware_id);
p += sprintf(p, "%s loaded by host\n", priv->firmware_id);
else
p += sprintf(p, "[%s loaded by hotplug]\n", priv->firmware_id);
p += sprintf(p, "%s loaded by hotplug\n", priv->firmware_id);
switch(priv->card_type) {
case CARD_TYPE_PARALLEL_FLASH: c = "Parallel flash"; break;
......@@ -1289,6 +1351,8 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)
p += sprintf(p, "Regulatory domain:\t%s\n", r);
p += sprintf(p, "Host CRC checking:\t%s\n",
priv->do_rx_crc ? "On" : "Off");
p += sprintf(p, "WPA-capable firmware:\t%s\n",
priv->use_wpa ? "Yes" : "No");
}
switch(priv->station_state) {
......@@ -1299,8 +1363,6 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)
case STATION_STATE_ASSOCIATING: s = "Associating"; break;
case STATION_STATE_READY: s = "Ready"; break;
case STATION_STATE_REASSOCIATING: s = "Reassociating"; break;
case STATION_STATE_FORCED_JOINNING: s = "Forced joining"; break;
case STATION_STATE_FORCED_JOIN_FAILURE: s = "Forced join failure"; break;
case STATION_STATE_NO_CARD: s = "No card"; break;
case STATION_STATE_MGMT_ERROR: s = "Management error"; break;
case STATION_STATE_DOWN: s = "Down"; break;
......@@ -1348,12 +1410,12 @@ struct net_device *init_atmel_card( unsigned short irq, int port, char *firmware
priv->present_callback = card_present;
priv->card = card;
priv->firmware = NULL;
priv->firmware_id[0] = '\0';
priv->firmware_template[0] = '\0';
if (firmware) /* module parameter */
strcpy(priv->firmware_id, firmware);
else if (firmware_id) /* from PCMCIA card-matching or PCI */
strcpy(priv->firmware_id, firmware_id);
else
priv->firmware_id[0] = '\0';
strcpy(priv->firmware_template, firmware_id);
priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI;
priv->station_state = STATION_STATE_DOWN;
priv->is3com = is3com;
......@@ -1389,9 +1451,16 @@ struct net_device *init_atmel_card( unsigned short irq, int port, char *firmware
priv->rts_threshold = 2347;
priv->short_retry = 7;
priv->long_retry = 4;
priv->wep.wep_is_on = 0;
priv->wep.default_key = 0;
priv->wep.encryption_level = 0;
priv->wep_is_on = 0;
priv->default_key = 0;
priv->encryption_level = 0;
priv->exclude_unencrypted = 0;
priv->group_cipher_suite = priv->pairwise_cipher_suite = CIPHER_SUITE_NONE;
priv->use_wpa = 0;
memset(priv->wep_keys, 0, sizeof(priv->wep_keys));
memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len));
priv->default_beacon_period = priv->beacon_period = 100;
priv->listen_interval = 1;
......@@ -1426,8 +1495,12 @@ struct net_device *init_atmel_card( unsigned short irq, int port, char *firmware
if (register_netdev(dev))
goto err_out_res;
if (!probe_atmel_card(dev))
if (!probe_atmel_card(dev)){
unregister_netdev(dev);
goto err_out_res;
}
netif_carrier_off(dev);
create_proc_read_entry ("driver/atmel", 0, 0, atmel_read_proc, priv);
......@@ -1443,7 +1516,7 @@ struct net_device *init_atmel_card( unsigned short irq, int port, char *firmware
err_out_irq:
free_irq(dev->irq, dev);
err_out_free:
kfree(dev);
free_netdev(dev);
return NULL;
}
......@@ -1582,7 +1655,7 @@ static int atmel_set_encode(struct net_device *dev,
* don't do it. - Jean II */
if (dwrq->length > 0) {
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
int current_index = priv->wep.default_key;
int current_index = priv->default_key;
/* Check the size of the key */
if (dwrq->length > 13) {
return -EINVAL;
......@@ -1591,7 +1664,7 @@ static int atmel_set_encode(struct net_device *dev,
if (index < 0 || index >= 4)
index = current_index;
else
priv->wep.default_key = index;
priv->default_key = index;
/* Set the length */
if (dwrq->length > 5)
priv->wep_key_len[index] = 13;
......@@ -1604,27 +1677,30 @@ static int atmel_set_encode(struct net_device *dev,
/* Check if the key is not marked as invalid */
if(!(dwrq->flags & IW_ENCODE_NOKEY)) {
/* Cleanup */
memset(priv->wep.wep_keys[index], 0, 13);
memset(priv->wep_keys[index], 0, 13);
/* Copy the key in the driver */
memcpy(priv->wep.wep_keys[index], extra, dwrq->length);
memcpy(priv->wep_keys[index], extra, dwrq->length);
}
/* WE specify that if a valid key is set, encryption
* should be enabled (user may turn it off later)
* This is also how "iwconfig ethX key on" works */
if (index == current_index &&
priv->wep_key_len[index] > 0) {
priv->wep.wep_is_on = 1;
priv->wep.exclude_unencrypted = 1;
if (priv->wep_key_len[index] > 5)
priv->wep.encryption_level = 2;
else
priv->wep.encryption_level = 1;
priv->wep_is_on = 1;
priv->exclude_unencrypted = 1;
if (priv->wep_key_len[index] > 5) {
priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64;
priv->encryption_level = 2;
} else {
priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128;
priv->encryption_level = 1;
}
}
} else {
/* Do we want to just set the transmit key index ? */
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
if ( index>=0 && index < 4 ) {
priv->wep.default_key = index;
priv->default_key = index;
} else
/* Don't complain if only change the mode */
if(!dwrq->flags & IW_ENCODE_MODE) {
......@@ -1633,19 +1709,23 @@ static int atmel_set_encode(struct net_device *dev,
}
/* Read the flags */
if(dwrq->flags & IW_ENCODE_DISABLED) {
priv->wep.wep_is_on = 0;
priv->wep.encryption_level = 0;
priv->wep_is_on = 0;
priv->encryption_level = 0;
priv->pairwise_cipher_suite = CIPHER_SUITE_NONE;
} else {
priv->wep.wep_is_on = 1;
if (priv->wep_key_len[priv->wep.default_key] > 5)
priv->wep.encryption_level = 2;
else
priv->wep.encryption_level = 1;
priv->wep_is_on = 1;
if (priv->wep_key_len[priv->default_key] > 5) {
priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128;
priv->encryption_level = 2;
} else {
priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64;
priv->encryption_level = 1;
}
}
if(dwrq->flags & IW_ENCODE_RESTRICTED)
priv->wep.exclude_unencrypted = 1;
priv->exclude_unencrypted = 1;
if(dwrq->flags & IW_ENCODE_OPEN)
priv->wep.exclude_unencrypted = 0;
priv->exclude_unencrypted = 0;
return -EINPROGRESS; /* Call commit handler */
}
......@@ -1659,16 +1739,16 @@ static int atmel_get_encode(struct net_device *dev,
struct atmel_private *priv = dev->priv;
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
if (!priv->wep.wep_is_on)
if (!priv->wep_is_on)
dwrq->flags = IW_ENCODE_DISABLED;
else if (priv->wep.exclude_unencrypted)
else if (priv->exclude_unencrypted)
dwrq->flags = IW_ENCODE_RESTRICTED;
else
dwrq->flags = IW_ENCODE_OPEN;
/* Which key do we want ? -1 -> tx index */
if (index < 0 || index >= 4)
index = priv->wep.default_key;
index = priv->default_key;
dwrq->flags |= index + 1;
/* Copy the key to the user buffer */
dwrq->length = priv->wep_key_len[index];
......@@ -1676,7 +1756,7 @@ static int atmel_get_encode(struct net_device *dev,
dwrq->length=0;
} else {
memset(extra, 0, 16);
memcpy(extra, priv->wep.wep_keys[index], dwrq->length);
memcpy(extra, priv->wep_keys[index], dwrq->length);
}
return 0;
......@@ -1711,10 +1791,10 @@ static int atmel_set_rate(struct net_device *dev,
} else {
/* Setting by frequency value */
switch (vwrq->value) {
case (int)1e6: priv->tx_rate = 0; break;
case (int)2e6: priv->tx_rate = 1; break;
case (int)5.5e6: priv->tx_rate = 2; break;
case (int)11e6: priv->tx_rate = 3; break;
case 1000000: priv->tx_rate = 0; break;
case 2000000: priv->tx_rate = 1; break;
case 5500000: priv->tx_rate = 2; break;
case 11000000: priv->tx_rate = 3; break;
default: return -EINVAL;
}
}
......@@ -1757,14 +1837,14 @@ static int atmel_get_rate(struct net_device *dev,
if (priv->auto_tx_rate) {
vwrq->fixed = 0;
vwrq->value = 11e6;
vwrq->value = 11000000;
} else {
vwrq->fixed = 1;
switch(priv->tx_rate) {
case 0: vwrq->value = 1e6; break;
case 1: vwrq->value = 2e6; break;
case 2: vwrq->value = 5.5e6; break;
case 3: vwrq->value = 11e6; break;
case 0: vwrq->value = 1000000; break;
case 1: vwrq->value = 2000000; break;
case 2: vwrq->value = 5500000; break;
case 3: vwrq->value = 11000000; break;
}
}
return 0;
......@@ -1982,6 +2062,7 @@ static int atmel_set_scan(struct net_device *dev,
atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */
del_timer_sync(&priv->management_timer);
priv->fast_scan = 0;
atmel_scan(priv, 0);
atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */
......@@ -2073,10 +2154,10 @@ static int atmel_get_range(struct net_device *dev,
range->max_qual.noise = 0;
range->sensitivity = 0;
range->bitrate[0] = 1e6;
range->bitrate[1] = 2e6;
range->bitrate[2] = 5.5e6;
range->bitrate[3] = 11e6;
range->bitrate[0] = 1000000;
range->bitrate[1] = 2000000;
range->bitrate[2] = 5500000;
range->bitrate[3] = 11000000;
range->num_bitrates = 4;
range->min_rts = 0;
......@@ -2129,9 +2210,9 @@ static int atmel_set_wap(struct net_device *dev,
for(i=0; i<priv->BSS_list_entries; i++) {
if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) {
if (!priv->wep.wep_is_on && priv->BSSinfo[i].UsingWEP) {
if (!priv->wep_is_on && priv->BSSinfo[i].UsingWEP) {
return -EINVAL;
} else if (priv->wep.wep_is_on && !priv->BSSinfo[i].UsingWEP) {
} else if (priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) {
return -EINVAL;
} else
atmel_join_bss(priv, i);
......@@ -2313,10 +2394,13 @@ static void atmel_enter_state(struct atmel_private *priv, int new_state)
if (new_state == old_state)
return;
if (new_state == STATION_STATE_READY)
if (new_state == STATION_STATE_READY) {
netif_start_queue(priv->dev);
netif_carrier_on(priv->dev);
}
if (old_state == STATION_STATE_READY) {
netif_carrier_off(priv->dev);
netif_stop_queue(priv->dev);
priv->last_beacon_timestamp = 0;
}
......@@ -2453,7 +2537,7 @@ static void send_authentication_request(struct atmel_private *priv, u8 *challeng
memcpy(header.addr2, priv->dev->dev_addr, 6);
memcpy(header.addr3, priv->CurrentBSSID, 6);
if (priv->wep.wep_is_on) {
if (priv->wep_is_on) {
auth.alg = C80211_MGMT_AAN_SHAREDKEY;
/* no WEP for authentication frames with TrSeqNo 1 */
if (priv->CurrentAuthentTransactionSeqNum != 1)
......@@ -2504,7 +2588,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
memcpy(header.addr3, priv->CurrentBSSID, 6);
body.capability = cpu_to_le16(C80211_MGMT_CAPABILITY_ESS);
if (priv->wep.wep_is_on)
if (priv->wep_is_on)
body.capability |= cpu_to_le16(C80211_MGMT_CAPABILITY_Privacy);
if (priv->preamble == SHORT_PREAMBLE)
body.capability |= cpu_to_le16(C80211_MGMT_CAPABILITY_ShortPreamble);
......@@ -2555,8 +2639,8 @@ static int retrieve_bss(struct atmel_private *priv)
priv->current_BSS = 0;
for(i=0; i<priv->BSS_list_entries; i++) {
if (priv->operating_mode == priv->BSSinfo[i].BSStype &&
((!priv->wep.wep_is_on && !priv->BSSinfo[i].UsingWEP) ||
(priv->wep.wep_is_on && priv->BSSinfo[i].UsingWEP)) &&
((!priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) ||
(priv->wep_is_on && priv->BSSinfo[i].UsingWEP)) &&
!(priv->BSSinfo[i].channel & 0x80)) {
max_rssi = priv->BSSinfo[i].RSSI;
priv->current_BSS = max_index = i;
......@@ -2630,7 +2714,7 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
u16 status = le16_to_cpu(auth->status);
u16 trans_seq_no = le16_to_cpu(auth->trans_seq);
if (status == C80211_MGMT_SC_Success && !priv->wep.wep_is_on) {
if (status == C80211_MGMT_SC_Success && !priv->wep_is_on) {
/* no WEP */
if (priv->station_was_associated) {
atmel_enter_state(priv, STATION_STATE_REASSOCIATING);
......@@ -2643,7 +2727,7 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
}
}
if (status == C80211_MGMT_SC_Success && priv->wep.wep_is_on) {
if (status == C80211_MGMT_SC_Success && priv->wep_is_on) {
/* WEP */
if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum)
return;
......@@ -2765,6 +2849,10 @@ void atmel_join_bss(struct atmel_private *priv, int bss_index)
memcpy(priv->CurrentBSSID, bss->BSSID, 6);
memcpy(priv->SSID, bss->SSID, priv->SSID_size = bss->SSIDsize);
/* The WPA stuff cares about the current AP address */
if (priv->use_wpa)
build_wpa_mib(priv);
/* When switching to AdHoc turn OFF Power Save if needed */
......@@ -2786,13 +2874,13 @@ void atmel_join_bss(struct atmel_private *priv, int bss_index)
atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, bss->preamble);
}
if (!priv->wep.wep_is_on && bss->UsingWEP) {
if (!priv->wep_is_on && bss->UsingWEP) {
atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
priv->station_is_associated = 0;
return;
}
if (priv->wep.wep_is_on && !bss->UsingWEP) {
if (priv->wep_is_on && !bss->UsingWEP) {
atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
priv->station_is_associated = 0;
return;
......@@ -3071,6 +3159,7 @@ static void atmel_command_irq(struct atmel_private *priv)
priv->fast_scan = !fast_scan;
atmel_scan(priv, 1);
}
priv->site_survey_state = SITE_SURVEY_COMPLETED;
}
break;
......@@ -3104,12 +3193,8 @@ static void atmel_command_irq(struct atmel_private *priv)
return;
}
if (priv->station_state == STATION_STATE_FORCED_JOINNING) {
atmel_enter_state(priv, STATION_STATE_FORCED_JOIN_FAILURE);
} else {
atmel_scan(priv, 1);
}
atmel_scan(priv, 1);
}
}
......@@ -3275,7 +3360,7 @@ static int probe_atmel_card(struct net_device *dev)
printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name);
memcpy(dev->dev_addr, default_mac, 6);
}
printk(KERN_INFO "%s: MAC address %x:%x:%x:%x:%x:%x\n",
printk(KERN_INFO "%s: MAC address %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
dev->name,
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
......@@ -3285,6 +3370,105 @@ static int probe_atmel_card(struct net_device *dev)
return rc;
}
static void build_wep_mib(struct atmel_private *priv)
/* Move the encyption information on the MIB structure.
This routine is for the pre-WPA firmware: later firmware has
a different format MIB and a different routine. */
{
struct { /* NB this is matched to the hardware, don't change. */
u8 wep_is_on;
u8 default_key; /* 0..3 */
u8 reserved;
u8 exclude_unencrypted;
u32 WEPICV_error_count;
u32 WEP_excluded_count;
u8 wep_keys[MAX_ENCRYPTION_KEYS][13];
u8 encryption_level; /* 0, 1, 2 */
u8 reserved2[3];
} mib;
int i;
mib.wep_is_on = priv->wep_is_on;
if (priv->wep_is_on) {
if (priv->wep_key_len[priv->default_key] > 5)
mib.encryption_level = 2;
else
mib.encryption_level = 1;
} else {
mib.encryption_level = 0;
}
mib.default_key = priv->default_key;
mib.exclude_unencrypted = priv->exclude_unencrypted;
for(i = 0; i < MAX_ENCRYPTION_KEYS; i++)
memcpy(mib.wep_keys[i], priv->wep_keys[i], 13);
atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib));
}
static void build_wpa_mib(struct atmel_private *priv)
{
/* This is for the later (WPA enabled) firmware. */
struct { /* NB this is matched to the hardware, don't change. */
u8 cipher_default_key_value[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE];
u8 receiver_address[6];
u8 wep_is_on;
u8 default_key; /* 0..3 */
u8 group_key;
u8 exclude_unencrypted;
u8 encryption_type;
u8 reserved;
u32 WEPICV_error_count;
u32 WEP_excluded_count;
u8 key_RSC[4][8];
} mib;
int i;
mib.wep_is_on = priv->wep_is_on;
mib.exclude_unencrypted = priv->exclude_unencrypted;
memcpy(mib.receiver_address, priv->CurrentBSSID, 6);
/* zero all the keys before adding in valid ones. */
memset(mib.cipher_default_key_value, 0, sizeof(mib.cipher_default_key_value));
if (priv->wep_is_on) {
/* There's a comment in the Atmel code to the effect that this is only valid
when still using WEP, it may need to be set to something to use WPA */
memset(mib.key_RSC, 0, sizeof(mib.key_RSC));
mib.default_key = mib.group_key = 255;
for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) {
if (priv->wep_key_len[i] > 0) {
memcpy(mib.cipher_default_key_value[i], priv->wep_keys[i], MAX_ENCRYPTION_KEY_SIZE);
if (i == priv->default_key) {
mib.default_key = i;
mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 7;
mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->pairwise_cipher_suite;
} else {
mib.group_key = i;
priv->group_cipher_suite = priv->pairwise_cipher_suite;
mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 1;
mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->group_cipher_suite;
}
}
}
if (mib.default_key == 255)
mib.default_key = mib.group_key != 255 ? mib.group_key : 0;
if (mib.group_key == 255)
mib.group_key = mib.default_key;
}
atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib));
}
int reset_atmel_card(struct net_device *dev)
{
/* do everything necessary to wake up the hardware, including
......@@ -3305,6 +3489,15 @@ int reset_atmel_card(struct net_device *dev)
struct atmel_private *priv = dev->priv;
u8 configuration;
/* data to add to the firmware names, in priority order
this implemenents firmware versioning */
static char *firmware_modifier[] = {
"-wpa",
"",
NULL
};
if (priv->station_state == STATION_STATE_NO_CARD ||
priv->station_state == STATION_STATE_DOWN)
return 0;
......@@ -3341,21 +3534,41 @@ int reset_atmel_card(struct net_device *dev)
unsigned char *fw;
int len = priv->firmware_length;
if (!(fw = priv->firmware)) {
if (strlen(priv->firmware_id) == 0) {
printk(KERN_INFO
"%s: card type is unknown: assuming at76c502 firmware is OK.\n",
dev->name);
printk(KERN_INFO
"%s: if not, use the firmware= module parameter.\n",
dev->name);
strcpy(priv->firmware_id, "atmel_at76c502.bin");
}
if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) != 0) {
printk(KERN_ALERT
"%s: firmware %s is missing, cannot start.\n",
dev->name, priv->firmware_id);
return 0;
if (strlen(priv->firmware_template) == 0) {
if (strlen(priv->firmware_id) == 0) {
printk(KERN_INFO
"%s: card type is unknown: assuming at76c502 firmware is OK.\n",
dev->name);
printk(KERN_INFO
"%s: if not, use the firmware= module parameter.\n",
dev->name);
strcpy(priv->firmware_id, "atmel_at76c502.bin");
}
if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) != 0) {
printk(KERN_ALERT
"%s: firmware %s is missing, cannot continue.\n",
dev->name, priv->firmware_id);
return 0;
}
} else {
int i;
for (i = 0; firmware_modifier[i]; i++) {
sprintf(priv->firmware_id, priv->firmware_template, firmware_modifier[i]);
if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) == 0)
break;
}
if (!firmware_modifier[i]) {
printk(KERN_ALERT
"%s: firmware %s is missing, cannot start.\n",
dev->name, priv->firmware_id);
priv->firmware_id[0] = '\0';
return 0;
}
priv->firmware_template[0] = '\0';
}
fw = fw_entry->data;
len = fw_entry->size;
}
......@@ -3379,6 +3592,10 @@ int reset_atmel_card(struct net_device *dev)
if (!atmel_wakeup_firmware(priv))
return 0;
/* Check the version and set the correct flag for wpa stuff,
old and new firmware is incompatible. */
priv->use_wpa = (priv->host_info.major_version >= 4);
/* unmask all irq sources */
atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff);
......@@ -3447,9 +3664,12 @@ int reset_atmel_card(struct net_device *dev)
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1);
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_BEACON_PER_POS, priv->default_beacon_period);
atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, atmel_basic_rates, 4);
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep.wep_is_on);
atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&priv->wep, sizeof(priv->wep));
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep_is_on);
if (priv->use_wpa)
build_wpa_mib(priv);
else
build_wep_mib(priv);
atmel_scan(priv, 1);
atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */
......@@ -3500,8 +3720,8 @@ static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index)
m.size = 1;
m.index = index;
atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, sizeof(m));
return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + 4));
atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + 1);
return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE));
}
static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data)
......@@ -3512,7 +3732,7 @@ static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 dat
m.index = index;
m.data[0] = data;
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m));
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 1);
}
static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, u16 data)
......@@ -3524,7 +3744,7 @@ static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, u16 d
m.data[0] = data;
m.data[1] = data >> 8;
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m));
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 2);
}
static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len)
......@@ -3534,8 +3754,11 @@ static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, u8 *dat
m.size = data_len;
m.index = index;
if (data_len > MIB_MAX_DATA_BYTES)
printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name);
memcpy(m.data, data, data_len);
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m));
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + data_len);
}
static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len)
......@@ -3545,10 +3768,14 @@ static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, u8 *dat
m.size = data_len;
m.index = index;
atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, sizeof(m));
atmel_copy_to_host(priv->dev, data, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + 4), data_len);
}
if (data_len > MIB_MAX_DATA_BYTES)
printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name);
atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + data_len);
atmel_copy_to_host(priv->dev, data,
atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE), data_len);
}
static void atmel_writeAR(struct net_device *dev, u16 data)
{
int i;
......
......@@ -330,20 +330,20 @@ static struct {
char *firmware;
char *name;
} card_table[] = {
{ 0, 0, "WLAN/802.11b PC CARD", "atmel_at76c502d.bin", "Actiontec 802CAT1" },
{ 0, 0, "ATMEL/AT76C502AR", "atmel_at76c502.bin", "NoName-RFMD" },
{ 0, 0, "ATMEL/AT76C502AR_D", "atmel_at76c502d.bin", "NoName-revD" },
{ 0, 0, "ATMEL/AT76C502AR_E", "atmel_at76c502e.bin", "NoName-revE" },
{ 0, 0, "ATMEL/AT76C504", "atmel_at76c504.bin", "NoName-504" },
{ MANFID_3COM, 0x0620, NULL, "atmel_at76c502_3com.bin", "3com 3CRWE62092B" },
{ MANFID_3COM, 0x0696, NULL, "atmel_at76c502_3com.bin", "3com 3CRSHPW_96" },
{ 0, 0, "SMC/2632W-V2", "atmel_at76c502.bin", "SMC 2632W-V2" },
{ 0, 0, "SMC/2632W", "atmel_at76c502d.bin", "SMC 2632W-V3" },
{ 0xd601, 0x0007, NULL, "atmel_at76c502.bin", "Sitecom WLAN-011"}, /* suspect - from a usenet posting. */
{ 0x01bf, 0x3302, NULL, "atmel_at76c502d.bin", "Belkin F5D6060u"}, /* " " " " " */
{ 0, 0, "BT/Voyager 1020 Laptop Adapter", "atmel_at76c502.bin", "BT Voyager 1020"},
{ 0, 0, "IEEE 802.11b/Wireless LAN PC Card", "atmel_at76c502.bin", "Siemens Gigaset PC Card II" },
{ 0, 0, "CNet/CNWLC 11Mbps Wireless PC Card V-5", "atmel_at76c502e.bin", "CNet CNWLC-811ARL" }
{ 0, 0, "WLAN/802.11b PC CARD", "atmel_at76c502d%s.bin", "Actiontec 802CAT1" },
{ 0, 0, "ATMEL/AT76C502AR", "atmel_at76c502%s.bin", "NoName-RFMD" },
{ 0, 0, "ATMEL/AT76C502AR_D", "atmel_at76c502d%s.bin", "NoName-revD" },
{ 0, 0, "ATMEL/AT76C502AR_E", "atmel_at76c502e%s.bin", "NoName-revE" },
{ 0, 0, "ATMEL/AT76C504", "atmel_at76c504%s.bin", "NoName-504" },
{ MANFID_3COM, 0x0620, NULL, "atmel_at76c502_3com%s.bin", "3com 3CRWE62092B" },
{ MANFID_3COM, 0x0696, NULL, "atmel_at76c502_3com%s.bin", "3com 3CRSHPW_96" },
{ 0, 0, "SMC/2632W-V2", "atmel_at76c502%s.bin", "SMC 2632W-V2" },
{ 0, 0, "SMC/2632W", "atmel_at76c502d%s.bin", "SMC 2632W-V3" },
{ 0xd601, 0x0007, NULL, "atmel_at76c502%s.bin", "Sitecom WLAN-011"}, /* suspect - from a usenet posting. */
{ 0x01bf, 0x3302, NULL, "atmel_at76c502d%s.bin", "Belkin F5D6060u"}, /* " " " " " */
{ 0, 0, "BT/Voyager 1020 Laptop Adapter", "atmel_at76c502%s.bin", "BT Voyager 1020"},
{ 0, 0, "IEEE 802.11b/Wireless LAN PC Card", "atmel_at76c502%s.bin", "Siemens Gigaset PC Card II" },
{ 0, 0, "CNet/CNWLC 11Mbps Wireless PC Card V-5", "atmel_at76c502e%s.bin", "CNet CNWLC-811ARL" }
};
/* This is strictly temporary, until PCMCIA devices get integrated into the device model. */
......
......@@ -315,8 +315,12 @@ unsigned long do_mremap(unsigned long addr,
old_len = PAGE_ALIGN(old_len);
new_len = PAGE_ALIGN(new_len);
/* Don't allow the degenerate cases */
if (!old_len || !new_len)
/*
* We allow a zero old-len as a special case
* for DOS-emu "duplicate shm area" thing. But
* a zero new-len is nonsensical.
*/
if (!new_len)
goto out;
/* new_addr is only valid if MREMAP_FIXED is specified */
......
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