diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-27 14:41:24 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-27 14:41:24 -0700 |
commit | a77c64c1a641950626181b4857abb701d8f38ccc (patch) | |
tree | 9bfd2a99cc969b3d863d583b9ef18114a4fc4793 /drivers/net | |
parent | ac7f6b5e44cb0982b98c31fa33298ba73fb5dcfc (diff) | |
parent | 0ba8821b12231386c8c1d506c682061f7225ae49 (diff) | |
download | blackbird-op-linux-a77c64c1a641950626181b4857abb701d8f38ccc.tar.gz blackbird-op-linux-a77c64c1a641950626181b4857abb701d8f38ccc.zip |
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6: (48 commits)
[PATCH] bonding: update version number
[PATCH] git-netdev-all: pc300_tty build fix
[PATCH] Make PC300 WAN driver compile again
[PATCH] Modularize generic HDLC
[PATCH] more s2io __iomem annotations
[PATCH] restore __iomem annotations in e1000
[PATCH] 64bit bugs in s2io
[PATCH] bonding: Fix primary selection error at enslavement time
[PATCH] bonding: Don't mangle LACPDUs
[PATCH] bonding: Validate probe replies in ARP monitor
[PATCH] bonding: Don't release slaves when master is admin down
[PATCH] bonding: Add priv_flag to avoid event mishandling
[PATCH] bonding: Handle large hard_header_len
[PATCH] bonding: Remove unneeded NULL test
[PATCH] bonding: Format fix in seq_printf call
[PATCH] bonding: Convert delay value from s16 to int
[PATCH] bonding: Allow bonding to enslave a 10 Gig adapter
Delete unused drivers/net/gt64240eth.h
[PATCH] skge: fiber support
[PATCH] fix possible NULL ptr deref in forcedeth
...
Diffstat (limited to 'drivers/net')
49 files changed, 1541 insertions, 1187 deletions
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index a075246f6f43..71a4f60f7325 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -163,11 +163,7 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl); #define SET_NETDEV_DEV(net, pdev) do{} while(0) #endif -#if LINUX_VERSION_CODE >= 0x2051c #define ace_sync_irq(irq) synchronize_irq(irq) -#else -#define ace_sync_irq(irq) synchronize_irq() -#endif #ifndef offset_in_page #define offset_in_page(ptr) ((unsigned long)(ptr) & ~PAGE_MASK) diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 6a407070c2e8..3fb354d9c515 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -85,6 +85,7 @@ #define AD_LINK_SPEED_BITMASK_10MBPS 0x2 #define AD_LINK_SPEED_BITMASK_100MBPS 0x4 #define AD_LINK_SPEED_BITMASK_1000MBPS 0x8 +#define AD_LINK_SPEED_BITMASK_10000MBPS 0x10 //endalloun // compare MAC addresses @@ -99,7 +100,7 @@ static u16 __get_link_speed(struct port *port); static u8 __get_duplex(struct port *port); static inline void __initialize_port_locks(struct port *port); //conversions -static void __ntohs_lacpdu(struct lacpdu *lacpdu); +static void __htons_lacpdu(struct lacpdu *lacpdu); static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par); @@ -330,7 +331,8 @@ static inline void __release_rx_machine_lock(struct port *port) * 0, * %AD_LINK_SPEED_BITMASK_10MBPS, * %AD_LINK_SPEED_BITMASK_100MBPS, - * %AD_LINK_SPEED_BITMASK_1000MBPS + * %AD_LINK_SPEED_BITMASK_1000MBPS, + * %AD_LINK_SPEED_BITMASK_10000MBPS */ static u16 __get_link_speed(struct port *port) { @@ -357,6 +359,10 @@ static u16 __get_link_speed(struct port *port) speed = AD_LINK_SPEED_BITMASK_1000MBPS; break; + case SPEED_10000: + speed = AD_LINK_SPEED_BITMASK_10000MBPS; + break; + default: speed = 0; // unknown speed value from ethtool. shouldn't happen break; @@ -414,23 +420,23 @@ static inline void __initialize_port_locks(struct port *port) //conversions /** - * __ntohs_lacpdu - convert the contents of a LACPDU to host byte order + * __htons_lacpdu - convert the contents of a LACPDU to network byte order * @lacpdu: the speicifed lacpdu * * For each multi-byte field in the lacpdu, convert its content */ -static void __ntohs_lacpdu(struct lacpdu *lacpdu) +static void __htons_lacpdu(struct lacpdu *lacpdu) { if (lacpdu) { - lacpdu->actor_system_priority = ntohs(lacpdu->actor_system_priority); - lacpdu->actor_key = ntohs(lacpdu->actor_key); - lacpdu->actor_port_priority = ntohs(lacpdu->actor_port_priority); - lacpdu->actor_port = ntohs(lacpdu->actor_port); - lacpdu->partner_system_priority = ntohs(lacpdu->partner_system_priority); - lacpdu->partner_key = ntohs(lacpdu->partner_key); - lacpdu->partner_port_priority = ntohs(lacpdu->partner_port_priority); - lacpdu->partner_port = ntohs(lacpdu->partner_port); - lacpdu->collector_max_delay = ntohs(lacpdu->collector_max_delay); + lacpdu->actor_system_priority = htons(lacpdu->actor_system_priority); + lacpdu->actor_key = htons(lacpdu->actor_key); + lacpdu->actor_port_priority = htons(lacpdu->actor_port_priority); + lacpdu->actor_port = htons(lacpdu->actor_port); + lacpdu->partner_system_priority = htons(lacpdu->partner_system_priority); + lacpdu->partner_key = htons(lacpdu->partner_key); + lacpdu->partner_port_priority = htons(lacpdu->partner_port_priority); + lacpdu->partner_port = htons(lacpdu->partner_port); + lacpdu->collector_max_delay = htons(lacpdu->collector_max_delay); } } @@ -490,11 +496,11 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port) // validate lacpdu and port if (lacpdu && port) { // record the new parameter values for the partner operational - port->partner_oper_port_number = lacpdu->actor_port; - port->partner_oper_port_priority = lacpdu->actor_port_priority; + port->partner_oper_port_number = ntohs(lacpdu->actor_port); + port->partner_oper_port_priority = ntohs(lacpdu->actor_port_priority); port->partner_oper_system = lacpdu->actor_system; - port->partner_oper_system_priority = lacpdu->actor_system_priority; - port->partner_oper_key = lacpdu->actor_key; + port->partner_oper_system_priority = ntohs(lacpdu->actor_system_priority); + port->partner_oper_key = ntohs(lacpdu->actor_key); // zero partener's lase states port->partner_oper_port_state = 0; port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_ACTIVITY); @@ -561,11 +567,11 @@ static void __update_selected(struct lacpdu *lacpdu, struct port *port) // validate lacpdu and port if (lacpdu && port) { // check if any parameter is different - if ((lacpdu->actor_port != port->partner_oper_port_number) || - (lacpdu->actor_port_priority != port->partner_oper_port_priority) || + if ((ntohs(lacpdu->actor_port) != port->partner_oper_port_number) || + (ntohs(lacpdu->actor_port_priority) != port->partner_oper_port_priority) || MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->partner_oper_system)) || - (lacpdu->actor_system_priority != port->partner_oper_system_priority) || - (lacpdu->actor_key != port->partner_oper_key) || + (ntohs(lacpdu->actor_system_priority) != port->partner_oper_system_priority) || + (ntohs(lacpdu->actor_key) != port->partner_oper_key) || ((lacpdu->actor_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION)) ) { // update the state machine Selected variable @@ -628,11 +634,11 @@ static void __choose_matched(struct lacpdu *lacpdu, struct port *port) // validate lacpdu and port if (lacpdu && port) { // check if all parameters are alike - if (((lacpdu->partner_port == port->actor_port_number) && - (lacpdu->partner_port_priority == port->actor_port_priority) && + if (((ntohs(lacpdu->partner_port) == port->actor_port_number) && + (ntohs(lacpdu->partner_port_priority) == port->actor_port_priority) && !MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) && - (lacpdu->partner_system_priority == port->actor_system_priority) && - (lacpdu->partner_key == port->actor_oper_port_key) && + (ntohs(lacpdu->partner_system_priority) == port->actor_system_priority) && + (ntohs(lacpdu->partner_key) == port->actor_oper_port_key) && ((lacpdu->partner_state & AD_STATE_AGGREGATION) == (port->actor_oper_port_state & AD_STATE_AGGREGATION))) || // or this is individual link(aggregation == FALSE) ((lacpdu->actor_state & AD_STATE_AGGREGATION) == 0) @@ -662,11 +668,11 @@ static void __update_ntt(struct lacpdu *lacpdu, struct port *port) // validate lacpdu and port if (lacpdu && port) { // check if any parameter is different - if ((lacpdu->partner_port != port->actor_port_number) || - (lacpdu->partner_port_priority != port->actor_port_priority) || + if ((ntohs(lacpdu->partner_port) != port->actor_port_number) || + (ntohs(lacpdu->partner_port_priority) != port->actor_port_priority) || MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) || - (lacpdu->partner_system_priority != port->actor_system_priority) || - (lacpdu->partner_key != port->actor_oper_port_key) || + (ntohs(lacpdu->partner_system_priority) != port->actor_system_priority) || + (ntohs(lacpdu->partner_key) != port->actor_oper_port_key) || ((lacpdu->partner_state & AD_STATE_LACP_ACTIVITY) != (port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY)) || ((lacpdu->partner_state & AD_STATE_LACP_TIMEOUT) != (port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT)) || ((lacpdu->partner_state & AD_STATE_SYNCHRONIZATION) != (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) || @@ -775,6 +781,9 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator) case AD_LINK_SPEED_BITMASK_1000MBPS: bandwidth = aggregator->num_of_ports * 1000; break; + case AD_LINK_SPEED_BITMASK_10000MBPS: + bandwidth = aggregator->num_of_ports * 10000; + break; default: bandwidth=0; // to silent the compilor .... } @@ -847,7 +856,7 @@ static inline void __update_lacpdu_from_port(struct port *port) */ /* Convert all non u8 parameters to Big Endian for transmit */ - __ntohs_lacpdu(lacpdu); + __htons_lacpdu(lacpdu); } ////////////////////////////////////////////////////////////////////////////////////// @@ -2171,7 +2180,6 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u switch (lacpdu->subtype) { case AD_TYPE_LACPDU: - __ntohs_lacpdu(lacpdu); dprintk("Received LACPDU on port %d\n", port->actor_port_number); ad_rx_machine(lacpdu, port); break; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 850aae21a2fe..0fb5f653d3ce 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -96,6 +96,7 @@ static char *lacp_rate = NULL; static char *xmit_hash_policy = NULL; static int arp_interval = BOND_LINK_ARP_INTERV; static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; +static char *arp_validate = NULL; struct bond_params bonding_defaults; module_param(max_bonds, int, 0); @@ -127,6 +128,8 @@ module_param(arp_interval, int, 0); MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); module_param_array(arp_ip_target, charp, NULL, 0); MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); +module_param(arp_validate, charp, 0); +MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all"); /*----------------------------- Global variables ----------------------------*/ @@ -170,6 +173,14 @@ struct bond_parm_tbl xmit_hashtype_tbl[] = { { NULL, -1}, }; +struct bond_parm_tbl arp_validate_tbl[] = { +{ "none", BOND_ARP_VALIDATE_NONE}, +{ "active", BOND_ARP_VALIDATE_ACTIVE}, +{ "backup", BOND_ARP_VALIDATE_BACKUP}, +{ "all", BOND_ARP_VALIDATE_ALL}, +{ NULL, -1}, +}; + /*-------------------------- Forward declarations ---------------------------*/ static void bond_send_gratuitous_arp(struct bonding *bond); @@ -638,6 +649,7 @@ verify: case SPEED_10: case SPEED_100: case SPEED_1000: + case SPEED_10000: break; default: return -1; @@ -1210,10 +1222,14 @@ static int bond_compute_features(struct bonding *bond) unsigned long features = BOND_INTERSECT_FEATURES; struct slave *slave; struct net_device *bond_dev = bond->dev; + unsigned short max_hard_header_len = ETH_HLEN; int i; - bond_for_each_slave(bond, slave, i) + bond_for_each_slave(bond, slave, i) { features &= (slave->dev->features & BOND_INTERSECT_FEATURES); + if (slave->dev->hard_header_len > max_hard_header_len) + max_hard_header_len = slave->dev->hard_header_len; + } if ((features & NETIF_F_SG) && !(features & NETIF_F_ALL_CSUM)) @@ -1231,6 +1247,7 @@ static int bond_compute_features(struct bonding *bond) features |= (bond_dev->features & ~BOND_INTERSECT_FEATURES); bond_dev->features = features; + bond_dev->hard_header_len = max_hard_header_len; return 0; } @@ -1365,6 +1382,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } new_slave->dev = slave_dev; + slave_dev->priv_flags |= IFF_BONDING; if ((bond->params.mode == BOND_MODE_TLB) || (bond->params.mode == BOND_MODE_ALB)) { @@ -1417,6 +1435,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_compute_features(bond); + new_slave->last_arp_rx = jiffies; + if (bond->params.miimon && !bond->params.use_carrier) { link_reporting = bond_check_dev_link(bond, slave_dev, 1); @@ -1493,29 +1513,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) switch (bond->params.mode) { case BOND_MODE_ACTIVEBACKUP: - /* if we're in active-backup mode, we need one and - * only one active interface. The backup interfaces - * will have their SLAVE_INACTIVE flag set because we - * need them to be drop all packets. Thus, since we - * guarantee that curr_active_slave always point to - * the last usable interface, we just have to verify - * this interface's flag. - */ - if (((!bond->curr_active_slave) || - (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) && - (new_slave->link != BOND_LINK_DOWN)) { - /* first slave or no active slave yet, and this link - is OK, so make this interface the active one */ - bond_change_active_slave(bond, new_slave); - printk(KERN_INFO DRV_NAME - ": %s: first active interface up!\n", - bond->dev->name); - netif_carrier_on(bond->dev); - - } else { - dprintk("This is just a backup slave\n"); - bond_set_slave_inactive_flags(new_slave); - } + bond_set_slave_inactive_flags(new_slave); + bond_select_active_slave(bond); break; case BOND_MODE_8023AD: /* in 802.3ad mode, the internal mechanism @@ -1778,7 +1777,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) dev_set_mac_address(slave_dev, &addr); slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | - IFF_SLAVE_INACTIVE); + IFF_SLAVE_INACTIVE | IFF_BONDING | + IFF_SLAVE_NEEDARP); kfree(slave); @@ -2291,6 +2291,25 @@ static int bond_has_ip(struct bonding *bond) return 0; } +static int bond_has_this_ip(struct bonding *bond, u32 ip) +{ + struct vlan_entry *vlan, *vlan_next; + + if (ip == bond->master_ip) + return 1; + + if (list_empty(&bond->vlan_list)) + return 0; + + list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, + vlan_list) { + if (ip == vlan->vlan_ip) + return 1; + } + + return 0; +} + /* * We go to the (large) trouble of VLAN tagging ARP frames because * switches in VLAN mode (especially if ports are configured as @@ -2429,6 +2448,93 @@ static void bond_send_gratuitous_arp(struct bonding *bond) } } +static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip) +{ + int i; + u32 *targets = bond->params.arp_targets; + + targets = bond->params.arp_targets; + for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) { + dprintk("bva: sip %u.%u.%u.%u tip %u.%u.%u.%u t[%d] " + "%u.%u.%u.%u bhti(tip) %d\n", + NIPQUAD(sip), NIPQUAD(tip), i, NIPQUAD(targets[i]), + bond_has_this_ip(bond, tip)); + if (sip == targets[i]) { + if (bond_has_this_ip(bond, tip)) + slave->last_arp_rx = jiffies; + return; + } + } +} + +static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) +{ + struct arphdr *arp; + struct slave *slave; + struct bonding *bond; + unsigned char *arp_ptr; + u32 sip, tip; + + if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) + goto out; + + bond = dev->priv; + read_lock(&bond->lock); + + dprintk("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n", + bond->dev->name, skb->dev ? skb->dev->name : "NULL", + orig_dev ? orig_dev->name : "NULL"); + + slave = bond_get_slave_by_dev(bond, orig_dev); + if (!slave || !slave_do_arp_validate(bond, slave)) + goto out_unlock; + + /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ + if (!pskb_may_pull(skb, (sizeof(struct arphdr) + + (2 * dev->addr_len) + + (2 * sizeof(u32))))) + goto out_unlock; + + arp = skb->nh.arph; + if (arp->ar_hln != dev->addr_len || + skb->pkt_type == PACKET_OTHERHOST || + skb->pkt_type == PACKET_LOOPBACK || + arp->ar_hrd != htons(ARPHRD_ETHER) || + arp->ar_pro != htons(ETH_P_IP) || + arp->ar_pln != 4) + goto out_unlock; + + arp_ptr = (unsigned char *)(arp + 1); + arp_ptr += dev->addr_len; + memcpy(&sip, arp_ptr, 4); + arp_ptr += 4 + dev->addr_len; + memcpy(&tip, arp_ptr, 4); + + dprintk("bond_arp_rcv: %s %s/%d av %d sv %d sip %u.%u.%u.%u" + " tip %u.%u.%u.%u\n", bond->dev->name, slave->dev->name, + slave->state, bond->params.arp_validate, + slave_do_arp_validate(bond, slave), NIPQUAD(sip), NIPQUAD(tip)); + + /* + * Backup slaves won't see the ARP reply, but do come through + * here for each ARP probe (so we swap the sip/tip to validate + * the probe). In a "redundant switch, common router" type of + * configuration, the ARP probe will (hopefully) travel from + * the active, through one switch, the router, then the other + * switch before reaching the backup. + */ + if (slave->state == BOND_STATE_ACTIVE) + bond_validate_arp(bond, slave, sip, tip); + else + bond_validate_arp(bond, slave, tip, sip); + +out_unlock: + read_unlock(&bond->lock); +out: + dev_kfree_skb(skb); + return NET_RX_SUCCESS; +} + /* * this function is called regularly to monitor each slave's link * ensuring that traffic is being sent and received when arp monitoring @@ -2593,7 +2699,8 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) */ bond_for_each_slave(bond, slave, i) { if (slave->link != BOND_LINK_UP) { - if ((jiffies - slave->dev->last_rx) <= delta_in_ticks) { + if ((jiffies - slave_last_rx(bond, slave)) <= + delta_in_ticks) { slave->link = BOND_LINK_UP; @@ -2638,7 +2745,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) if ((slave != bond->curr_active_slave) && (!bond->current_arp_slave) && - (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) && + (((jiffies - slave_last_rx(bond, slave)) >= 3*delta_in_ticks) && bond_has_ip(bond))) { /* a backup slave has gone down; three times * the delta allows the current slave to be @@ -2685,7 +2792,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) * if it is up and needs to take over as the curr_active_slave */ if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || - (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && + (((jiffies - slave_last_rx(bond, slave)) >= (2*delta_in_ticks)) && bond_has_ip(bond))) && ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) { @@ -2950,7 +3057,7 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); seq_printf(seq, "MII Status: %s\n", (slave->link == BOND_LINK_UP) ? "up" : "down"); - seq_printf(seq, "Link Failure Count: %d\n", + seq_printf(seq, "Link Failure Count: %u\n", slave->link_failure_count); seq_printf(seq, @@ -3210,6 +3317,9 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v (event_dev ? event_dev->name : "None"), event); + if (!(event_dev->priv_flags & IFF_BONDING)) + return NOTIFY_DONE; + if (event_dev->flags & IFF_MASTER) { dprintk("IFF_MASTER\n"); return bond_master_netdev_event(event, event_dev); @@ -3305,6 +3415,21 @@ static void bond_unregister_lacpdu(struct bonding *bond) dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); } +void bond_register_arp(struct bonding *bond) +{ + struct packet_type *pt = &bond->arp_mon_pt; + + pt->type = htons(ETH_P_ARP); + pt->dev = NULL; /*bond->dev;XXX*/ + pt->func = bond_arp_rcv; + dev_add_pack(pt); +} + +void bond_unregister_arp(struct bonding *bond) +{ + dev_remove_pack(&bond->arp_mon_pt); +} + /*---------------------------- Hashing Policies -----------------------------*/ /* @@ -3391,6 +3516,9 @@ static int bond_open(struct net_device *bond_dev) } else { arp_timer->function = (void *)&bond_loadbalance_arp_mon; } + if (bond->params.arp_validate) + bond_register_arp(bond); + add_timer(arp_timer); } @@ -3418,9 +3546,11 @@ static int bond_close(struct net_device *bond_dev) bond_unregister_lacpdu(bond); } + if (bond->params.arp_validate) + bond_unregister_arp(bond); + write_lock_bh(&bond->lock); - bond_mc_list_destroy(bond); /* signal timers not to re-arm */ bond->kill_timers = 1; @@ -3451,8 +3581,6 @@ static int bond_close(struct net_device *bond_dev) break; } - /* Release the bonded slaves */ - bond_release_all(bond_dev); if ((bond->params.mode == BOND_MODE_TLB) || (bond->params.mode == BOND_MODE_ALB)) { @@ -4179,6 +4307,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) /* Initialize the device options */ bond_dev->tx_queue_len = 0; bond_dev->flags |= IFF_MASTER|IFF_MULTICAST; + bond_dev->priv_flags |= IFF_BONDING; /* At first, we block adding VLANs. That's the only way to * prevent problems that occur when adding VLANs over an @@ -4237,6 +4366,9 @@ static void bond_free_all(void) list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) { struct net_device *bond_dev = bond->dev; + bond_mc_list_destroy(bond); + /* Release the bonded slaves */ + bond_release_all(bond_dev); unregister_netdevice(bond_dev); bond_deinit(bond_dev); } @@ -4270,6 +4402,8 @@ int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) static int bond_check_params(struct bond_params *params) { + int arp_validate_value; + /* * Convert string parameters. */ @@ -4473,6 +4607,29 @@ static int bond_check_params(struct bond_params *params) arp_interval = 0; } + if (arp_validate) { + if (bond_mode != BOND_MODE_ACTIVEBACKUP) { + printk(KERN_ERR DRV_NAME + ": arp_validate only supported in active-backup mode\n"); + return -EINVAL; + } + if (!arp_interval) { + printk(KERN_ERR DRV_NAME + ": arp_validate requires arp_interval\n"); + return -EINVAL; + } + + arp_validate_value = bond_parse_parm(arp_validate, + arp_validate_tbl); + if (arp_validate_value == -1) { + printk(KERN_ERR DRV_NAME + ": Error: invalid arp_validate \"%s\"\n", + arp_validate == NULL ? "NULL" : arp_validate); + return -EINVAL; + } + } else + arp_validate_value = 0; + if (miimon) { printk(KERN_INFO DRV_NAME ": MII link monitoring set to %d ms\n", @@ -4481,8 +4638,10 @@ static int bond_check_params(struct bond_params *params) int i; printk(KERN_INFO DRV_NAME - ": ARP monitoring set to %d ms with %d target(s):", - arp_interval, arp_ip_count); + ": ARP monitoring set to %d ms, validate %s, with %d target(s):", + arp_interval, + arp_validate_tbl[arp_validate_value].modename, + arp_ip_count); for (i = 0; i < arp_ip_count; i++) printk (" %s", arp_ip_target[i]); @@ -4516,6 +4675,7 @@ static int bond_check_params(struct bond_params *params) params->xmit_policy = xmit_hashtype; params->miimon = miimon; params->arp_interval = arp_interval; + params->arp_validate = arp_validate_value; params->updelay = updelay; params->downdelay = downdelay; params->use_carrier = use_carrier; diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index cfe4dc3a93a3..ced9ed8f995a 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -51,6 +51,7 @@ extern struct bond_params bonding_defaults; extern struct bond_parm_tbl bond_mode_tbl[]; extern struct bond_parm_tbl bond_lacp_tbl[]; extern struct bond_parm_tbl xmit_hashtype_tbl[]; +extern struct bond_parm_tbl arp_validate_tbl[]; static int expected_refcount = -1; static struct class *netdev_class; @@ -503,6 +504,53 @@ out: static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash); /* + * Show and set arp_validate. + */ +static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf) +{ + struct bonding *bond = to_bond(cd); + + return sprintf(buf, "%s %d\n", + arp_validate_tbl[bond->params.arp_validate].modename, + bond->params.arp_validate) + 1; +} + +static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count) +{ + int new_value; + struct bonding *bond = to_bond(cd); + + new_value = bond_parse_parm((char *)buf, arp_validate_tbl); + if (new_value < 0) { + printk(KERN_ERR DRV_NAME + ": %s: Ignoring invalid arp_validate value %s\n", + bond->dev->name, buf); + return -EINVAL; + } + if (new_value && (bond->params.mode != BOND_MODE_ACTIVEBACKUP)) { + printk(KERN_ERR DRV_NAME + ": %s: arp_validate only supported in active-backup mode.\n", + bond->dev->name); + return -EINVAL; + } + printk(KERN_INFO DRV_NAME ": %s: setting arp_validate to %s (%d).\n", + bond->dev->name, arp_validate_tbl[new_value].modename, + new_value); + + if (!bond->params.arp_validate && new_value) { + bond_register_arp(bond); + } else if (bond->params.arp_validate && !new_value) { + bond_unregister_arp(bond); + } + + bond->params.arp_validate = new_value; + + return count; +} + +static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); + +/* * Show and set the arp timer interval. There are two tricky bits * here. First, if ARP monitoring is activated, then we must disable * MII monitoring. Second, if the ARP timer isn't running, we must @@ -914,6 +962,11 @@ static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, si "ARP monitoring. Disabling ARP monitoring...\n", bond->dev->name); bond->params.arp_interval = 0; + if (bond->params.arp_validate) { + bond_unregister_arp(bond); + bond->params.arp_validate = + BOND_ARP_VALIDATE_NONE; + } /* Kill ARP timer, else it brings bond's link down */ if (bond->mii_timer.function) { printk(KERN_INFO DRV_NAME @@ -1093,7 +1146,7 @@ static ssize_t bonding_store_active_slave(struct class_device *cd, const char *b strlen(slave->dev->name)) == 0) { old_active = bond->curr_active_slave; new_active = slave; - if (new_active && (new_active == old_active)) { + if (new_active == old_active) { /* do nothing */ printk(KERN_INFO DRV_NAME ": %s: %s is already the current active slave.\n", @@ -1273,6 +1326,7 @@ static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, N static struct attribute *per_bond_attrs[] = { &class_device_attr_slaves.attr, &class_device_attr_mode.attr, + &class_device_attr_arp_validate.attr, &class_device_attr_arp_interval.attr, &class_device_attr_arp_ip_target.attr, &class_device_attr_downdelay.attr, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 0bdfe2c71453..dc434fb6da85 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -22,8 +22,8 @@ #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.0.3" -#define DRV_RELDATE "March 23, 2006" +#define DRV_VERSION "3.1.1" +#define DRV_RELDATE "September 26, 2006" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" @@ -126,6 +126,7 @@ struct bond_params { int xmit_policy; int miimon; int arp_interval; + int arp_validate; int use_carrier; int updelay; int downdelay; @@ -149,8 +150,9 @@ struct slave { struct net_device *dev; /* first - useful for panic debug */ struct slave *next; struct slave *prev; - s16 delay; + int delay; u32 jiffies; + u32 last_arp_rx; s8 link; /* one of BOND_LINK_XXXX */ s8 state; /* one of BOND_STATE_XXXX */ u32 original_flags; @@ -198,6 +200,7 @@ struct bonding { struct bond_params params; struct list_head vlan_list; struct vlan_group *vlgrp; + struct packet_type arp_mon_pt; }; /** @@ -228,6 +231,25 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) return (struct bonding *)slave->dev->master->priv; } +#define BOND_ARP_VALIDATE_NONE 0 +#define BOND_ARP_VALIDATE_ACTIVE (1 << BOND_STATE_ACTIVE) +#define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP) +#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \ + BOND_ARP_VALIDATE_BACKUP) + +extern inline int slave_do_arp_validate(struct bonding *bond, struct slave *slave) +{ + return bond->params.arp_validate & (1 << slave->state); +} + +extern inline u32 slave_last_rx(struct bonding *bond, struct slave *slave) +{ + if (slave_do_arp_validate(bond, slave)) + return slave->last_arp_rx; + + return slave->dev->last_rx; +} + static inline void bond_set_slave_inactive_flags(struct slave *slave) { struct bonding *bond = slave->dev->master->priv; @@ -235,12 +257,14 @@ static inline void bond_set_slave_inactive_flags(struct slave *slave) bond->params.mode != BOND_MODE_ALB) slave->state = BOND_STATE_BACKUP; slave->dev->priv_flags |= IFF_SLAVE_INACTIVE; + if (slave_do_arp_validate(bond, slave)) + slave->dev->priv_flags |= IFF_SLAVE_NEEDARP; } static inline void bond_set_slave_active_flags(struct slave *slave) { slave->state = BOND_STATE_ACTIVE; - slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE; + slave->dev->priv_flags &= ~(IFF_SLAVE_INACTIVE | IFF_SLAVE_NEEDARP); } static inline void bond_set_master_3ad_flags(struct bonding *bond) @@ -284,6 +308,8 @@ int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl); const char *bond_mode_name(int mode); void bond_select_active_slave(struct bonding *bond); void bond_change_active_slave(struct bonding *bond, struct slave *new_active); +void bond_register_arp(struct bonding *); +void bond_unregister_arp(struct bonding *); #endif /* _LINUX_BONDING_H */ diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index a170e96251f6..4020acb55005 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -1367,8 +1367,8 @@ struct e1000_hw_stats { /* Structure containing variables used by the shared code (e1000_hw.c) */ struct e1000_hw { - uint8_t *hw_addr; - uint8_t *flash_address; + uint8_t __iomem *hw_addr; + uint8_t __iomem *flash_address; e1000_mac_type mac_type; e1000_phy_type phy_type; uint32_t phy_init_script; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 97db910fbc8c..eea1d66c530e 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -3789,6 +3789,12 @@ static int nv_loopback_test(struct net_device *dev) /* setup packet for tx */ pkt_len = ETH_DATA_LEN; tx_skb = dev_alloc_skb(pkt_len); + if (!tx_skb) { + printk(KERN_ERR "dev_alloc_skb() failed during loopback test" + " of %s\n", dev->name); + ret = 0; + goto out; + } pkt_data = skb_put(tx_skb, pkt_len); for (i = 0; i < pkt_len; i++) pkt_data[i] = (u8)(i & 0xff); @@ -3853,7 +3859,7 @@ static int nv_loopback_test(struct net_device *dev) tx_skb->end-tx_skb->data, PCI_DMA_TODEVICE); dev_kfree_skb_any(tx_skb); - + out: /* stop engines */ nv_stop_rx(dev); nv_stop_tx(dev); diff --git a/drivers/net/gt64240eth.h b/drivers/net/gt64240eth.h deleted file mode 100644 index 0d6f486e4579..000000000000 --- a/drivers/net/gt64240eth.h +++ /dev/null @@ -1,402 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001 Patton Electronics Company - * Copyright (C) 2002 Momentum Computer - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * stevel@mvista.com or support@mvista.com - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - * - * Ethernet driver definitions for the MIPS GT96100 Advanced - * Communication Controller. - * - * Modified for the Marvellous GT64240 Retarded Communication Controller. - */ -#ifndef _GT64240ETH_H -#define _GT64240ETH_H - -#include <asm/gt64240.h> - -#define ETHERNET_PORTS_DIFFERENCE_OFFSETS 0x400 - -/* Translate those weanie names from Galileo/VxWorks header files: */ - -#define GT64240_MRR MAIN_ROUTING_REGISTER -#define GT64240_CIU_ARBITER_CONFIG COMM_UNIT_ARBITER_CONFIGURATION_REGISTER -#define GT64240_CIU_ARBITER_CONTROL COMM_UNIT_ARBITER_CONTROL -#define GT64240_MAIN_LOW_CAUSE LOW_INTERRUPT_CAUSE_REGISTER -#define GT64240_MAIN_HIGH_CAUSE HIGH_INTERRUPT_CAUSE_REGISTER -#define GT64240_CPU_LOW_MASK CPU_INTERRUPT_MASK_REGISTER_LOW -#define GT64240_CPU_HIGH_MASK CPU_INTERRUPT_MASK_REGISTER_HIGH -#define GT64240_CPU_SELECT_CAUSE CPU_SELECT_CAUSE_REGISTER - -#define GT64240_ETH_PHY_ADDR_REG ETHERNET_PHY_ADDRESS_REGISTER -#define GT64240_ETH_PORT_CONFIG ETHERNET0_PORT_CONFIGURATION_REGISTER -#define GT64240_ETH_PORT_CONFIG_EXT ETHERNET0_PORT_CONFIGURATION_EXTEND_REGISTER -#define GT64240_ETH_PORT_COMMAND ETHERNET0_PORT_COMMAND_REGISTER -#define GT64240_ETH_PORT_STATUS ETHERNET0_PORT_STATUS_REGISTER -#define GT64240_ETH_IO_SIZE ETHERNET_PORTS_DIFFERENCE_OFFSETS -#define GT64240_ETH_SMI_REG ETHERNET_SMI_REGISTER -#define GT64240_ETH_MIB_COUNT_BASE ETHERNET0_MIB_COUNTER_BASE -#define GT64240_ETH_SDMA_CONFIG ETHERNET0_SDMA_CONFIGURATION_REGISTER -#define GT64240_ETH_SDMA_COMM ETHERNET0_SDMA_COMMAND_REGISTER -#define GT64240_ETH_INT_MASK ETHERNET0_INTERRUPT_MASK_REGISTER -#define GT64240_ETH_INT_CAUSE ETHERNET0_INTERRUPT_CAUSE_REGISTER -#define GT64240_ETH_CURR_TX_DESC_PTR0 ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER0 -#define GT64240_ETH_CURR_TX_DESC_PTR1 ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER1 -#define GT64240_ETH_1ST_RX_DESC_PTR0 ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER0 -#define GT64240_ETH_CURR_RX_DESC_PTR0 ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER0 -#define GT64240_ETH_HASH_TBL_PTR ETHERNET0_HASH_TABLE_POINTER_REGISTER - -/* Turn on NAPI by default */ - -#define GT64240_NAPI 1 - -/* Some 64240 settings that SHOULD eventually be setup in PROM monitor: */ -/* (Board-specific to the DSL3224 Rev A board ONLY!) */ -#define D3224_MPP_CTRL0_SETTING 0x66669900 -#define D3224_MPP_CTRL1_SETTING 0x00000000 -#define D3224_MPP_CTRL2_SETTING 0x00887700 -#define D3224_MPP_CTRL3_SETTING 0x00000044 -#define D3224_GPP_IO_CTRL_SETTING 0x0000e800 -#define D3224_GPP_LEVEL_CTRL_SETTING 0xf001f703 -#define D3224_GPP_VALUE_SETTING 0x00000000 - -/* Keep the ring sizes a power of two for efficiency. */ -//-#define TX_RING_SIZE 16 -#define TX_RING_SIZE 64 /* TESTING !!! */ -#define RX_RING_SIZE 32 -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ - -#define RX_HASH_TABLE_SIZE 16384 -#define HASH_HOP_NUMBER 12 - -#define NUM_INTERFACES 3 - -#define GT64240ETH_TX_TIMEOUT HZ/4 - -#define MIPS_GT64240_BASE 0xf4000000 -#define GT64240_ETH0_BASE (MIPS_GT64240_BASE + GT64240_ETH_PORT_CONFIG) -#define GT64240_ETH1_BASE (GT64240_ETH0_BASE + GT64240_ETH_IO_SIZE) -#define GT64240_ETH2_BASE (GT64240_ETH1_BASE + GT64240_ETH_IO_SIZE) - -#if defined(CONFIG_MIPS_DSL3224) -#define GT64240_ETHER0_IRQ 4 -#define GT64240_ETHER1_IRQ 4 -#else -#define GT64240_ETHER0_IRQ -1 -#define GT64240_ETHER1_IRQ -1 -#endif - -#define REV_GT64240 0x1 -#define REV_GT64240A 0x10 - -#define GT64240ETH_READ(gp, offset) \ - GT_READ((gp)->port_offset + (offset)) - -#define GT64240ETH_WRITE(gp, offset, data) \ - GT_WRITE((gp)->port_offset + (offset), (data)) - -#define GT64240ETH_SETBIT(gp, offset, bits) \ - GT64240ETH_WRITE((gp), (offset), \ - GT64240ETH_READ((gp), (offset)) | (bits)) - -#define GT64240ETH_CLRBIT(gp, offset, bits) \ - GT64240ETH_WRITE((gp), (offset), \ - GT64240ETH_READ((gp), (offset)) & ~(bits)) - -#define GT64240_READ(ofs) GT_READ(ofs) -#define GT64240_WRITE(ofs, data) GT_WRITE((ofs), (data)) - -/* Bit definitions of the SMI Reg */ -enum { - smirDataMask = 0xffff, - smirPhyAdMask = 0x1f << 16, - smirPhyAdBit = 16, - smirRegAdMask = 0x1f << 21, - smirRegAdBit = 21, - smirOpCode = 1 << 26, - smirReadValid = 1 << 27, - smirBusy = 1 << 28 -}; - -/* Bit definitions of the Port Config Reg */ -enum pcr_bits { - pcrPM = 1 << 0, - pcrRBM = 1 << 1, - pcrPBF = 1 << 2, - pcrEN = 1 << 7, - pcrLPBKMask = 0x3 << 8, - pcrLPBKBit = 1 << 8, - pcrFC = 1 << 10, - pcrHS = 1 << 12, - pcrHM = 1 << 13, - pcrHDM = 1 << 14, - pcrHD = 1 << 15, - pcrISLMask = 0x7 << 28, - pcrISLBit = 28, - pcrACCS = 1 << 31 -}; - -/* Bit definitions of the Port Config Extend Reg */ -enum pcxr_bits { - pcxrIGMP = 1, - pcxrSPAN = 2, - pcxrPAR = 4, - pcxrPRIOtxMask = 0x7 << 3, - pcxrPRIOtxBit = 3, - pcxrPRIOrxMask = 0x3 << 6, - pcxrPRIOrxBit = 6, - pcxrPRIOrxOverride = 1 << 8, - pcxrDPLXen = 1 << 9, - pcxrFCTLen = 1 << 10, - pcxrFLP = 1 << 11, - pcxrFCTL = 1 << 12, - pcxrMFLMask = 0x3 << 14, - pcxrMFLBit = 14, - pcxrMIBclrMode = 1 << 16, - pcxrSpeed = 1 << 18, - pcxrSpeeden = 1 << 19, - pcxrRMIIen = 1 << 20, - pcxrDSCPen = 1 << 21 -}; - -/* Bit definitions of the Port Command Reg */ -enum pcmr_bits { - pcmrFJ = 1 << 15 -}; - - -/* Bit definitions of the Port Status Reg */ -enum psr_bits { - psrSpeed = 1, - psrDuplex = 2, - psrFctl = 4, - psrLink = 8, - psrPause = 1 << 4, - psrTxLow = 1 << 5, - psrTxHigh = 1 << 6, - psrTxInProg = 1 << 7 -}; - -/* Bit definitions of the SDMA Config Reg */ -enum sdcr_bits { - sdcrRCMask = 0xf << 2, - sdcrRCBit = 2, - sdcrBLMR = 1 << 6, - sdcrBLMT = 1 << 7, - sdcrPOVR = 1 << 8, - sdcrRIFB = 1 << 9, - sdcrBSZMask = 0x3 << 12, - sdcrBSZBit = 12 -}; - -/* Bit definitions of the SDMA Command Reg */ -enum sdcmr_bits { - sdcmrERD = 1 << 7, - sdcmrAR = 1 << 15, - sdcmrSTDH = 1 << 16, - sdcmrSTDL = 1 << 17, - sdcmrTXDH = 1 << 23, - sdcmrTXDL = 1 << 24, - sdcmrAT = 1 << 31 -}; - -/* Bit definitions of the Interrupt Cause Reg */ -enum icr_bits { - icrRxBuffer = 1, - icrTxBufferHigh = 1 << 2, - icrTxBufferLow = 1 << 3, - icrTxEndHigh = 1 << 6, - icrTxEndLow = 1 << 7, - icrRxError = 1 << 8, - icrTxErrorHigh = 1 << 10, - icrTxErrorLow = 1 << 11, - icrRxOVR = 1 << 12, - icrTxUdr = 1 << 13, - icrRxBufferQ0 = 1 << 16, - icrRxBufferQ1 = 1 << 17, - icrRxBufferQ2 = 1 << 18, - icrRxBufferQ3 = 1 << 19, - icrRxErrorQ0 = 1 << 20, - icrRxErrorQ1 = 1 << 21, - icrRxErrorQ2 = 1 << 22, - icrRxErrorQ3 = 1 << 23, - icrMIIPhySTC = 1 << 28, - icrSMIdone = 1 << 29, - icrEtherIntSum = 1 << 31 -}; - - -/* The Rx and Tx descriptor lists. */ -#ifdef __LITTLE_ENDIAN -typedef struct { - u32 cmdstat; - u16 reserved; //-prk21aug01 u32 reserved:16; - u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16; - u32 buff_ptr; - u32 next; -} gt64240_td_t; - -typedef struct { - u32 cmdstat; - u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16; - u16 buff_sz; //-prk21aug01 u32 buff_sz:16; - u32 buff_ptr; - u32 next; -} gt64240_rd_t; -#elif defined(__BIG_ENDIAN) -typedef struct { - u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16; - u16 reserved; //-prk21aug01 u32 reserved:16; - u32 cmdstat; - u32 next; - u32 buff_ptr; -} gt64240_td_t; - -typedef struct { - u16 buff_sz; //-prk21aug01 u32 buff_sz:16; - u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16; - u32 cmdstat; - u32 next; - u32 buff_ptr; -} gt64240_rd_t; -#else -#error Either __BIG_ENDIAN or __LITTLE_ENDIAN must be defined! -#endif - - -/* Values for the Tx command-status descriptor entry. */ -enum td_cmdstat { - txOwn = 1 << 31, - txAutoMode = 1 << 30, - txEI = 1 << 23, - txGenCRC = 1 << 22, - txPad = 1 << 18, - txFirst = 1 << 17, - txLast = 1 << 16, - txErrorSummary = 1 << 15, - txReTxCntMask = 0x0f << 10, - txReTxCntBit = 10, - txCollision = 1 << 9, - txReTxLimit = 1 << 8, - txUnderrun = 1 << 6, - txLateCollision = 1 << 5 -}; - - -/* Values for the Rx command-status descriptor entry. */ -enum rd_cmdstat { - rxOwn = 1 << 31, - rxAutoMode = 1 << 30, - rxEI = 1 << 23, - rxFirst = 1 << 17, - rxLast = 1 << 16, - rxErrorSummary = 1 << 15, - rxIGMP = 1 << 14, - rxHashExpired = 1 << 13, - rxMissedFrame = 1 << 12, - rxFrameType = 1 << 11, - rxShortFrame = 1 << 8, - rxMaxFrameLen = 1 << 7, - rxOverrun = 1 << 6, - rxCollision = 1 << 4, - rxCRCError = 1 -}; - -/* Bit fields of a Hash Table Entry */ -enum hash_table_entry { - hteValid = 1, - hteSkip = 2, - hteRD = 4 -}; - -// The MIB counters -typedef struct { - u32 byteReceived; - u32 byteSent; - u32 framesReceived; - u32 framesSent; - u32 totalByteReceived; - u32 totalFramesReceived; - u32 broadcastFramesReceived; - u32 multicastFramesReceived; - u32 cRCError; - u32 oversizeFrames; - u32 fragments; - u32 jabber; - u32 collision; - u32 lateCollision; - u32 frames64; - u32 frames65_127; - u32 frames128_255; - u32 frames256_511; - u32 frames512_1023; - u32 frames1024_MaxSize; - u32 macRxError; - u32 droppedFrames; - u32 outMulticastFrames; - u32 outBroadcastFrames; - u32 undersizeFrames; -} mib_counters_t; - - -struct gt64240_private { - gt64240_rd_t *rx_ring; - gt64240_td_t *tx_ring; - // The Rx and Tx rings must be 16-byte aligned - dma_addr_t rx_ring_dma; - dma_addr_t tx_ring_dma; - char *hash_table; - // The Hash Table must be 8-byte aligned - dma_addr_t hash_table_dma; - int hash_mode; - - // The Rx buffers must be 8-byte aligned - char *rx_buff; - dma_addr_t rx_buff_dma; - // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes - // of payload must be 8-byte aligned - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - int rx_next_out; /* The next free ring entry to receive */ - int tx_next_in; /* The next free ring entry to send */ - int tx_next_out; /* The last ring entry the ISR processed */ - int tx_count; /* current # of pkts waiting to be sent in Tx ring */ - int intr_work_done; /* number of Rx and Tx pkts processed in the isr */ - int tx_full; /* Tx ring is full */ - - mib_counters_t mib; - struct net_device_stats stats; - - int io_size; - int port_num; // 0 or 1 - u32 port_offset; - - int phy_addr; // PHY address - u32 last_psr; // last value of the port status register - - int options; /* User-settable misc. driver options. */ - int drv_flags; - spinlock_t lock; /* Serialise access to device */ - struct mii_if_info mii_if; - - u32 msg_enable; -}; - -#endif /* _GT64240ETH_H */ diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 2d1ecfdc80db..ecd3da151e2d 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -522,7 +522,7 @@ EXPORT_SYMBOL(genphy_read_status); static int genphy_config_init(struct phy_device *phydev) { - u32 val; + int val; u32 features; /* For now, I'll claim that the generic driver supports diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index f5dbeb27b6f0..1bf23e41f580 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -2904,7 +2904,7 @@ static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device { u64 val64 = 0x0; nic_t *sp = dev->priv; - XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0; + XENA_dev_config_t __iomem *bar0 = sp->bar0; //address transaction val64 = val64 | MDIO_MMD_INDX_ADDR(addr) @@ -2953,7 +2953,7 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev) u64 val64 = 0x0; u64 rval64 = 0x0; nic_t *sp = dev->priv; - XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0; + XENA_dev_config_t __iomem *bar0 = sp->bar0; /* address transaction */ val64 = val64 | MDIO_MMD_INDX_ADDR(addr) @@ -3276,7 +3276,7 @@ static void alarm_intr_handler(struct s2io_nic *nic) * SUCCESS on success and FAILURE on failure. */ -static int wait_for_cmd_complete(void *addr, u64 busy_bit) +static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit) { int ret = FAILURE, cnt = 0; u64 val64; @@ -4303,11 +4303,11 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev) sp->stats.tx_errors = le32_to_cpu(mac_control->stats_info->tmac_any_err_frms); sp->stats.rx_errors = - le32_to_cpu(mac_control->stats_info->rmac_drop_frms); + le64_to_cpu(mac_control->stats_info->rmac_drop_frms); sp->stats.multicast = le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms); sp->stats.rx_length_errors = - le32_to_cpu(mac_control->stats_info->rmac_long_frms); + le64_to_cpu(mac_control->stats_info->rmac_long_frms); return (&sp->stats); } diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 9142d91355bc..705e9a8fa30f 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -58,6 +58,7 @@ #define TX_WATCHDOG (5 * HZ) #define NAPI_WEIGHT 64 #define BLINK_MS 250 +#define LINK_HZ (HZ/2) MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>"); @@ -605,7 +606,12 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) if (hw->chip_id == CHIP_ID_GENESIS) { switch (mode) { case LED_MODE_OFF: - xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF); + if (hw->phy_type == SK_PHY_BCOM) + xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF); + else { + skge_write32(hw, SK_REG(port, TX_LED_VAL), 0); + skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_T_OFF); + } skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF); skge_write32(hw, SK_REG(port, RX_LED_VAL), 0); skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF); @@ -625,8 +631,14 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) skge_write32(hw, SK_REG(port, RX_LED_VAL), 100); skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START); - xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON); - break; + if (hw->phy_type == SK_PHY_BCOM) + xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON); + else { + skge_write8(hw, SK_REG(port, TX_LED_TST), LED_T_ON); + skge_write32(hw, SK_REG(port, TX_LED_VAL), 100); + skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START); + } + } } else { switch (mode) { @@ -879,6 +891,9 @@ static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val) xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); *val = xm_read16(hw, port, XM_PHY_DATA); + if (hw->phy_type == SK_PHY_XMAC) + goto ready; + for (i = 0; i < PHY_RETRIES; i++) { if (xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_RDY) goto ready; @@ -965,7 +980,8 @@ static void genesis_reset(struct skge_hw *hw, int port) xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */ /* disable Broadcom PHY IRQ */ - xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff); + if (hw->phy_type == SK_PHY_BCOM) + xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff); xm_outhash(hw, port, XM_HSM, zero); } @@ -1000,60 +1016,64 @@ static void bcom_check_link(struct skge_hw *hw, int port) if (netif_carrier_ok(dev)) skge_link_down(skge); - } else { - if (skge->autoneg == AUTONEG_ENABLE && - (status & PHY_ST_AN_OVER)) { - u16 lpa = xm_phy_read(hw, port, PHY_BCOM_AUNE_LP); - u16 aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT); - - if (lpa & PHY_B_AN_RF) { - printk(KERN_NOTICE PFX "%s: remote fault\n", - dev->name); - return; - } + return; + } - /* Check Duplex mismatch */ - switch (aux & PHY_B_AS_AN_RES_MSK) { - case PHY_B_RES_1000FD: - skge->duplex = DUPLEX_FULL; - break; - case PHY_B_RES_1000HD: - skge->duplex = DUPLEX_HALF; - break; - default: - printk(KERN_NOTICE PFX "%s: duplex mismatch\n", - dev->name); - return; - } + if (skge->autoneg == AUTONEG_ENABLE) { + u16 lpa, aux; + if (!(status & PHY_ST_AN_OVER)) + return; - /* We are using IEEE 802.3z/D5.0 Table 37-4 */ - switch (aux & PHY_B_AS_PAUSE_MSK) { - case PHY_B_AS_PAUSE_MSK: - skge->flow_control = FLOW_MODE_SYMMETRIC; - break; - case PHY_B_AS_PRR: - skge->flow_control = FLOW_MODE_REM_SEND; - break; - case PHY_B_AS_PRT: - skge->flow_control = FLOW_MODE_LOC_SEND; - break; - default: - skge->flow_control = FLOW_MODE_NONE; - } + lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP); + if (lpa & PHY_B_AN_RF) { + printk(KERN_NOTICE PFX "%s: remote fault\n", + dev->name); + return; + } - skge->speed = SPEED_1000; + aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT); + + /* Check Duplex mismatch */ + switch (aux & PHY_B_AS_AN_RES_MSK) { + case PHY_B_RES_1000FD: + skge->duplex = DUPLEX_FULL; + break; + case PHY_B_RES_1000HD: + skge->duplex = DUPLEX_HALF; + break; + default: + printk(KERN_NOTICE PFX "%s: duplex mismatch\n", + dev->name); + return; } - if (!netif_carrier_ok(dev)) - genesis_link_up(skge); + + /* We are using IEEE 802.3z/D5.0 Table 37-4 */ + switch (aux & PHY_B_AS_PAUSE_MSK) { + case PHY_B_AS_PAUSE_MSK: + skge->flow_control = FLOW_MODE_SYMMETRIC; + break; + case PHY_B_AS_PRR: + skge->flow_control = FLOW_MODE_REM_SEND; + break; + case PHY_B_AS_PRT: + skge->flow_control = FLOW_MODE_LOC_SEND; + break; + default: + skge->flow_control = FLOW_MODE_NONE; + } + skge->speed = SPEED_1000; } + + if (!netif_carrier_ok(dev)) + genesis_link_up(skge); } /* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional * Phy on for 100 or 10Mbit operation */ -static void bcom_phy_init(struct skge_port *skge, int jumbo) +static void bcom_phy_init(struct skge_port *skge) { struct skge_hw *hw = skge->hw; int port = skge->port; @@ -1144,7 +1164,7 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo) phy_pause_map[skge->flow_control] | PHY_AN_CSMA); /* Handle Jumbo frames */ - if (jumbo) { + if (hw->dev[port]->mtu > ETH_DATA_LEN) { xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK); @@ -1157,8 +1177,154 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo) /* Use link status change interrupt */ xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); +} - bcom_check_link(hw, port); +static void xm_phy_init(struct skge_port *skge) +{ + struct skge_hw *hw = skge->hw; + int port = skge->port; + u16 ctrl = 0; + + if (skge->autoneg == AUTONEG_ENABLE) { + if (skge->advertising & ADVERTISED_1000baseT_Half) + ctrl |= PHY_X_AN_HD; + if (skge->advertising & ADVERTISED_1000baseT_Full) + ctrl |= PHY_X_AN_FD; + + switch(skge->flow_control) { + case FLOW_MODE_NONE: + ctrl |= PHY_X_P_NO_PAUSE; + break; + case FLOW_MODE_LOC_SEND: + ctrl |= PHY_X_P_ASYM_MD; + break; + case FLOW_MODE_SYMMETRIC: + ctrl |= PHY_X_P_BOTH_MD; + break; + } + + xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl); + + /* Restart Auto-negotiation */ + ctrl = PHY_CT_ANE | PHY_CT_RE_CFG; + } else { + /* Set DuplexMode in Config register */ + if (skge->duplex == DUPLEX_FULL) + ctrl |= PHY_CT_DUP_MD; + /* + * Do NOT enable Auto-negotiation here. This would hold + * the link down because no IDLEs are transmitted + */ + } + + xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl); + + /* Poll PHY for status changes */ + schedule_delayed_work(&skge->link_thread, LINK_HZ); +} + +static void xm_check_link(struct net_device *dev) +{ + struct skge_port *skge = netdev_priv(dev); + struct skge_hw *hw = skge->hw; + int port = skge->port; + u16 status; + + /* read twice because of latch */ + (void) xm_phy_read(hw, port, PHY_XMAC_STAT); + status = xm_phy_read(hw, port, PHY_XMAC_STAT); + + if ((status & PHY_ST_LSYNC) == 0) { + u16 cmd = xm_read16(hw, port, XM_MMU_CMD); + cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); + xm_write16(hw, port, XM_MMU_CMD, cmd); + /* dummy read to ensure writing */ + (void) xm_read16(hw, port, XM_MMU_CMD); + + if (netif_carrier_ok(dev)) + skge_link_down(skge); + return; + } + + if (skge->autoneg == AUTONEG_ENABLE) { + u16 lpa, res; + + if (!(status & PHY_ST_AN_OVER)) + return; + + lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP); + if (lpa & PHY_B_AN_RF) { + printk(KERN_NOTICE PFX "%s: remote fault\n", + dev->name); + return; + } + + res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI); + + /* Check Duplex mismatch */ + switch (res & (PHY_X_RS_HD | PHY_X_RS_FD)) { + case PHY_X_RS_FD: + skge->duplex = DUPLEX_FULL; + break; + case PHY_X_RS_HD: + skge->duplex = DUPLEX_HALF; + break; + default: + printk(KERN_NOTICE PFX "%s: duplex mismatch\n", + dev->name); + return; + } + + /* We are using IEEE 802.3z/D5.0 Table 37-4 */ + if (lpa & PHY_X_P_SYM_MD) + skge->flow_control = FLOW_MODE_SYMMETRIC; + else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) + skge->flow_control = FLOW_MODE_REM_SEND; + else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) + skge->flow_control = FLOW_MODE_LOC_SEND; + else + skge->flow_control = FLOW_MODE_NONE; + + + skge->speed = SPEED_1000; + } + + if (!netif_carrier_ok(dev)) + genesis_link_up(skge); +} + +/* Poll to check for link coming up. + * Since internal PHY is wired to a level triggered pin, can't + * get an interrupt when carrier is detected. + */ +static void xm_link_timer(void *arg) +{ + struct net_device *dev = arg; + struct skge_port *skge = netdev_priv(arg); + struct skge_hw *hw = skge->hw; + int port = skge->port; + + if (!netif_running(dev)) + return; + + if (netif_carrier_ok(dev)) { + xm_read16(hw, port, XM_ISRC); + if (!(xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)) + goto nochange; + } else { + if (xm_read32(hw, port, XM_GP_PORT) & XM_GP_INP_ASS) + goto nochange; + xm_read16(hw, port, XM_ISRC); + if (xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS) + goto nochange; + } + + mutex_lock(&hw->phy_mutex); + xm_check_link(dev); + mutex_unlock(&hw->phy_mutex); + +nochange: + schedule_delayed_work(&skge->link_thread, LINK_HZ); } static void genesis_mac_init(struct skge_hw *hw, int port) @@ -1189,20 +1355,29 @@ static void genesis_mac_init(struct skge_hw *hw, int port) * namely for the 1000baseTX cards that use the XMAC's * GMII mode. */ - /* Take external Phy out of reset */ - r = skge_read32(hw, B2_GP_IO); - if (port == 0) - r |= GP_DIR_0|GP_IO_0; - else - r |= GP_DIR_2|GP_IO_2; + if (hw->phy_type != SK_PHY_XMAC) { + /* Take external Phy out of reset */ + r = skge_read32(hw, B2_GP_IO); + if (port == 0) + r |= GP_DIR_0|GP_IO_0; + else + r |= GP_DIR_2|GP_IO_2; - skge_write32(hw, B2_GP_IO, r); + skge_write32(hw, B2_GP_IO, r); + /* Enable GMII interface */ + xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD); + } - /* Enable GMII interface */ - xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD); - bcom_phy_init(skge, jumbo); + switch(hw->phy_type) { + case SK_PHY_XMAC: + xm_phy_init(skge); + break; + case SK_PHY_BCOM: + bcom_phy_init(skge); + bcom_check_link(hw, port); + } /* Set Station Address */ xm_outaddr(hw, port, XM_SA, dev->dev_addr); @@ -1335,16 +1510,18 @@ static void genesis_stop(struct skge_port *skge) skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST); /* For external PHYs there must be special handling */ - reg = skge_read32(hw, B2_GP_IO); - if (port == 0) { - reg |= GP_DIR_0; - reg &= ~GP_IO_0; - } else { - reg |= GP_DIR_2; - reg &= ~GP_IO_2; + if (hw->phy_type != SK_PHY_XMAC) { + reg = skge_read32(hw, B2_GP_IO); + if (port == 0) { + reg |= GP_DIR_0; + reg &= ~GP_IO_0; + } else { + reg |= GP_DIR_2; + reg &= ~GP_IO_2; + } + skge_write32(hw, B2_GP_IO, reg); + skge_read32(hw, B2_GP_IO); } - skge_write32(hw, B2_GP_IO, reg); - skge_read32(hw, B2_GP_IO); xm_write16(hw, port, XM_MMU_CMD, xm_read16(hw, port, XM_MMU_CMD) @@ -1406,7 +1583,7 @@ static void genesis_link_up(struct skge_port *skge) struct skge_hw *hw = skge->hw; int port = skge->port; u16 cmd; - u32 mode, msk; + u32 mode; cmd = xm_read16(hw, port, XM_MMU_CMD); @@ -1454,27 +1631,24 @@ static void genesis_link_up(struct skge_port *skge) } xm_write32(hw, port, XM_MODE, mode); - - msk = XM_DEF_MSK; - /* disable GP0 interrupt bit for external Phy */ - msk |= XM_IS_INP_ASS; - - xm_write16(hw, port, XM_IMSK, msk); + xm_write16(hw, port, XM_IMSK, XM_DEF_MSK); xm_read16(hw, port, XM_ISRC); /* get MMU Command Reg. */ cmd = xm_read16(hw, port, XM_MMU_CMD); - if (skge->duplex == DUPLEX_FULL) + if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL) cmd |= XM_MMU_GMII_FD; /* * Workaround BCOM Errata (#10523) for all BCom Phys * Enable Power Management after link up */ - xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, - xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL) - & ~PHY_B_AC_DIS_PM); - xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); + if (hw->phy_type == SK_PHY_BCOM) { + xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, + xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL) + & ~PHY_B_AC_DIS_PM); + xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); + } /* enable Rx/Tx */ xm_write16(hw, port, XM_MMU_CMD, @@ -2240,6 +2414,8 @@ static int skge_down(struct net_device *dev) printk(KERN_INFO PFX "%s: disabling interface\n", dev->name); netif_stop_queue(dev); + if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC) + cancel_rearming_delayed_work(&skge->link_thread); skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF); if (hw->chip_id == CHIP_ID_GENESIS) @@ -2862,7 +3038,7 @@ static void skge_extirq(void *arg) if (netif_running(dev)) { if (hw->chip_id != CHIP_ID_GENESIS) yukon_phy_intr(skge); - else + else if (hw->phy_type == SK_PHY_BCOM) bcom_phy_intr(skge); } } @@ -3014,7 +3190,7 @@ static int skge_reset(struct skge_hw *hw) { u32 reg; u16 ctst, pci_status; - u8 t8, mac_cfg, pmd_type, phy_type; + u8 t8, mac_cfg, pmd_type; int i; ctst = skge_read16(hw, B0_CTST); @@ -3038,19 +3214,22 @@ static int skge_reset(struct skge_hw *hw) ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA)); hw->chip_id = skge_read8(hw, B2_CHIP_ID); - phy_type = skge_read8(hw, B2_E_1) & 0xf; + hw->phy_type = skge_read8(hw, B2_E_1) & 0xf; pmd_type = skge_read8(hw, B2_PMD_TYP); hw->copper = (pmd_type == 'T' || pmd_type == '1'); switch (hw->chip_id) { case CHIP_ID_GENESIS: - switch (phy_type) { + switch (hw->phy_type) { + case SK_PHY_XMAC: + hw->phy_addr = PHY_ADDR_XMAC; + break; case SK_PHY_BCOM: hw->phy_addr = PHY_ADDR_BCOM; break; default: printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n", - pci_name(hw->pdev), phy_type); + pci_name(hw->pdev), hw->phy_type); return -EOPNOTSUPP; } break; @@ -3058,7 +3237,7 @@ static int skge_reset(struct skge_hw *hw) case CHIP_ID_YUKON: case CHIP_ID_YUKON_LITE: case CHIP_ID_YUKON_LP: - if (phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S') + if (hw->phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S') hw->copper = 1; hw->phy_addr = PHY_ADDR_MARV; @@ -3089,10 +3268,13 @@ static int skge_reset(struct skge_hw *hw) else hw->ram_size = t8 * 4096; - hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1; + hw->intr_mask = IS_HW_ERR | IS_PORT_1; if (hw->ports > 1) hw->intr_mask |= IS_PORT_2; + if (!(hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)) + hw->intr_mask |= IS_EXT_REG; + if (hw->chip_id == CHIP_ID_GENESIS) genesis_init(hw); else { @@ -3226,6 +3408,9 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, skge->port = port; + /* Only used for Genesis XMAC */ + INIT_WORK(&skge->link_thread, xm_link_timer, dev); + if (hw->chip_id != CHIP_ID_GENESIS) { dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; skge->rx_csum = 1; diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 79e09271bcf9..d0b47d46cf9d 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -934,7 +934,7 @@ enum { PHY_XMAC_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */ PHY_XMAC_AUNE_LP = 0x05,/* 16 bit r/o Link Partner Abi Reg */ PHY_XMAC_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */ - PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */ + PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */ PHY_XMAC_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner */ PHY_XMAC_EXT_STAT = 0x0f,/* 16 bit r/o Ext Status Register */ @@ -1097,13 +1097,36 @@ enum { /* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */ enum { - PHY_X_P_NO_PAUSE = 0<<7,/* Bit 8..7: no Pause Mode */ + PHY_X_P_NO_PAUSE= 0<<7,/* Bit 8..7: no Pause Mode */ PHY_X_P_SYM_MD = 1<<7, /* Bit 8..7: symmetric Pause Mode */ PHY_X_P_ASYM_MD = 2<<7,/* Bit 8..7: asymmetric Pause Mode */ PHY_X_P_BOTH_MD = 3<<7,/* Bit 8..7: both Pause Mode */ }; +/***** PHY_XMAC_EXT_STAT 16 bit r/w Extended Status Register *****/ +enum { + PHY_X_EX_FD = 1<<15, /* Bit 15: Device Supports Full Duplex */ + PHY_X_EX_HD = 1<<14, /* Bit 14: Device Supports Half Duplex */ +}; + +/***** PHY_XMAC_RES_ABI 16 bit r/o PHY Resolved Ability *****/ +enum { + PHY_X_RS_PAUSE = 3<<7, /* Bit 8..7: selected Pause Mode */ + PHY_X_RS_HD = 1<<6, /* Bit 6: Half Duplex Mode selected */ + PHY_X_RS_FD = 1<<5, /* Bit 5: Full Duplex Mode selected */ + PHY_X_RS_ABLMIS = 1<<4, /* Bit 4: duplex or pause cap mismatch */ + PHY_X_RS_PAUMIS = 1<<3, /* Bit 3: pause capability mismatch */ +}; + +/* Remote Fault Bits (PHY_X_AN_RFB) encoding */ +enum { + X_RFB_OK = 0<<12,/* Bit 13..12 No errors, Link OK */ + X_RFB_LF = 1<<12,/* Bit 13..12 Link Failure */ + X_RFB_OFF = 2<<12,/* Bit 13..12 Offline */ + X_RFB_AN_ERR = 3<<12,/* Bit 13..12 Auto-Negotiation Error */ +}; + /* Broadcom-Specific */ /***** PHY_BCOM_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/ enum { @@ -2158,8 +2181,8 @@ enum { XM_IS_LNK_AE = 1<<14, /* Bit 14: Link Asynchronous Event */ XM_IS_TX_ABORT = 1<<13, /* Bit 13: Transmit Abort, late Col. etc */ XM_IS_FRC_INT = 1<<12, /* Bit 12: Force INT bit set in GP */ - XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */ - XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */ + XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */ + XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */ XM_IS_RX_PAGE = 1<<9, /* Bit 9: Page Received */ XM_IS_TX_PAGE = 1<<8, /* Bit 8: Next Page Loaded for Transmit */ XM_IS_AND = 1<<7, /* Bit 7: Auto-Negotiation Done */ @@ -2172,9 +2195,7 @@ enum { XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */ }; -#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | \ - XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | \ - XM_IS_RXF_OV | XM_IS_TXF_UR)) +#define XM_DEF_MSK (~(XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_RXF_OV | XM_IS_TXF_UR)) /* XM_HW_CFG 16 bit r/w Hardware Config Register */ @@ -2396,6 +2417,7 @@ struct skge_hw { u8 chip_rev; u8 copper; u8 ports; + u8 phy_type; u32 ram_size; u32 ram_offset; @@ -2422,6 +2444,7 @@ struct skge_port { struct net_device_stats net_stats; + struct work_struct link_thread; u8 rx_csum; u8 blink_on; u8 flow_control; diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 7aa7fbac8224..c660e33f43a2 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -379,6 +379,24 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r, #define SMC_IRQ_FLAGS (0) +#elif defined(CONFIG_ARCH_VERSATILE) + +#define SMC_CAN_USE_8BIT 1 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 1 +#define SMC_NOWAIT 1 + +#define SMC_inb(a, r) readb((a) + (r)) +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_inl(a, r) readl((a) + (r)) +#define SMC_outb(v, a, r) writeb(v, (a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_outl(v, a, r) writel(v, (a) + (r)) +#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) +#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) + +#define SMC_IRQ_FLAGS (0) + #else #define SMC_CAN_USE_8BIT 1 diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 0d66700c6ced..bfc8c3eae9a1 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -1876,7 +1876,6 @@ static int sprintf_info(char *buffer, struct net_device *dev) datap[size+1]=io_word & 0xff; } - size = sprintf(buffer, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name); size += sprintf(buffer + size, @@ -1932,64 +1931,6 @@ static int sprintf_info(char *buffer, struct net_device *dev) #endif #endif -#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) -static int streamer_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - int i; - struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; - u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; - - switch(cmd) { - case IOCTL_SISR_MASK: - writew(SISR_MI, streamer_mmio + SISR_MASK_SUM); - break; - case IOCTL_SPIN_LOCK_TEST: - printk(KERN_INFO "spin_lock() called.\n"); - spin_lock(&streamer_priv->streamer_lock); - spin_unlock(&streamer_priv->streamer_lock); - printk(KERN_INFO "spin_unlock() finished.\n"); - break; - case IOCTL_PRINT_BDAS: - printk(KERN_INFO "bdas: RXBDA: %x RXLBDA: %x TX2FDA: %x TX2LFDA: %x\n", - readw(streamer_mmio + RXBDA), - readw(streamer_mmio + RXLBDA), - readw(streamer_mmio + TX2FDA), - readw(streamer_mmio + TX2LFDA)); - break; - case IOCTL_PRINT_REGISTERS: - printk(KERN_INFO "registers:\n"); - printk(KERN_INFO "SISR: %04x MISR: %04x LISR: %04x BCTL: %04x BMCTL: %04x\nmask %04x mask %04x\n", - readw(streamer_mmio + SISR), - readw(streamer_mmio + MISR_RUM), - readw(streamer_mmio + LISR), - readw(streamer_mmio + BCTL), - readw(streamer_mmio + BMCTL_SUM), - readw(streamer_mmio + SISR_MASK), - readw(streamer_mmio + MISR_MASK)); - break; - case IOCTL_PRINT_RX_BUFS: - printk(KERN_INFO "Print rx bufs:\n"); - for(i=0; i<STREAMER_RX_RING_SIZE; i++) - printk(KERN_INFO "rx_ring %d status: 0x%x\n", i, - streamer_priv->streamer_rx_ring[i].status); - break; - case IOCTL_PRINT_TX_BUFS: - printk(KERN_INFO "Print tx bufs:\n"); - for(i=0; i<STREAMER_TX_RING_SIZE; i++) - printk(KERN_INFO "tx_ring %d status: 0x%x\n", i, - streamer_priv->streamer_tx_ring[i].status); - break; - case IOCTL_RX_CMD: - streamer_rx(dev); - printk(KERN_INFO "Sent rx command.\n"); - break; - default: - printk(KERN_INFO "Bad ioctl!\n"); - } - return 0; -} -#endif - static struct pci_driver streamer_pci_driver = { .name = "lanstreamer", .id_table = streamer_pci_tbl, diff --git a/drivers/net/tokenring/lanstreamer.h b/drivers/net/tokenring/lanstreamer.h index 5557d8e1e22d..e7bb3494afc7 100644 --- a/drivers/net/tokenring/lanstreamer.h +++ b/drivers/net/tokenring/lanstreamer.h @@ -62,18 +62,6 @@ #include <linux/version.h> -#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) -#include <asm/ioctl.h> -#define IOCTL_PRINT_RX_BUFS SIOCDEVPRIVATE -#define IOCTL_PRINT_TX_BUFS SIOCDEVPRIVATE+1 -#define IOCTL_RX_CMD SIOCDEVPRIVATE+2 -#define IOCTL_TX_CMD SIOCDEVPRIVATE+3 -#define IOCTL_PRINT_REGISTERS SIOCDEVPRIVATE+4 -#define IOCTL_PRINT_BDAS SIOCDEVPRIVATE+5 -#define IOCTL_SPIN_LOCK_TEST SIOCDEVPRIVATE+6 -#define IOCTL_SISR_MASK SIOCDEVPRIVATE+7 -#endif - /* MAX_INTR - the maximum number of times we can loop * inside the interrupt function before returning * control to the OS (maximum value is 256) diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 8f6f6fd8b87d..d5c32e9caa97 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -333,11 +333,7 @@ enum state_values { #define TYPHOON_RESET_TIMEOUT_NOSLEEP ((6 * 1000000) / TYPHOON_UDELAY) #define TYPHOON_WAIT_TIMEOUT ((1000000 / 2) / TYPHOON_UDELAY) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28) -#define typhoon_synchronize_irq(x) synchronize_irq() -#else #define typhoon_synchronize_irq(x) synchronize_irq(x) -#endif #if defined(NETIF_F_TSO) #define skb_tso_size(x) (skb_shinfo(x)->gso_size) diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 54b8e492ef97..58b7efbb0750 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -154,7 +154,7 @@ config HDLC If unsure, say N. config HDLC_RAW - bool "Raw HDLC support" + tristate "Raw HDLC support" depends on HDLC help Generic HDLC driver supporting raw HDLC over WAN connections. @@ -162,7 +162,7 @@ config HDLC_RAW If unsure, say N. config HDLC_RAW_ETH - bool "Raw HDLC Ethernet device support" + tristate "Raw HDLC Ethernet device support" depends on HDLC help Generic HDLC driver supporting raw HDLC Ethernet device emulation @@ -173,7 +173,7 @@ config HDLC_RAW_ETH If unsure, say N. config HDLC_CISCO - bool "Cisco HDLC support" + tristate "Cisco HDLC support" depends on HDLC help Generic HDLC driver supporting Cisco HDLC over WAN connections. @@ -181,7 +181,7 @@ config HDLC_CISCO If unsure, say N. config HDLC_FR - bool "Frame Relay support" + tristate "Frame Relay support" depends on HDLC help Generic HDLC driver supporting Frame Relay over WAN connections. @@ -189,7 +189,7 @@ config HDLC_FR If unsure, say N. config HDLC_PPP - bool "Synchronous Point-to-Point Protocol (PPP) support" + tristate "Synchronous Point-to-Point Protocol (PPP) support" depends on HDLC help Generic HDLC driver supporting PPP over WAN connections. @@ -197,7 +197,7 @@ config HDLC_PPP If unsure, say N. config HDLC_X25 - bool "X.25 protocol support" + tristate "X.25 protocol support" depends on HDLC && (LAPB=m && HDLC=m || LAPB=y) help Generic HDLC driver supporting X.25 over WAN connections. diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index 316ca6869d5e..83ec2c87ba3f 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -9,14 +9,13 @@ cyclomx-y := cycx_main.o cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o cyclomx-objs := $(cyclomx-y) -hdlc-y := hdlc_generic.o -hdlc-$(CONFIG_HDLC_RAW) += hdlc_raw.o -hdlc-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o -hdlc-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o -hdlc-$(CONFIG_HDLC_FR) += hdlc_fr.o -hdlc-$(CONFIG_HDLC_PPP) += hdlc_ppp.o -hdlc-$(CONFIG_HDLC_X25) += hdlc_x25.o -hdlc-objs := $(hdlc-y) +obj-$(CONFIG_HDLC) += hdlc.o +obj-$(CONFIG_HDLC_RAW) += hdlc_raw.o +obj-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o +obj-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o +obj-$(CONFIG_HDLC_FR) += hdlc_fr.o +obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o syncppp.o +obj-$(CONFIG_HDLC_X25) += hdlc_x25.o pc300-y := pc300_drv.o pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o @@ -38,10 +37,6 @@ obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o obj-$(CONFIG_LAPBETHER) += lapbether.o obj-$(CONFIG_SBNI) += sbni.o obj-$(CONFIG_PC300) += pc300.o -obj-$(CONFIG_HDLC) += hdlc.o -ifeq ($(CONFIG_HDLC_PPP),y) - obj-$(CONFIG_HDLC) += syncppp.o -endif obj-$(CONFIG_N2) += n2.o obj-$(CONFIG_C101) += c101.o obj-$(CONFIG_WANXL) += wanxl.o diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc.c index 04ca1f7b6424..db354e0edbe5 100644 --- a/drivers/net/wan/hdlc_generic.c +++ b/drivers/net/wan/hdlc.c @@ -1,7 +1,7 @@ /* * Generic HDLC support routines for Linux * - * Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl> + * Copyright (C) 1999 - 2006 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 @@ -17,9 +17,9 @@ * Use sethdlc utility to set line parameters, protocol and PVCs * * How does it work: - * - proto.open(), close(), start(), stop() calls are serialized. + * - proto->open(), close(), start(), stop() calls are serialized. * The order is: open, [ start, stop ... ] close ... - * - proto.start() and stop() are called with spin_lock_irq held. + * - proto->start() and stop() are called with spin_lock_irq held. */ #include <linux/module.h> @@ -38,10 +38,12 @@ #include <linux/hdlc.h> -static const char* version = "HDLC support module revision 1.19"; +static const char* version = "HDLC support module revision 1.20"; #undef DEBUG_LINK +static struct hdlc_proto *first_proto = NULL; + static int hdlc_change_mtu(struct net_device *dev, int new_mtu) { @@ -63,11 +65,11 @@ static struct net_device_stats *hdlc_get_stats(struct net_device *dev) static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); - if (hdlc->proto.netif_rx) - return hdlc->proto.netif_rx(skb); + struct hdlc_device_desc *desc = dev_to_desc(dev); + if (desc->netif_rx) + return desc->netif_rx(skb); - hdlc->stats.rx_dropped++; /* Shouldn't happen */ + desc->stats.rx_dropped++; /* Shouldn't happen */ dev_kfree_skb(skb); return NET_RX_DROP; } @@ -77,8 +79,8 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, static inline void hdlc_proto_start(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); - if (hdlc->proto.start) - return hdlc->proto.start(dev); + if (hdlc->proto->start) + return hdlc->proto->start(dev); } @@ -86,8 +88,8 @@ static inline void hdlc_proto_start(struct net_device *dev) static inline void hdlc_proto_stop(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); - if (hdlc->proto.stop) - return hdlc->proto.stop(dev); + if (hdlc->proto->stop) + return hdlc->proto->stop(dev); } @@ -144,15 +146,15 @@ int hdlc_open(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); #ifdef DEBUG_LINK - printk(KERN_DEBUG "hdlc_open() carrier %i open %i\n", + printk(KERN_DEBUG "%s: hdlc_open() carrier %i open %i\n", dev->name, hdlc->carrier, hdlc->open); #endif - if (hdlc->proto.id == -1) + if (hdlc->proto == NULL) return -ENOSYS; /* no protocol attached */ - if (hdlc->proto.open) { - int result = hdlc->proto.open(dev); + if (hdlc->proto->open) { + int result = hdlc->proto->open(dev); if (result) return result; } @@ -178,7 +180,7 @@ void hdlc_close(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); #ifdef DEBUG_LINK - printk(KERN_DEBUG "hdlc_close() carrier %i open %i\n", + printk(KERN_DEBUG "%s: hdlc_close() carrier %i open %i\n", dev->name, hdlc->carrier, hdlc->open); #endif @@ -190,68 +192,34 @@ void hdlc_close(struct net_device *dev) spin_unlock_irq(&hdlc->state_lock); - if (hdlc->proto.close) - hdlc->proto.close(dev); + if (hdlc->proto->close) + hdlc->proto->close(dev); } -#ifndef CONFIG_HDLC_RAW -#define hdlc_raw_ioctl(dev, ifr) -ENOSYS -#endif - -#ifndef CONFIG_HDLC_RAW_ETH -#define hdlc_raw_eth_ioctl(dev, ifr) -ENOSYS -#endif - -#ifndef CONFIG_HDLC_PPP -#define hdlc_ppp_ioctl(dev, ifr) -ENOSYS -#endif - -#ifndef CONFIG_HDLC_CISCO -#define hdlc_cisco_ioctl(dev, ifr) -ENOSYS -#endif - -#ifndef CONFIG_HDLC_FR -#define hdlc_fr_ioctl(dev, ifr) -ENOSYS -#endif - -#ifndef CONFIG_HDLC_X25 -#define hdlc_x25_ioctl(dev, ifr) -ENOSYS -#endif - - int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - hdlc_device *hdlc = dev_to_hdlc(dev); - unsigned int proto; + struct hdlc_proto *proto = first_proto; + int result; if (cmd != SIOCWANDEV) return -EINVAL; - switch(ifr->ifr_settings.type) { - case IF_PROTO_HDLC: - case IF_PROTO_HDLC_ETH: - case IF_PROTO_PPP: - case IF_PROTO_CISCO: - case IF_PROTO_FR: - case IF_PROTO_X25: - proto = ifr->ifr_settings.type; - break; - - default: - proto = hdlc->proto.id; + if (dev_to_hdlc(dev)->proto) { + result = dev_to_hdlc(dev)->proto->ioctl(dev, ifr); + if (result != -EINVAL) + return result; } - switch(proto) { - case IF_PROTO_HDLC: return hdlc_raw_ioctl(dev, ifr); - case IF_PROTO_HDLC_ETH: return hdlc_raw_eth_ioctl(dev, ifr); - case IF_PROTO_PPP: return hdlc_ppp_ioctl(dev, ifr); - case IF_PROTO_CISCO: return hdlc_cisco_ioctl(dev, ifr); - case IF_PROTO_FR: return hdlc_fr_ioctl(dev, ifr); - case IF_PROTO_X25: return hdlc_x25_ioctl(dev, ifr); - default: return -EINVAL; + /* Not handled by currently attached protocol (if any) */ + + while (proto) { + if ((result = proto->ioctl(dev, ifr)) != -EINVAL) + return result; + proto = proto->next; } + return -EINVAL; } void hdlc_setup(struct net_device *dev) @@ -267,8 +235,6 @@ void hdlc_setup(struct net_device *dev) dev->flags = IFF_POINTOPOINT | IFF_NOARP; - hdlc->proto.id = -1; - hdlc->proto.detach = NULL; hdlc->carrier = 1; hdlc->open = 0; spin_lock_init(&hdlc->state_lock); @@ -277,7 +243,8 @@ void hdlc_setup(struct net_device *dev) struct net_device *alloc_hdlcdev(void *priv) { struct net_device *dev; - dev = alloc_netdev(sizeof(hdlc_device), "hdlc%d", hdlc_setup); + dev = alloc_netdev(sizeof(struct hdlc_device_desc) + + sizeof(hdlc_device), "hdlc%d", hdlc_setup); if (dev) dev_to_hdlc(dev)->priv = priv; return dev; @@ -286,13 +253,71 @@ struct net_device *alloc_hdlcdev(void *priv) void unregister_hdlc_device(struct net_device *dev) { rtnl_lock(); - hdlc_proto_detach(dev_to_hdlc(dev)); unregister_netdevice(dev); + detach_hdlc_protocol(dev); rtnl_unlock(); } +int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto, + int (*rx)(struct sk_buff *skb), size_t size) +{ + detach_hdlc_protocol(dev); + + if (!try_module_get(proto->module)) + return -ENOSYS; + + if (size) + if ((dev_to_hdlc(dev)->state = kmalloc(size, + GFP_KERNEL)) == NULL) { + printk(KERN_WARNING "Memory squeeze on" + " hdlc_proto_attach()\n"); + module_put(proto->module); + return -ENOBUFS; + } + dev_to_hdlc(dev)->proto = proto; + dev_to_desc(dev)->netif_rx = rx; + return 0; +} + + +void detach_hdlc_protocol(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + + if (hdlc->proto) { + if (hdlc->proto->detach) + hdlc->proto->detach(dev); + module_put(hdlc->proto->module); + hdlc->proto = NULL; + } + kfree(hdlc->state); + hdlc->state = NULL; +} + + +void register_hdlc_protocol(struct hdlc_proto *proto) +{ + proto->next = first_proto; + first_proto = proto; +} + + +void unregister_hdlc_protocol(struct hdlc_proto *proto) +{ + struct hdlc_proto **p = &first_proto; + while (*p) { + if (*p == proto) { + *p = proto->next; + return; + } + p = &((*p)->next); + } +} + + + MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); MODULE_DESCRIPTION("HDLC support module"); MODULE_LICENSE("GPL v2"); @@ -303,6 +328,10 @@ EXPORT_SYMBOL(hdlc_ioctl); EXPORT_SYMBOL(hdlc_setup); EXPORT_SYMBOL(alloc_hdlcdev); EXPORT_SYMBOL(unregister_hdlc_device); +EXPORT_SYMBOL(register_hdlc_protocol); +EXPORT_SYMBOL(unregister_hdlc_protocol); +EXPORT_SYMBOL(attach_hdlc_protocol); +EXPORT_SYMBOL(detach_hdlc_protocol); static struct packet_type hdlc_packet_type = { .type = __constant_htons(ETH_P_HDLC), diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index f289daba0c7b..7ec2b2f9b7ee 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -2,7 +2,7 @@ * Generic HDLC support routines for Linux * Cisco HDLC support * - * Copyright (C) 2000 - 2003 Krzysztof Halasa <khc@pm.waw.pl> + * Copyright (C) 2000 - 2006 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 @@ -34,17 +34,56 @@ #define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ +struct hdlc_header { + u8 address; + u8 control; + u16 protocol; +}__attribute__ ((packed)); + + +struct cisco_packet { + u32 type; /* code */ + u32 par1; + u32 par2; + u16 rel; /* reliability */ + u32 time; +}__attribute__ ((packed)); +#define CISCO_PACKET_LEN 18 +#define CISCO_BIG_PACKET_LEN 20 + + +struct cisco_state { + cisco_proto settings; + + struct timer_list timer; + unsigned long last_poll; + int up; + int request_sent; + u32 txseq; /* TX sequence number */ + u32 rxseq; /* RX sequence number */ +}; + + +static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr); + + +static inline struct cisco_state * state(hdlc_device *hdlc) +{ + return(struct cisco_state *)(hdlc->state); +} + + static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, u16 type, void *daddr, void *saddr, unsigned int len) { - hdlc_header *data; + struct hdlc_header *data; #ifdef DEBUG_HARD_HEADER printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name); #endif - skb_push(skb, sizeof(hdlc_header)); - data = (hdlc_header*)skb->data; + skb_push(skb, sizeof(struct hdlc_header)); + data = (struct hdlc_header*)skb->data; if (type == CISCO_KEEPALIVE) data->address = CISCO_MULTICAST; else @@ -52,7 +91,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, data->control = 0; data->protocol = htons(type); - return sizeof(hdlc_header); + return sizeof(struct hdlc_header); } @@ -61,9 +100,10 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, u32 par1, u32 par2) { struct sk_buff *skb; - cisco_packet *data; + struct cisco_packet *data; - skb = dev_alloc_skb(sizeof(hdlc_header) + sizeof(cisco_packet)); + skb = dev_alloc_skb(sizeof(struct hdlc_header) + + sizeof(struct cisco_packet)); if (!skb) { printk(KERN_WARNING "%s: Memory squeeze on cisco_keepalive_send()\n", @@ -72,7 +112,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, } skb_reserve(skb, 4); cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0); - data = (cisco_packet*)(skb->data + 4); + data = (struct cisco_packet*)(skb->data + 4); data->type = htonl(type); data->par1 = htonl(par1); @@ -81,7 +121,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, /* we will need do_div here if 1000 % HZ != 0 */ data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ)); - skb_put(skb, sizeof(cisco_packet)); + skb_put(skb, sizeof(struct cisco_packet)); skb->priority = TC_PRIO_CONTROL; skb->dev = dev; skb->nh.raw = skb->data; @@ -93,9 +133,9 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev) { - hdlc_header *data = (hdlc_header*)skb->data; + struct hdlc_header *data = (struct hdlc_header*)skb->data; - if (skb->len < sizeof(hdlc_header)) + if (skb->len < sizeof(struct hdlc_header)) return __constant_htons(ETH_P_HDLC); if (data->address != CISCO_MULTICAST && @@ -106,7 +146,7 @@ static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev) case __constant_htons(ETH_P_IP): case __constant_htons(ETH_P_IPX): case __constant_htons(ETH_P_IPV6): - skb_pull(skb, sizeof(hdlc_header)); + skb_pull(skb, sizeof(struct hdlc_header)); return data->protocol; default: return __constant_htons(ETH_P_HDLC); @@ -118,12 +158,12 @@ static int cisco_rx(struct sk_buff *skb) { struct net_device *dev = skb->dev; hdlc_device *hdlc = dev_to_hdlc(dev); - hdlc_header *data = (hdlc_header*)skb->data; - cisco_packet *cisco_data; + struct hdlc_header *data = (struct hdlc_header*)skb->data; + struct cisco_packet *cisco_data; struct in_device *in_dev; u32 addr, mask; - if (skb->len < sizeof(hdlc_header)) + if (skb->len < sizeof(struct hdlc_header)) goto rx_error; if (data->address != CISCO_MULTICAST && @@ -137,15 +177,17 @@ static int cisco_rx(struct sk_buff *skb) return NET_RX_SUCCESS; case CISCO_KEEPALIVE: - if (skb->len != sizeof(hdlc_header) + CISCO_PACKET_LEN && - skb->len != sizeof(hdlc_header) + CISCO_BIG_PACKET_LEN) { - printk(KERN_INFO "%s: Invalid length of Cisco " - "control packet (%d bytes)\n", - dev->name, skb->len); + if ((skb->len != sizeof(struct hdlc_header) + + CISCO_PACKET_LEN) && + (skb->len != sizeof(struct hdlc_header) + + CISCO_BIG_PACKET_LEN)) { + printk(KERN_INFO "%s: Invalid length of Cisco control" + " packet (%d bytes)\n", dev->name, skb->len); goto rx_error; } - cisco_data = (cisco_packet*)(skb->data + sizeof(hdlc_header)); + cisco_data = (struct cisco_packet*)(skb->data + sizeof + (struct hdlc_header)); switch(ntohl (cisco_data->type)) { case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */ @@ -178,11 +220,11 @@ static int cisco_rx(struct sk_buff *skb) goto rx_error; case CISCO_KEEPALIVE_REQ: - hdlc->state.cisco.rxseq = ntohl(cisco_data->par1); - if (hdlc->state.cisco.request_sent && - ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) { - hdlc->state.cisco.last_poll = jiffies; - if (!hdlc->state.cisco.up) { + state(hdlc)->rxseq = ntohl(cisco_data->par1); + if (state(hdlc)->request_sent && + ntohl(cisco_data->par2) == state(hdlc)->txseq) { + state(hdlc)->last_poll = jiffies; + if (!state(hdlc)->up) { u32 sec, min, hrs, days; sec = ntohl(cisco_data->time) / 1000; min = sec / 60; sec -= min * 60; @@ -193,7 +235,7 @@ static int cisco_rx(struct sk_buff *skb) dev->name, days, hrs, min, sec); netif_dormant_off(dev); - hdlc->state.cisco.up = 1; + state(hdlc)->up = 1; } } @@ -208,7 +250,7 @@ static int cisco_rx(struct sk_buff *skb) return NET_RX_DROP; rx_error: - hdlc->stats.rx_errors++; /* Mark error */ + dev_to_desc(dev)->stats.rx_errors++; /* Mark error */ dev_kfree_skb_any(skb); return NET_RX_DROP; } @@ -220,23 +262,22 @@ static void cisco_timer(unsigned long arg) struct net_device *dev = (struct net_device *)arg; hdlc_device *hdlc = dev_to_hdlc(dev); - if (hdlc->state.cisco.up && - time_after(jiffies, hdlc->state.cisco.last_poll + - hdlc->state.cisco.settings.timeout * HZ)) { - hdlc->state.cisco.up = 0; + if (state(hdlc)->up && + time_after(jiffies, state(hdlc)->last_poll + + state(hdlc)->settings.timeout * HZ)) { + state(hdlc)->up = 0; printk(KERN_INFO "%s: Link down\n", dev->name); netif_dormant_on(dev); } - cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, - ++hdlc->state.cisco.txseq, - hdlc->state.cisco.rxseq); - hdlc->state.cisco.request_sent = 1; - hdlc->state.cisco.timer.expires = jiffies + - hdlc->state.cisco.settings.interval * HZ; - hdlc->state.cisco.timer.function = cisco_timer; - hdlc->state.cisco.timer.data = arg; - add_timer(&hdlc->state.cisco.timer); + cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++state(hdlc)->txseq, + state(hdlc)->rxseq); + state(hdlc)->request_sent = 1; + state(hdlc)->timer.expires = jiffies + + state(hdlc)->settings.interval * HZ; + state(hdlc)->timer.function = cisco_timer; + state(hdlc)->timer.data = arg; + add_timer(&state(hdlc)->timer); } @@ -244,15 +285,15 @@ static void cisco_timer(unsigned long arg) static void cisco_start(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); - hdlc->state.cisco.up = 0; - hdlc->state.cisco.request_sent = 0; - hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0; - - init_timer(&hdlc->state.cisco.timer); - hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/ - hdlc->state.cisco.timer.function = cisco_timer; - hdlc->state.cisco.timer.data = (unsigned long)dev; - add_timer(&hdlc->state.cisco.timer); + state(hdlc)->up = 0; + state(hdlc)->request_sent = 0; + state(hdlc)->txseq = state(hdlc)->rxseq = 0; + + init_timer(&state(hdlc)->timer); + state(hdlc)->timer.expires = jiffies + HZ; /*First poll after 1s*/ + state(hdlc)->timer.function = cisco_timer; + state(hdlc)->timer.data = (unsigned long)dev; + add_timer(&state(hdlc)->timer); } @@ -260,15 +301,24 @@ static void cisco_start(struct net_device *dev) static void cisco_stop(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); - del_timer_sync(&hdlc->state.cisco.timer); + del_timer_sync(&state(hdlc)->timer); netif_dormant_on(dev); - hdlc->state.cisco.up = 0; - hdlc->state.cisco.request_sent = 0; + state(hdlc)->up = 0; + state(hdlc)->request_sent = 0; } -int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr) +static struct hdlc_proto proto = { + .start = cisco_start, + .stop = cisco_stop, + .type_trans = cisco_type_trans, + .ioctl = cisco_ioctl, + .module = THIS_MODULE, +}; + + +static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr) { cisco_proto __user *cisco_s = ifr->ifr_settings.ifs_ifsu.cisco; const size_t size = sizeof(cisco_proto); @@ -278,12 +328,14 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr) switch (ifr->ifr_settings.type) { case IF_GET_PROTO: + if (dev_to_hdlc(dev)->proto != &proto) + return -EINVAL; ifr->ifr_settings.type = IF_PROTO_CISCO; if (ifr->ifr_settings.size < size) { ifr->ifr_settings.size = size; /* data size wanted */ return -ENOBUFS; } - if (copy_to_user(cisco_s, &hdlc->state.cisco.settings, size)) + if (copy_to_user(cisco_s, &state(hdlc)->settings, size)) return -EFAULT; return 0; @@ -302,19 +354,15 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr) return -EINVAL; result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); - if (result) return result; - hdlc_proto_detach(hdlc); - memcpy(&hdlc->state.cisco.settings, &new_settings, size); - memset(&hdlc->proto, 0, sizeof(hdlc->proto)); + result = attach_hdlc_protocol(dev, &proto, cisco_rx, + sizeof(struct cisco_state)); + if (result) + return result; - hdlc->proto.start = cisco_start; - hdlc->proto.stop = cisco_stop; - hdlc->proto.netif_rx = cisco_rx; - hdlc->proto.type_trans = cisco_type_trans; - hdlc->proto.id = IF_PROTO_CISCO; + memcpy(&state(hdlc)->settings, &new_settings, size); dev->hard_start_xmit = hdlc->xmit; dev->hard_header = cisco_hard_header; dev->hard_header_cache = NULL; @@ -327,3 +375,25 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr) return -EINVAL; } + + +static int __init mod_init(void) +{ + register_hdlc_protocol(&proto); + return 0; +} + + + +static void __exit mod_exit(void) +{ + unregister_hdlc_protocol(&proto); +} + + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); +MODULE_DESCRIPTION("Cisco HDLC protocol support for generic HDLC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 7bb737bbdeb9..b45ab680d2d6 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -2,7 +2,7 @@ * Generic HDLC support routines for Linux * Frame Relay support * - * Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl> + * Copyright (C) 1999 - 2006 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 @@ -52,6 +52,8 @@ #undef DEBUG_PKT #undef DEBUG_ECN #undef DEBUG_LINK +#undef DEBUG_PROTO +#undef DEBUG_PVC #define FR_UI 0x03 #define FR_PAD 0x00 @@ -115,13 +117,53 @@ typedef struct { }__attribute__ ((packed)) fr_hdr; +typedef struct pvc_device_struct { + struct net_device *frad; + struct net_device *main; + struct net_device *ether; /* bridged Ethernet interface */ + struct pvc_device_struct *next; /* Sorted in ascending DLCI order */ + int dlci; + int open_count; + + struct { + unsigned int new: 1; + unsigned int active: 1; + unsigned int exist: 1; + unsigned int deleted: 1; + unsigned int fecn: 1; + unsigned int becn: 1; + unsigned int bandwidth; /* Cisco LMI reporting only */ + }state; +}pvc_device; + + +struct frad_state { + fr_proto settings; + pvc_device *first_pvc; + int dce_pvc_count; + + struct timer_list timer; + unsigned long last_poll; + int reliable; + int dce_changed; + int request; + int fullrep_sent; + u32 last_errors; /* last errors bit list */ + u8 n391cnt; + u8 txseq; /* TX sequence number */ + u8 rxseq; /* RX sequence number */ +}; + + +static int fr_ioctl(struct net_device *dev, struct ifreq *ifr); + + static inline u16 q922_to_dlci(u8 *hdr) { return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4); } - static inline void dlci_to_q922(u8 *hdr, u16 dlci) { hdr[0] = (dlci >> 2) & 0xFC; @@ -129,10 +171,21 @@ static inline void dlci_to_q922(u8 *hdr, u16 dlci) } +static inline struct frad_state * state(hdlc_device *hdlc) +{ + return(struct frad_state *)(hdlc->state); +} + + +static __inline__ pvc_device* dev_to_pvc(struct net_device *dev) +{ + return dev->priv; +} + static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) { - pvc_device *pvc = hdlc->state.fr.first_pvc; + pvc_device *pvc = state(hdlc)->first_pvc; while (pvc) { if (pvc->dlci == dlci) @@ -146,10 +199,10 @@ static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) } -static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci) +static pvc_device* add_pvc(struct net_device *dev, u16 dlci) { hdlc_device *hdlc = dev_to_hdlc(dev); - pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc; + pvc_device *pvc, **pvc_p = &state(hdlc)->first_pvc; while (*pvc_p) { if ((*pvc_p)->dlci == dlci) @@ -160,12 +213,15 @@ static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci) } pvc = kmalloc(sizeof(pvc_device), GFP_ATOMIC); +#ifdef DEBUG_PVC + printk(KERN_DEBUG "add_pvc: allocated pvc %p, frad %p\n", pvc, dev); +#endif if (!pvc) return NULL; memset(pvc, 0, sizeof(pvc_device)); pvc->dlci = dlci; - pvc->master = dev; + pvc->frad = dev; pvc->next = *pvc_p; /* Put it in the chain */ *pvc_p = pvc; return pvc; @@ -174,7 +230,7 @@ static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci) static inline int pvc_is_used(pvc_device *pvc) { - return pvc->main != NULL || pvc->ether != NULL; + return pvc->main || pvc->ether; } @@ -200,11 +256,14 @@ static inline void pvc_carrier(int on, pvc_device *pvc) static inline void delete_unused_pvcs(hdlc_device *hdlc) { - pvc_device **pvc_p = &hdlc->state.fr.first_pvc; + pvc_device **pvc_p = &state(hdlc)->first_pvc; while (*pvc_p) { if (!pvc_is_used(*pvc_p)) { pvc_device *pvc = *pvc_p; +#ifdef DEBUG_PVC + printk(KERN_DEBUG "freeing unused pvc: %p\n", pvc); +#endif *pvc_p = pvc->next; kfree(pvc); continue; @@ -295,16 +354,16 @@ static int pvc_open(struct net_device *dev) { pvc_device *pvc = dev_to_pvc(dev); - if ((pvc->master->flags & IFF_UP) == 0) - return -EIO; /* Master must be UP in order to activate PVC */ + if ((pvc->frad->flags & IFF_UP) == 0) + return -EIO; /* Frad must be UP in order to activate PVC */ if (pvc->open_count++ == 0) { - hdlc_device *hdlc = dev_to_hdlc(pvc->master); - if (hdlc->state.fr.settings.lmi == LMI_NONE) - pvc->state.active = netif_carrier_ok(pvc->master); + hdlc_device *hdlc = dev_to_hdlc(pvc->frad); + if (state(hdlc)->settings.lmi == LMI_NONE) + pvc->state.active = netif_carrier_ok(pvc->frad); pvc_carrier(pvc->state.active, pvc); - hdlc->state.fr.dce_changed = 1; + state(hdlc)->dce_changed = 1; } return 0; } @@ -316,12 +375,12 @@ static int pvc_close(struct net_device *dev) pvc_device *pvc = dev_to_pvc(dev); if (--pvc->open_count == 0) { - hdlc_device *hdlc = dev_to_hdlc(pvc->master); - if (hdlc->state.fr.settings.lmi == LMI_NONE) + hdlc_device *hdlc = dev_to_hdlc(pvc->frad); + if (state(hdlc)->settings.lmi == LMI_NONE) pvc->state.active = 0; - if (hdlc->state.fr.settings.dce) { - hdlc->state.fr.dce_changed = 1; + if (state(hdlc)->settings.dce) { + state(hdlc)->dce_changed = 1; pvc->state.active = 0; } } @@ -348,7 +407,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } info.dlci = pvc->dlci; - memcpy(info.master, pvc->master->name, IFNAMSIZ); + memcpy(info.master, pvc->frad->name, IFNAMSIZ); if (copy_to_user(ifr->ifr_settings.ifs_ifsu.fr_pvc_info, &info, sizeof(info))) return -EFAULT; @@ -361,7 +420,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static inline struct net_device_stats *pvc_get_stats(struct net_device *dev) { - return netdev_priv(dev); + return &dev_to_desc(dev)->stats; } @@ -393,7 +452,7 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) stats->tx_packets++; if (pvc->state.fecn) /* TX Congestion counter */ stats->tx_compressed++; - skb->dev = pvc->master; + skb->dev = pvc->frad; dev_queue_xmit(skb); return 0; } @@ -419,7 +478,7 @@ static int pvc_change_mtu(struct net_device *dev, int new_mtu) static inline void fr_log_dlci_active(pvc_device *pvc) { printk(KERN_INFO "%s: DLCI %d [%s%s%s]%s %s\n", - pvc->master->name, + pvc->frad->name, pvc->dlci, pvc->main ? pvc->main->name : "", pvc->main && pvc->ether ? " " : "", @@ -438,21 +497,20 @@ static inline u8 fr_lmi_nextseq(u8 x) } - static void fr_lmi_send(struct net_device *dev, int fullrep) { hdlc_device *hdlc = dev_to_hdlc(dev); struct sk_buff *skb; - pvc_device *pvc = hdlc->state.fr.first_pvc; - int lmi = hdlc->state.fr.settings.lmi; - int dce = hdlc->state.fr.settings.dce; + pvc_device *pvc = state(hdlc)->first_pvc; + int lmi = state(hdlc)->settings.lmi; + int dce = state(hdlc)->settings.dce; int len = lmi == LMI_ANSI ? LMI_ANSI_LENGTH : LMI_CCITT_CISCO_LENGTH; int stat_len = (lmi == LMI_CISCO) ? 6 : 3; u8 *data; int i = 0; if (dce && fullrep) { - len += hdlc->state.fr.dce_pvc_count * (2 + stat_len); + len += state(hdlc)->dce_pvc_count * (2 + stat_len); if (len > HDLC_MAX_MRU) { printk(KERN_WARNING "%s: Too many PVCs while sending " "LMI full report\n", dev->name); @@ -486,8 +544,9 @@ static void fr_lmi_send(struct net_device *dev, int fullrep) data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY; data[i++] = lmi == LMI_CCITT ? LMI_CCITT_ALIVE : LMI_ANSI_CISCO_ALIVE; data[i++] = LMI_INTEG_LEN; - data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq); - data[i++] = hdlc->state.fr.rxseq; + data[i++] = state(hdlc)->txseq = + fr_lmi_nextseq(state(hdlc)->txseq); + data[i++] = state(hdlc)->rxseq; if (dce && fullrep) { while (pvc) { @@ -496,7 +555,7 @@ static void fr_lmi_send(struct net_device *dev, int fullrep) data[i++] = stat_len; /* LMI start/restart */ - if (hdlc->state.fr.reliable && !pvc->state.exist) { + if (state(hdlc)->reliable && !pvc->state.exist) { pvc->state.exist = pvc->state.new = 1; fr_log_dlci_active(pvc); } @@ -541,15 +600,15 @@ static void fr_lmi_send(struct net_device *dev, int fullrep) static void fr_set_link_state(int reliable, struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); - pvc_device *pvc = hdlc->state.fr.first_pvc; + pvc_device *pvc = state(hdlc)->first_pvc; - hdlc->state.fr.reliable = reliable; + state(hdlc)->reliable = reliable; if (reliable) { netif_dormant_off(dev); - hdlc->state.fr.n391cnt = 0; /* Request full status */ - hdlc->state.fr.dce_changed = 1; + state(hdlc)->n391cnt = 0; /* Request full status */ + state(hdlc)->dce_changed = 1; - if (hdlc->state.fr.settings.lmi == LMI_NONE) { + if (state(hdlc)->settings.lmi == LMI_NONE) { while (pvc) { /* Activate all PVCs */ pvc_carrier(1, pvc); pvc->state.exist = pvc->state.active = 1; @@ -563,7 +622,7 @@ static void fr_set_link_state(int reliable, struct net_device *dev) pvc_carrier(0, pvc); pvc->state.exist = pvc->state.active = 0; pvc->state.new = 0; - if (!hdlc->state.fr.settings.dce) + if (!state(hdlc)->settings.dce) pvc->state.bandwidth = 0; pvc = pvc->next; } @@ -571,7 +630,6 @@ static void fr_set_link_state(int reliable, struct net_device *dev) } - static void fr_timer(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; @@ -579,62 +637,61 @@ static void fr_timer(unsigned long arg) int i, cnt = 0, reliable; u32 list; - if (hdlc->state.fr.settings.dce) { - reliable = hdlc->state.fr.request && - time_before(jiffies, hdlc->state.fr.last_poll + - hdlc->state.fr.settings.t392 * HZ); - hdlc->state.fr.request = 0; + if (state(hdlc)->settings.dce) { + reliable = state(hdlc)->request && + time_before(jiffies, state(hdlc)->last_poll + + state(hdlc)->settings.t392 * HZ); + state(hdlc)->request = 0; } else { - hdlc->state.fr.last_errors <<= 1; /* Shift the list */ - if (hdlc->state.fr.request) { - if (hdlc->state.fr.reliable) + state(hdlc)->last_errors <<= 1; /* Shift the list */ + if (state(hdlc)->request) { + if (state(hdlc)->reliable) printk(KERN_INFO "%s: No LMI status reply " "received\n", dev->name); - hdlc->state.fr.last_errors |= 1; + state(hdlc)->last_errors |= 1; } - list = hdlc->state.fr.last_errors; - for (i = 0; i < hdlc->state.fr.settings.n393; i++, list >>= 1) + list = state(hdlc)->last_errors; + for (i = 0; i < state(hdlc)->settings.n393; i++, list >>= 1) cnt += (list & 1); /* errors count */ - reliable = (cnt < hdlc->state.fr.settings.n392); + reliable = (cnt < state(hdlc)->settings.n392); } - if (hdlc->state.fr.reliable != reliable) { + if (state(hdlc)->reliable != reliable) { printk(KERN_INFO "%s: Link %sreliable\n", dev->name, reliable ? "" : "un"); fr_set_link_state(reliable, dev); } - if (hdlc->state.fr.settings.dce) - hdlc->state.fr.timer.expires = jiffies + - hdlc->state.fr.settings.t392 * HZ; + if (state(hdlc)->settings.dce) + state(hdlc)->timer.expires = jiffies + + state(hdlc)->settings.t392 * HZ; else { - if (hdlc->state.fr.n391cnt) - hdlc->state.fr.n391cnt--; + if (state(hdlc)->n391cnt) + state(hdlc)->n391cnt--; - fr_lmi_send(dev, hdlc->state.fr.n391cnt == 0); + fr_lmi_send(dev, state(hdlc)->n391cnt == 0); - hdlc->state.fr.last_poll = jiffies; - hdlc->state.fr.request = 1; - hdlc->state.fr.timer.expires = jiffies + - hdlc->state.fr.settings.t391 * HZ; + state(hdlc)->last_poll = jiffies; + state(hdlc)->request = 1; + state(hdlc)->timer.expires = jiffies + + state(hdlc)->settings.t391 * HZ; } - hdlc->state.fr.timer.function = fr_timer; - hdlc->state.fr.timer.data = arg; - add_timer(&hdlc->state.fr.timer); + state(hdlc)->timer.function = fr_timer; + state(hdlc)->timer.data = arg; + add_timer(&state(hdlc)->timer); } - static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) { hdlc_device *hdlc = dev_to_hdlc(dev); pvc_device *pvc; u8 rxseq, txseq; - int lmi = hdlc->state.fr.settings.lmi; - int dce = hdlc->state.fr.settings.dce; + int lmi = state(hdlc)->settings.lmi; + int dce = state(hdlc)->settings.dce; int stat_len = (lmi == LMI_CISCO) ? 6 : 3, reptype, error, no_ram, i; if (skb->len < (lmi == LMI_ANSI ? LMI_ANSI_LENGTH : @@ -645,8 +702,8 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) if (skb->data[3] != (lmi == LMI_CISCO ? NLPID_CISCO_LMI : NLPID_CCITT_ANSI_LMI)) { - printk(KERN_INFO "%s: Received non-LMI frame with LMI" - " DLCI\n", dev->name); + printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n", + dev->name); return 1; } @@ -706,53 +763,53 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) } i++; - hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */ + state(hdlc)->rxseq = skb->data[i++]; /* TX sequence from peer */ rxseq = skb->data[i++]; /* Should confirm our sequence */ - txseq = hdlc->state.fr.txseq; + txseq = state(hdlc)->txseq; if (dce) - hdlc->state.fr.last_poll = jiffies; + state(hdlc)->last_poll = jiffies; error = 0; - if (!hdlc->state.fr.reliable) + if (!state(hdlc)->reliable) error = 1; - if (rxseq == 0 || rxseq != txseq) { - hdlc->state.fr.n391cnt = 0; /* Ask for full report next time */ + if (rxseq == 0 || rxseq != txseq) { /* Ask for full report next time */ + state(hdlc)->n391cnt = 0; error = 1; } if (dce) { - if (hdlc->state.fr.fullrep_sent && !error) { + if (state(hdlc)->fullrep_sent && !error) { /* Stop sending full report - the last one has been confirmed by DTE */ - hdlc->state.fr.fullrep_sent = 0; - pvc = hdlc->state.fr.first_pvc; + state(hdlc)->fullrep_sent = 0; + pvc = state(hdlc)->first_pvc; while (pvc) { if (pvc->state.new) { pvc->state.new = 0; /* Tell DTE that new PVC is now active */ - hdlc->state.fr.dce_changed = 1; + state(hdlc)->dce_changed = 1; } pvc = pvc->next; } } - if (hdlc->state.fr.dce_changed) { + if (state(hdlc)->dce_changed) { reptype = LMI_FULLREP; - hdlc->state.fr.fullrep_sent = 1; - hdlc->state.fr.dce_changed = 0; + state(hdlc)->fullrep_sent = 1; + state(hdlc)->dce_changed = 0; } - hdlc->state.fr.request = 1; /* got request */ + state(hdlc)->request = 1; /* got request */ fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0); return 0; } /* DTE */ - hdlc->state.fr.request = 0; /* got response, no request pending */ + state(hdlc)->request = 0; /* got response, no request pending */ if (error) return 0; @@ -760,7 +817,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) if (reptype != LMI_FULLREP) return 0; - pvc = hdlc->state.fr.first_pvc; + pvc = state(hdlc)->first_pvc; while (pvc) { pvc->state.deleted = 1; @@ -827,7 +884,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) i += stat_len; } - pvc = hdlc->state.fr.first_pvc; + pvc = state(hdlc)->first_pvc; while (pvc) { if (pvc->state.deleted && pvc->state.exist) { @@ -841,17 +898,16 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) } /* Next full report after N391 polls */ - hdlc->state.fr.n391cnt = hdlc->state.fr.settings.n391; + state(hdlc)->n391cnt = state(hdlc)->settings.n391; return 0; } - static int fr_rx(struct sk_buff *skb) { - struct net_device *ndev = skb->dev; - hdlc_device *hdlc = dev_to_hdlc(ndev); + struct net_device *frad = skb->dev; + hdlc_device *hdlc = dev_to_hdlc(frad); fr_hdr *fh = (fr_hdr*)skb->data; u8 *data = skb->data; u16 dlci; @@ -864,11 +920,11 @@ static int fr_rx(struct sk_buff *skb) dlci = q922_to_dlci(skb->data); if ((dlci == LMI_CCITT_ANSI_DLCI && - (hdlc->state.fr.settings.lmi == LMI_ANSI || - hdlc->state.fr.settings.lmi == LMI_CCITT)) || + (state(hdlc)->settings.lmi == LMI_ANSI || + state(hdlc)->settings.lmi == LMI_CCITT)) || (dlci == LMI_CISCO_DLCI && - hdlc->state.fr.settings.lmi == LMI_CISCO)) { - if (fr_lmi_recv(ndev, skb)) + state(hdlc)->settings.lmi == LMI_CISCO)) { + if (fr_lmi_recv(frad, skb)) goto rx_error; dev_kfree_skb_any(skb); return NET_RX_SUCCESS; @@ -878,7 +934,7 @@ static int fr_rx(struct sk_buff *skb) if (!pvc) { #ifdef DEBUG_PKT printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n", - ndev->name, dlci); + frad->name, dlci); #endif dev_kfree_skb_any(skb); return NET_RX_DROP; @@ -886,7 +942,7 @@ static int fr_rx(struct sk_buff *skb) if (pvc->state.fecn != fh->fecn) { #ifdef DEBUG_ECN - printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", ndev->name, + printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", frad->name, dlci, fh->fecn ? "N" : "FF"); #endif pvc->state.fecn ^= 1; @@ -894,7 +950,7 @@ static int fr_rx(struct sk_buff *skb) if (pvc->state.becn != fh->becn) { #ifdef DEBUG_ECN - printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", ndev->name, + printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", frad->name, dlci, fh->becn ? "N" : "FF"); #endif pvc->state.becn ^= 1; @@ -902,7 +958,7 @@ static int fr_rx(struct sk_buff *skb) if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { - hdlc->stats.rx_dropped++; + dev_to_desc(frad)->stats.rx_dropped++; return NET_RX_DROP; } @@ -938,13 +994,13 @@ static int fr_rx(struct sk_buff *skb) default: printk(KERN_INFO "%s: Unsupported protocol, OUI=%x " - "PID=%x\n", ndev->name, oui, pid); + "PID=%x\n", frad->name, oui, pid); dev_kfree_skb_any(skb); return NET_RX_DROP; } } else { printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x " - "length = %i\n", ndev->name, data[3], skb->len); + "length = %i\n", frad->name, data[3], skb->len); dev_kfree_skb_any(skb); return NET_RX_DROP; } @@ -964,7 +1020,7 @@ static int fr_rx(struct sk_buff *skb) } rx_error: - hdlc->stats.rx_errors++; /* Mark error */ + dev_to_desc(frad)->stats.rx_errors++; /* Mark error */ dev_kfree_skb_any(skb); return NET_RX_DROP; } @@ -977,44 +1033,42 @@ static void fr_start(struct net_device *dev) #ifdef DEBUG_LINK printk(KERN_DEBUG "fr_start\n"); #endif - if (hdlc->state.fr.settings.lmi != LMI_NONE) { - hdlc->state.fr.reliable = 0; - hdlc->state.fr.dce_changed = 1; - hdlc->state.fr.request = 0; - hdlc->state.fr.fullrep_sent = 0; - hdlc->state.fr.last_errors = 0xFFFFFFFF; - hdlc->state.fr.n391cnt = 0; - hdlc->state.fr.txseq = hdlc->state.fr.rxseq = 0; - - init_timer(&hdlc->state.fr.timer); + if (state(hdlc)->settings.lmi != LMI_NONE) { + state(hdlc)->reliable = 0; + state(hdlc)->dce_changed = 1; + state(hdlc)->request = 0; + state(hdlc)->fullrep_sent = 0; + state(hdlc)->last_errors = 0xFFFFFFFF; + state(hdlc)->n391cnt = 0; + state(hdlc)->txseq = state(hdlc)->rxseq = 0; + + init_timer(&state(hdlc)->timer); /* First poll after 1 s */ - hdlc->state.fr.timer.expires = jiffies + HZ; - hdlc->state.fr.timer.function = fr_timer; - hdlc->state.fr.timer.data = (unsigned long)dev; - add_timer(&hdlc->state.fr.timer); + state(hdlc)->timer.expires = jiffies + HZ; + state(hdlc)->timer.function = fr_timer; + state(hdlc)->timer.data = (unsigned long)dev; + add_timer(&state(hdlc)->timer); } else fr_set_link_state(1, dev); } - static void fr_stop(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); #ifdef DEBUG_LINK printk(KERN_DEBUG "fr_stop\n"); #endif - if (hdlc->state.fr.settings.lmi != LMI_NONE) - del_timer_sync(&hdlc->state.fr.timer); + if (state(hdlc)->settings.lmi != LMI_NONE) + del_timer_sync(&state(hdlc)->timer); fr_set_link_state(0, dev); } - static void fr_close(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); - pvc_device *pvc = hdlc->state.fr.first_pvc; + pvc_device *pvc = state(hdlc)->first_pvc; while (pvc) { /* Shutdown all PVCs for this FRAD */ if (pvc->main) @@ -1025,7 +1079,8 @@ static void fr_close(struct net_device *dev) } } -static void dlci_setup(struct net_device *dev) + +static void pvc_setup(struct net_device *dev) { dev->type = ARPHRD_DLCI; dev->flags = IFF_POINTOPOINT; @@ -1033,9 +1088,9 @@ static void dlci_setup(struct net_device *dev) dev->addr_len = 2; } -static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type) +static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) { - hdlc_device *hdlc = dev_to_hdlc(master); + hdlc_device *hdlc = dev_to_hdlc(frad); pvc_device *pvc = NULL; struct net_device *dev; int result, used; @@ -1044,9 +1099,9 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type) if (type == ARPHRD_ETHER) prefix = "pvceth%d"; - if ((pvc = add_pvc(master, dlci)) == NULL) { + if ((pvc = add_pvc(frad, dlci)) == NULL) { printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n", - master->name); + frad->name); return -ENOBUFS; } @@ -1060,11 +1115,11 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type) "pvceth%d", ether_setup); else dev = alloc_netdev(sizeof(struct net_device_stats), - "pvc%d", dlci_setup); + "pvc%d", pvc_setup); if (!dev) { printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n", - master->name); + frad->name); delete_unused_pvcs(hdlc); return -ENOBUFS; } @@ -1102,8 +1157,8 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type) dev->destructor = free_netdev; *get_dev_p(pvc, type) = dev; if (!used) { - hdlc->state.fr.dce_changed = 1; - hdlc->state.fr.dce_pvc_count++; + state(hdlc)->dce_changed = 1; + state(hdlc)->dce_pvc_count++; } return 0; } @@ -1128,8 +1183,8 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type) *get_dev_p(pvc, type) = NULL; if (!pvc_is_used(pvc)) { - hdlc->state.fr.dce_pvc_count--; - hdlc->state.fr.dce_changed = 1; + state(hdlc)->dce_pvc_count--; + state(hdlc)->dce_changed = 1; } delete_unused_pvcs(hdlc); return 0; @@ -1137,14 +1192,13 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type) -static void fr_destroy(hdlc_device *hdlc) +static void fr_destroy(struct net_device *frad) { - pvc_device *pvc; - - pvc = hdlc->state.fr.first_pvc; - hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */ - hdlc->state.fr.dce_pvc_count = 0; - hdlc->state.fr.dce_changed = 1; + hdlc_device *hdlc = dev_to_hdlc(frad); + pvc_device *pvc = state(hdlc)->first_pvc; + state(hdlc)->first_pvc = NULL; /* All PVCs destroyed */ + state(hdlc)->dce_pvc_count = 0; + state(hdlc)->dce_changed = 1; while (pvc) { pvc_device *next = pvc->next; @@ -1161,8 +1215,17 @@ static void fr_destroy(hdlc_device *hdlc) } +static struct hdlc_proto proto = { + .close = fr_close, + .start = fr_start, + .stop = fr_stop, + .detach = fr_destroy, + .ioctl = fr_ioctl, + .module = THIS_MODULE, +}; + -int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr) +static int fr_ioctl(struct net_device *dev, struct ifreq *ifr) { fr_proto __user *fr_s = ifr->ifr_settings.ifs_ifsu.fr; const size_t size = sizeof(fr_proto); @@ -1173,12 +1236,14 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr) switch (ifr->ifr_settings.type) { case IF_GET_PROTO: + if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */ + return -EINVAL; ifr->ifr_settings.type = IF_PROTO_FR; if (ifr->ifr_settings.size < size) { ifr->ifr_settings.size = size; /* data size wanted */ return -ENOBUFS; } - if (copy_to_user(fr_s, &hdlc->state.fr.settings, size)) + if (copy_to_user(fr_s, &state(hdlc)->settings, size)) return -EFAULT; return 0; @@ -1213,20 +1278,16 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - if (hdlc->proto.id != IF_PROTO_FR) { - hdlc_proto_detach(hdlc); - hdlc->state.fr.first_pvc = NULL; - hdlc->state.fr.dce_pvc_count = 0; + if (dev_to_hdlc(dev)->proto != &proto) { /* Different proto */ + result = attach_hdlc_protocol(dev, &proto, fr_rx, + sizeof(struct frad_state)); + if (result) + return result; + state(hdlc)->first_pvc = NULL; + state(hdlc)->dce_pvc_count = 0; } - memcpy(&hdlc->state.fr.settings, &new_settings, size); - memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - - hdlc->proto.close = fr_close; - hdlc->proto.start = fr_start; - hdlc->proto.stop = fr_stop; - hdlc->proto.detach = fr_destroy; - hdlc->proto.netif_rx = fr_rx; - hdlc->proto.id = IF_PROTO_FR; + memcpy(&state(hdlc)->settings, &new_settings, size); + dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_FRAD; @@ -1238,6 +1299,9 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr) case IF_PROTO_FR_DEL_PVC: case IF_PROTO_FR_ADD_ETH_PVC: case IF_PROTO_FR_DEL_ETH_PVC: + if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */ + return -EINVAL; + if(!capable(CAP_NET_ADMIN)) return -EPERM; @@ -1263,3 +1327,24 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr) return -EINVAL; } + + +static int __init mod_init(void) +{ + register_hdlc_protocol(&proto); + return 0; +} + + +static void __exit mod_exit(void) +{ + unregister_hdlc_protocol(&proto); +} + + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); +MODULE_DESCRIPTION("Frame-Relay protocol support for generic HDLC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index fbaab5bf71eb..e9f717070fde 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -2,7 +2,7 @@ * Generic HDLC support routines for Linux * Point-to-point protocol support * - * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl> + * Copyright (C) 1999 - 2006 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 @@ -22,6 +22,21 @@ #include <linux/lapb.h> #include <linux/rtnetlink.h> #include <linux/hdlc.h> +#include <net/syncppp.h> + +struct ppp_state { + struct ppp_device pppdev; + struct ppp_device *syncppp_ptr; + int (*old_change_mtu)(struct net_device *dev, int new_mtu); +}; + +static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr); + + +static inline struct ppp_state* state(hdlc_device *hdlc) +{ + return(struct ppp_state *)(hdlc->state); +} static int ppp_open(struct net_device *dev) @@ -30,16 +45,16 @@ static int ppp_open(struct net_device *dev) void *old_ioctl; int result; - dev->priv = &hdlc->state.ppp.syncppp_ptr; - hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev; - hdlc->state.ppp.pppdev.dev = dev; + dev->priv = &state(hdlc)->syncppp_ptr; + state(hdlc)->syncppp_ptr = &state(hdlc)->pppdev; + state(hdlc)->pppdev.dev = dev; old_ioctl = dev->do_ioctl; - hdlc->state.ppp.old_change_mtu = dev->change_mtu; - sppp_attach(&hdlc->state.ppp.pppdev); + state(hdlc)->old_change_mtu = dev->change_mtu; + sppp_attach(&state(hdlc)->pppdev); /* sppp_attach nukes them. We don't need syncppp's ioctl */ dev->do_ioctl = old_ioctl; - hdlc->state.ppp.pppdev.sppp.pp_flags &= ~PP_CISCO; + state(hdlc)->pppdev.sppp.pp_flags &= ~PP_CISCO; dev->type = ARPHRD_PPP; result = sppp_open(dev); if (result) { @@ -59,7 +74,7 @@ static void ppp_close(struct net_device *dev) sppp_close(dev); sppp_detach(dev); dev->rebuild_header = NULL; - dev->change_mtu = hdlc->state.ppp.old_change_mtu; + dev->change_mtu = state(hdlc)->old_change_mtu; dev->mtu = HDLC_MAX_MTU; dev->hard_header_len = 16; } @@ -73,13 +88,24 @@ static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev) -int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr) +static struct hdlc_proto proto = { + .open = ppp_open, + .close = ppp_close, + .type_trans = ppp_type_trans, + .ioctl = ppp_ioctl, + .module = THIS_MODULE, +}; + + +static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr) { hdlc_device *hdlc = dev_to_hdlc(dev); int result; switch (ifr->ifr_settings.type) { case IF_GET_PROTO: + if (dev_to_hdlc(dev)->proto != &proto) + return -EINVAL; ifr->ifr_settings.type = IF_PROTO_PPP; return 0; /* return protocol only, no settable parameters */ @@ -96,13 +122,10 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - hdlc_proto_detach(hdlc); - memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - - hdlc->proto.open = ppp_open; - hdlc->proto.close = ppp_close; - hdlc->proto.type_trans = ppp_type_trans; - hdlc->proto.id = IF_PROTO_PPP; + result = attach_hdlc_protocol(dev, &proto, NULL, + sizeof(struct ppp_state)); + if (result) + return result; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_PPP; @@ -113,3 +136,25 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr) return -EINVAL; } + + +static int __init mod_init(void) +{ + register_hdlc_protocol(&proto); + return 0; +} + + + +static void __exit mod_exit(void) +{ + unregister_hdlc_protocol(&proto); +} + + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); +MODULE_DESCRIPTION("PPP protocol support for generic HDLC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c index f15aa6ba77f1..fe3cae5c6b9d 100644 --- a/drivers/net/wan/hdlc_raw.c +++ b/drivers/net/wan/hdlc_raw.c @@ -2,7 +2,7 @@ * Generic HDLC support routines for Linux * HDLC support * - * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl> + * Copyright (C) 1999 - 2006 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 @@ -24,6 +24,8 @@ #include <linux/hdlc.h> +static int raw_ioctl(struct net_device *dev, struct ifreq *ifr); + static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev) { return __constant_htons(ETH_P_IP); @@ -31,7 +33,14 @@ static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev) -int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr) +static struct hdlc_proto proto = { + .type_trans = raw_type_trans, + .ioctl = raw_ioctl, + .module = THIS_MODULE, +}; + + +static int raw_ioctl(struct net_device *dev, struct ifreq *ifr) { raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc; const size_t size = sizeof(raw_hdlc_proto); @@ -41,12 +50,14 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr) switch (ifr->ifr_settings.type) { case IF_GET_PROTO: + if (dev_to_hdlc(dev)->proto != &proto) + return -EINVAL; ifr->ifr_settings.type = IF_PROTO_HDLC; if (ifr->ifr_settings.size < size) { ifr->ifr_settings.size = size; /* data size wanted */ return -ENOBUFS; } - if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size)) + if (copy_to_user(raw_s, hdlc->state, size)) return -EFAULT; return 0; @@ -71,12 +82,11 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - hdlc_proto_detach(hdlc); - memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); - memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - - hdlc->proto.type_trans = raw_type_trans; - hdlc->proto.id = IF_PROTO_HDLC; + result = attach_hdlc_protocol(dev, &proto, NULL, + sizeof(raw_hdlc_proto)); + if (result) + return result; + memcpy(hdlc->state, &new_settings, size); dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_RAWHDLC; @@ -88,3 +98,25 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr) return -EINVAL; } + + +static int __init mod_init(void) +{ + register_hdlc_protocol(&proto); + return 0; +} + + + +static void __exit mod_exit(void) +{ + unregister_hdlc_protocol(&proto); +} + + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); +MODULE_DESCRIPTION("Raw HDLC protocol support for generic HDLC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c index d1884987f94e..1a69a9aaa9b9 100644 --- a/drivers/net/wan/hdlc_raw_eth.c +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -2,7 +2,7 @@ * Generic HDLC support routines for Linux * HDLC Ethernet emulation support * - * Copyright (C) 2002-2003 Krzysztof Halasa <khc@pm.waw.pl> + * Copyright (C) 2002-2006 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 @@ -25,6 +25,7 @@ #include <linux/etherdevice.h> #include <linux/hdlc.h> +static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr); static int eth_tx(struct sk_buff *skb, struct net_device *dev) { @@ -44,7 +45,14 @@ static int eth_tx(struct sk_buff *skb, struct net_device *dev) } -int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) +static struct hdlc_proto proto = { + .type_trans = eth_type_trans, + .ioctl = raw_eth_ioctl, + .module = THIS_MODULE, +}; + + +static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) { raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc; const size_t size = sizeof(raw_hdlc_proto); @@ -56,12 +64,14 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) switch (ifr->ifr_settings.type) { case IF_GET_PROTO: + if (dev_to_hdlc(dev)->proto != &proto) + return -EINVAL; ifr->ifr_settings.type = IF_PROTO_HDLC_ETH; if (ifr->ifr_settings.size < size) { ifr->ifr_settings.size = size; /* data size wanted */ return -ENOBUFS; } - if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size)) + if (copy_to_user(raw_s, hdlc->state, size)) return -EFAULT; return 0; @@ -86,12 +96,11 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - hdlc_proto_detach(hdlc); - memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); - memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - - hdlc->proto.type_trans = eth_type_trans; - hdlc->proto.id = IF_PROTO_HDLC_ETH; + result = attach_hdlc_protocol(dev, &proto, NULL, + sizeof(raw_hdlc_proto)); + if (result) + return result; + memcpy(hdlc->state, &new_settings, size); dev->hard_start_xmit = eth_tx; old_ch_mtu = dev->change_mtu; old_qlen = dev->tx_queue_len; @@ -106,3 +115,25 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) return -EINVAL; } + + +static int __init mod_init(void) +{ + register_hdlc_protocol(&proto); + return 0; +} + + + +static void __exit mod_exit(void) +{ + unregister_hdlc_protocol(&proto); +} + + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); +MODULE_DESCRIPTION("Ethernet encapsulation support for generic HDLC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c index a867fb411f89..e4bb9f8ad433 100644 --- a/drivers/net/wan/hdlc_x25.c +++ b/drivers/net/wan/hdlc_x25.c @@ -2,7 +2,7 @@ * Generic HDLC support routines for Linux * X.25 support * - * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl> + * Copyright (C) 1999 - 2006 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 @@ -25,6 +25,8 @@ #include <net/x25device.h> +static int x25_ioctl(struct net_device *dev, struct ifreq *ifr); + /* These functions are callbacks called by LAPB layer */ static void x25_connect_disconnect(struct net_device *dev, int reason, int code) @@ -162,30 +164,39 @@ static void x25_close(struct net_device *dev) static int x25_rx(struct sk_buff *skb) { - hdlc_device *hdlc = dev_to_hdlc(skb->dev); + struct hdlc_device_desc *desc = dev_to_desc(skb->dev); if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { - hdlc->stats.rx_dropped++; + desc->stats.rx_dropped++; return NET_RX_DROP; } if (lapb_data_received(skb->dev, skb) == LAPB_OK) return NET_RX_SUCCESS; - hdlc->stats.rx_errors++; + desc->stats.rx_errors++; dev_kfree_skb_any(skb); return NET_RX_DROP; } +static struct hdlc_proto proto = { + .open = x25_open, + .close = x25_close, + .ioctl = x25_ioctl, + .module = THIS_MODULE, +}; + -int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr) +static int x25_ioctl(struct net_device *dev, struct ifreq *ifr) { hdlc_device *hdlc = dev_to_hdlc(dev); int result; switch (ifr->ifr_settings.type) { case IF_GET_PROTO: + if (dev_to_hdlc(dev)->proto != &proto) + return -EINVAL; ifr->ifr_settings.type = IF_PROTO_X25; return 0; /* return protocol only, no settable parameters */ @@ -200,14 +211,9 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - hdlc_proto_detach(hdlc); - memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - - hdlc->proto.open = x25_open; - hdlc->proto.close = x25_close; - hdlc->proto.netif_rx = x25_rx; - hdlc->proto.type_trans = NULL; - hdlc->proto.id = IF_PROTO_X25; + if ((result = attach_hdlc_protocol(dev, &proto, + x25_rx, 0)) != 0) + return result; dev->hard_start_xmit = x25_xmit; dev->hard_header = NULL; dev->type = ARPHRD_X25; @@ -218,3 +224,25 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr) return -EINVAL; } + + +static int __init mod_init(void) +{ + register_hdlc_protocol(&proto); + return 0; +} + + + +static void __exit mod_exit(void) +{ + unregister_hdlc_protocol(&proto); +} + + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); +MODULE_DESCRIPTION("X.25 protocol support for generic HDLC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wan/pc300.h b/drivers/net/wan/pc300.h index 2024b26b99e6..63e9fcf31fb8 100644 --- a/drivers/net/wan/pc300.h +++ b/drivers/net/wan/pc300.h @@ -100,6 +100,7 @@ #define _PC300_H #include <linux/hdlc.h> +#include <net/syncppp.h> #include "hd64572.h" #include "pc300-falc-lh.h" diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index 56e69403d178..8d9b959bf15b 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -2016,7 +2016,6 @@ static void sca_intr(pc300_t * card) pc300ch_t *chan = &card->chan[ch]; pc300dev_t *d = &chan->d; struct net_device *dev = d->dev; - hdlc_device *hdlc = dev_to_hdlc(dev); spin_lock(&card->card_lock); @@ -2049,8 +2048,8 @@ static void sca_intr(pc300_t * card) } cpc_net_rx(dev); /* Discard invalid frames */ - hdlc->stats.rx_errors++; - hdlc->stats.rx_over_errors++; + hdlc_stats(dev)->rx_errors++; + hdlc_stats(dev)->rx_over_errors++; chan->rx_first_bd = 0; chan->rx_last_bd = N_DMA_RX_BUF - 1; rx_dma_start(card, ch); @@ -2116,8 +2115,8 @@ static void sca_intr(pc300_t * card) card->hw.cpld_reg2) & ~ (CPLD_REG2_FALC_LED1 << (2 * ch))); } - hdlc->stats.tx_errors++; - hdlc->stats.tx_fifo_errors++; + hdlc_stats(dev)->tx_errors++; + hdlc_stats(dev)->tx_fifo_errors++; sca_tx_intr(d); } } @@ -2534,7 +2533,6 @@ static int cpc_change_mtu(struct net_device *dev, int new_mtu) static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - hdlc_device *hdlc = dev_to_hdlc(dev); pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; @@ -2552,10 +2550,10 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCGPC300CONF: #ifdef CONFIG_PC300_MLPPP if (conf->proto != PC300_PROTO_MLPPP) { - conf->proto = hdlc->proto.id; + conf->proto = /* FIXME hdlc->proto.id */ 0; } #else - conf->proto = hdlc->proto.id; + conf->proto = /* FIXME hdlc->proto.id */ 0; #endif memcpy(&conf_aux.conf, conf, sizeof(pc300chconf_t)); memcpy(&conf_aux.hw, &card->hw, sizeof(pc300hw_t)); @@ -2588,12 +2586,12 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } } else { memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t)); - hdlc->proto.id = conf->proto; + /* FIXME hdlc->proto.id = conf->proto; */ } } #else memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t)); - hdlc->proto.id = conf->proto; + /* FIXME hdlc->proto.id = conf->proto; */ #endif return 0; case SIOCGPC300STATUS: @@ -2606,7 +2604,7 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCGPC300UTILSTATS: { if (!arg) { /* clear statistics */ - memset(&hdlc->stats, 0, sizeof(struct net_device_stats)); + memset(hdlc_stats(dev), 0, sizeof(struct net_device_stats)); if (card->hw.type == PC300_TE) { memset(&chan->falc, 0, sizeof(falc_t)); } @@ -2617,7 +2615,7 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) pc300stats.hw_type = card->hw.type; pc300stats.line_on = card->chan[ch].d.line_on; pc300stats.line_off = card->chan[ch].d.line_off; - memcpy(&pc300stats.gen_stats, &hdlc->stats, + memcpy(&pc300stats.gen_stats, hdlc_stats(dev), sizeof(struct net_device_stats)); if (card->hw.type == PC300_TE) memcpy(&pc300stats.te_stats,&chan->falc,sizeof(falc_t)); @@ -3147,7 +3145,6 @@ static void cpc_closech(pc300dev_t * d) int cpc_open(struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); pc300dev_t *d = (pc300dev_t *) dev->priv; struct ifreq ifr; int result; @@ -3156,12 +3153,14 @@ int cpc_open(struct net_device *dev) printk("pc300: cpc_open"); #endif +#ifdef FIXME if (hdlc->proto.id == IF_PROTO_PPP) { d->if_ptr = &hdlc->state.ppp.pppdev; } +#endif result = hdlc_open(dev); - if (hdlc->proto.id == IF_PROTO_PPP) { + if (/* FIXME hdlc->proto.id == IF_PROTO_PPP*/ 0) { dev->priv = d; } if (result) { @@ -3176,7 +3175,6 @@ int cpc_open(struct net_device *dev) static int cpc_close(struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; @@ -3193,7 +3191,7 @@ static int cpc_close(struct net_device *dev) CPC_UNLOCK(card, flags); hdlc_close(dev); - if (hdlc->proto.id == IF_PROTO_PPP) { + if (/* FIXME hdlc->proto.id == IF_PROTO_PPP*/ 0) { d->if_ptr = NULL; } #ifdef CONFIG_PC300_MLPPP diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index bff04cba3fed..ba737c6cebec 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -5868,7 +5868,7 @@ static int airo_set_essid(struct net_device *dev, int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; /* Check the size of the string */ - if(dwrq->length > IW_ESSID_MAX_SIZE+1) { + if(dwrq->length > IW_ESSID_MAX_SIZE) { return -E2BIG ; } /* Check if index is valid */ @@ -5880,7 +5880,7 @@ static int airo_set_essid(struct net_device *dev, memset(SSID_rid.ssids[index].ssid, 0, sizeof(SSID_rid.ssids[index].ssid)); memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length); - SSID_rid.ssids[index].len = dwrq->length - 1; + SSID_rid.ssids[index].len = dwrq->length; } SSID_rid.len = sizeof(SSID_rid); /* Write it to the card */ @@ -5990,7 +5990,7 @@ static int airo_set_nick(struct net_device *dev, struct airo_info *local = dev->priv; /* Check the size of the string */ - if(dwrq->length > 16 + 1) { + if(dwrq->length > 16) { return -E2BIG; } readConfigRid(local, 1); @@ -6015,7 +6015,7 @@ static int airo_get_nick(struct net_device *dev, readConfigRid(local, 1); strncpy(extra, local->config.nodeName, 16); extra[16] = '\0'; - dwrq->length = strlen(extra) + 1; + dwrq->length = strlen(extra); return 0; } @@ -6767,9 +6767,9 @@ static int airo_set_retry(struct net_device *dev, } readConfigRid(local, 1); if(vwrq->flags & IW_RETRY_LIMIT) { - if(vwrq->flags & IW_RETRY_MAX) + if(vwrq->flags & IW_RETRY_LONG) local->config.longRetryLimit = vwrq->value; - else if (vwrq->flags & IW_RETRY_MIN) + else if (vwrq->flags & IW_RETRY_SHORT) local->config.shortRetryLimit = vwrq->value; else { /* No modifier : set both */ @@ -6805,14 +6805,14 @@ static int airo_get_retry(struct net_device *dev, if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { vwrq->flags = IW_RETRY_LIFETIME; vwrq->value = (int)local->config.txLifetime * 1024; - } else if((vwrq->flags & IW_RETRY_MAX)) { - vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + } else if((vwrq->flags & IW_RETRY_LONG)) { + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; vwrq->value = (int)local->config.longRetryLimit; } else { vwrq->flags = IW_RETRY_LIMIT; vwrq->value = (int)local->config.shortRetryLimit; if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit) - vwrq->flags |= IW_RETRY_MIN; + vwrq->flags |= IW_RETRY_SHORT; } return 0; @@ -6990,6 +6990,7 @@ static int airo_set_power(struct net_device *dev, local->config.rmode |= RXMODE_BC_MC_ADDR; set_bit (FLAG_COMMIT, &local->flags); case IW_POWER_ON: + /* This is broken, fixme ;-) */ break; default: return -EINVAL; diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 995c7bea5897..0fc267d626dc 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -1656,13 +1656,13 @@ static int atmel_set_essid(struct net_device *dev, priv->connect_to_any_BSS = 0; /* Check the size of the string */ - if (dwrq->length > MAX_SSID_LENGTH + 1) + if (dwrq->length > MAX_SSID_LENGTH) return -E2BIG; if (index != 0) return -EINVAL; - memcpy(priv->new_SSID, extra, dwrq->length - 1); - priv->new_SSID_size = dwrq->length - 1; + memcpy(priv->new_SSID, extra, dwrq->length); + priv->new_SSID_size = dwrq->length; } return -EINPROGRESS; @@ -2120,9 +2120,9 @@ static int atmel_set_retry(struct net_device *dev, struct atmel_private *priv = netdev_priv(dev); if (!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) { - if (vwrq->flags & IW_RETRY_MAX) + if (vwrq->flags & IW_RETRY_LONG) priv->long_retry = vwrq->value; - else if (vwrq->flags & IW_RETRY_MIN) + else if (vwrq->flags & IW_RETRY_SHORT) priv->short_retry = vwrq->value; else { /* No modifier : set both */ @@ -2144,15 +2144,15 @@ static int atmel_get_retry(struct net_device *dev, vwrq->disabled = 0; /* Can't be disabled */ - /* Note : by default, display the min retry number */ - if (vwrq->flags & IW_RETRY_MAX) { - vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + /* Note : by default, display the short retry number */ + if (vwrq->flags & IW_RETRY_LONG) { + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; vwrq->value = priv->long_retry; } else { vwrq->flags = IW_RETRY_LIMIT; vwrq->value = priv->short_retry; if (priv->long_retry != priv->short_retry) - vwrq->flags |= IW_RETRY_MIN; + vwrq->flags |= IW_RETRY_SHORT; } return 0; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 6d4ea36bc564..d6a8bf09878e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -666,7 +666,6 @@ struct bcm43xx_noise_calculation { }; struct bcm43xx_stats { - u8 link_quality; u8 noise; struct iw_statistics wstats; /* Store the last TX/RX times here for updating the leds. */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index cb9a3ae8463a..eb65db7393ba 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2405,9 +2405,10 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) BCM43xx_UCODE_TIME) & 0x1f); if ( value16 > 0x128 ) { - dprintk(KERN_ERR PFX - "Firmware: no support for microcode rev > 0x128\n"); - err = -1; + printk(KERN_ERR PFX + "Firmware: no support for microcode extracted " + "from version 4.x binary drivers.\n"); + err = -EOPNOTSUPP; goto err_release_fw; } @@ -3169,8 +3170,7 @@ static void bcm43xx_periodic_work_handler(void *d) * be preemtible. */ mutex_lock(&bcm->mutex); - netif_stop_queue(bcm->net_dev); - synchronize_net(); + netif_tx_disable(bcm->net_dev); spin_lock_irqsave(&bcm->irq_lock, flags); bcm43xx_mac_suspend(bcm); if (bcm43xx_using_pio(bcm)) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index eafd0f662686..52ce2a9334fb 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -361,7 +361,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) if (phy->rev <= 2) for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]); - else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200)) + else if ((phy->rev >= 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200)) for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]); else @@ -371,7 +371,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) if (phy->rev == 2) for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); - else if ((phy->rev > 2) && (phy->rev <= 7)) + else if ((phy->rev > 2) && (phy->rev <= 8)) for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]); @@ -1197,7 +1197,7 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) if (phy->rev == 1) bcm43xx_phy_initb5(bcm); - else if (phy->rev >= 2 && phy->rev <= 7) + else bcm43xx_phy_initb6(bcm); if (phy->rev >= 2 || phy->connected) bcm43xx_phy_inita(bcm); @@ -1241,23 +1241,22 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) bcm43xx_phy_lo_g_measure(bcm); } else { if (radio->version == 0x2050 && radio->revision == 8) { - //FIXME + bcm43xx_radio_write16(bcm, 0x0052, + (radio->txctl1 << 4) | radio->txctl2); } else { bcm43xx_radio_write16(bcm, 0x0052, (bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0) | radio->txctl1); } if (phy->rev >= 6) { - /* bcm43xx_phy_write(bcm, 0x0036, (bcm43xx_phy_read(bcm, 0x0036) - & 0xF000) | (FIXME << 12)); - */ + & 0xF000) | (radio->txctl2 << 12)); } if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) bcm43xx_phy_write(bcm, 0x002E, 0x8075); else - bcm43xx_phy_write(bcm, 0x003E, 0x807F); + bcm43xx_phy_write(bcm, 0x002E, 0x807F); if (phy->rev < 2) bcm43xx_phy_write(bcm, 0x002F, 0x0101); else diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 888077fc14c4..9b7b15cf6561 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -334,7 +334,7 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev, size_t len; mutex_lock(&bcm->mutex); - len = strlen(bcm->nick) + 1; + len = strlen(bcm->nick); memcpy(extra, bcm->nick, len); data->data.length = (__u16)len; data->data.flags = 1; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c index c0efbfe605a5..0159e4e93201 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c @@ -496,15 +496,14 @@ int bcm43xx_rx(struct bcm43xx_private *bcm, stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); -//TODO stats.noise = + stats.noise = bcm->stats.noise; if (is_ofdm) stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp); else stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp); stats.received_channel = radio->channel; -//TODO stats.control = stats.mask = IEEE80211_STATMASK_SIGNAL | -//TODO IEEE80211_STATMASK_NOISE | + IEEE80211_STATMASK_NOISE | IEEE80211_STATMASK_RATE | IEEE80211_STATMASK_RSSI; if (phy->type == BCM43xx_PHYTYPE_A) diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 7a4978516eac..d061fb3443ff 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -1412,9 +1412,9 @@ static int prism2_ioctl_siwretry(struct net_device *dev, /* what could be done, if firmware would support this.. */ if (rrq->flags & IW_RETRY_LIMIT) { - if (rrq->flags & IW_RETRY_MAX) + if (rrq->flags & IW_RETRY_LONG) HFA384X_RID_LONGRETRYLIMIT = rrq->value; - else if (rrq->flags & IW_RETRY_MIN) + else if (rrq->flags & IW_RETRY_SHORT) HFA384X_RID_SHORTRETRYLIMIT = rrq->value; else { HFA384X_RID_LONGRETRYLIMIT = rrq->value; @@ -1468,14 +1468,14 @@ static int prism2_ioctl_giwretry(struct net_device *dev, rrq->value = le16_to_cpu(altretry); else rrq->value = local->manual_retry_count; - } else if ((rrq->flags & IW_RETRY_MAX)) { - rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + } else if ((rrq->flags & IW_RETRY_LONG)) { + rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; rrq->value = longretry; } else { rrq->flags = IW_RETRY_LIMIT; rrq->value = shortretry; if (shortretry != longretry) - rrq->flags |= IW_RETRY_MIN; + rrq->flags |= IW_RETRY_SHORT; } } return 0; diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index b4d81a04c895..6c5add701a6f 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -6958,7 +6958,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev, } if (wrqu->essid.flags && wrqu->essid.length) { - length = wrqu->essid.length - 1; + length = wrqu->essid.length; essid = extra; } @@ -7051,7 +7051,7 @@ static int ipw2100_wx_get_nick(struct net_device *dev, struct ipw2100_priv *priv = ieee80211_priv(dev); - wrqu->data.length = strlen(priv->nick) + 1; + wrqu->data.length = strlen(priv->nick); memcpy(extra, priv->nick, wrqu->data.length); wrqu->data.flags = 1; /* active */ @@ -7343,14 +7343,14 @@ static int ipw2100_wx_set_retry(struct net_device *dev, goto done; } - if (wrqu->retry.flags & IW_RETRY_MIN) { + if (wrqu->retry.flags & IW_RETRY_SHORT) { err = ipw2100_set_short_retry(priv, wrqu->retry.value); IPW_DEBUG_WX("SET Short Retry Limit -> %d \n", wrqu->retry.value); goto done; } - if (wrqu->retry.flags & IW_RETRY_MAX) { + if (wrqu->retry.flags & IW_RETRY_LONG) { err = ipw2100_set_long_retry(priv, wrqu->retry.value); IPW_DEBUG_WX("SET Long Retry Limit -> %d \n", wrqu->retry.value); @@ -7383,14 +7383,14 @@ static int ipw2100_wx_get_retry(struct net_device *dev, if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) return -EINVAL; - if (wrqu->retry.flags & IW_RETRY_MAX) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + if (wrqu->retry.flags & IW_RETRY_LONG) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG; wrqu->retry.value = priv->long_retry_limit; } else { wrqu->retry.flags = (priv->short_retry_limit != priv->long_retry_limit) ? - IW_RETRY_LIMIT | IW_RETRY_MIN : IW_RETRY_LIMIT; + IW_RETRY_LIMIT | IW_RETRY_SHORT : IW_RETRY_LIMIT; wrqu->retry.value = priv->short_retry_limit; } diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 7358664e0908..5685d7ba55bb 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -8875,8 +8875,6 @@ static int ipw_wx_set_essid(struct net_device *dev, } length = min((int)wrqu->essid.length, IW_ESSID_MAX_SIZE); - if (!extra[length - 1]) - length--; priv->config |= CFG_STATIC_ESSID; @@ -8953,7 +8951,7 @@ static int ipw_wx_get_nick(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); IPW_DEBUG_WX("Getting nick\n"); mutex_lock(&priv->mutex); - wrqu->data.length = strlen(priv->nick) + 1; + wrqu->data.length = strlen(priv->nick); memcpy(extra, priv->nick, wrqu->data.length); wrqu->data.flags = 1; /* active */ mutex_unlock(&priv->mutex); @@ -9276,9 +9274,9 @@ static int ipw_wx_set_retry(struct net_device *dev, return -EINVAL; mutex_lock(&priv->mutex); - if (wrqu->retry.flags & IW_RETRY_MIN) + if (wrqu->retry.flags & IW_RETRY_SHORT) priv->short_retry_limit = (u8) wrqu->retry.value; - else if (wrqu->retry.flags & IW_RETRY_MAX) + else if (wrqu->retry.flags & IW_RETRY_LONG) priv->long_retry_limit = (u8) wrqu->retry.value; else { priv->short_retry_limit = (u8) wrqu->retry.value; @@ -9307,11 +9305,11 @@ static int ipw_wx_get_retry(struct net_device *dev, return -EINVAL; } - if (wrqu->retry.flags & IW_RETRY_MAX) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + if (wrqu->retry.flags & IW_RETRY_LONG) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG; wrqu->retry.value = priv->long_retry_limit; - } else if (wrqu->retry.flags & IW_RETRY_MIN) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; + } else if (wrqu->retry.flags & IW_RETRY_SHORT) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; wrqu->retry.value = priv->short_retry_limit; } else { wrqu->retry.flags = IW_RETRY_LIMIT; diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 1840b69e3cb5..9e19a963febc 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -3037,7 +3037,7 @@ static int orinoco_ioctl_getessid(struct net_device *dev, } erq->flags = 1; - erq->length = strlen(essidbuf) + 1; + erq->length = strlen(essidbuf); return 0; } @@ -3078,7 +3078,7 @@ static int orinoco_ioctl_getnick(struct net_device *dev, memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1); orinoco_unlock(priv, &flags); - nrq->length = strlen(nickbuf)+1; + nrq->length = strlen(nickbuf); return 0; } @@ -3575,14 +3575,14 @@ static int orinoco_ioctl_getretry(struct net_device *dev, rrq->value = lifetime * 1000; /* ??? */ } else { /* By default, display the min number */ - if ((rrq->flags & IW_RETRY_MAX)) { - rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + if ((rrq->flags & IW_RETRY_LONG)) { + rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; rrq->value = long_limit; } else { rrq->flags = IW_RETRY_LIMIT; rrq->value = short_limit; if(short_limit != long_limit) - rrq->flags |= IW_RETRY_MIN; + rrq->flags |= IW_RETRY_SHORT; } } diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index c09fbf733b3a..286325ca3293 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -742,9 +742,9 @@ prism54_set_essid(struct net_device *ndev, struct iw_request_info *info, /* Check if we were asked for `any' */ if (dwrq->flags && dwrq->length) { - if (dwrq->length > min(33, IW_ESSID_MAX_SIZE + 1)) + if (dwrq->length > 32) return -E2BIG; - essid.length = dwrq->length - 1; + essid.length = dwrq->length; memcpy(essid.octets, extra, dwrq->length); } else essid.length = 0; @@ -814,7 +814,7 @@ prism54_get_nick(struct net_device *ndev, struct iw_request_info *info, dwrq->length = 0; down_read(&priv->mib_sem); - dwrq->length = strlen(priv->nickname) + 1; + dwrq->length = strlen(priv->nickname); memcpy(extra, priv->nickname, dwrq->length); up_read(&priv->mib_sem); @@ -992,9 +992,9 @@ prism54_set_retry(struct net_device *ndev, struct iw_request_info *info, return -EINVAL; if (vwrq->flags & IW_RETRY_LIMIT) { - if (vwrq->flags & IW_RETRY_MIN) + if (vwrq->flags & IW_RETRY_SHORT) slimit = vwrq->value; - else if (vwrq->flags & IW_RETRY_MAX) + else if (vwrq->flags & IW_RETRY_LONG) llimit = vwrq->value; else { /* we are asked to set both */ @@ -1035,18 +1035,18 @@ prism54_get_retry(struct net_device *ndev, struct iw_request_info *info, mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r); vwrq->value = r.u * 1024; vwrq->flags = IW_RETRY_LIFETIME; - } else if ((vwrq->flags & IW_RETRY_MAX)) { + } else if ((vwrq->flags & IW_RETRY_LONG)) { /* we are asked for the long retry limit */ rvalue |= mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r); vwrq->value = r.u; - vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; } else { /* default. get the short retry limit */ rvalue |= mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r); vwrq->value = r.u; - vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MIN; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; } return rvalue; diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 4574290f971f..e82548ea609a 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -1173,7 +1173,7 @@ static int ray_set_essid(struct net_device *dev, return -EOPNOTSUPP; } else { /* Check the size of the string */ - if(dwrq->length > IW_ESSID_MAX_SIZE + 1) { + if(dwrq->length > IW_ESSID_MAX_SIZE) { return -E2BIG; } diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index e0d294c12970..e3ae5f60d5be 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1802,15 +1802,15 @@ static int wl3501_get_retry(struct net_device *dev, &retry, sizeof(retry)); if (rc) goto out; - if (wrqu->retry.flags & IW_RETRY_MAX) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + if (wrqu->retry.flags & IW_RETRY_LONG) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG; goto set_value; } rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT, &retry, sizeof(retry)); if (rc) goto out; - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; set_value: wrqu->retry.value = retry; wrqu->retry.disabled = 0; diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index f50ec10675d1..80af9a9fcbb3 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -1218,7 +1218,7 @@ static int zd1201_set_essid(struct net_device *dev, return -EINVAL; if (data->length < 1) data->length = 1; - zd->essidlen = data->length-1; + zd->essidlen = data->length; memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1); memcpy(zd->essid, essid, data->length); return zd1201_join(zd, zd->essid, zd->essidlen); diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 7c4e32cf0d47..aa661b2b76c7 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -249,7 +249,6 @@ int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value) { int r; - ZD_ASSERT(!mutex_is_locked(&chip->mutex)); mutex_lock(&chip->mutex); r = zd_ioread16_locked(chip, value, addr); mutex_unlock(&chip->mutex); @@ -260,7 +259,6 @@ int zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value) { int r; - ZD_ASSERT(!mutex_is_locked(&chip->mutex)); mutex_lock(&chip->mutex); r = zd_ioread32_locked(chip, value, addr); mutex_unlock(&chip->mutex); @@ -271,7 +269,6 @@ int zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value) { int r; - ZD_ASSERT(!mutex_is_locked(&chip->mutex)); mutex_lock(&chip->mutex); r = zd_iowrite16_locked(chip, value, addr); mutex_unlock(&chip->mutex); @@ -282,7 +279,6 @@ int zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value) { int r; - ZD_ASSERT(!mutex_is_locked(&chip->mutex)); mutex_lock(&chip->mutex); r = zd_iowrite32_locked(chip, value, addr); mutex_unlock(&chip->mutex); @@ -294,7 +290,6 @@ int zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses, { int r; - ZD_ASSERT(!mutex_is_locked(&chip->mutex)); mutex_lock(&chip->mutex); r = zd_ioread32v_locked(chip, values, addresses, count); mutex_unlock(&chip->mutex); @@ -306,7 +301,6 @@ int zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs, { int r; - ZD_ASSERT(!mutex_is_locked(&chip->mutex)); mutex_lock(&chip->mutex); r = zd_iowrite32a_locked(chip, ioreqs, count); mutex_unlock(&chip->mutex); @@ -331,13 +325,22 @@ static int read_pod(struct zd_chip *chip, u8 *rf_type) chip->patch_cr157 = (value >> 13) & 0x1; chip->patch_6m_band_edge = (value >> 21) & 0x1; chip->new_phy_layout = (value >> 31) & 0x1; + chip->link_led = ((value >> 4) & 1) ? LED1 : LED2; + chip->supports_tx_led = 1; + if (value & (1 << 24)) { /* LED scenario */ + if (value & (1 << 29)) + chip->supports_tx_led = 0; + } dev_dbg_f(zd_chip_dev(chip), "RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d " - "patch 6M %d new PHY %d\n", + "patch 6M %d new PHY %d link LED%d tx led %d\n", zd_rf_name(*rf_type), *rf_type, chip->pa_type, chip->patch_cck_gain, - chip->patch_cr157, chip->patch_6m_band_edge, chip->new_phy_layout); + chip->patch_cr157, chip->patch_6m_band_edge, + chip->new_phy_layout, + chip->link_led == LED1 ? 1 : 2, + chip->supports_tx_led); return 0; error: *rf_type = 0; @@ -1181,7 +1184,7 @@ static int update_pwr_int(struct zd_chip *chip, u8 channel) u8 value = chip->pwr_int_values[channel - 1]; dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_int %#04x\n", channel, value); - return zd_iowrite32_locked(chip, value, CR31); + return zd_iowrite16_locked(chip, value, CR31); } static int update_pwr_cal(struct zd_chip *chip, u8 channel) @@ -1189,12 +1192,12 @@ static int update_pwr_cal(struct zd_chip *chip, u8 channel) u8 value = chip->pwr_cal_values[channel-1]; dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_cal %#04x\n", channel, value); - return zd_iowrite32_locked(chip, value, CR68); + return zd_iowrite16_locked(chip, value, CR68); } static int update_ofdm_cal(struct zd_chip *chip, u8 channel) { - struct zd_ioreq32 ioreqs[3]; + struct zd_ioreq16 ioreqs[3]; ioreqs[0].addr = CR67; ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1]; @@ -1206,7 +1209,7 @@ static int update_ofdm_cal(struct zd_chip *chip, u8 channel) dev_dbg_f(zd_chip_dev(chip), "channel %d ofdm_cal 36M %#04x 48M %#04x 54M %#04x\n", channel, ioreqs[0].value, ioreqs[1].value, ioreqs[2].value); - return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); } static int update_channel_integration_and_calibration(struct zd_chip *chip, @@ -1218,7 +1221,7 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip, if (r) return r; if (chip->is_zd1211b) { - static const struct zd_ioreq32 ioreqs[] = { + static const struct zd_ioreq16 ioreqs[] = { { CR69, 0x28 }, {}, { CR69, 0x2a }, @@ -1230,7 +1233,7 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip, r = update_pwr_cal(chip, channel); if (r) return r; - r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); + r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); if (r) return r; } @@ -1252,7 +1255,7 @@ static int patch_cck_gain(struct zd_chip *chip) if (r) return r; dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff); - return zd_iowrite32_locked(chip, value & 0xff, CR47); + return zd_iowrite16_locked(chip, value & 0xff, CR47); } int zd_chip_set_channel(struct zd_chip *chip, u8 channel) @@ -1295,89 +1298,60 @@ u8 zd_chip_get_channel(struct zd_chip *chip) return channel; } -static u16 led_mask(int led) +int zd_chip_control_leds(struct zd_chip *chip, enum led_status status) { - switch (led) { - case 1: - return LED1; - case 2: - return LED2; - default: - return 0; - } -} - -static int read_led_reg(struct zd_chip *chip, u16 *status) -{ - ZD_ASSERT(mutex_is_locked(&chip->mutex)); - return zd_ioread16_locked(chip, status, CR_LED); -} - -static int write_led_reg(struct zd_chip *chip, u16 status) -{ - ZD_ASSERT(mutex_is_locked(&chip->mutex)); - return zd_iowrite16_locked(chip, status, CR_LED); -} + static const zd_addr_t a[] = { + FW_LINK_STATUS, + CR_LED, + }; -int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status) -{ - int r, ret; - u16 mask = led_mask(led); - u16 reg; + int r; + u16 v[ARRAY_SIZE(a)]; + struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = { + [0] = { FW_LINK_STATUS }, + [1] = { CR_LED }, + }; + u16 other_led; - if (!mask) - return -EINVAL; mutex_lock(&chip->mutex); - r = read_led_reg(chip, ®); + r = zd_ioread16v_locked(chip, v, (const zd_addr_t *)a, ARRAY_SIZE(a)); if (r) - return r; + goto out; + + other_led = chip->link_led == LED1 ? LED2 : LED1; + switch (status) { - case LED_STATUS: - return (reg & mask) ? LED_ON : LED_OFF; case LED_OFF: - reg &= ~mask; - ret = LED_OFF; + ioreqs[0].value = FW_LINK_OFF; + ioreqs[1].value = v[1] & ~(LED1|LED2); break; - case LED_FLIP: - reg ^= mask; - ret = (reg&mask) ? LED_ON : LED_OFF; + case LED_SCANNING: + ioreqs[0].value = FW_LINK_OFF; + ioreqs[1].value = v[1] & ~other_led; + if (get_seconds() % 3 == 0) { + ioreqs[1].value &= ~chip->link_led; + } else { + ioreqs[1].value |= chip->link_led; + } break; - case LED_ON: - reg |= mask; - ret = LED_ON; + case LED_ASSOCIATED: + ioreqs[0].value = FW_LINK_TX; + ioreqs[1].value = v[1] & ~other_led; + ioreqs[1].value |= chip->link_led; break; default: - return -EINVAL; - } - r = write_led_reg(chip, reg); - if (r) { - ret = r; + r = -EINVAL; goto out; } -out: - mutex_unlock(&chip->mutex); - return r; -} - -int zd_chip_led_flip(struct zd_chip *chip, int led, - const unsigned int *phases_msecs, unsigned int count) -{ - int i, r; - enum led_status status; - r = zd_chip_led_status(chip, led, LED_STATUS); - if (r) - return r; - status = r; - for (i = 0; i < count; i++) { - r = zd_chip_led_status(chip, led, LED_FLIP); - if (r < 0) + if (v[0] != ioreqs[0].value || v[1] != ioreqs[1].value) { + r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); + if (r) goto out; - msleep(phases_msecs[i]); } - + r = 0; out: - zd_chip_led_status(chip, led, status); + mutex_unlock(&chip->mutex); return r; } @@ -1679,4 +1653,3 @@ int zd_rfwritev_cr_locked(struct zd_chip *chip, return 0; } - diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 4b1250859897..ae59597ce4e1 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -428,6 +428,7 @@ /* masks for controlling LEDs */ #define LED1 0x0100 #define LED2 0x0200 +#define LED_SW 0x0400 /* Seems to indicate that the configuration is over. */ @@ -629,6 +630,10 @@ #define FW_SOFT_RESET FW_REG(4) #define FW_FLASH_CHK FW_REG(5) +#define FW_LINK_OFF 0x0 +#define FW_LINK_TX 0x1 +/* 0x2 - link led on? */ + enum { CR_BASE_OFFSET = 0x9000, FW_START_OFFSET = 0xee00, @@ -663,8 +668,11 @@ struct zd_chip { u8 pwr_int_values[E2P_CHANNEL_COUNT]; /* SetPointOFDM in the vendor driver */ u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT]; - u8 pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1, - new_phy_layout:1, is_zd1211b:1; + u16 link_led; + unsigned int pa_type:4, + patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1, + new_phy_layout:1, + is_zd1211b:1, supports_tx_led:1; }; static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb) @@ -812,15 +820,12 @@ int zd_chip_lock_phy_regs(struct zd_chip *chip); int zd_chip_unlock_phy_regs(struct zd_chip *chip); enum led_status { - LED_OFF = 0, - LED_ON = 1, - LED_FLIP = 2, - LED_STATUS = 3, + LED_OFF = 0, + LED_SCANNING = 1, + LED_ASSOCIATED = 2, }; -int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status); -int zd_chip_led_flip(struct zd_chip *chip, int led, - const unsigned int *phases_msecs, unsigned int count); +int zd_chip_control_leds(struct zd_chip *chip, enum led_status status); int zd_set_beacon_interval(struct zd_chip *chip, u32 interval); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 1989f1c05fbe..2d12837052b0 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -33,6 +33,10 @@ static void ieee_init(struct ieee80211_device *ieee); static void softmac_init(struct ieee80211softmac_device *sm); +static void housekeeping_init(struct zd_mac *mac); +static void housekeeping_enable(struct zd_mac *mac); +static void housekeeping_disable(struct zd_mac *mac); + int zd_mac_init(struct zd_mac *mac, struct net_device *netdev, struct usb_interface *intf) @@ -46,6 +50,7 @@ int zd_mac_init(struct zd_mac *mac, ieee_init(ieee); softmac_init(ieee80211_priv(netdev)); zd_chip_init(&mac->chip, netdev, intf); + housekeeping_init(mac); return 0; } @@ -178,6 +183,7 @@ int zd_mac_open(struct net_device *netdev) if (r < 0) goto disable_rx; + housekeeping_enable(mac); ieee80211softmac_start(netdev); return 0; disable_rx: @@ -204,6 +210,7 @@ int zd_mac_stop(struct net_device *netdev) */ zd_chip_disable_rx(chip); + housekeeping_disable(mac); ieee80211softmac_stop(netdev); zd_chip_disable_hwint(chip); @@ -1080,3 +1087,46 @@ void zd_dump_rx_status(const struct rx_status *status) } } #endif /* DEBUG */ + +#define LINK_LED_WORK_DELAY HZ + +static void link_led_handler(void *p) +{ + struct zd_mac *mac = p; + struct zd_chip *chip = &mac->chip; + struct ieee80211softmac_device *sm = ieee80211_priv(mac->netdev); + int is_associated; + int r; + + spin_lock_irq(&mac->lock); + is_associated = sm->associated != 0; + spin_unlock_irq(&mac->lock); + + r = zd_chip_control_leds(chip, + is_associated ? LED_ASSOCIATED : LED_SCANNING); + if (r) + dev_err(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); + + queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work, + LINK_LED_WORK_DELAY); +} + +static void housekeeping_init(struct zd_mac *mac) +{ + INIT_WORK(&mac->housekeeping.link_led_work, link_led_handler, mac); +} + +static void housekeeping_enable(struct zd_mac *mac) +{ + dev_dbg_f(zd_mac_dev(mac), "\n"); + queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work, + 0); +} + +static void housekeeping_disable(struct zd_mac *mac) +{ + dev_dbg_f(zd_mac_dev(mac), "\n"); + cancel_rearming_delayed_workqueue(zd_workqueue, + &mac->housekeeping.link_led_work); + zd_chip_control_leds(&mac->chip, LED_OFF); +} diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 29b51fd7d4e5..b8ea3de7924a 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -120,6 +120,10 @@ enum mac_flags { MAC_FIXED_CHANNEL = 0x01, }; +struct housekeeping { + struct work_struct link_led_work; +}; + #define ZD_MAC_STATS_BUFFER_SIZE 16 struct zd_mac { @@ -128,6 +132,7 @@ struct zd_mac { struct net_device *netdev; /* Unlocked reading possible */ struct iw_statistics iw_stats; + struct housekeeping housekeeping; unsigned int stats_count; u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE]; u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE]; diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c index 440ef24b5fd1..af3a7b36d078 100644 --- a/drivers/net/wireless/zd1211rw/zd_netdev.c +++ b/drivers/net/wireless/zd1211rw/zd_netdev.c @@ -82,7 +82,7 @@ static int iw_get_nick(struct net_device *netdev, union iwreq_data *req, char *extra) { strcpy(extra, "zd1211"); - req->data.length = strlen(extra) + 1; + req->data.length = strlen(extra); req->data.flags = 1; return 0; } diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 31027e52b04b..5c265ad0485a 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -24,6 +24,7 @@ #include <linux/errno.h> #include <linux/skbuff.h> #include <linux/usb.h> +#include <linux/workqueue.h> #include <net/ieee80211.h> #include "zd_def.h" @@ -1112,12 +1113,20 @@ static struct usb_driver driver = { .disconnect = disconnect, }; +struct workqueue_struct *zd_workqueue; + static int __init usb_init(void) { int r; pr_debug("usb_init()\n"); + zd_workqueue = create_singlethread_workqueue(driver.name); + if (zd_workqueue == NULL) { + printk(KERN_ERR "%s: couldn't create workqueue\n", driver.name); + return -ENOMEM; + } + r = usb_register(&driver); if (r) { printk(KERN_ERR "usb_register() failed. Error number %d\n", r); @@ -1132,6 +1141,7 @@ static void __exit usb_exit(void) { pr_debug("usb_exit()\n"); usb_deregister(&driver); + destroy_workqueue(zd_workqueue); } module_init(usb_init); diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index ded39de5f72d..e81a2d3cfffd 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h @@ -238,4 +238,6 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits); +extern struct workqueue_struct *zd_workqueue; + #endif /* _ZD_USB_H */ |