diff options
| author | Paul Mackerras <paulus@samba.org> | 2003-05-27 07:31:32 +1000 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2003-05-27 07:31:32 +1000 |
| commit | 8a865f4a97f4eecdba606a444601148668210ef1 (patch) | |
| tree | 2f0f8451051a8cb82ecb0b27c459ab2e66ec976f | |
| parent | 927bc10f742f603ced09dae59c94be4c70b5e949 (diff) | |
| parent | 2f124a73c7e036388e2e998c8ae1abf9d0b3204a (diff) | |
Merge samba.org:/home/paulus/kernel/linux-2.5
into samba.org:/home/paulus/kernel/for-linus-ppc
178 files changed, 5471 insertions, 1339 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 133bc87505fd..03f43b68e801 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -120,7 +120,7 @@ by better scheme anyway. --------------------------- file_system_type --------------------------- prototypes: - struct super_block *(*get_sb) (struct file_system_type *, int, char *, void *); + struct super_block *(*get_sb) (struct file_system_type *, int, const char *, void *); void (*kill_sb) (struct super_block *); locking rules: may block BKL diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 2f526cadf84f..2f388460cbe7 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -51,7 +51,7 @@ success and negative number in case of error (-EINVAL unless you have more informative error value to report). Call it foo_fill_super(). Now declare struct super_block foo_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super); } diff --git a/arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S b/arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S index 18ed9b2ad8ec..c28be59a53b2 100644 --- a/arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S +++ b/arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S @@ -118,8 +118,8 @@ _start: move.l #(0x00<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_CP,%d0 movec %d0,%ACR3 - /* Enable cache */ - move.l #0x86088400, %d0 + /* Enable cache */ + move.l #0xa4098400, %d0 /* Write buffer, dflt precise */ movec %d0,%CACR nop diff --git a/arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S index b84bef00c5c9..38c2b6d5592a 100644 --- a/arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S +++ b/arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S @@ -99,7 +99,7 @@ _start: movec %d0, %ACR3 /* Enable cache */ - move.l #0x86088400, %d0 + move.l #0xa4098400, %d0 /* Write buffer, dflt precise */ movec %d0,%CACR nop diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 9d4e16eea0de..e290ffe53bdb 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -544,11 +544,11 @@ int bus_register(struct bus_type * bus) subsys_set_kset(bus,bus_subsys); subsystem_register(&bus->subsys); - snprintf(bus->devices.kobj.name,KOBJ_NAME_LEN,"devices"); + strlcpy(bus->devices.kobj.name, "devices", KOBJ_NAME_LEN); bus->devices.subsys = &bus->subsys; kset_register(&bus->devices); - snprintf(bus->drivers.kobj.name,KOBJ_NAME_LEN,"drivers"); + strlcpy(bus->drivers.kobj.name, "drivers", KOBJ_NAME_LEN); bus->drivers.subsys = &bus->subsys; bus->drivers.ktype = &ktype_driver; kset_register(&bus->drivers); diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 2d8972537461..41e8a546252f 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -63,8 +63,8 @@ int sys_register_root(struct sys_root * root) error = device_register(&root->dev); if (!error) { - strncpy(root->sysdev.bus_id,"sys",BUS_ID_SIZE); - strncpy(root->sysdev.name,"System Bus",DEVICE_NAME_SIZE); + strlcpy(root->sysdev.bus_id,"sys",BUS_ID_SIZE); + strlcpy(root->sysdev.name,"System Bus",DEVICE_NAME_SIZE); root->sysdev.parent = &root->dev; error = device_register(&root->sysdev); }; diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index e86d60a4477d..f86304224663 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -721,7 +721,7 @@ pmac_find_ide_boot(char *bootdevice, int n) } } - return NODEV; + return 0; } void __init diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c index 8cdf0e65f9c6..945357b2c7c4 100644 --- a/drivers/isdn/capi/capifs.c +++ b/drivers/isdn/capi/capifs.c @@ -141,7 +141,7 @@ static int capifs_fill_super(struct super_block *s, void *data, int silent) } static struct super_block *capifs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_single(fs_type, flags, data, capifs_fill_super); } diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index d9009024ac53..f47a476620fb 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -42,6 +42,10 @@ #include <linux/adb.h> #include <linux/cuda.h> #include <linux/pmu.h> + +#include <asm/machdep.h> +#include <asm/pmac_feature.h> + #ifdef CONFIG_PMAC_BACKLIGHT #include <asm/backlight.h> #endif @@ -65,7 +69,7 @@ unsigned char adb_to_linux_keycodes[128] = { 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 98, 96, 0, 74, 0, 0,117, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73,183,181,124, 63, 64, 65, 61, 66, 67,191, 87,190, 99, 0, 70, 0, 68,101, 88, - 0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,116,116 + 0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,126,116 }; struct adbhid { @@ -84,7 +88,7 @@ static struct adbhid *adbhid[16] = { 0 }; static void adbhid_probe(void); -static void adbhid_input_keycode(int, int, int); +static void adbhid_input_keycode(int, int, int, struct pt_regs *); static void leds_done(struct adb_request *); static void init_trackpad(int id); @@ -140,7 +144,7 @@ adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apo } static void -adbhid_input_keycode(int id, int keycode, int repeat, pt_regs *regs) +adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs) { int up_flag; @@ -156,6 +160,15 @@ adbhid_input_keycode(int id, int keycode, int repeat, pt_regs *regs) return; case 0x3f: /* ignore Powerbook Fn key */ return; + case 0x7e: /* Power key on PBook 3400 needs remapping */ + switch(pmac_call_feature(PMAC_FTR_GET_MB_INFO, + NULL, PMAC_MB_INFO_MODEL, 0)) { + case PMAC_TYPE_COMET: + case PMAC_TYPE_HOOPER: + case PMAC_TYPE_KANGA: + keycode = 0x7f; + } + break; } if (adbhid[id]->keycode[keycode]) { @@ -343,13 +356,12 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto case 0xa: /* brightness decrease */ #ifdef CONFIG_PMAC_BACKLIGHT if (!disable_kernel_backlight) { - if (!down || backlight < 0) - break; - if (backlight > BACKLIGHT_OFF) - set_backlight_level(backlight-1); - else - set_backlight_level(BACKLIGHT_OFF); - break; + if (down && backlight >= 0) { + if (backlight > BACKLIGHT_OFF) + set_backlight_level(backlight-1); + else + set_backlight_level(BACKLIGHT_OFF); + } } #endif /* CONFIG_PMAC_BACKLIGHT */ input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSDOWN, down); @@ -358,13 +370,12 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto case 0x9: /* brightness increase */ #ifdef CONFIG_PMAC_BACKLIGHT if (!disable_kernel_backlight) { - if (!down || backlight < 0) - break; - if (backlight < BACKLIGHT_MAX) - set_backlight_level(backlight+1); - else - set_backlight_level(BACKLIGHT_MAX); - break; + if (down && backlight >= 0) { + if (backlight < BACKLIGHT_MAX) + set_backlight_level(backlight+1); + else + set_backlight_level(BACKLIGHT_MAX); + } } #endif /* CONFIG_PMAC_BACKLIGHT */ input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSUP, down); diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 3a77c6b81664..199bcfbdc1cd 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -671,7 +671,7 @@ static void arcnet_timeout(struct net_device *dev) * interrupts. Establish which device needs attention, and call the correct * chipset interrupt handler. */ -void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; struct arcnet_local *lp; @@ -696,7 +696,7 @@ void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) ACOMMAND(CFLAGScmd | RESETclear); AINTMASK(0); spin_unlock(&arcnet_lock); - return; + return IRQ_HANDLED; } BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n", @@ -864,6 +864,7 @@ void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) AINTMASK(lp->intmask); spin_unlock(&arcnet_lock); + return IRQ_RETVAL(didsomething); } diff --git a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h index aa58407de02d..188bd6e19a21 100644 --- a/drivers/net/e100/e100.h +++ b/drivers/net/e100/e100.h @@ -60,7 +60,14 @@ #include <linux/if_vlan.h> #include <linux/mii.h> -#define E100_REGS_LEN 1 +#define E100_CABLE_UNKNOWN 0 +#define E100_CABLE_OK 1 +#define E100_CABLE_OPEN_NEAR 2 /* Open Circuit Near End */ +#define E100_CABLE_OPEN_FAR 3 /* Open Circuit Far End */ +#define E100_CABLE_SHORT_NEAR 4 /* Short Circuit Near End */ +#define E100_CABLE_SHORT_FAR 5 /* Short Circuit Far End */ + +#define E100_REGS_LEN 2 /* * Configure parameters for buffers per controller. * If the machine this is being used on is a faster machine (i.e. > 150MHz) @@ -105,8 +112,6 @@ #define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in wait_cus_idle */ /* HWI feature related constant */ -#define HWI_MAX_LOOP 100 -#define MAX_SAME_RESULTS 3 #define HWI_REGISTER_GRANULARITY 80 /* register granularity = 80 Cm */ #define HWI_NEAR_END_BOUNDARY 1000 /* Near end is defined as < 10 meters */ @@ -942,7 +947,6 @@ struct e100_private { #ifdef CONFIG_PM u32 pci_state[16]; #endif - char ifname[IFNAMSIZ]; #ifdef E100_CU_DEBUG u8 last_cmd; u8 last_sub_cmd; @@ -956,7 +960,10 @@ struct e100_private { #define E100_SPEED_100_FULL 4 /********* function prototypes *************/ +extern int e100_open(struct net_device *); +extern int e100_close(struct net_device *); extern void e100_isolate_driver(struct e100_private *bdp); +extern unsigned char e100_hw_init(struct e100_private *); extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd); extern u8 e100_start_cu(struct e100_private *bdp, tcb_t *tcb); extern void e100_free_non_tx_cmd(struct e100_private *bdp, @@ -981,14 +988,13 @@ extern unsigned char e100_cu_unknown_state(struct e100_private *bdp); #define TEST_TIMEOUT 0x08 enum test_offsets { - E100_EEPROM_TEST_FAIL = 0, - E100_CHIP_TIMEOUT, - E100_ROM_TEST_FAIL, - E100_REG_TEST_FAIL, - E100_MAC_TEST_FAIL, - E100_LPBK_MAC_FAIL, - E100_LPBK_PHY_FAIL, - E100_MAX_TEST_RES + test_link, + test_eeprom, + test_self_test, + test_loopback_mac, + test_loopback_phy, + cable_diag, + max_test_res, /* must be last */ }; #endif diff --git a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c index 070c9fb9f0f4..4b503d7b50b8 100644 --- a/drivers/net/e100/e100_main.c +++ b/drivers/net/e100/e100_main.c @@ -46,6 +46,24 @@ /* Change Log * + * 2.3.13 05/08/03 + * o Feature remove: /proc/net/PRO_LAN_Adapters support gone completely + * o Feature remove: IDIAG support (use ethtool -t instead) + * o Cleanup: fixed spelling mistakes found by community + * o Feature add: ethtool cable diag test + * o Feature add: ethtool parameter support (ring size, xsum, flow ctrl) + * o Cleanup: move e100_asf_enable under CONFIG_PM to avoid warning + * [Stephen Rothwell (sfr@canb.auug.org.au)] + * o Bug fix: don't call any netif_carrier_* until netdev registered. + * [Andrew Morton (akpm@digeo.com)] + * o Cleanup: replace (skb->len - skb->data_len) with skb_headlen(skb) + * [jmorris@intercode.com.au] + * o Bug fix: cleanup of Tx skbs after running ethtool diags + * o Bug fix: incorrect reporting of ethtool diag overall results + * o Bug fix: must hold xmit_lock before stopping queue in ethtool + * operations that require reset h/w and driver structures. + * o Bug fix: statistic command failure would stop statistic collection. + * * 2.2.21 02/11/03 * o Removed marketing brand strings. Instead, Using generic string * "Intel(R) PRO/100 Network Connection" for all adapters. @@ -61,21 +79,6 @@ * o New feature: added ICH5 support * * 2.1.27 11/20/02 - * o Bug fix: Device command timeout due to SMBus processing during init - * o Bug fix: Not setting/clearing I (Interrupt) bit in tcb correctly - * o Bug fix: Not using EEPROM WoL setting as default in ethtool - * o Bug fix: Not able to set autoneg on using ethtool when interface down - * o Bug fix: Not able to change speed/duplex using ethtool/mii - * when interface up - * o Bug fix: Ethtool shows autoneg on when forced to 100/Full - * o Bug fix: Compiler error when CONFIG_PROC_FS not defined - * o Bug fix: 2.5.44 e100 doesn't load with preemptive kernel enabled - * (sleep while holding spinlock) - * o Bug fix: 2.1.24-k1 doesn't display complete statistics - * o Bug fix: System panic due to NULL watchdog timer dereference during - * ifconfig down, rmmod and insmod - * - * 2.1.24 10/7/02 */ #include <linux/config.h> @@ -121,14 +124,13 @@ extern void e100_config_wol(struct e100_private *bdp); extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags); static int e100_ethtool_test(struct net_device *, struct ifreq *); static int e100_ethtool_gstrings(struct net_device *, struct ifreq *); -static char *test_strings[] = { - "E100_EEPROM_TEST_FAIL", - "E100_CHIP_TIMEOUT", - "E100_ROM_TEST_FAIL", - "E100_REG_TEST_FAIL", - "E100_MAC_TEST_FAIL", - "E100_LPBK_MAC_FAIL", - "E100_LPBK_PHY_FAIL" +static char test_strings[][ETH_GSTRING_LEN] = { + "Link test (on/offline)", + "Eeprom test (on/offline)", + "Self test (offline)", + "Mac loopback (offline)", + "Phy loopback (offline)", + "Cable diagnostic (offline)" }; static int e100_ethtool_led_blink(struct net_device *, struct ifreq *); @@ -139,10 +141,10 @@ static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *, nxmit_cb_entry_t *); static void e100_free_nontx_list(struct e100_private *); static void e100_non_tx_background(unsigned long); - +static inline void e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb); /* Global Data structures and variables */ char e100_copyright[] __devinitdata = "Copyright (c) 2003 Intel Corporation"; -char e100_driver_version[]="2.2.21-k1"; +char e100_driver_version[]="2.3.13-k1"; const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver"; char e100_short_driver_name[] = "e100"; static int e100nics = 0; @@ -155,6 +157,7 @@ static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid); static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr); static int e100_suspend(struct pci_dev *pcid, u32 state); static int e100_resume(struct pci_dev *pcid); +static unsigned char e100_asf_enabled(struct e100_private *bdp); struct notifier_block e100_notifier_reboot = { .notifier_call = e100_notify_reboot, .next = NULL, @@ -182,8 +185,6 @@ struct notifier_block e100_notifier_reboot = { static u8 e100_D101M_checksum(struct e100_private *, struct sk_buff *); static u8 e100_D102_check_checksum(rfd_t *); static int e100_ioctl(struct net_device *, struct ifreq *, int); -static int e100_open(struct net_device *); -static int e100_close(struct net_device *); static int e100_change_mtu(struct net_device *, int); static int e100_xmit_frame(struct sk_buff *, struct net_device *); static unsigned char e100_init(struct e100_private *); @@ -193,7 +194,6 @@ struct net_device_stats *e100_get_stats(struct net_device *); static irqreturn_t e100intr(int, void *, struct pt_regs *); static void e100_print_brd_conf(struct e100_private *); static void e100_set_multi(struct net_device *); -void e100_set_speed_duplex(struct e100_private *); static u8 e100_pci_setup(struct pci_dev *, struct e100_private *); static u8 e100_sw_init(struct e100_private *); @@ -215,7 +215,6 @@ u16 e100_eeprom_calculate_chksum(struct e100_private *adapter); static unsigned char e100_clr_cntrs(struct e100_private *); static unsigned char e100_load_microcode(struct e100_private *); -static unsigned char e100_hw_init(struct e100_private *); static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *); static unsigned char e100_update_stats(struct e100_private *bdp); @@ -228,7 +227,6 @@ static void e100_set_bool_option(struct e100_private *bdp, int, u32, int, char *); unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8); void e100_exec_cmplx(struct e100_private *, u32, u8); -static unsigned char e100_asf_enabled(struct e100_private *bdp); /** * e100_get_rx_struct - retrieve cell to hold skb buff from the pool @@ -616,6 +614,10 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) goto err_dealloc; } + if ((rc = register_netdev(dev)) != 0) { + goto err_pci; + } + if (((bdp->pdev->device > 0x1030) && (bdp->pdev->device < 0x103F)) || ((bdp->pdev->device >= 0x1050) @@ -645,7 +647,7 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) printk(KERN_ERR "e100: Failed to initialize, instance #%d\n", e100nics); rc = -ENODEV; - goto err_pci; + goto err_unregister_netdev; } /* Check if checksum is valid */ @@ -655,7 +657,7 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n", e100nics); rc = -ENODEV; - goto err_pci; + goto err_unregister_netdev; } dev->vlan_rx_register = e100_vlan_rx_register; @@ -679,12 +681,6 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) e100_get_speed_duplex_caps(bdp); - if ((rc = register_netdev(dev)) != 0) { - goto err_pci; - } - memcpy(bdp->ifname, dev->name, IFNAMSIZ); - bdp->ifname[IFNAMSIZ-1] = 0; - printk(KERN_NOTICE "e100: %s: %s\n", bdp->device->name, "Intel(R) PRO/100 Network Connection"); @@ -709,6 +705,8 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) goto out; +err_unregister_netdev: + unregister_netdev(dev); err_pci: iounmap(bdp->scb); pci_release_regions(pcid); @@ -974,7 +972,7 @@ e100_set_bool_option(struct e100_private *bdp, int val, u32 mask, } } -static int +int e100_open(struct net_device *dev) { struct e100_private *bdp; @@ -1012,7 +1010,11 @@ e100_open(struct net_device *dev) mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); - netif_start_queue(dev); + if (dev->flags & IFF_UP) + /* Otherwise process may sleep forever */ + netif_wake_queue(dev); + else + netif_start_queue(dev); e100_start_ru(bdp); if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ, @@ -1033,7 +1035,7 @@ exit: return rc; } -static int +int e100_close(struct net_device *dev) { struct e100_private *bdp = dev->priv; @@ -1074,7 +1076,8 @@ e100_xmit_frame(struct sk_buff *skb, struct net_device *dev) goto exit2; } - if (!TCBS_AVAIL(bdp->tcb_pool) || + /* tcb list may be empty temporarily during releasing resources */ + if (!TCBS_AVAIL(bdp->tcb_pool) || (bdp->tcb_phys == 0) || (bdp->non_tx_command_state != E100_NON_TX_IDLE)) { notify_stop = true; rc = 1; @@ -1285,10 +1288,8 @@ e100_init(struct e100_private *bdp) /* read NIC's part number */ e100_rd_pwa_no(bdp); - if (!e100_hw_init(bdp)) { - printk(KERN_ERR "e100: hw init failed\n"); + if (!e100_hw_init(bdp)) return false; - } /* Interrupts are enabled after device reset */ e100_disable_clear_intr(bdp); @@ -1330,6 +1331,8 @@ e100_sw_init(struct e100_private *bdp) spin_lock_init(&(bdp->bd_non_tx_lock)); spin_lock_init(&(bdp->config_lock)); spin_lock_init(&(bdp->mdi_access_lock)); + /* Initialize configuration data */ + e100_config_init(bdp); return 1; } @@ -1384,11 +1387,11 @@ e100_tco_workaround(struct e100_private *bdp) * true - If the adapter was initialized * false - If the adapter failed initialization */ -unsigned char __devinit +unsigned char e100_hw_init(struct e100_private *bdp) { if (!e100_phy_init(bdp)) - return false; + goto err; e100_sw_reset(bdp, PORT_SELECTIVE_RESET); @@ -1398,27 +1401,25 @@ e100_hw_init(struct e100_private *bdp) /* Load the CU BASE (set to 0, because we use linear mode) */ if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) - return false; + goto err; if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) - return false; + goto err; /* Load interrupt microcode */ if (e100_load_microcode(bdp)) { bdp->flags |= DF_UCODE_LOADED; } - e100_config_init(bdp); - if (!e100_config(bdp)) { - return false; - } + if (!e100_config(bdp)) + goto err; if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) - return false; + goto err; /* Clear the internal counters */ if (!e100_clr_cntrs(bdp)) - return false; + goto err; /* Change for 82558 enhancement */ /* If 82558/9 and if the user has enabled flow control, set up the @@ -1431,6 +1432,9 @@ e100_hw_init(struct e100_private *bdp) } return true; +err: + printk(KERN_ERR "e100: hw init failed\n"); + return false; } /** @@ -1591,9 +1595,22 @@ e100_alloc_tcb_pool(struct e100_private *bdp) void e100_free_tcb_pool(struct e100_private *bdp) { + tcb_t *tcb; + int i; + /* Return tx skbs */ + for (i = 0; i < bdp->params.TxDescriptors; i++) { + tcb = bdp->tcb_pool.data; + tcb += bdp->tcb_pool.head; + e100_tx_skb_free(bdp, tcb); + if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail) + break; + bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head); + } pci_free_consistent(bdp->pdev, sizeof (tcb_t) * bdp->params.TxDescriptors, bdp->tcb_pool.data, bdp->tcb_phys); + bdp->tcb_pool.head = 0; + bdp->tcb_pool.tail = 1; bdp->tcb_phys = 0; } @@ -1747,12 +1764,10 @@ e100_watchdog(struct net_device *dev) e100_set_multi(dev); } } - - /* Update the statistics needed by the upper interface */ - /* This should be the last statistic related command - * as it's async. now */ - e100_dump_stats_cntrs(bdp); } + /* Issue command to dump statistics from device. */ + /* Check for command completion on next watchdog timer. */ + e100_dump_stats_cntrs(bdp); wmb(); @@ -2544,6 +2559,7 @@ e100_update_stats(struct e100_private *bdp) pcmd_complete = e100_cmd_complete_location(bdp); if (*pcmd_complete != le32_to_cpu(DUMP_RST_STAT_COMPLETED) && *pcmd_complete != le32_to_cpu(DUMP_STAT_COMPLETED)) { + *pcmd_complete = 0; return false; } @@ -3041,23 +3057,6 @@ e100_isolate_driver(struct e100_private *bdp) e100_sw_reset(bdp, PORT_SELECTIVE_RESET); } -void -e100_set_speed_duplex(struct e100_private *bdp) -{ - int carrier_ok; - /* Device may lose link with some siwtches when */ - /* changing speed/duplex to non-autoneg. e100 */ - /* needs to remember carrier state in order to */ - /* start watchdog timer for recovering link */ - if ((carrier_ok = netif_carrier_ok(bdp->device))) - e100_isolate_driver(bdp); - e100_phy_set_speed_duplex(bdp, true); - e100_config_fc(bdp); /* re-config flow-control if necessary */ - e100_config(bdp); - if (carrier_ok) - e100_deisolate_driver(bdp, false); -} - static void e100_tcb_add_C_bit(struct e100_private *bdp) { @@ -3213,6 +3212,144 @@ e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) case ETHTOOL_PHYS_ID: rc = e100_ethtool_led_blink(dev,ifr); break; +#ifdef ETHTOOL_GRINGPARAM + case ETHTOOL_GRINGPARAM: { + struct ethtool_ringparam ering; + struct e100_private *bdp = dev->priv; + memset((void *) &ering, 0, sizeof(ering)); + ering.rx_max_pending = E100_MAX_RFD; + ering.tx_max_pending = E100_MAX_TCB; + ering.rx_pending = bdp->params.RxDescriptors; + ering.tx_pending = bdp->params.TxDescriptors; + rc = copy_to_user(ifr->ifr_data, &ering, sizeof(ering)) + ? -EFAULT : 0; + return rc; + } +#endif +#ifdef ETHTOOL_SRINGPARAM + case ETHTOOL_SRINGPARAM: { + struct ethtool_ringparam ering; + struct e100_private *bdp = dev->priv; + if (copy_from_user(&ering, ifr->ifr_data, sizeof(ering))) + return -EFAULT; + if (ering.rx_pending > E100_MAX_RFD + || ering.rx_pending < E100_MIN_RFD) + return -EINVAL; + if (ering.tx_pending > E100_MAX_TCB + || ering.tx_pending < E100_MIN_TCB) + return -EINVAL; + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + /* Use new values to open interface */ + bdp->params.RxDescriptors = ering.rx_pending; + bdp->params.TxDescriptors = ering.tx_pending; + e100_hw_init(bdp); + e100_open(dev); + } + else { + bdp->params.RxDescriptors = ering.rx_pending; + bdp->params.TxDescriptors = ering.tx_pending; + } + return 0; + } +#endif +#ifdef ETHTOOL_GPAUSEPARAM + case ETHTOOL_GPAUSEPARAM: { + struct ethtool_pauseparam epause; + struct e100_private *bdp = dev->priv; + memset((void *) &epause, 0, sizeof(epause)); + if ((bdp->flags & IS_BACHELOR) + && (bdp->params.b_params & PRM_FC)) { + epause.autoneg = 1; + if (bdp->flags && DF_LINK_FC_CAP) { + epause.rx_pause = 1; + epause.tx_pause = 1; + } + if (bdp->flags && DF_LINK_FC_TX_ONLY) + epause.tx_pause = 1; + } + rc = copy_to_user(ifr->ifr_data, &epause, sizeof(epause)) + ? -EFAULT : 0; + return rc; + } +#endif +#ifdef ETHTOOL_SPAUSEPARAM + case ETHTOOL_SPAUSEPARAM: { + struct ethtool_pauseparam epause; + struct e100_private *bdp = dev->priv; + if (!(bdp->flags & IS_BACHELOR)) + return -EINVAL; + if (copy_from_user(&epause, ifr->ifr_data, sizeof(epause))) + return -EFAULT; + if (epause.autoneg == 1) + bdp->params.b_params |= PRM_FC; + else + bdp->params.b_params &= ~PRM_FC; + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + e100_hw_init(bdp); + e100_open(dev); + } + return 0; + } +#endif +#ifdef ETHTOOL_GRXCSUM + case ETHTOOL_GRXCSUM: + case ETHTOOL_GTXCSUM: + case ETHTOOL_GSG: + { struct ethtool_value eval; + struct e100_private *bdp = dev->priv; + memset((void *) &eval, 0, sizeof(eval)); + if ((ecmd.cmd == ETHTOOL_GRXCSUM) + && (bdp->params.b_params & PRM_XSUMRX)) + eval.data = 1; + else + eval.data = 0; + rc = copy_to_user(ifr->ifr_data, &eval, sizeof(eval)) + ? -EFAULT : 0; + return rc; + } +#endif +#ifdef ETHTOOL_SRXCSUM + case ETHTOOL_SRXCSUM: + case ETHTOOL_STXCSUM: + case ETHTOOL_SSG: + { struct ethtool_value eval; + struct e100_private *bdp = dev->priv; + if (copy_from_user(&eval, ifr->ifr_data, sizeof(eval))) + return -EFAULT; + if (ecmd.cmd == ETHTOOL_SRXCSUM) { + if (eval.data == 1) { + if (bdp->rev_id >= D101MA_REV_ID) + bdp->params.b_params |= PRM_XSUMRX; + else + return -EINVAL; + } else { + if (bdp->rev_id >= D101MA_REV_ID) + bdp->params.b_params &= ~PRM_XSUMRX; + else + return 0; + } + } else { + if (eval.data == 1) + return -EINVAL; + else + return 0; + } + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + e100_hw_init(bdp); + e100_open(dev); + } + return 0; + } +#endif default: break; } //switch @@ -3298,7 +3435,13 @@ e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr) if ((ecmd.autoneg == AUTONEG_ENABLE) && (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) { bdp->params.e100_speed_duplex = E100_AUTONEG; - e100_set_speed_duplex(bdp); + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + e100_hw_init(bdp); + e100_open(dev); + } } else { if (ecmd.speed == SPEED_10) { if (ecmd.duplex == DUPLEX_HALF) { @@ -3329,7 +3472,13 @@ e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr) if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) { bdp->params.e100_speed_duplex = e100_new_speed_duplex; - e100_set_speed_duplex(bdp); + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + e100_hw_init(bdp); + e100_open(dev); + } } else { return -EOPNOTSUPP; } @@ -3364,14 +3513,14 @@ e100_ethtool_test(struct net_device *dev, struct ifreq *ifr) struct ethtool_test *info; int rc = -EFAULT; - info = kmalloc(sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64), + info = kmalloc(sizeof(*info) + max_test_res * sizeof(u64), GFP_ATOMIC); if (!info) return -ENOMEM; memset((void *) info, 0, sizeof(*info) + - E100_MAX_TEST_RES * sizeof(u64)); + max_test_res * sizeof(u64)); if (copy_from_user(info, ifr->ifr_data, sizeof(*info))) goto exit; @@ -3379,7 +3528,7 @@ e100_ethtool_test(struct net_device *dev, struct ifreq *ifr) info->flags = e100_run_diag(dev, info->data, info->flags); if (!copy_to_user(ifr->ifr_data, info, - sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64))) + sizeof(*info) + max_test_res * sizeof(u64))) rc = 0; exit: kfree(info); @@ -3393,6 +3542,7 @@ e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr) u32 regs_buff[E100_REGS_LEN]; struct ethtool_regs regs = {ETHTOOL_GREGS}; void *addr = ifr->ifr_data; + u16 mdi_reg; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -3405,6 +3555,8 @@ e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr) regs_buff[0] = readb(&(bdp->scb->scb_cmd_hi)) << 24 | readb(&(bdp->scb->scb_cmd_low)) << 16 | readw(&(bdp->scb->scb_status)); + e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &mdi_reg); + regs_buff[1] = mdi_reg; if(copy_to_user(addr, ®s, sizeof(regs))) return -EFAULT; @@ -3428,7 +3580,13 @@ e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr) if ((bdp->speed_duplex_caps & SUPPORTED_Autoneg) && (bdp->params.e100_speed_duplex == E100_AUTONEG)) { - e100_set_speed_duplex(bdp); + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + e100_hw_init(bdp); + e100_open(dev); + } } else { return -EFAULT; } @@ -3454,7 +3612,7 @@ e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr) info.n_stats = E100_STATS_LEN; info.regdump_len = E100_REGS_LEN * sizeof(u32); info.eedump_len = (bdp->eeprom_size << 1); - info.testinfo_len = E100_MAX_TEST_RES; + info.testinfo_len = max_test_res; if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) return -EFAULT; @@ -3804,15 +3962,15 @@ static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr) switch (info.string_set) { case ETH_SS_TEST: { int ret = 0; - if (info.len > E100_MAX_TEST_RES) - info.len = E100_MAX_TEST_RES; + if (info.len > max_test_res) + info.len = max_test_res; strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC); if (!strings) return -ENOMEM; memset(strings, 0, info.len * ETH_GSTRING_LEN); for (i = 0; i < info.len; i++) { - sprintf(strings + i * ETH_GSTRING_LEN, "%-31s", + sprintf(strings + i * ETH_GSTRING_LEN, "%s", test_strings[i]); } if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) @@ -3881,7 +4039,13 @@ e100_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) bdp->params.e100_speed_duplex = E100_SPEED_10_FULL; else bdp->params.e100_speed_duplex = E100_SPEED_10_HALF; - e100_set_speed_duplex(bdp); + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + e100_hw_init(bdp); + e100_open(dev); + } } else /* Only allows changing speed/duplex */ @@ -4164,7 +4328,6 @@ e100_resume(struct pci_dev *pcid) return 0; } -#endif /* CONFIG_PM */ /** * e100_asf_enabled - checks if ASF is configured on the current adaper @@ -4190,6 +4353,7 @@ e100_asf_enabled(struct e100_private *bdp) } return false; } +#endif /* CONFIG_PM */ #ifdef E100_CU_DEBUG unsigned char diff --git a/drivers/net/e100/e100_phy.c b/drivers/net/e100/e100_phy.c index 08782934bdf6..e1473e816f1c 100644 --- a/drivers/net/e100/e100_phy.c +++ b/drivers/net/e100/e100_phy.c @@ -628,8 +628,6 @@ e100_force_speed_duplex(struct e100_private *bdp) u16 control; unsigned long expires; - e100_phy_reset(bdp); - bdp->flags |= DF_SPEED_FORCED; e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); @@ -912,6 +910,10 @@ e100_phy_reset(struct e100_private *bdp) u16 ctrl_reg; ctrl_reg = BMCR_RESET; e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); + /* ieee 802.3 : The reset process shall be completed */ + /* within 0.5 seconds from the settting of PHY reset bit. */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 2); } unsigned char __devinit @@ -928,6 +930,7 @@ e100_phy_init(struct e100_private *bdp) bdp->PhyDelay = 0; bdp->zlock_state = ZLOCK_INITIAL; + e100_phy_reset(bdp); e100_phy_set_speed_duplex(bdp, false); e100_fix_polarity(bdp); diff --git a/drivers/net/e100/e100_test.c b/drivers/net/e100/e100_test.c index 0ff7266ef8e2..208a92049f19 100644 --- a/drivers/net/e100/e100_test.c +++ b/drivers/net/e100/e100_test.c @@ -25,7 +25,7 @@ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ -#include "e100.h" +#include "e100_phy.h" #include "e100_config.h" extern u16 e100_eeprom_read(struct e100_private *, u16); @@ -46,6 +46,7 @@ static u8 e100_diag_loopback_alloc(struct e100_private *); static void e100_diag_loopback_cu_ru_exec(struct e100_private *); static u8 e100_diag_check_pkt(u8 *); static void e100_diag_loopback_free(struct e100_private *); +static int e100_cable_diag(struct e100_private *bdp); #define LB_PACKET_SIZE 1500 @@ -60,46 +61,52 @@ u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags) { struct e100_private* bdp = dev->priv; - u8 test_result = true; - - e100_isolate_driver(bdp); + u8 test_result = 0; + if (!e100_get_link_state(bdp)) { + test_result = ETH_TEST_FL_FAILED; + test_info[test_link] = true; + } + if (!e100_diag_eeprom(dev)) { + test_result = ETH_TEST_FL_FAILED; + test_info[test_eeprom] = true; + } if (flags & ETH_TEST_FL_OFFLINE) { u8 fail_mask; - - fail_mask = e100_diag_selftest(dev); - if (fail_mask) { - test_result = false; - if (fail_mask & REGISTER_TEST_FAIL) - test_info [E100_REG_TEST_FAIL] = true; - if (fail_mask & ROM_TEST_FAIL) - test_info [E100_ROM_TEST_FAIL] = true; - if (fail_mask & SELF_TEST_FAIL) - test_info [E100_MAC_TEST_FAIL] = true; - if (fail_mask & TEST_TIMEOUT) - test_info [E100_CHIP_TIMEOUT] = true; + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + } + if (e100_diag_selftest(dev)) { + test_result = ETH_TEST_FL_FAILED; + test_info[test_self_test] = true; } fail_mask = e100_diag_loopback(dev); if (fail_mask) { - test_result = false; + test_result = ETH_TEST_FL_FAILED; if (fail_mask & PHY_LOOPBACK) - test_info [E100_LPBK_PHY_FAIL] = true; + test_info[test_loopback_phy] = true; if (fail_mask & MAC_LOOPBACK) - test_info [E100_LPBK_MAC_FAIL] = true; + test_info[test_loopback_mac] = true; } - } - if (!e100_diag_eeprom(dev)) { - test_result = false; - test_info [E100_EEPROM_TEST_FAIL] = true; + test_info[cable_diag] = e100_cable_diag(bdp); + /* Need hw init regardless of netif_running */ + e100_hw_init(bdp); + if (netif_running(dev)) { + e100_open(dev); + } + } + else { + test_info[test_self_test] = false; + test_info[test_loopback_phy] = false; + test_info[test_loopback_mac] = false; + test_info[cable_diag] = false; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ * 2); - e100_deisolate_driver(bdp, false); - - return flags | (test_result ? 0 : ETH_TEST_FL_FAILED); + return flags | test_result; } /** @@ -126,8 +133,6 @@ e100_diag_selftest(struct net_device *dev) } } - e100_configure_device(bdp); - return retval; } @@ -165,14 +170,14 @@ e100_diag_loopback (struct net_device *dev) u8 rc = 0; printk(KERN_DEBUG "%s: PHY loopback test starts\n", dev->name); - e100_sw_reset(dev->priv, PORT_SELECTIVE_RESET); + e100_hw_init(dev->priv); if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) { rc |= PHY_LOOPBACK; } printk(KERN_DEBUG "%s: PHY loopback test ends\n", dev->name); printk(KERN_DEBUG "%s: MAC loopback test starts\n", dev->name); - e100_sw_reset(dev->priv, PORT_SELECTIVE_RESET); + e100_hw_init(dev->priv); if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) { rc |= MAC_LOOPBACK; } @@ -257,15 +262,10 @@ e100_diag_config_loopback(struct e100_private* bdp, if (set_loopback) /* Set PHY loopback mode */ e100_phy_set_loopback(bdp); - else { /* Back to normal speed and duplex */ - if (bdp->params.e100_speed_duplex == E100_AUTONEG) - /* Reset PHY and do autoneg */ - e100_phy_autoneg(bdp); - else - /* Reset PHY and force speed and duplex */ - e100_force_speed_duplex(bdp); - } - /* Wait for PHY state change */ + else + /* Reset PHY loopback mode */ + e100_phy_reset(bdp); + /* Wait for PHY state change */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ); } else { /* For MAC loopback wait 500 msec to take effect */ @@ -348,10 +348,6 @@ static void e100_diag_loopback_cu_ru_exec(struct e100_private *bdp) { /*load CU & RU base */ - if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) - printk(KERN_ERR "e100: SCB_CUC_LOAD_BASE failed\n"); - if(!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) - printk(KERN_ERR "e100: SCB_RUC_LOAD_BASE failed!\n"); if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START, 0)) printk(KERN_ERR "e100: SCB_RUC_START failed!\n"); @@ -433,3 +429,72 @@ e100_diag_loopback_free (struct e100_private *bdp) bdp->loopback.dma_handle); } +static int +e100_cable_diag(struct e100_private *bdp) +{ + int saved_open_circut = 0xffff; + int saved_short_circut = 0xffff; + int saved_distance = 0xffff; + int saved_same = 0; + int cable_status = E100_CABLE_UNKNOWN; + int i; + + /* If we have link, */ + if (e100_get_link_state(bdp)) + return E100_CABLE_OK; + + if (bdp->rev_id < D102_REV_ID) + return E100_CABLE_UNKNOWN; + + /* Disable MDI/MDI-X auto switching */ + e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, + MDI_MDIX_RESET_ALL_MASK); + /* Set to 100 Full as required by cable test */ + e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, + BMCR_SPEED100 | BMCR_FULLDPLX); + + /* Test up to 100 times */ + for (i = 0; i < 100; i++) { + u16 ctrl_reg; + int distance, open_circut, short_circut, near_end; + + /* Enable and execute cable test */ + e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, + (HWI_TEST_ENABLE | HWI_TEST_EXECUTE)); + /* Wait for cable test finished */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/100 + 1); + /* Read results */ + e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg); + distance = ctrl_reg & HWI_TEST_DISTANCE; + open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM; + short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM; + + if ((distance == saved_distance) && + (open_circut == saved_open_circut) && + (short_circut == saved_short_circut)) + saved_same++; + else { + saved_same = 0; + saved_distance = distance; + saved_open_circut = open_circut; + saved_short_circut = short_circut; + } + /* If results are the same 3 times */ + if (saved_same == 3) { + near_end = ((distance * HWI_REGISTER_GRANULARITY) < + HWI_NEAR_END_BOUNDARY); + if (open_circut) + cable_status = (near_end) ? + E100_CABLE_OPEN_NEAR : E100_CABLE_OPEN_FAR; + if (short_circut) + cable_status = (near_end) ? + E100_CABLE_SHORT_NEAR : E100_CABLE_SHORT_FAR; + break; + } + } + /* Reset cable test */ + e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, HWI_RESET_ALL_MASK); + return cable_status; +} + diff --git a/drivers/net/e1000/Makefile b/drivers/net/e1000/Makefile index 898c6a3a2c09..ca9f89552da3 100644 --- a/drivers/net/e1000/Makefile +++ b/drivers/net/e1000/Makefile @@ -1,7 +1,7 @@ ################################################################################ # # -# Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. +# Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 307a2b1b22ad..8891f273269e 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -134,6 +134,7 @@ struct e1000_buffer { uint64_t dma; unsigned long length; unsigned long time_stamp; + unsigned int next_to_watch; }; struct e1000_desc_ring { @@ -169,7 +170,6 @@ struct e1000_adapter { struct timer_list watchdog_timer; struct timer_list phy_info_timer; struct vlan_group *vlgrp; - char *id_string; uint32_t bd_number; uint32_t rx_buffer_len; uint32_t part_num; @@ -218,6 +218,9 @@ struct e1000_adapter { struct e1000_phy_info phy_info; struct e1000_phy_stats phy_stats; + uint32_t test_icr; + struct e1000_desc_ring test_tx_ring; + struct e1000_desc_ring test_rx_ring; uint32_t pci_state[16]; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index c64530107467..43b60a55ed58 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -40,15 +40,60 @@ extern void e1000_down(struct e1000_adapter *adapter); extern void e1000_reset(struct e1000_adapter *adapter); extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); -static char e1000_gstrings_stats[][ETH_GSTRING_LEN] = { - "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", - "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", - "rx_length_errors", "rx_over_errors", "rx_crc_errors", - "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", - "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", - "tx_heartbeat_errors", "tx_window_errors", +struct e1000_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; }; -#define E1000_STATS_LEN sizeof(e1000_gstrings_stats) / ETH_GSTRING_LEN + +#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \ + offsetof(struct e1000_adapter, m) +static struct e1000_stats e1000_gstrings_stats[] = { + { "rx_packets", E1000_STAT(net_stats.rx_packets) }, + { "tx_packets", E1000_STAT(net_stats.tx_packets) }, + { "rx_bytes", E1000_STAT(net_stats.rx_bytes) }, + { "tx_bytes", E1000_STAT(net_stats.tx_bytes) }, + { "rx_errors", E1000_STAT(net_stats.rx_errors) }, + { "tx_errors", E1000_STAT(net_stats.tx_errors) }, + { "rx_dropped", E1000_STAT(net_stats.rx_dropped) }, + { "tx_dropped", E1000_STAT(net_stats.tx_dropped) }, + { "multicast", E1000_STAT(net_stats.multicast) }, + { "collisions", E1000_STAT(net_stats.collisions) }, + { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) }, + { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) }, + { "rx_crc_errors", E1000_STAT(net_stats.rx_crc_errors) }, + { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) }, + { "rx_fifo_errors", E1000_STAT(net_stats.rx_fifo_errors) }, + { "rx_missed_errors", E1000_STAT(net_stats.rx_missed_errors) }, + { "tx_aborted_errors", E1000_STAT(net_stats.tx_aborted_errors) }, + { "tx_carrier_errors", E1000_STAT(net_stats.tx_carrier_errors) }, + { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) }, + { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) }, + { "tx_window_errors", E1000_STAT(net_stats.tx_window_errors) }, + { "tx_abort_late_coll", E1000_STAT(stats.latecol) }, + { "tx_deferred_ok", E1000_STAT(stats.dc) }, + { "tx_single_coll_ok", E1000_STAT(stats.scc) }, + { "tx_multi_coll_ok", E1000_STAT(stats.mcc) }, + { "rx_long_length_errors", E1000_STAT(stats.roc) }, + { "rx_short_length_errors", E1000_STAT(stats.ruc) }, + { "rx_align_errors", E1000_STAT(stats.algnerrc) }, + { "tx_tcp_seg_good", E1000_STAT(stats.tsctc) }, + { "tx_tcp_seg_failed", E1000_STAT(stats.tsctfc) }, + { "rx_flow_control_xon", E1000_STAT(stats.xonrxc) }, + { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) }, + { "tx_flow_control_xon", E1000_STAT(stats.xontxc) }, + { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, + { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, + { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) } +}; +#define E1000_STATS_LEN \ + sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) +static char e1000_gstrings_test[][ETH_GSTRING_LEN] = { + "Register test (offline)", "Eeprom test (offline)", + "Interrupt test (offline)", "Loopback test (offline)", + "Link test (on/offline)" +}; +#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN static void e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd) @@ -154,6 +199,7 @@ e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter, strncpy(drvinfo->fw_version, "N/A", 32); strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32); drvinfo->n_stats = E1000_STATS_LEN; + drvinfo->testinfo_len = E1000_TEST_LEN; #define E1000_REGS_LEN 32 drvinfo->regdump_len = E1000_REGS_LEN * sizeof(uint32_t); drvinfo->eedump_len = adapter->hw.eeprom.word_size * 2; @@ -164,6 +210,7 @@ e1000_ethtool_gregs(struct e1000_adapter *adapter, struct ethtool_regs *regs, uint32_t *regs_buff) { struct e1000_hw *hw = &adapter->hw; + uint16_t phy_data; regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id; @@ -182,6 +229,62 @@ e1000_ethtool_gregs(struct e1000_adapter *adapter, regs_buff[10] = E1000_READ_REG(hw, TDT); regs_buff[11] = E1000_READ_REG(hw, TIDV); + regs_buff[12] = adapter->hw.phy_type; /* PHY type (IGP=1, M88=0) */ + if(hw->phy_type == e1000_phy_igp) { + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + IGP01E1000_PHY_AGC_A); + e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_A & + IGP01E1000_PHY_PAGE_SELECT, &phy_data); + regs_buff[13] = (uint32_t)phy_data; /* cable length */ + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + IGP01E1000_PHY_AGC_B); + e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_B & + IGP01E1000_PHY_PAGE_SELECT, &phy_data); + regs_buff[14] = (uint32_t)phy_data; /* cable length */ + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + IGP01E1000_PHY_AGC_C); + e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_C & + IGP01E1000_PHY_PAGE_SELECT, &phy_data); + regs_buff[15] = (uint32_t)phy_data; /* cable length */ + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + IGP01E1000_PHY_AGC_D); + e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_D & + IGP01E1000_PHY_PAGE_SELECT, &phy_data); + regs_buff[16] = (uint32_t)phy_data; /* cable length */ + regs_buff[17] = 0; /* extended 10bt distance (not needed) */ + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0); + e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS & + IGP01E1000_PHY_PAGE_SELECT, &phy_data); + regs_buff[18] = (uint32_t)phy_data; /* cable polarity */ + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + IGP01E1000_PHY_PCS_INIT_REG); + e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG & + IGP01E1000_PHY_PAGE_SELECT, &phy_data); + regs_buff[19] = (uint32_t)phy_data; /* cable polarity */ + regs_buff[20] = 0; /* polarity correction enabled (always) */ + regs_buff[22] = 0; /* phy receive errors (unavailable) */ + regs_buff[23] = regs_buff[18]; /* mdix mode */ + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0); + } else { + e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); + regs_buff[13] = (uint32_t)phy_data; /* cable length */ + regs_buff[14] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[15] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[16] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + regs_buff[17] = (uint32_t)phy_data; /* extended 10bt distance */ + regs_buff[18] = regs_buff[13]; /* cable polarity */ + regs_buff[19] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[20] = regs_buff[17]; /* polarity correction */ + /* phy receive errors */ + regs_buff[22] = adapter->phy_stats.receive_errors; + regs_buff[23] = regs_buff[13]; /* mdix mode */ + } + regs_buff[21] = adapter->phy_stats.idle_errors; /* phy idle errors */ + e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data); + regs_buff[24] = (uint32_t)phy_data; /* phy local receiver status */ + regs_buff[25] = regs_buff[24]; /* phy remote receiver status */ + return; } @@ -219,7 +322,7 @@ e1000_ethtool_geeprom(struct e1000_adapter *adapter, uint16_t i; for (i = 0; i < last_word - first_word + 1; i++) if((ret_val = e1000_read_eeprom(hw, first_word + i, 1, - &eeprom_buff[i]))) + &eeprom_buff[i]))) break; } geeprom_error: @@ -249,7 +352,7 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter, first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; eeprom_buff = kmalloc(max_len, GFP_KERNEL); - if(eeprom_buff == NULL) + if(!eeprom_buff) return -ENOMEM; ptr = (void *)eeprom_buff; @@ -284,6 +387,765 @@ seeprom_error: return ret_val; } +#define REG_PATTERN_TEST(R, M, W) \ +{ \ + uint32_t pat, value; \ + uint32_t test[] = \ + {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ + for(pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \ + E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \ + value = E1000_READ_REG(&adapter->hw, R); \ + if(value != (test[pat] & W & M)) { \ + *data = (adapter->hw.mac_type < e1000_82543) ? \ + E1000_82542_##R : E1000_##R; \ + return 1; \ + } \ + } \ +} + +#define REG_SET_AND_CHECK(R, M, W) \ +{ \ + uint32_t value; \ + E1000_WRITE_REG(&adapter->hw, R, W & M); \ + value = E1000_READ_REG(&adapter->hw, R); \ + if ((W & M) != (value & M)) { \ + *data = (adapter->hw.mac_type < e1000_82543) ? \ + E1000_82542_##R : E1000_##R; \ + return 1; \ + } \ +} + +static int +e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) +{ + uint32_t value; + uint32_t i; + + /* The status register is Read Only, so a write should fail. + * Some bits that get toggled are ignored. + */ + value = (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833)); + E1000_WRITE_REG(&adapter->hw, STATUS, (0xFFFFFFFF)); + if(value != (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833))) { + *data = 1; + return 1; + } + + REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(FCT, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(VET, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(RDTR, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(RDBAH, 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(RDLEN, 0x000FFF80, 0x000FFFFF); + REG_PATTERN_TEST(RDH, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(RDT, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(FCRTH, 0x0000FFF8, 0x0000FFF8); + REG_PATTERN_TEST(FCTTV, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(TIPG, 0x3FFFFFFF, 0x3FFFFFFF); + REG_PATTERN_TEST(TDBAH, 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(TDLEN, 0x000FFF80, 0x000FFFFF); + + REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x00000000); + REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0x003FFFFB); + REG_SET_AND_CHECK(TCTL, 0xFFFFFFFF, 0x00000000); + + if(adapter->hw.mac_type >= e1000_82543) { + + REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0xFFFFFFFF); + REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF); + REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(TDBAL, 0xFFFFFFF0, 0xFFFFFFFF); + REG_PATTERN_TEST(TIDV, 0x0000FFFF, 0x0000FFFF); + + for(i = 0; i < E1000_RAR_ENTRIES; i++) { + REG_PATTERN_TEST(RA + ((i << 1) << 2), 0xFFFFFFFF, + 0xFFFFFFFF); + REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF, + 0xFFFFFFFF); + } + + } else { + + REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x01FFFFFF); + REG_PATTERN_TEST(RDBAL, 0xFFFFF000, 0xFFFFFFFF); + REG_PATTERN_TEST(TXCW, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(TDBAL, 0xFFFFF000, 0xFFFFFFFF); + + } + + for(i = 0; i < E1000_MC_TBL_SIZE; i++) + REG_PATTERN_TEST(MTA + (i << 2), 0xFFFFFFFF, 0xFFFFFFFF); + + return 0; +} + +static int +e1000_eeprom_test(struct e1000_adapter *adapter, uint64_t *data) +{ + uint16_t temp; + uint16_t checksum = 0; + uint16_t i; + + *data = 0; + /* Read and add up the contents of the EEPROM */ + for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { + if((e1000_read_eeprom(&adapter->hw, i, 1, &temp)) < 0) { + *data = 1; + break; + } + checksum += temp; + } + + /* If Checksum is not Correct return error else test passed */ + if((checksum != (uint16_t) EEPROM_SUM) && !(*data)) + *data = 2; + + return *data; +} + +static irqreturn_t +e1000_test_intr(int irq, + void *data, + struct pt_regs *regs) +{ + struct net_device *netdev = (struct net_device *) data; + struct e1000_adapter *adapter = netdev->priv; + + adapter->test_icr |= E1000_READ_REG(&adapter->hw, ICR); + + return IRQ_HANDLED; +} + +static int +e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) +{ + struct net_device *netdev = adapter->netdev; + uint32_t icr, mask, i=0; + + *data = 0; + + /* Hook up test interrupt handler just for this test */ + if(request_irq + (netdev->irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)) { + *data = 1; + return -1; + } + + /* Disable all the interrupts */ + E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF); + msec_delay(10); + + /* Interrupts are disabled, so read interrupt cause + * register (icr) twice to verify that there are no interrupts + * pending. icr is clear on read. + */ + icr = E1000_READ_REG(&adapter->hw, ICR); + icr = E1000_READ_REG(&adapter->hw, ICR); + + if(icr != 0) { + /* if icr is non-zero, there is no point + * running other interrupt tests. + */ + *data = 2; + i = 10; + } + + /* Test each interrupt */ + for(; i < 10; i++) { + + /* Interrupt to test */ + mask = 1 << i; + + /* Disable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + E1000_WRITE_REG(&adapter->hw, IMC, mask); + E1000_WRITE_REG(&adapter->hw, ICS, mask); + msec_delay(10); + + if(adapter->test_icr & mask) { + *data = 3; + break; + } + + /* Enable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was not posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + E1000_WRITE_REG(&adapter->hw, IMS, mask); + E1000_WRITE_REG(&adapter->hw, ICS, mask); + msec_delay(10); + + if(!(adapter->test_icr & mask)) { + *data = 4; + break; + } + + /* Disable the other interrupts to be reported in + * the cause register and then force the other + * interrupts and see if any get posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + E1000_WRITE_REG(&adapter->hw, IMC, ~mask); + E1000_WRITE_REG(&adapter->hw, ICS, ~mask); + msec_delay(10); + + if(adapter->test_icr) { + *data = 5; + break; + } + } + + /* Disable all the interrupts */ + E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF); + msec_delay(10); + + /* Unhook test interrupt handler */ + free_irq(netdev->irq, netdev); + + return *data; +} + +static void +e1000_free_desc_rings(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *txdr = &adapter->test_tx_ring; + struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + int i; + + if(txdr->desc && txdr->buffer_info) { + for(i = 0; i < txdr->count; i++) { + if(txdr->buffer_info[i].dma) + pci_unmap_single(pdev, txdr->buffer_info[i].dma, + txdr->buffer_info[i].length, + PCI_DMA_TODEVICE); + if(txdr->buffer_info[i].skb) + dev_kfree_skb(txdr->buffer_info[i].skb); + } + } + + if(rxdr->desc && rxdr->buffer_info) { + for(i = 0; i < rxdr->count; i++) { + if(rxdr->buffer_info[i].dma) + pci_unmap_single(pdev, rxdr->buffer_info[i].dma, + rxdr->buffer_info[i].length, + PCI_DMA_FROMDEVICE); + if(rxdr->buffer_info[i].skb) + dev_kfree_skb(rxdr->buffer_info[i].skb); + } + } + + if(txdr->desc) + pci_free_consistent(pdev, txdr->size, txdr->desc, txdr->dma); + if(rxdr->desc) + pci_free_consistent(pdev, rxdr->size, rxdr->desc, rxdr->dma); + + if(txdr->buffer_info) + kfree(txdr->buffer_info); + if(rxdr->buffer_info) + kfree(rxdr->buffer_info); + + return; +} + +static int +e1000_setup_desc_rings(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *txdr = &adapter->test_tx_ring; + struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + uint32_t rctl; + int size, i, ret_val; + + /* Setup Tx descriptor ring and Tx buffers */ + + txdr->count = 80; + + size = txdr->count * sizeof(struct e1000_buffer); + if(!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) { + ret_val = 1; + goto err_nomem; + } + memset(txdr->buffer_info, 0, size); + + txdr->size = txdr->count * sizeof(struct e1000_tx_desc); + E1000_ROUNDUP(txdr->size, 4096); + if(!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) { + ret_val = 2; + goto err_nomem; + } + memset(txdr->desc, 0, txdr->size); + txdr->next_to_use = txdr->next_to_clean = 0; + + E1000_WRITE_REG(&adapter->hw, TDBAL, + ((uint64_t) txdr->dma & 0x00000000FFFFFFFF)); + E1000_WRITE_REG(&adapter->hw, TDBAH, ((uint64_t) txdr->dma >> 32)); + E1000_WRITE_REG(&adapter->hw, TDLEN, + txdr->count * sizeof(struct e1000_tx_desc)); + E1000_WRITE_REG(&adapter->hw, TDH, 0); + E1000_WRITE_REG(&adapter->hw, TDT, 0); + E1000_WRITE_REG(&adapter->hw, TCTL, + E1000_TCTL_PSP | E1000_TCTL_EN | + E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT | + E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT); + + for(i = 0; i < txdr->count; i++) { + struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*txdr, i); + struct sk_buff *skb; + unsigned int size = 1024; + + if(!(skb = alloc_skb(size, GFP_KERNEL))) { + ret_val = 3; + goto err_nomem; + } + skb_put(skb, size); + txdr->buffer_info[i].skb = skb; + txdr->buffer_info[i].length = skb->len; + txdr->buffer_info[i].dma = + pci_map_single(pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + tx_desc->buffer_addr = cpu_to_le64(txdr->buffer_info[i].dma); + tx_desc->lower.data = cpu_to_le32(skb->len); + tx_desc->lower.data |= E1000_TXD_CMD_EOP; + tx_desc->lower.data |= E1000_TXD_CMD_IFCS; + tx_desc->lower.data |= E1000_TXD_CMD_RPS; + tx_desc->upper.data = 0; + } + + /* Setup Rx descriptor ring and Rx buffers */ + + rxdr->count = 80; + + size = rxdr->count * sizeof(struct e1000_buffer); + if(!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) { + ret_val = 4; + goto err_nomem; + } + memset(rxdr->buffer_info, 0, size); + + rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc); + if(!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) { + ret_val = 5; + goto err_nomem; + } + memset(rxdr->desc, 0, rxdr->size); + rxdr->next_to_use = rxdr->next_to_clean = 0; + + rctl = E1000_READ_REG(&adapter->hw, RCTL); + E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN); + E1000_WRITE_REG(&adapter->hw, RDBAL, + ((uint64_t) rxdr->dma & 0xFFFFFFFF)); + E1000_WRITE_REG(&adapter->hw, RDBAH, ((uint64_t) rxdr->dma >> 32)); + E1000_WRITE_REG(&adapter->hw, RDLEN, rxdr->size); + E1000_WRITE_REG(&adapter->hw, RDH, 0); + E1000_WRITE_REG(&adapter->hw, RDT, 0); + rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | + E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT); + E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + + for(i = 0; i < rxdr->count; i++) { + struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rxdr, i); + struct sk_buff *skb; + + if(!(skb = alloc_skb(E1000_RXBUFFER_2048 + 2, GFP_KERNEL))) { + ret_val = 6; + goto err_nomem; + } + skb_reserve(skb, 2); + rxdr->buffer_info[i].skb = skb; + rxdr->buffer_info[i].length = E1000_RXBUFFER_2048; + rxdr->buffer_info[i].dma = + pci_map_single(pdev, skb->data, E1000_RXBUFFER_2048, + PCI_DMA_FROMDEVICE); + rx_desc->buffer_addr = cpu_to_le64(rxdr->buffer_info[i].dma); + memset(skb->data, 0x00, skb->len); + } + + return 0; + + err_nomem: + e1000_free_desc_rings(adapter); + return ret_val; +} + +static void +e1000_phy_disable_receiver(struct e1000_adapter *adapter) +{ + /* Write out to PHY registers 29 and 30 to disable the Receiver. */ + e1000_write_phy_reg(&adapter->hw, 29, 0x001F); + e1000_write_phy_reg(&adapter->hw, 30, 0x8FFC); + e1000_write_phy_reg(&adapter->hw, 29, 0x001A); + e1000_write_phy_reg(&adapter->hw, 30, 0x8FF0); + + return; +} + +static void +e1000_phy_reset_clk_and_crs(struct e1000_adapter *adapter) +{ + uint16_t phy_reg; + + /* Because we reset the PHY above, we need to re-force TX_CLK in the + * Extended PHY Specific Control Register to 25MHz clock. This + * value defaults back to a 2.5MHz clock when the PHY is reset. + */ + e1000_read_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg); + phy_reg |= M88E1000_EPSCR_TX_CLK_25; + e1000_write_phy_reg(&adapter->hw, + M88E1000_EXT_PHY_SPEC_CTRL, phy_reg); + + /* In addition, because of the s/w reset above, we need to enable + * CRS on TX. This must be set for both full and half duplex + * operation. + */ + e1000_read_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, &phy_reg); + phy_reg |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + e1000_write_phy_reg(&adapter->hw, + M88E1000_PHY_SPEC_CTRL, phy_reg); +} + +static int +e1000_nonintegrated_phy_loopback(struct e1000_adapter *adapter) +{ + uint32_t ctrl_reg; + uint16_t phy_reg; + + /* Setup the Device Control Register for PHY loopback test. */ + + ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL); + ctrl_reg |= (E1000_CTRL_ILOS | /* Invert Loss-Of-Signal */ + E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ + E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ + E1000_CTRL_SPD_1000 | /* Force Speed to 1000 */ + E1000_CTRL_FD); /* Force Duplex to FULL */ + + E1000_WRITE_REG(&adapter->hw, CTRL, ctrl_reg); + + /* Read the PHY Specific Control Register (0x10) */ + e1000_read_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, &phy_reg); + + /* Clear Auto-Crossover bits in PHY Specific Control Register + * (bits 6:5). + */ + phy_reg &= ~M88E1000_PSCR_AUTO_X_MODE; + e1000_write_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, phy_reg); + + /* Perform software reset on the PHY */ + e1000_phy_reset(&adapter->hw); + + /* Have to setup TX_CLK and TX_CRS after software reset */ + e1000_phy_reset_clk_and_crs(adapter); + + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8100); + + /* Wait for reset to complete. */ + udelay(500); + + /* Have to setup TX_CLK and TX_CRS after software reset */ + e1000_phy_reset_clk_and_crs(adapter); + + /* Write out to PHY registers 29 and 30 to disable the Receiver. */ + e1000_phy_disable_receiver(adapter); + + /* Set the loopback bit in the PHY control register. */ + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg); + phy_reg |= MII_CR_LOOPBACK; + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg); + + /* Setup TX_CLK and TX_CRS one more time. */ + e1000_phy_reset_clk_and_crs(adapter); + + /* Check Phy Configuration */ + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg); + if(phy_reg != 0x4100) + return 9; + + e1000_read_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg); + if(phy_reg != 0x0070) + return 10; + + e1000_read_phy_reg(&adapter->hw, 29, &phy_reg); + if(phy_reg != 0x001A) + return 11; + + return 0; +} + +static int +e1000_integrated_phy_loopback(struct e1000_adapter *adapter) +{ + uint32_t ctrl_reg = 0; + uint32_t stat_reg = 0; + + adapter->hw.autoneg = FALSE; + + if(adapter->hw.phy_type == e1000_phy_m88) { + /* Auto-MDI/MDIX Off */ + e1000_write_phy_reg(&adapter->hw, + M88E1000_PHY_SPEC_CTRL, 0x0808); + /* reset to update Auto-MDI/MDIX */ + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x9140); + /* autoneg off */ + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8140); + } + /* force 1000, set loopback */ + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140); + + /* Now set up the MAC to the same speed/duplex as the PHY. */ + ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL); + ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ + ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ + E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ + E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */ + E1000_CTRL_FD); /* Force Duplex to FULL */ + + if(adapter->hw.media_type == e1000_media_type_copper && + adapter->hw.phy_type == e1000_phy_m88) { + ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ + } else { + /* Set the ILOS bit on the fiber Nic is half + * duplex link is detected. */ + stat_reg = E1000_READ_REG(&adapter->hw, STATUS); + if((stat_reg & E1000_STATUS_FD) == 0) + ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); + } + + E1000_WRITE_REG(&adapter->hw, CTRL, ctrl_reg); + + /* Disable the receiver on the PHY so when a cable is plugged in, the + * PHY does not begin to autoneg when a cable is reconnected to the NIC. + */ + if(adapter->hw.phy_type == e1000_phy_m88) + e1000_phy_disable_receiver(adapter); + + udelay(500); + + return 0; +} + +static int +e1000_set_phy_loopback(struct e1000_adapter *adapter) +{ + uint16_t phy_reg = 0; + uint16_t count = 0; + + switch (adapter->hw.mac_type) { + case e1000_82543: + if(adapter->hw.media_type == e1000_media_type_copper) { + /* Attempt to setup Loopback mode on Non-integrated PHY. + * Some PHY registers get corrupted at random, so + * attempt this 10 times. + */ + while(e1000_nonintegrated_phy_loopback(adapter) && + count++ < 10); + if(count < 11) + return 0; + } + break; + + case e1000_82544: + case e1000_82540: + case e1000_82545: + case e1000_82546: + case e1000_82541: + case e1000_82547: + return e1000_integrated_phy_loopback(adapter); + break; + + default: + /* Default PHY loopback work is to read the MII + * control register and assert bit 14 (loopback mode). + */ + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg); + phy_reg |= MII_CR_LOOPBACK; + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg); + return 0; + break; + } + + return 8; +} + +static int +e1000_setup_loopback_test(struct e1000_adapter *adapter) +{ + uint32_t rctl; + + if(adapter->hw.media_type == e1000_media_type_fiber) { + if(adapter->hw.mac_type == e1000_82545 || + adapter->hw.mac_type == e1000_82546) + return e1000_set_phy_loopback(adapter); + else { + rctl = E1000_READ_REG(&adapter->hw, RCTL); + rctl |= E1000_RCTL_LBM_TCVR; + E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + return 0; + } + } else if(adapter->hw.media_type == e1000_media_type_copper) + return e1000_set_phy_loopback(adapter); + + return 7; +} + +static void +e1000_loopback_cleanup(struct e1000_adapter *adapter) +{ + uint32_t rctl; + uint16_t phy_reg; + + rctl = E1000_READ_REG(&adapter->hw, RCTL); + rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); + E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + + if(adapter->hw.media_type == e1000_media_type_copper || + (adapter->hw.media_type == e1000_media_type_fiber && + (adapter->hw.mac_type == e1000_82545 || + adapter->hw.mac_type == e1000_82546))) { + adapter->hw.autoneg = TRUE; + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg); + if(phy_reg & MII_CR_LOOPBACK) { + phy_reg &= ~MII_CR_LOOPBACK; + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg); + e1000_phy_reset(&adapter->hw); + } + } +} + +static void +e1000_create_lbtest_frame(struct sk_buff *skb, unsigned int frame_size) +{ + memset(skb->data, 0xFF, frame_size); + frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size; + memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1); + memset(&skb->data[frame_size / 2 + 10], 0xBE, 1); + memset(&skb->data[frame_size / 2 + 12], 0xAF, 1); +} + +static int +e1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size) +{ + frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size; + if(*(skb->data + 3) == 0xFF) { + if((*(skb->data + frame_size / 2 + 10) == 0xBE) && + (*(skb->data + frame_size / 2 + 12) == 0xAF)) { + return 0; + } + } + return 13; +} + +static int +e1000_run_loopback_test(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *txdr = &adapter->test_tx_ring; + struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + int i; + + E1000_WRITE_REG(&adapter->hw, RDT, rxdr->count - 1); + + for(i = 0; i < 64; i++) { + e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 1024); + pci_dma_sync_single(pdev, txdr->buffer_info[i].dma, + txdr->buffer_info[i].length, + PCI_DMA_TODEVICE); + } + E1000_WRITE_REG(&adapter->hw, TDT, i); + + msec_delay(200); + + pci_dma_sync_single(pdev, rxdr->buffer_info[0].dma, + rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE); + + return e1000_check_lbtest_frame(rxdr->buffer_info[0].skb, 1024); +} + +static int +e1000_loopback_test(struct e1000_adapter *adapter, uint64_t *data) +{ + if((*data = e1000_setup_desc_rings(adapter))) goto err_loopback; + if((*data = e1000_setup_loopback_test(adapter))) goto err_loopback; + *data = e1000_run_loopback_test(adapter); + e1000_loopback_cleanup(adapter); + e1000_free_desc_rings(adapter); +err_loopback: + return *data; +} + +static int +e1000_link_test(struct e1000_adapter *adapter, uint64_t *data) +{ + *data = 0; + e1000_check_for_link(&adapter->hw); + + if(!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) { + *data = 1; + } + return *data; +} + +static int +e1000_ethtool_test(struct e1000_adapter *adapter, + struct ethtool_test *eth_test, uint64_t *data) +{ + boolean_t if_running = netif_running(adapter->netdev); + + if(eth_test->flags == ETH_TEST_FL_OFFLINE) { + /* Offline tests */ + + /* Link test performed before hardware reset so autoneg doesn't + * interfere with test result */ + if(e1000_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + if(if_running) + e1000_down(adapter); + + e1000_reset(adapter); + if(e1000_reg_test(adapter, &data[0])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000_reset(adapter); + if(e1000_eeprom_test(adapter, &data[1])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000_reset(adapter); + if(e1000_intr_test(adapter, &data[2])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000_reset(adapter); + if(e1000_loopback_test(adapter, &data[3])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000_reset(adapter); + if(if_running) + e1000_up(adapter); + } else { + /* Online tests */ + if(e1000_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* Offline tests aren't run; pass by default */ + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + } + return 0; +} + static void e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol) { @@ -443,24 +1305,46 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr) case ETHTOOL_GSTRINGS: { struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS }; char *strings = NULL; + int err = 0; if(copy_from_user(&gstrings, addr, sizeof(gstrings))) return -EFAULT; switch(gstrings.string_set) { - case ETH_SS_STATS: + case ETH_SS_TEST: + gstrings.len = E1000_TEST_LEN; + strings = kmalloc(E1000_TEST_LEN * ETH_GSTRING_LEN, + GFP_KERNEL); + if(!strings) + return -ENOMEM; + memcpy(strings, e1000_gstrings_test, E1000_TEST_LEN * + ETH_GSTRING_LEN); + break; + case ETH_SS_STATS: { + int i; gstrings.len = E1000_STATS_LEN; - strings = *e1000_gstrings_stats; + strings = kmalloc(E1000_STATS_LEN * ETH_GSTRING_LEN, + GFP_KERNEL); + if(!strings) + return -ENOMEM; + for(i=0; i < E1000_STATS_LEN; i++) { + memcpy(&strings[i * ETH_GSTRING_LEN], + e1000_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + } break; + } default: return -EOPNOTSUPP; } if(copy_to_user(addr, &gstrings, sizeof(gstrings))) - return -EFAULT; + err = -EFAULT; addr += offsetof(struct ethtool_gstrings, data); - if(copy_to_user(addr, strings, + if(!err && copy_to_user(addr, strings, gstrings.len * ETH_GSTRING_LEN)) - return -EFAULT; - return 0; + err = -EFAULT; + + kfree(strings); + return err; } case ETHTOOL_GREGS: { struct ethtool_regs regs = {ETHTOOL_GREGS}; @@ -522,16 +1406,14 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr) void *ptr; int err = 0; + if(copy_from_user(&eeprom, addr, sizeof(eeprom))) + return -EFAULT; + eeprom_buff = kmalloc(hw->eeprom.word_size * 2, GFP_KERNEL); - if(eeprom_buff == NULL) + if(!eeprom_buff) return -ENOMEM; - if(copy_from_user(&eeprom, addr, sizeof(eeprom))) { - err = -EFAULT; - goto err_geeprom_ioctl; - } - if((err = e1000_ethtool_geeprom(adapter, &eeprom, eeprom_buff))) goto err_geeprom_ioctl; @@ -565,18 +1447,45 @@ err_geeprom_ioctl: } case ETHTOOL_GSTATS: { struct { - struct ethtool_stats cmd; + struct ethtool_stats eth_stats; uint64_t data[E1000_STATS_LEN]; } stats = { {ETHTOOL_GSTATS, E1000_STATS_LEN} }; int i; for(i = 0; i < E1000_STATS_LEN; i++) - stats.data[i] = - ((unsigned long *)&adapter->net_stats)[i]; + stats.data[i] = (e1000_gstrings_stats[i].sizeof_stat == + sizeof(uint64_t)) ? + *(uint64_t *)((char *)adapter + + e1000_gstrings_stats[i].stat_offset) : + *(uint32_t *)((char *)adapter + + e1000_gstrings_stats[i].stat_offset); if(copy_to_user(addr, &stats, sizeof(stats))) return -EFAULT; return 0; } + case ETHTOOL_TEST: { + struct { + struct ethtool_test eth_test; + uint64_t data[E1000_TEST_LEN]; + } test = { {ETHTOOL_TEST} }; + int err; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + if(copy_from_user(&test.eth_test, addr, sizeof(test.eth_test))) + return -EFAULT; + + test.eth_test.len = E1000_TEST_LEN; + + if((err = e1000_ethtool_test(adapter, &test.eth_test, + test.data))) + return err; + + if(copy_to_user(addr, &test, sizeof(test)) != 0) + return -EFAULT; + return 0; + } default: return -EOPNOTSUPP; } diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 3527e7794635..539533515e20 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -185,6 +185,7 @@ e1000_set_mac_type(struct e1000_hw *hw) break; case E1000_DEV_ID_82546EB_COPPER: case E1000_DEV_ID_82546EB_FIBER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: hw->mac_type = e1000_82546; break; case E1000_DEV_ID_82541EI: @@ -288,9 +289,7 @@ e1000_reset_hw(struct e1000_hw *hw) /* Configure activity LED after PHY reset */ led_ctrl = E1000_READ_REG(hw, LEDCTL); led_ctrl &= IGP_ACTIVITY_LED_MASK; - led_ctrl |= IGP_ACTIVITY_LED_ENABLE; - if(hw->mac_type == e1000_82547) - led_ctrl |= IGP_LED3_MODE; + led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); E1000_WRITE_REG(hw, LEDCTL, led_ctrl); } @@ -737,9 +736,7 @@ e1000_setup_copper_link(struct e1000_hw *hw) /* Configure activity LED after PHY reset */ led_ctrl = E1000_READ_REG(hw, LEDCTL); led_ctrl &= IGP_ACTIVITY_LED_MASK; - led_ctrl |= IGP_ACTIVITY_LED_ENABLE; - if(hw->mac_type == e1000_82547) - led_ctrl |= IGP_LED3_MODE; + led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); E1000_WRITE_REG(hw, LEDCTL, led_ctrl); if(hw->autoneg_advertised == ADVERTISE_1000_FULL) { @@ -2293,9 +2290,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw) /* Configure activity LED after PHY reset */ led_ctrl = E1000_READ_REG(hw, LEDCTL); led_ctrl &= IGP_ACTIVITY_LED_MASK; - led_ctrl |= IGP_ACTIVITY_LED_ENABLE; - if(hw->mac_type == e1000_82547) - led_ctrl |= IGP_LED3_MODE; + led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); E1000_WRITE_REG(hw, LEDCTL, led_ctrl); } } @@ -3801,6 +3796,7 @@ e1000_setup_led(struct e1000_hw *hw) case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: case E1000_DEV_ID_82541EI: case E1000_DEV_ID_82541EP: case E1000_DEV_ID_82547EI: @@ -3842,6 +3838,7 @@ e1000_cleanup_led(struct e1000_hw *hw) case E1000_DEV_ID_82545EM_FIBER: case E1000_DEV_ID_82546EB_COPPER: case E1000_DEV_ID_82546EB_FIBER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: case E1000_DEV_ID_82541EI: case E1000_DEV_ID_82541EP: case E1000_DEV_ID_82547EI: @@ -3896,6 +3893,7 @@ e1000_led_on(struct e1000_hw *hw) case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: case E1000_DEV_ID_82541EI: case E1000_DEV_ID_82541EP: case E1000_DEV_ID_82547EI: @@ -3949,6 +3947,7 @@ e1000_led_off(struct e1000_hw *hw) case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: case E1000_DEV_ID_82541EI: case E1000_DEV_ID_82541EP: case E1000_DEV_ID_82547EI: @@ -4206,7 +4205,11 @@ e1000_get_bus_info(struct e1000_hw *hw) status = E1000_READ_REG(hw, STATUS); hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ? e1000_bus_type_pcix : e1000_bus_type_pci; - if(hw->bus_type == e1000_bus_type_pci) { + + if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) { + hw->bus_speed = (hw->bus_type == e1000_bus_type_pci) ? + e1000_bus_speed_66 : e1000_bus_speed_120; + } else if(hw->bus_type == e1000_bus_type_pci) { hw->bus_speed = (status & E1000_STATUS_PCI66) ? e1000_bus_speed_66 : e1000_bus_speed_33; } else { diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 3fe0febaa7e7..bfb91bc5d8a2 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -99,6 +99,7 @@ typedef enum { e1000_bus_speed_33, e1000_bus_speed_66, e1000_bus_speed_100, + e1000_bus_speed_120, e1000_bus_speed_133, e1000_bus_speed_reserved } e1000_bus_speed; @@ -314,10 +315,11 @@ void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value); #define E1000_DEV_ID_82545EM_FIBER 0x1011 #define E1000_DEV_ID_82546EB_COPPER 0x1010 #define E1000_DEV_ID_82546EB_FIBER 0x1012 +#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D #define E1000_DEV_ID_82541EI 0x1013 #define E1000_DEV_ID_82541EP 0x1018 #define E1000_DEV_ID_82547EI 0x1019 -#define NUM_DEV_IDS 19 +#define NUM_DEV_IDS 20 #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -601,7 +603,7 @@ struct e1000_ffvt_entry { #define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ #define E1000_EERD 0x00014 /* EEPROM Read - RW */ #define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ -#define E1000_FLA 0x0001C /* Flash Access Register - RW */ +#define E1000_FLA 0x0001C /* Flash Access - RW */ #define E1000_MDIC 0x00020 /* MDI Control - RW */ #define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ #define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ @@ -730,6 +732,7 @@ struct e1000_ffvt_entry { * the registers function in the same manner. */ #define E1000_82542_CTRL E1000_CTRL +#define E1000_82542_CTRL_DUP E1000_CTRL_DUP #define E1000_82542_STATUS E1000_STATUS #define E1000_82542_EECD E1000_EECD #define E1000_82542_EERD E1000_EERD @@ -1485,7 +1488,6 @@ struct e1000_hw { #define E1000_COLLISION_DISTANCE 64 #define E1000_FDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE #define E1000_HDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE -#define E1000_GB_HDX_COLLISION_DISTANCE 512 #define E1000_COLD_SHIFT 12 /* The number of Transmit and Receive Descriptors must be a multiple of 8 */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 86f15dbb0a21..377596f3f443 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -30,7 +30,14 @@ /* Change Log * - * 5.0.43 3/5/03 + * 5.1.11 5/6/03 + * o Feature: Added support for 82546EB (Quad-port) hardware. + * o Feature: Added support for Diagnostics through Ethtool. + * o Cleanup: Removed /proc support. + * o Cleanup: Removed proprietary IDIAG interface. + * o Bug fix: TSO bug fixes. + * + * 5.0.42 3/5/03 * o Feature: Added support for 82541 and 82547 hardware. * o Feature: Added support for Intel Gigabit PHY (IGP) and a variety of * eeproms. @@ -46,51 +53,22 @@ * shared interrupt instances. * * 4.4.18 11/27/02 - * o Feature: Added user-settable knob for interrupt throttle rate (ITR). - * o Cleanup: removed large static array allocations. - * o Cleanup: C99 struct initializer format. - * o Bug fix: restore VLAN settings when interface is brought up. - * o Bug fix: return cleanly in probe if error in detecting MAC type. - * o Bug fix: Wake up on magic packet by default only if enabled in eeprom. - * o Bug fix: Validate MAC address in set_mac. - * o Bug fix: Throw away zero-length Tx skbs. - * o Bug fix: Make ethtool EEPROM acceses work on older versions of ethtool. - * - * 4.4.12 10/15/02 */ char e1000_driver_name[] = "e1000"; char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -char e1000_driver_version[] = "5.0.43-k3"; +char e1000_driver_version[] = "5.1.11-k1"; char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table * - * Private driver_data field (last one) stores an index into e1000_strings * Wildcard entries (PCI_ANY_ID) should come last * Last entry must be all 0s * * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, - * Class, Class Mask, String Index } + * Class, Class Mask, private data (not used) } */ static struct pci_device_id e1000_pci_tbl[] __devinitdata = { - /* Intel(R) PRO/1000 Network Connection */ - {0x8086, 0x1000, 0x8086, 0x1000, 0, 0, 0}, - {0x8086, 0x1001, 0x8086, 0x1003, 0, 0, 0}, - {0x8086, 0x1004, 0x8086, 0x1004, 0, 0, 0}, - {0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0}, - {0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0}, - {0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0}, - {0x8086, 0x100E, 0x8086, 0x001E, 0, 0, 0}, - /* Compaq Gigabit Ethernet Server Adapter */ - {0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1}, - {0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1}, - {0x8086, 0x1004, 0x0E11, PCI_ANY_ID, 0, 0, 1}, - /* IBM Mobile, Desktop & Server Adapters */ - {0x8086, 0x1000, 0x1014, PCI_ANY_ID, 0, 0, 2}, - {0x8086, 0x1001, 0x1014, PCI_ANY_ID, 0, 0, 2}, - {0x8086, 0x1004, 0x1014, PCI_ANY_ID, 0, 0, 2}, - /* Generic */ {0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -106,6 +84,7 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = { {0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* required last entry */ @@ -114,12 +93,6 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = { MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); -static char *e1000_strings[] = { - "Intel(R) PRO/1000 Network Connection", - "HP Gigabit Ethernet Server Adapter", - "IBM Mobile, Desktop & Server Adapters" -}; - /* Local Function Prototypes */ int e1000_up(struct e1000_adapter *adapter); @@ -130,7 +103,7 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); static int e1000_init_module(void); static void e1000_exit_module(void); static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent); -static void e1000_remove(struct pci_dev *pdev); +static void __devexit e1000_remove(struct pci_dev *pdev); static int e1000_sw_init(struct e1000_adapter *adapter); static int e1000_open(struct net_device *netdev); static int e1000_close(struct net_device *netdev); @@ -195,7 +168,6 @@ struct notifier_block e1000_notifier_reboot = { .priority = 0 }; - /* Exported from other modules */ extern void e1000_check_options(struct e1000_adapter *adapter); @@ -234,8 +206,9 @@ e1000_init_module(void) printk(KERN_INFO "%s\n", e1000_copyright); ret = pci_module_init(&e1000_driver); - if(ret >= 0) + if(ret >= 0) { register_reboot_notifier(&e1000_notifier_reboot); + } return ret; } @@ -439,7 +412,6 @@ e1000_probe(struct pci_dev *pdev, netdev->base_addr = adapter->hw.io_base; adapter->bd_number = cards_found; - adapter->id_string = e1000_strings[ent->driver_data]; /* setup the private structure */ @@ -500,15 +472,14 @@ e1000_probe(struct pci_dev *pdev, (void (*)(void *))e1000_tx_timeout_task, netdev); register_netdev(netdev); - memcpy(adapter->ifname, netdev->name, IFNAMSIZ); - adapter->ifname[IFNAMSIZ-1] = 0; /* we're going to reset, so assume we have no link for now */ netif_carrier_off(netdev); netif_stop_queue(netdev); - printk(KERN_INFO "%s: %s\n", netdev->name, adapter->id_string); + printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Connection\n", + netdev->name); e1000_check_options(adapter); /* Initial Wake on LAN setting @@ -568,7 +539,6 @@ e1000_remove(struct pci_dev *pdev) e1000_phy_hw_reset(&adapter->hw); - iounmap(adapter->hw.hw_addr); pci_release_regions(pdev); @@ -831,8 +801,9 @@ e1000_configure_tx(struct e1000_adapter *adapter) e1000_config_collision_dist(&adapter->hw); - /* Setup Transmit Descriptor Settings for this adapter */ - adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_IDE; + /* Setup Transmit Descriptor Settings for eop descriptor */ + adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP | + E1000_TXD_CMD_IFCS; if(adapter->hw.report_tx_early == 1) adapter->txd_cmd |= E1000_TXD_CMD_RS; @@ -1435,7 +1406,7 @@ e1000_watchdog(unsigned long data) #define E1000_TX_FLAGS_VLAN_SHIFT 16 static inline boolean_t -e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags) +e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) { #ifdef NETIF_F_TSO struct e1000_context_desc *context_desc; @@ -1471,7 +1442,7 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags) context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse); context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss); context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; - context_desc->cmd_and_length = cpu_to_le32(adapter->txd_cmd | + context_desc->cmd_and_length = cpu_to_le32( E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP | (skb->len - (hdr_len))); @@ -1504,8 +1475,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) context_desc->upper_setup.tcp_fields.tucso = cso; context_desc->upper_setup.tcp_fields.tucse = 0; context_desc->tcp_seg_setup.data = 0; - context_desc->cmd_and_length = - cpu_to_le32(adapter->txd_cmd | E1000_TXD_CMD_DEXT); + context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); if(++i == adapter->tx_ring.count) i = 0; adapter->tx_ring.next_to_use = i; @@ -1520,7 +1490,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) #define E1000_MAX_DATA_PER_TXD (1<<E1000_MAX_TXD_PWR) static inline int -e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb) +e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, + unsigned int first) { struct e1000_desc_ring *tx_ring = &adapter->tx_ring; int len = skb->len, offset = 0, size, count = 0, i; @@ -1588,6 +1559,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb) } if(--i < 0) i = tx_ring->count - 1; tx_ring->buffer_info[i].skb = skb; + tx_ring->buffer_info[first].next_to_watch = i; return count; } @@ -1597,12 +1569,9 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) { struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct e1000_tx_desc *tx_desc = NULL; - uint32_t txd_upper, txd_lower; + uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; int i; - txd_upper = 0; - txd_lower = adapter->txd_cmd; - if(tx_flags & E1000_TX_FLAGS_TSO) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | E1000_TXD_CMD_TSE; @@ -1630,7 +1599,7 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) if(++i == tx_ring->count) i = 0; } - tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP); + tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd); /* Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only @@ -1690,6 +1659,7 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct e1000_adapter *adapter = netdev->priv; + unsigned int first; int tx_flags = 0; if(skb->len <= 0) { @@ -1715,12 +1685,14 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); } - if(e1000_tso(adapter, skb, tx_flags)) + first = adapter->tx_ring.next_to_use; + + if(e1000_tso(adapter, skb)) tx_flags |= E1000_TX_FLAGS_TSO; else if(e1000_tx_csum(adapter, skb)) tx_flags |= E1000_TX_FLAGS_CSUM; - e1000_tx_queue(adapter, e1000_tx_map(adapter, skb), tx_flags); + e1000_tx_queue(adapter, e1000_tx_map(adapter, skb, first), tx_flags); netdev->trans_start = jiffies; @@ -1952,6 +1924,7 @@ e1000_update_stats(struct e1000_adapter *adapter) } if((hw->mac_type <= e1000_82546) && + (hw->phy_type == e1000_phy_m88) && !e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp)) adapter->phy_stats.receive_errors += phy_tmp; } @@ -2069,39 +2042,47 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; - struct e1000_tx_desc *tx_desc; - int i, cleaned = FALSE; + struct e1000_tx_desc *tx_desc, *eop_desc; + struct e1000_buffer *buffer_info; + int i, eop, cleaned = FALSE; i = tx_ring->next_to_clean; - tx_desc = E1000_TX_DESC(*tx_ring, i); + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC(*tx_ring, eop); - while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { + while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { - cleaned = TRUE; + for(cleaned = FALSE; !cleaned; ) { + tx_desc = E1000_TX_DESC(*tx_ring, i); + buffer_info = &tx_ring->buffer_info[i]; - if(tx_ring->buffer_info[i].dma) { + if(buffer_info->dma) { - pci_unmap_page(pdev, - tx_ring->buffer_info[i].dma, - tx_ring->buffer_info[i].length, - PCI_DMA_TODEVICE); + pci_unmap_page(pdev, + buffer_info->dma, + buffer_info->length, + PCI_DMA_TODEVICE); - tx_ring->buffer_info[i].dma = 0; - } + buffer_info->dma = 0; + } - if(tx_ring->buffer_info[i].skb) { + if(buffer_info->skb) { - dev_kfree_skb_any(tx_ring->buffer_info[i].skb); + dev_kfree_skb_any(buffer_info->skb); - tx_ring->buffer_info[i].skb = NULL; - } + buffer_info->skb = NULL; + } - tx_desc->buffer_addr = 0; - tx_desc->lower.data = 0; - tx_desc->upper.data = 0; + tx_desc->buffer_addr = 0; + tx_desc->lower.data = 0; + tx_desc->upper.data = 0; - if(++i == tx_ring->count) i = 0; - tx_desc = E1000_TX_DESC(*tx_ring, i); + cleaned = (i == eop); + if(++i == tx_ring->count) i = 0; + } + + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC(*tx_ring, eop); } tx_ring->next_to_clean = i; @@ -2224,7 +2205,6 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) netif_rx(skb); } #endif /* CONFIG_E1000_NAPI */ - netdev->last_rx = jiffies; rx_desc->status = 0; @@ -2677,7 +2657,6 @@ e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) return NOTIFY_DONE; } - static int e1000_suspend(struct pci_dev *pdev, uint32_t state) { diff --git a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c index ded48bef9f82..7ce83879b811 100644 --- a/drivers/net/fc/iph5526.c +++ b/drivers/net/fc/iph5526.c @@ -134,7 +134,7 @@ clone_list[] __initdata = { {0,} }; -static void tachyon_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t tachyon_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs); static int initialize_register_pointers(struct fc_info *fi); @@ -623,7 +623,7 @@ u_int bus_addr, bus_indx_addr, i; } -static void tachyon_interrupt(int irq, void* dev_id, struct pt_regs* regs) +static irqreturn_t tachyon_interrupt(int irq, void* dev_id, struct pt_regs* regs) { struct Scsi_Host *host = dev_id; struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata; @@ -632,6 +632,7 @@ u_long flags; spin_lock_irqsave(&fi->fc_lock, flags); tachyon_interrupt_handler(irq, dev_id, regs); spin_unlock_irqrestore(&fi->fc_lock, flags); + return IRQ_HANDLED; } static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs) @@ -3720,12 +3721,13 @@ struct fc_info *fi = (struct fc_info*)dev->priv; int iph5526_detect(Scsi_Host_Template *tmpt) { -struct Scsi_Host *host = NULL; -struct iph5526_hostdata *hostdata; -struct fc_info *fi = NULL; -int no_of_hosts = 0, timeout, i, j, count = 0; -u_int pci_maddr = 0; -struct pci_dev *pdev = NULL; + struct Scsi_Host *host = NULL; + struct iph5526_hostdata *hostdata; + struct fc_info *fi = NULL; + int no_of_hosts = 0, i, j, count = 0; + u_int pci_maddr = 0; + struct pci_dev *pdev = NULL; + unsigned long timeout; tmpt->proc_name = "iph5526"; if (pci_present() == 0) { diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 539e9d434d10..47ce93a052f2 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -188,7 +188,7 @@ struct fec_enet_private { static int fec_enet_open(struct net_device *dev); static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); static void fec_enet_mii(struct net_device *dev); -static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); +static irqreturn_t fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); static void fec_enet_tx(struct net_device *dev); static void fec_enet_rx(struct net_device *dev); static int fec_enet_close(struct net_device *dev); @@ -393,12 +393,13 @@ fec_timeout(struct net_device *dev) /* The interrupt handler. * This is called from the MPC core interrupt. */ -static void +static irqreturn_t fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; volatile fec_t *fecp; uint int_events; + int handled = 0; fecp = (volatile fec_t*)dev->base_addr; @@ -413,20 +414,27 @@ fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) /* Handle receive event in its own function. */ - if (int_events & FEC_ENET_RXF) + if (int_events & FEC_ENET_RXF) { + handled = 1; fec_enet_rx(dev); + } /* Transmit OK, or non-fatal error. Update the buffer descriptors. FEC handles all errors, we just discover them as part of the transmit process. */ - if (int_events & FEC_ENET_TXF) + if (int_events & FEC_ENET_TXF) { + handled = 1; fec_enet_tx(dev); + } - if (int_events & FEC_ENET_MII) + if (int_events & FEC_ENET_MII) { + handled = 1; fec_enet_mii(dev); + } } + return IRQ_RETVAL(handled); } diff --git a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c index 1e79b90e3718..be537a80fce7 100644 --- a/drivers/net/fmv18x.c +++ b/drivers/net/fmv18x.c @@ -114,7 +114,7 @@ extern int fmv18x_probe(struct net_device *dev); static int fmv18x_probe1(struct net_device *dev, short ioaddr); static int net_open(struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev); -static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void net_rx(struct net_device *dev); static void net_timeout(struct net_device *dev); static int net_close(struct net_device *dev); @@ -423,7 +423,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) /* The typical workload of the driver: Handle the network interface interrupts. */ -static void +static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; @@ -476,7 +476,7 @@ net_interrupt(int irq, void *dev_id, struct pt_regs *regs) spin_unlock(&lp->lock); } } - return; + return IRQ_RETVAL(status); } /* We have a good packet(s), get it/them out of the buffers. */ diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 538e35c128e8..1c5de989caaf 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -199,7 +199,7 @@ static void z8530_init(void); static void init_channel(struct scc_channel *scc); static void scc_key_trx (struct scc_channel *scc, char tx); -static void scc_isr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs); static void scc_init_timer(struct scc_channel *scc); static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev); @@ -625,7 +625,7 @@ static void scc_isr_dispatch(struct scc_channel *scc, int vector) #define SCC_IRQTIMEOUT 30000 -static void scc_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs) { unsigned char vector; struct scc_channel *scc; @@ -653,7 +653,7 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs *regs) if (k == SCC_IRQTIMEOUT) printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n"); - return; + return IRQ_HANDLED; } /* Find the SCC generating the interrupt by polling all attached SCCs @@ -701,6 +701,7 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs *regs) } else ctrl++; } + return IRQ_HANDLED; } diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index 379a7f6b3b6a..dfcb2e5dab44 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -289,16 +289,29 @@ config TOSHIBA_FIR <file:Documentation/modules.txt>. The module will be called donauboe. -config SMC_IRCC_FIR - tristate "SMC IrCC (EXPERIMENTAL)" +config SMC_IRCC_OLD + tristate "SMC IrCC (old driver) (EXPERIMENTAL)" depends on EXPERIMENTAL && IRDA help Say Y here if you want to build support for the SMC Infrared Communications Controller. It is used in the Fujitsu Lifebook 635t - and Sony PCG-505TX. If you want to compile it as a module, say M - here and read <file:Documentation/modules.txt>. The module will be + and Sony PCG-505TX. This driver is obsolete, will no more be + maintained and will be removed in favor of the new driver. + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called smc-ircc. +config SMC_IRCC_FIR + tristate "SMSC IrCC (EXPERIMENTAL)" + depends on EXPERIMENTAL && IRDA + help + Say Y here if you want to build support for the SMC Infrared + Communications Controller. It is used in a wide variety of + laptops (Fujitsu, Sony, Compaq and some Toshiba). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be + called smsc-ircc2.o. + config ALI_FIR tristate "ALi M5123 FIR (EXPERIMENTAL)" depends on EXPERIMENTAL && IRDA diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 4d31d2b3c95c..fa89bee5c77b 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -15,13 +15,14 @@ obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o obj-$(CONFIG_SA1100_FIR) += sa1100_ir.o obj-$(CONFIG_TOSHIBA_OLD) += toshoboe.o obj-$(CONFIG_TOSHIBA_FIR) += donauboe.o -obj-$(CONFIG_SMC_IRCC_FIR) += smc-ircc.o irport.o +obj-$(CONFIG_SMC_IRCC_OLD) += smc-ircc.o irport.o +obj-$(CONFIG_SMC_IRCC_FIR) += smsc-ircc2.o obj-$(CONFIG_ALI_FIR) += ali-ircc.o obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o # Old dongle drivers for old SIR drivers -obj-$(CONFIG_ESI_OLD) += esi.o -obj-$(CONFIG_TEKRAM_OLD) += tekram.o -obj-$(CONFIG_ACTISYS_OLD) += actisys.o +obj-$(CONFIG_ESI_DONGLE_OLD) += esi.o +obj-$(CONFIG_TEKRAM_DONGLE_OLD) += tekram.o +obj-$(CONFIG_ACTISYS_DONGLE_OLD) += actisys.o obj-$(CONFIG_GIRBIL_DONGLE) += girbil.o obj-$(CONFIG_LITELINK_DONGLE) += litelink.o obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin.o diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 46223bbbb7c3..15a81f7b3775 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -1451,6 +1451,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) /* Check for empty frame */ if (!skb->len) { ali_ircc_change_speed(self, speed); + dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0; @@ -1560,6 +1561,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) /* Restore bank register */ switch_bank(iobase, BANK0); + dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); @@ -1974,6 +1976,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) /* Check for empty frame */ if (!skb->len) { ali_ircc_change_speed(self, speed); + dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0; @@ -1993,6 +1996,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) /* Turn on transmit finished interrupt. Will fire immediately! */ outb(UART_IER_THRI, iobase+UART_IER); + dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 185035d28b17..25d510e5deb3 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -1051,7 +1051,9 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) toshoboe_checkstuck (self); - /* Check if we need to change the speed */ + dev->trans_start = jiffies; + + /* Check if we need to change the speed */ /* But not now. Wait after transmission if mtt not required */ speed=irda_get_next_speed(skb); if ((speed != self->io.speed) && (speed != -1)) diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index 310e7ead2f4a..e0d26d1b5cd5 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c @@ -11,6 +11,7 @@ * Sources: serial.c by Linus Torvalds * * Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes, All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -48,6 +49,7 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/spinlock.h> +#include <linux/delay.h> #include <linux/rtnetlink.h> #include <asm/system.h> @@ -72,14 +74,14 @@ static unsigned int qos_mtt_bits = 0x03; static struct irport_cb *dev_self[] = { NULL, NULL, NULL, NULL}; static char *driver_name = "irport"; -static void irport_write_wakeup(struct irport_cb *self); -static int irport_write(int iobase, int fifo_size, __u8 *buf, int len); -static void irport_receive(struct irport_cb *self); +static inline void irport_write_wakeup(struct irport_cb *self); +static inline int irport_write(int iobase, int fifo_size, __u8 *buf, int len); +static inline void irport_receive(struct irport_cb *self); static int irport_net_init(struct net_device *dev); static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static int irport_is_receiving(struct irport_cb *self); +static inline int irport_is_receiving(struct irport_cb *self); static int irport_set_dtr_rts(struct net_device *dev, int dtr, int rts); static int irport_raw_write(struct net_device *dev, __u8 *buf, int len); static struct net_device_stats *irport_net_get_stats(struct net_device *dev); @@ -169,7 +171,7 @@ irport_open(int i, unsigned int iobase, unsigned int irq) self->io.sir_base = iobase; self->io.sir_ext = IO_EXTENT; self->io.irq = irq; - self->io.fifo_size = 16; + self->io.fifo_size = 16; /* 16550A and compatible */ /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); @@ -181,39 +183,47 @@ irport_open(int i, unsigned int iobase, unsigned int irq) irda_qos_bits_to_value(&self->qos); self->flags = IFF_SIR|IFF_PIO; + self->mode = IRDA_IRLAP; + + /* Bootstrap ZeroCopy Rx */ + self->rx_buff.truesize = IRDA_SKB_MAX_MTU; + self->rx_buff.skb = __dev_alloc_skb(self->rx_buff.truesize, + GFP_KERNEL); + if (self->rx_buff.skb == NULL) + return NULL; + skb_reserve(self->rx_buff.skb, 1); + self->rx_buff.head = self->rx_buff.skb->data; + /* No need to memset the buffer, unless you are really pedantic */ + + /* Finish setup the Rx buffer descriptor */ + self->rx_buff.in_frame = FALSE; + self->rx_buff.state = OUTSIDE_FRAME; + self->rx_buff.data = self->rx_buff.head; /* Specify how much memory we want */ - self->rx_buff.truesize = 4000; self->tx_buff.truesize = 4000; /* Allocate memory if needed */ - if (self->rx_buff.truesize > 0) { - self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize, - GFP_KERNEL); - if (self->rx_buff.head == NULL) - return NULL; - memset(self->rx_buff.head, 0, self->rx_buff.truesize); - } if (self->tx_buff.truesize > 0) { self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, GFP_KERNEL); if (self->tx_buff.head == NULL) { - kfree(self->rx_buff.head); + kfree_skb(self->rx_buff.skb); + self->rx_buff.skb = NULL; + self->rx_buff.head = NULL; return NULL; } memset(self->tx_buff.head, 0, self->tx_buff.truesize); } - self->rx_buff.in_frame = FALSE; - self->rx_buff.state = OUTSIDE_FRAME; self->tx_buff.data = self->tx_buff.head; - self->rx_buff.data = self->rx_buff.head; - self->mode = IRDA_IRLAP; if (!(dev = dev_alloc("irda%d", &err))) { ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__); return NULL; } self->netdev = dev; + /* Keep track of module usage */ + SET_MODULE_OWNER(dev); /* May be overridden by piggyback drivers */ dev->priv = (void *) self; @@ -241,7 +251,8 @@ irport_open(int i, unsigned int iobase, unsigned int irq) ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); return NULL; } - MESSAGE("IrDA: Registered device %s\n", dev->name); + MESSAGE("IrDA: Registered device %s (irport io=0x%X irq=%d)\n", + dev->name, iobase, irq); return self; } @@ -270,8 +281,9 @@ int irport_close(struct irport_cb *self) if (self->tx_buff.head) kfree(self->tx_buff.head); - if (self->rx_buff.head) - kfree(self->rx_buff.head); + if (self->rx_buff.skb) + kfree_skb(self->rx_buff.skb); + self->rx_buff.skb = NULL; /* Remove ourselves */ dev_self[self->index] = NULL; @@ -306,6 +318,9 @@ void irport_stop(struct irport_cb *self) /* We can't lock, we may be called from a FIR driver - Jean II */ + /* We are not transmitting any more */ + self->transmitting = 0; + /* Reset UART */ outb(0, iobase+UART_MCR); @@ -327,6 +342,33 @@ int irport_probe(int iobase) } /* + * Function irport_get_fcr (speed) + * + * Compute value of fcr + * + */ +static inline unsigned int irport_get_fcr(__u32 speed) +{ + unsigned int fcr; /* FIFO control reg */ + + /* Enable fifos */ + fcr = UART_FCR_ENABLE_FIFO; + + /* + * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and + * almost 1,7 ms at 19200 bps. At speeds above that we can just forget + * about this timeout since it will always be fast enough. + */ + if (speed < 38400) + fcr |= UART_FCR_TRIGGER_1; + else + //fcr |= UART_FCR_TRIGGER_14; + fcr |= UART_FCR_TRIGGER_8; + + return(fcr); +} + +/* * Function irport_change_speed (self, speed) * * Set speed of IrDA port to specified baudrate @@ -337,11 +379,12 @@ void irport_change_speed(void *priv, __u32 speed) { struct irport_cb *self = (struct irport_cb *) priv; int iobase; - int fcr; /* FIFO control reg */ - int lcr; /* Line control reg */ + unsigned int fcr; /* FIFO control reg */ + unsigned int lcr; /* Line control reg */ int divisor; ASSERT(self != NULL, return;); + ASSERT(speed != 0, return;); IRDA_DEBUG(1, "%s(), Setting speed to: %d - iobase=%#x\n", __FUNCTION__, speed, self->io.sir_base); @@ -358,18 +401,9 @@ void irport_change_speed(void *priv, __u32 speed) divisor = SPEED_MAX/speed; - fcr = UART_FCR_ENABLE_FIFO; + /* Get proper fifo configuration */ + fcr = irport_get_fcr(speed); - /* - * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and - * almost 1,7 ms at 19200 bps. At speeds above that we can just forget - * about this timeout since it will always be fast enough. - */ - if (self->io.speed < 38400) - fcr |= UART_FCR_TRIGGER_1; - else - fcr |= UART_FCR_TRIGGER_14; - /* IrDA ports use 8N1 */ lcr = UART_LCR_WLEN8; @@ -380,7 +414,7 @@ void irport_change_speed(void *priv, __u32 speed) outb(fcr, iobase+UART_FCR); /* Enable FIFO's */ /* Turn on interrups */ - /* This will generate a fata interrupt storm. + /* This will generate a fatal interrupt storm. * People calling us will do that properly - Jean II */ //outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER); } @@ -467,8 +501,8 @@ int __irport_change_speed(struct irda_task *task) irda_task_next_state(task, IRDA_TASK_DONE); ret = -1; break; - } - /* Put stuff in the sate we found them - Jean II */ + } + /* Put stuff in the state we found them - Jean II */ if(wasunlocked) { spin_unlock_irqrestore(&self->lock, flags); } @@ -477,98 +511,6 @@ int __irport_change_speed(struct irda_task *task) } /* - * Function irport_write_wakeup (tty) - * - * Called by the driver when there's room for more data. If we have - * more packets to send, we send them here. - * - */ -static void irport_write_wakeup(struct irport_cb *self) -{ - int actual = 0; - int iobase; - int fcr; - - ASSERT(self != NULL, return;); - - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); - - iobase = self->io.sir_base; - - /* Finished with frame? */ - if (self->tx_buff.len > 0) { - /* Write data left in transmit buffer */ - actual = irport_write(iobase, self->io.fifo_size, - self->tx_buff.data, self->tx_buff.len); - self->tx_buff.data += actual; - self->tx_buff.len -= actual; - - /* Turn on transmit finished interrupt. */ - outb(UART_IER_THRI, iobase+UART_IER); - } else { - /* - * Now serial buffer is almost free & we can start - * transmission of another packet. But first we must check - * if we need to change the speed of the hardware - */ - if (self->new_speed) { - IRDA_DEBUG(5, "%s(), Changing speed!\n", __FUNCTION__); - irda_task_execute(self, __irport_change_speed, - irport_change_speed_complete, - NULL, (void *) self->new_speed); - self->new_speed = 0; - IRDA_DEBUG(5, "%s(), Speed changed!\n", __FUNCTION__ ); - } else { - /* Tell network layer that we want more frames */ - netif_wake_queue(self->netdev); - } - self->stats.tx_packets++; - - /* - * Reset Rx FIFO to make sure that all reflected transmit data - * is discarded. This is needed for half duplex operation - */ - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR; - if (self->io.speed < 38400) - fcr |= UART_FCR_TRIGGER_1; - else - fcr |= UART_FCR_TRIGGER_14; - - outb(fcr, iobase+UART_FCR); - - /* Turn on receive interrupts */ - outb(UART_IER_RDI, iobase+UART_IER); - } -} - -/* - * Function irport_write (driver) - * - * Fill Tx FIFO with transmit data - * - */ -static int irport_write(int iobase, int fifo_size, __u8 *buf, int len) -{ - int actual = 0; - - /* Tx FIFO should be empty! */ - if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { - IRDA_DEBUG(0, "%s(), failed, fifo not empty!\n", __FUNCTION__); - return 0; - } - - /* Fill FIFO with current frame */ - while ((fifo_size-- > 0) && (actual < len)) { - /* Transmit next byte */ - outb(buf[actual], iobase+UART_TX); - - actual++; - } - - return actual; -} - -/* * Function irport_change_speed_complete (task) * * Called when the change speed operation completes @@ -604,24 +546,80 @@ static void irport_timeout(struct net_device *dev) { struct irport_cb *self; int iobase; + int iir, lsr; unsigned long flags; self = (struct irport_cb *) dev->priv; + ASSERT(self != NULL, return;); iobase = self->io.sir_base; - WARNING("%s: transmit timed out\n", dev->name); + WARNING("%s: transmit timed out, jiffies = %ld, trans_start = %ld\n", + dev->name, jiffies, dev->trans_start); spin_lock_irqsave(&self->lock, flags); + + /* Debug what's happening... */ + + /* Get interrupt status */ + lsr = inb(iobase+UART_LSR); + /* Read interrupt register */ + iir = inb(iobase+UART_IIR); + IRDA_DEBUG(0, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", + __FUNCTION__, iir, lsr, iobase); + + IRDA_DEBUG(0, "%s(), transmitting=%d, remain=%d, done=%d\n", + __FUNCTION__, self->transmitting, self->tx_buff.len, + self->tx_buff.data - self->tx_buff.head); + + /* Now, restart the port */ irport_start(self); self->change_speed(self->priv, self->io.speed); /* This will re-enable irqs */ outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER); + dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); - dev->trans_start = jiffies; netif_wake_queue(dev); } /* + * Function irport_wait_hw_transmitter_finish () + * + * Wait for the real end of HW transmission + * + * The UART is a strict FIFO, and we get called only when we have finished + * pushing data to the FIFO, so the maximum amount of time we must wait + * is only for the FIFO to drain out. + * + * We use a simple calibrated loop. We may need to adjust the loop + * delay (udelay) to balance I/O traffic and latency. And we also need to + * adjust the maximum timeout. + * It would probably be better to wait for the proper interrupt, + * but it doesn't seem to be available. + * + * We can't use jiffies or kernel timers because : + * 1) We are called from the interrupt handler, which disable softirqs, + * so jiffies won't be increased + * 2) Jiffies granularity is usually very coarse (10ms), and we don't + * want to wait that long to detect stuck hardware. + * Jean II + */ + +static void irport_wait_hw_transmitter_finish(struct irport_cb *self) +{ + int iobase; + int count = 1000; /* 1 ms */ + + iobase = self->io.sir_base; + + /* Calibrated busy loop */ + while((count-- > 0) && !(inb(iobase+UART_LSR) & UART_LSR_TEMT)) + udelay(1); + + if(count == 0) + IRDA_DEBUG(0, "%s(): stuck transmitter\n", __FUNCTION__); +} + +/* * Function irport_hard_start_xmit (struct sk_buff *skb, struct net_device *dev) * * Transmits the current frame until FIFO is full, then @@ -645,8 +643,8 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) iobase = self->io.sir_base; netif_stop_queue(dev); - - /* Make sure tests *& speed change are atomic */ + + /* Make sure tests & speed change are atomic */ spin_lock_irqsave(&self->lock, flags); /* Check if we need to change the speed */ @@ -654,10 +652,21 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) if ((speed != self->io.speed) && (speed != -1)) { /* Check for empty frame */ if (!skb->len) { + /* + * We send frames one by one in SIR mode (no + * pipelining), so at this point, if we were sending + * a previous frame, we just received the interrupt + * telling us it is finished (UART_IIR_THRI). + * Therefore, waiting for the transmitter to really + * finish draining the fifo won't take too long. + * And the interrupt handler is not expected to run. + * - Jean II */ + irport_wait_hw_transmitter_finish(self); /* Better go there already locked - Jean II */ irda_task_execute(self, __irport_change_speed, irport_change_speed_complete, NULL, (void *) speed); + dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0; @@ -674,9 +683,13 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) self->stats.tx_bytes += self->tx_buff.len; + /* We are transmitting */ + self->transmitting = 1; + /* Turn on transmit finished interrupt. Will fire immediately! */ outb(UART_IER_THRI, iobase+UART_IER); + dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); @@ -685,12 +698,100 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) } /* + * Function irport_write (driver) + * + * Fill Tx FIFO with transmit data + * + * Called only from irport_write_wakeup() + */ +static inline int irport_write(int iobase, int fifo_size, __u8 *buf, int len) +{ + int actual = 0; + + /* Fill FIFO with current frame */ + while ((actual < fifo_size) && (actual < len)) { + /* Transmit next byte */ + outb(buf[actual], iobase+UART_TX); + + actual++; + } + + return actual; +} + +/* + * Function irport_write_wakeup (tty) + * + * Called by the driver when there's room for more data. If we have + * more packets to send, we send them here. + * + * Called only from irport_interrupt() + * Make sure this function is *not* called while we are receiving, + * otherwise we will reset fifo and loose data :-( + */ +static inline void irport_write_wakeup(struct irport_cb *self) +{ + int actual = 0; + int iobase; + unsigned int fcr; + + ASSERT(self != NULL, return;); + + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + + iobase = self->io.sir_base; + + /* Finished with frame? */ + if (self->tx_buff.len > 0) { + /* Write data left in transmit buffer */ + actual = irport_write(iobase, self->io.fifo_size, + self->tx_buff.data, self->tx_buff.len); + self->tx_buff.data += actual; + self->tx_buff.len -= actual; + } else { + /* + * Now serial buffer is almost free & we can start + * transmission of another packet. But first we must check + * if we need to change the speed of the hardware + */ + if (self->new_speed) { + irport_wait_hw_transmitter_finish(self); + irda_task_execute(self, __irport_change_speed, + irport_change_speed_complete, + NULL, (void *) self->new_speed); + self->new_speed = 0; + } else { + /* Tell network layer that we want more frames */ + netif_wake_queue(self->netdev); + } + self->stats.tx_packets++; + + /* + * Reset Rx FIFO to make sure that all reflected transmit data + * is discarded. This is needed for half duplex operation + */ + fcr = irport_get_fcr(self->io.speed); + fcr |= UART_FCR_CLEAR_RCVR; + outb(fcr, iobase+UART_FCR); + + /* Finished transmitting */ + self->transmitting = 0; + + /* Turn on receive interrupts */ + outb(UART_IER_RDI, iobase+UART_IER); + + IRDA_DEBUG(1, "%s() : finished Tx\n", __FUNCTION__); + } +} + +/* * Function irport_receive (self) * * Receive one frame from the infrared port * + * Called only from irport_interrupt() */ -static void irport_receive(struct irport_cb *self) +static inline void irport_receive(struct irport_cb *self) { int boguscount = 0; int iobase; @@ -739,40 +840,51 @@ irqreturn_t irport_interrupt(int irq, void *dev_id, struct pt_regs *regs) iobase = self->io.sir_base; - iir = inb(iobase+UART_IIR) & UART_IIR_ID; - while (iir) { - handled = 1; + /* Cut'n'paste interrupt routine from serial.c + * This version try to minimise latency and I/O operations. + * Simplified and modified to enforce half duplex operation. + * - Jean II */ - /* Clear interrupt */ + /* Check status even is iir reg is cleared, more robust and + * eliminate a read on the I/O bus - Jean II */ + do { + /* Get interrupt status ; Clear interrupt */ lsr = inb(iobase+UART_LSR); + + /* Are we receiving or transmitting ? */ + if(!self->transmitting) { + /* Received something ? */ + if (lsr & UART_LSR_DR) + irport_receive(self); + } else { + /* Room in Tx fifo ? */ + if (lsr & (UART_LSR_THRE | UART_LSR_TEMT)) + irport_write_wakeup(self); + } - IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", - __FUNCTION__, iir, lsr, iobase); + /* A bit hackish, but working as expected... Jean II */ + if(lsr & (UART_LSR_THRE | UART_LSR_TEMT | UART_LSR_DR)) + handled = 1; - switch (iir) { - case UART_IIR_RLSI: - IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__); - break; - case UART_IIR_RDI: - /* Receive interrupt */ - irport_receive(self); - break; - case UART_IIR_THRI: - if (lsr & UART_LSR_THRE) - /* Transmitter ready for data */ - irport_write_wakeup(self); - break; - default: - IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", __FUNCTION__, iir); - break; - } - - /* Make sure we don't stay here too long */ - if (boguscount++ > 100) + /* Make sure we don't stay here to long */ + if (boguscount++ > 10) { + WARNING("%s() irq handler looping : lsr=%02x\n", + __FUNCTION__, lsr); break; + } + + /* Read interrupt register */ + iir = inb(iobase+UART_IIR); + + /* Enable this debug only when no other options and at low + * bit rates, otherwise it may cause Rx overruns (lsr=63). + * - Jean II */ + IRDA_DEBUG(6, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", + __FUNCTION__, iir, lsr, iobase); + + /* As long as interrupt pending... */ + } while ((iir & UART_IIR_NO_INT) == 0); - iir = inb(iobase + UART_IIR) & UART_IIR_ID; - } spin_unlock(&self->lock); return IRQ_RETVAL(handled); } @@ -800,8 +912,8 @@ int irport_net_open(struct net_device *dev) char hwname[16]; unsigned long flags; - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); - + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + ASSERT(dev != NULL, return -1;); self = (struct irport_cb *) dev->priv; @@ -815,7 +927,12 @@ int irport_net_open(struct net_device *dev) } spin_lock_irqsave(&self->lock, flags); + /* Init uart */ irport_start(self); + /* Set 9600 bauds per default, including at the dongle */ + irda_task_execute(self, __irport_change_speed, + irport_change_speed_complete, + NULL, (void *) 9600); spin_unlock_irqrestore(&self->lock, flags); @@ -828,12 +945,9 @@ int irport_net_open(struct net_device *dev) */ self->irlap = irlap_open(dev, &self->qos, hwname); - /* FIXME: change speed of dongle */ /* Ready to play! */ netif_start_queue(dev); - - MOD_INC_USE_COUNT; return 0; } @@ -873,40 +987,16 @@ int irport_net_close(struct net_device *dev) free_irq(self->io.irq, dev); - MOD_DEC_USE_COUNT; - return 0; } /* - * Function irport_wait_until_sent (self) - * - * Delay exectution until finished transmitting - * - */ -#if 0 -void irport_wait_until_sent(struct irport_cb *self) -{ - int iobase; - - iobase = self->io.sir_base; - - /* Wait until Tx FIFO is empty */ - while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { - IRDA_DEBUG(2, "%s(), waiting!\n", __FUNCTION__); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(MSECS_TO_JIFFIES(60)); - } -} -#endif - -/* * Function irport_is_receiving (self) * * Returns true is we are currently receiving data * */ -static int irport_is_receiving(struct irport_cb *self) +static inline int irport_is_receiving(struct irport_cb *self) { return (self->rx_buff.state != OUTSIDE_FRAME); } @@ -998,6 +1088,12 @@ static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) break; } + /* Locking : + * irda_device_dongle_init() can't be locked. + * irda_task_execute() doesn't need to be locked. + * Jean II + */ + /* Initialize dongle */ dongle = irda_device_dongle_init(dev, irq->ifr_dongle); if (!dongle) diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 87deb312b94c..a2d387ced051 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -504,10 +504,7 @@ static int irtty_open(struct tty_struct *tty) struct sirtty_cb *priv; int ret = 0; - /* unfortunately, there's no tty_ldisc->owner field - * so there is some window for SMP race with rmmod - */ - MOD_INC_USE_COUNT; + /* Module stuff handled via irda_ldisc.owner - Jean II */ /* First make sure we're not already connected. */ if (tty->disc_data != NULL) { @@ -569,7 +566,6 @@ static int irtty_open(struct tty_struct *tty) out_put: sirdev_put_instance(dev); out: - MOD_DEC_USE_COUNT; return ret; } @@ -614,8 +610,6 @@ static void irtty_close(struct tty_struct *tty) tty->driver->stop(tty); kfree(priv); - - MOD_DEC_USE_COUNT; } /* ------------------------------------------------------- */ @@ -633,6 +627,7 @@ static struct tty_ldisc irda_ldisc = { .receive_buf = irtty_receive_buf, .receive_room = irtty_receive_room, .write_wakeup = irtty_write_wakeup, + .owner = THIS_MODULE, }; /* ------------------------------------------------------- */ diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index ada9a3feda69..6f847c07d710 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -1096,6 +1096,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) * to make sure packets gets through the * proper xmit handler - Jean II */ } + dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0; @@ -1120,6 +1121,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) /* Restore bank register */ outb(bank, iobase+BSR); + dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); @@ -1164,6 +1166,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) * the speed change has been done. * Jean II */ } + dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0; @@ -1250,6 +1253,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) /* Restore bank register */ outb(bank, iobase+BSR); + dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); diff --git a/drivers/net/irda/sir_kthread.c b/drivers/net/irda/sir_kthread.c index 293c05c27cd0..cc38b8809b14 100644 --- a/drivers/net/irda/sir_kthread.c +++ b/drivers/net/irda/sir_kthread.c @@ -151,6 +151,13 @@ static int irda_thread(void *startup) while (irda_rq_queue.thread != NULL) { + /* We use TASK_INTERRUPTIBLE, rather than + * TASK_UNINTERRUPTIBLE. Andrew Morton made this + * change ; he told me that it is safe, because "signal + * blocking is now handled in daemonize()", he added + * that the problem is that "uninterruptible sleep + * contributes to load average", making user worry. + * Jean II */ set_task_state(current, TASK_INTERRUPTIBLE); add_wait_queue(&irda_rq_queue.kick, &wait); if (list_empty(&irda_rq_queue.request_list)) diff --git a/drivers/net/irda/smc-ircc.c b/drivers/net/irda/smc-ircc.c index f802455b8ada..91f476547a83 100644 --- a/drivers/net/irda/smc-ircc.c +++ b/drivers/net/irda/smc-ircc.c @@ -529,6 +529,9 @@ static int __init ircc_open(unsigned int fir_base, unsigned int sir_base) irport->priv = self; + /* Keep track of module usage */ + SET_MODULE_OWNER(self->netdev); + /* Initialize IO */ self->io = &irport->io; self->io->fir_base = fir_base; @@ -747,6 +750,7 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev) /* Check for empty frame */ if (!skb->len) { ircc_change_speed(self, speed); + dev->trans_start = jiffies; spin_unlock_irqrestore(&self->irport->lock, flags); dev_kfree_skb(skb); return 0; @@ -776,6 +780,7 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev) /* Transmit frame */ ircc_dma_xmit(self, iobase, 0); } + dev->trans_start = jiffies; spin_unlock_irqrestore(&self->irport->lock, flags); dev_kfree_skb(skb); @@ -1090,8 +1095,6 @@ static int ircc_net_open(struct net_device *dev) WARNING("%s(), unable to allocate DMA=%d\n", __FUNCTION__, self->io->dma); return -EAGAIN; } - - MOD_INC_USE_COUNT; return 0; } @@ -1124,8 +1127,6 @@ static int ircc_net_close(struct net_device *dev) free_dma(self->io->dma); - MOD_DEC_USE_COUNT; - return 0; } @@ -1187,6 +1188,9 @@ static int __exit ircc_close(struct ircc_cb *self) iobase = self->irport->io.fir_base; + if (self->pmdev) + pm_unregister(self->pmdev); + /* This will destroy irport */ irport_close(self->irport); diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c new file mode 100644 index 000000000000..447c6aa4d1c8 --- /dev/null +++ b/drivers/net/irda/smsc-ircc2.c @@ -0,0 +1,2441 @@ +/********************************************************************* + * $Id: smsc-ircc2.c,v 1.19.2.5 2002/10/27 11:34:26 dip Exp $ + * + * Description: Driver for the SMC Infrared Communications Controller + * Status: Experimental. + * Author: Daniele Peri (peri@csai.unipa.it) + * Created at: + * Modified at: + * Modified by: + * + * Copyright (c) 2002 Daniele Peri + * All Rights Reserved. + * Copyright (c) 2002 Jean Tourrilhes + * + * + * Based on smc-ircc.c: + * + * Copyright (c) 2001 Stefani Seibold + * Copyright (c) 1999-2001 Dag Brattli + * Copyright (c) 1998-1999 Thomas Davis, + * + * and irport.c: + * + * Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, All Rights Reserved. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/rtnetlink.h> +#include <linux/serial_reg.h> + +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/byteorder.h> + +#include <linux/spinlock.h> +#include <linux/pm.h> + +#include <net/irda/wrapper.h> +#include <net/irda/irda.h> +#include <net/irda/irda_device.h> + +#include "smsc-ircc2.h" +#include "smsc-sio.h" + +/* Types */ + +struct smsc_transceiver { + char *name; + void (*set_for_speed)(int fir_base, u32 speed); + int (*probe)(int fir_base); +}; +typedef struct smsc_transceiver smsc_transceiver_t; + +#if 0 +struct smc_chip { + char *name; + u16 flags; + u8 devid; + u8 rev; +}; +typedef struct smc_chip smc_chip_t; +#endif + +struct smsc_chip { + char *name; + #if 0 + u8 type; + #endif + u16 flags; + u8 devid; + u8 rev; +}; +typedef struct smsc_chip smsc_chip_t; + +struct smsc_chip_address { + unsigned int cfg_base; + unsigned int type; +}; +typedef struct smsc_chip_address smsc_chip_address_t; + +/* Private data for each instance */ +struct smsc_ircc_cb { + struct net_device *netdev; /* Yes! we are some kind of netdevice */ + struct net_device_stats stats; + struct irlap_cb *irlap; /* The link layer we are binded to */ + + chipio_t io; /* IrDA controller information */ + iobuff_t tx_buff; /* Transmit buffer */ + iobuff_t rx_buff; /* Receive buffer */ + + struct qos_info qos; /* QoS capabilities for this device */ + + spinlock_t lock; /* For serializing operations */ + + __u32 new_speed; + __u32 flags; /* Interface flags */ + + int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */ + int tx_len; /* Number of frames in tx_buff */ + + int transceiver; + struct pm_dev *pmdev; +}; + +/* Constants */ + +static const char *driver_name = "smsc-ircc2"; +#define DIM(x) (sizeof(x)/(sizeof(*(x)))) +#define SMSC_IRCC2_C_IRDA_FALLBACK_SPEED 9600 +#define SMSC_IRCC2_C_DEFAULT_TRANSCEIVER 1 +#define SMSC_IRCC2_C_NET_TIMEOUT 0 +#define SMSC_IRCC2_C_SIR_STOP 0 + +/* Prototypes */ + +static int smsc_ircc_open(unsigned int firbase, unsigned int sirbase, u8 dma, u8 irq); +static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base); +static int smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq); +static int smsc_ircc_setup_buffers(struct smsc_ircc_cb *self); +static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self); +static int smsc_ircc_setup_netdev(struct smsc_ircc_cb *self); +static void smsc_ircc_init_chip(struct smsc_ircc_cb *self); +static int __exit smsc_ircc_close(struct smsc_ircc_cb *self); +static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase); +static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase); +static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self); +static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev); +static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev); +static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int iobase, int bofs); +static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self, int iobase); +static void smsc_ircc_change_speed(void *priv, u32 speed); +static void smsc_ircc_set_sir_speed(void *priv, u32 speed); +static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void smsc_ircc_interrupt_sir(int irq, void *dev_id, struct pt_regs *regs); +static void smsc_ircc_sir_start(struct smsc_ircc_cb *self); +#if SMSC_IRCC2_C_SIR_STOP +static void smsc_ircc_sir_stop(struct smsc_ircc_cb *self); +#endif +static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self); +static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len); +static int smsc_ircc_net_init(struct net_device *dev); +static int smsc_ircc_net_open(struct net_device *dev); +static int smsc_ircc_net_close(struct net_device *dev); +static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +#if SMSC_IRCC2_C_NET_TIMEOUT +static void smsc_ircc_timeout(struct net_device *dev); +#endif +static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev); +static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data); +static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self); +static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self); +static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed); +static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self); + +/* Probing */ +static int __init smsc_ircc_look_for_chips(void); +static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg,const smsc_chip_t *chip,char *type); +static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfg_base, char *type); +static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cfg_base, char *type); +static int __init smsc_superio_fdc(unsigned short cfg_base); +static int __init smsc_superio_lpc(unsigned short cfg_base); + +/* Transceivers specific functions */ + +static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed); +static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base); +static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed); +static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base); +static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed); +static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base); + +/* Power Management */ + +static void smsc_ircc_suspend(struct smsc_ircc_cb *self); +static void smsc_ircc_wakeup(struct smsc_ircc_cb *self); +static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data); + + +/* Transceivers for SMSC-ircc */ + +smsc_transceiver_t smsc_transceivers[]= +{ + { "Toshiba Satellite 1800 (GP data pin select)", smsc_ircc_set_transceiver_toshiba_sat1800, smsc_ircc_probe_transceiver_toshiba_sat1800}, + { "Fast pin select", smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select, smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select}, + { "ATC IRMode", smsc_ircc_set_transceiver_smsc_ircc_atc, smsc_ircc_probe_transceiver_smsc_ircc_atc}, + { NULL, NULL} +}; +#define SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS (DIM(smsc_transceivers)-1) + +/* SMC SuperIO chipsets definitions */ + +#define KEY55_1 0 /* SuperIO Configuration mode with Key <0x55> */ +#define KEY55_2 1 /* SuperIO Configuration mode with Key <0x55,0x55> */ +#define NoIRDA 2 /* SuperIO Chip has no IRDA Port */ +#define SIR 0 /* SuperIO Chip has only slow IRDA */ +#define FIR 4 /* SuperIO Chip has fast IRDA */ +#define SERx4 8 /* SuperIO Chip supports 115,2 KBaud * 4=460,8 KBaud */ + +static smsc_chip_t __initdata fdc_chips_flat[]= +{ + /* Base address 0x3f0 or 0x370 */ + { "37C44", KEY55_1|NoIRDA, 0x00, 0x00 }, /* This chip cannot be detected */ + { "37C665GT", KEY55_2|NoIRDA, 0x65, 0x01 }, + { "37C665GT", KEY55_2|NoIRDA, 0x66, 0x01 }, + { "37C669", KEY55_2|SIR|SERx4, 0x03, 0x02 }, + { "37C669", KEY55_2|SIR|SERx4, 0x04, 0x02 }, /* ID? */ + { "37C78", KEY55_2|NoIRDA, 0x78, 0x00 }, + { "37N769", KEY55_1|FIR|SERx4, 0x28, 0x00 }, + { "37N869", KEY55_1|FIR|SERx4, 0x29, 0x00 }, + { NULL } +}; + +static smsc_chip_t __initdata fdc_chips_paged[]= +{ + /* Base address 0x3f0 or 0x370 */ + { "37B72X", KEY55_1|SIR|SERx4, 0x4c, 0x00 }, + { "37B77X", KEY55_1|SIR|SERx4, 0x43, 0x00 }, + { "37B78X", KEY55_1|SIR|SERx4, 0x44, 0x00 }, + { "37B80X", KEY55_1|SIR|SERx4, 0x42, 0x00 }, + { "37C67X", KEY55_1|FIR|SERx4, 0x40, 0x00 }, + { "37C93X", KEY55_2|SIR|SERx4, 0x02, 0x01 }, + { "37C93XAPM", KEY55_1|SIR|SERx4, 0x30, 0x01 }, + { "37C93XFR", KEY55_2|FIR|SERx4, 0x03, 0x01 }, + { "37M707", KEY55_1|SIR|SERx4, 0x42, 0x00 }, + { "37M81X", KEY55_1|SIR|SERx4, 0x4d, 0x00 }, + { "37N958FR", KEY55_1|FIR|SERx4, 0x09, 0x04 }, + { "37N971", KEY55_1|FIR|SERx4, 0x0a, 0x00 }, + { "37N972", KEY55_1|FIR|SERx4, 0x0b, 0x00 }, + { NULL } +}; + +static smsc_chip_t __initdata lpc_chips_flat[]= +{ + /* Base address 0x2E or 0x4E */ + { "47N227", KEY55_1|FIR|SERx4, 0x5a, 0x00 }, + { "47N267", KEY55_1|FIR|SERx4, 0x5e, 0x00 }, + { NULL } +}; + +static smsc_chip_t __initdata lpc_chips_paged[]= +{ + /* Base address 0x2E or 0x4E */ + { "47B27X", KEY55_1|SIR|SERx4, 0x51, 0x00 }, + { "47B37X", KEY55_1|SIR|SERx4, 0x52, 0x00 }, + { "47M10X", KEY55_1|SIR|SERx4, 0x59, 0x00 }, + { "47M120", KEY55_1|NoIRDA|SERx4, 0x5c, 0x00 }, + { "47M13X", KEY55_1|SIR|SERx4, 0x59, 0x00 }, + { "47M14X", KEY55_1|SIR|SERx4, 0x5f, 0x00 }, + { "47N252", KEY55_1|FIR|SERx4, 0x0e, 0x00 }, + { "47S42X", KEY55_1|SIR|SERx4, 0x57, 0x00 }, + { NULL } +}; + +#define SMSCSIO_TYPE_FDC 1 +#define SMSCSIO_TYPE_LPC 2 +#define SMSCSIO_TYPE_FLAT 4 +#define SMSCSIO_TYPE_PAGED 8 + +static smsc_chip_address_t __initdata possible_addresses[]= +{ + {0x3f0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED}, + {0x370, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED}, + {0xe0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED}, + {0x2e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED}, + {0x4e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED}, + {0,0} +}; + +/* Globals */ + +static struct smsc_ircc_cb *dev_self[] = { NULL, NULL}; + +static int ircc_irq=255; +static int ircc_dma=255; +static int ircc_fir=0; +static int ircc_sir=0; +static int ircc_cfg=0; +static int ircc_transceiver=0; + +static unsigned short dev_count=0; + +static inline void register_bank(int iobase, int bank) +{ + outb(((inb(iobase+IRCC_MASTER) & 0xf0) | (bank & 0x07)), + iobase+IRCC_MASTER); +} + + +/******************************************************************************* + * + * + * SMSC-ircc stuff + * + * + *******************************************************************************/ + +/* + * Function smsc_ircc_init () + * + * Initialize chip. Just try to find out how many chips we are dealing with + * and where they are + */ +int __init smsc_ircc_init(void) +{ + int ret=-ENODEV; + + IRDA_DEBUG(1, "%s\n", __FUNCTION__); + + dev_count=0; + + if ((ircc_fir>0)&&(ircc_sir>0)) { + MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir); + MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir); + + if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq) == 0) + return 0; + + return -ENODEV; + } + + /* try user provided configuration register base address */ + if (ircc_cfg>0) { + MESSAGE(" Overriding configuration address 0x%04x\n", ircc_cfg); + if (!smsc_superio_fdc(ircc_cfg)) + ret = 0; + if (!smsc_superio_lpc(ircc_cfg)) + ret = 0; + } + + if(smsc_ircc_look_for_chips()>0) ret = 0; + + return ret; +} + +/* + * Function smsc_ircc_open (firbase, sirbase, dma, irq) + * + * Try to open driver instance + * + */ +static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq) +{ + struct smsc_ircc_cb *self; + int err; + + IRDA_DEBUG(1, "%s\n", __FUNCTION__); + + err= smsc_ircc_present(fir_base, sir_base); + if(err) return -ENODEV; + + if (dev_count>DIM(dev_self)) { + WARNING("%s(), too many devices!\n", __FUNCTION__); + return -ENOMEM; + } + + /* + * Allocate new instance of the driver + */ + self = kmalloc(sizeof(struct smsc_ircc_cb), GFP_KERNEL); + if (self == NULL) { + ERROR("%s, Can't allocate memory for control block!\n", + driver_name); + return -ENOMEM; + } + memset(self, 0, sizeof(struct smsc_ircc_cb)); + + /* Need to store self somewhere */ + dev_self[dev_count++] = self; + spin_lock_init(&self->lock); + + err = smsc_ircc_setup_buffers(self); + if(err) return err; + + err= smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq); + if(err) return err; + + smsc_ircc_setup_qos(self); + + self->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO; + + smsc_ircc_init_chip(self); + + if(ircc_transceiver > 0 && ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS) self->transceiver = ircc_transceiver; + else smsc_ircc_probe_transceiver(self); + + err = smsc_ircc_setup_netdev(self); + if(err) return err; + + self->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, smsc_ircc_pmproc); + if (self->pmdev) + self->pmdev->data = self; + + return 0; +} + +/* + * Function smsc_ircc_present(fir_base, sir_base) + * + * Check the smsc-ircc chip presence + * + */ +static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base) +{ + unsigned char low, high, chip, config, dma, irq, version; + + if (check_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT) < 0) { + WARNING("%s: can't get fir_base of 0x%03x\n", + __FUNCTION__, fir_base); + return -ENODEV; + } +#if POSSIBLE_USED_BY_SERIAL_DRIVER + if (check_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT) < 0) { + WARNING("%s: can't get sir_base of 0x%03x\n", + __FUNCTION__, sir_base); + return -ENODEV; + } +#endif + + register_bank(fir_base, 3); + + high = inb(fir_base+IRCC_ID_HIGH); + low = inb(fir_base+IRCC_ID_LOW); + chip = inb(fir_base+IRCC_CHIP_ID); + version = inb(fir_base+IRCC_VERSION); + config = inb(fir_base+IRCC_INTERFACE); + dma = config & IRCC_INTERFACE_DMA_MASK; + irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4; + + if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) { + WARNING("%s(), addr 0x%04x - no device found!\n", + __FUNCTION__, fir_base); + return -ENODEV; + } + MESSAGE("SMsC IrDA Controller found\n IrCC version %d.%d, " + "firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n", + chip & 0x0f, version, fir_base, sir_base, dma, irq); + + return 0; +} + +/* + * Function smsc_ircc_setup_buffers(self) + * + * Setup RX/TX buffers + * + */ +static int smsc_ircc_setup_buffers(struct smsc_ircc_cb *self) +{ + self->rx_buff.truesize = SMSC_IRCC2_RX_BUFF_TRUESIZE; + self->tx_buff.truesize = SMSC_IRCC2_TX_BUFF_TRUESIZE; + + self->rx_buff.head = (u8 *) kmalloc(self->rx_buff.truesize, + GFP_KERNEL|GFP_DMA); + if (self->rx_buff.head == NULL) { + ERROR("%s, Can't allocate memory for receive buffer!\n", + driver_name); + kfree(self); + return -ENOMEM; + } + + self->tx_buff.head = (u8 *) kmalloc(self->tx_buff.truesize, + GFP_KERNEL|GFP_DMA); + if (self->tx_buff.head == NULL) { + ERROR("%s, Can't allocate memory for transmit buffer!\n", + driver_name); + kfree(self->rx_buff.head); + kfree(self); + return -ENOMEM; + } + + memset(self->rx_buff.head, 0, self->rx_buff.truesize); + memset(self->tx_buff.head, 0, self->tx_buff.truesize); + + self->rx_buff.in_frame = FALSE; + self->rx_buff.state = OUTSIDE_FRAME; + self->tx_buff.data = self->tx_buff.head; + self->rx_buff.data = self->rx_buff.head; + + return 0; +} + +/* + * Function smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq) + * + * Setup I/O + * + */ +static int smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq) +{ + unsigned char config, chip_dma, chip_irq; + void *ret; + + register_bank(fir_base, 3); + config = inb(fir_base+IRCC_INTERFACE); + chip_dma = config & IRCC_INTERFACE_DMA_MASK; + chip_irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4; + + self->io.fir_base = fir_base; + self->io.sir_base = sir_base; + self->io.fir_ext = SMSC_IRCC2_FIR_CHIP_IO_EXTENT; + self->io.sir_ext = SMSC_IRCC2_SIR_CHIP_IO_EXTENT; + self->io.fifo_size = SMSC_IRCC2_FIFO_SIZE; + self->io.speed = SMSC_IRCC2_C_IRDA_FALLBACK_SPEED; + + if (irq < 255) { + if (irq != chip_irq) + MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n", + driver_name, chip_irq, irq); + self->io.irq = irq; + } + else + self->io.irq = chip_irq; + + if (dma < 255) { + if (dma != chip_dma) + MESSAGE("%s, Overriding DMA - chip says %d, using %d\n", + driver_name, chip_dma, dma); + self->io.dma = dma; + } + else + self->io.dma = chip_dma; + + ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name); + if (!ret) { + WARNING("%s(), can't get iobase of 0x%03x\n", + __FUNCTION__, self->io.fir_base); + kfree(self->tx_buff.head); + kfree(self->rx_buff.head); + kfree(self); + return -ENODEV; + } + ret = request_region(self->io.sir_base, self->io.sir_ext, driver_name); + if (!ret) { + WARNING("%s(), can't get iobase of 0x%03x\n", + __FUNCTION__, self->io.sir_base); + release_region(self->io.fir_base, self->io.fir_ext); + kfree(self->tx_buff.head); + kfree(self->rx_buff.head); + kfree(self); + return -ENODEV; + } + + return 0; +} + +/* + * Function smsc_ircc_setup_qos(self) + * + * Setup qos + * + */ +static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self) +{ + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&self->qos); + + self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| + IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); + + self->qos.min_turn_time.bits = SMSC_IRCC2_MIN_TURN_TIME; + self->qos.window_size.bits = SMSC_IRCC2_WINDOW_SIZE; + irda_qos_bits_to_value(&self->qos); +} + +/* + * Function smsc_ircc_init_chip(self) + * + * Init chip + * + */ +static void smsc_ircc_init_chip(struct smsc_ircc_cb *self) +{ + int iobase, ir_mode, ctrl, fast; + + ASSERT( self != NULL, return; ); + iobase = self->io.fir_base; + + ir_mode = IRCC_CFGA_IRDA_SIR_A; + ctrl = 0; + fast = 0; + + register_bank(iobase, 0); + outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER); + outb(0x00, iobase+IRCC_MASTER); + + register_bank(iobase, 1); + outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode), + iobase+IRCC_SCE_CFGA); + +#ifdef smsc_669 /* Uses pin 88/89 for Rx/Tx */ + outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), + iobase+IRCC_SCE_CFGB); +#else + outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR), + iobase+IRCC_SCE_CFGB); +#endif + (void) inb(iobase+IRCC_FIFO_THRESHOLD); + outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase+IRCC_FIFO_THRESHOLD); + + register_bank(iobase, 4); + outb((inb(iobase+IRCC_CONTROL) & 0x30) | ctrl, iobase+IRCC_CONTROL); + + register_bank(iobase, 0); + outb(fast, iobase+IRCC_LCR_A); + + smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); + + /* Power on device */ + outb(0x00, iobase+IRCC_MASTER); +} + +/* + * Function smsc_ircc_setup_netdev(self) + * + * Alloc and setup network device + * + */ +static int smsc_ircc_setup_netdev(struct smsc_ircc_cb *self) +{ + struct net_device *dev; + int err; + /* Alloc netdev */ + + if (!(dev = dev_alloc("irda%d", &err))) { + ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__); + kfree(self->tx_buff.head); + kfree(self->rx_buff.head); + kfree(self); + return -ENOMEM; + } + + dev->priv = (void *) self; + self->netdev = dev; + + dev->init = smsc_ircc_net_init; + dev->hard_start_xmit = smsc_ircc_hard_xmit_sir; + #if SMSC_IRCC2_C_NET_TIMEOUT + dev->tx_timeout = smsc_ircc_timeout; + dev->watchdog_timeo = HZ*2; /* Allow enough time for speed change */ + #endif + dev->open = smsc_ircc_net_open; + dev->stop = smsc_ircc_net_close; + dev->do_ioctl = smsc_ircc_net_ioctl; + dev->get_stats = smsc_ircc_net_get_stats; + + /* Make ifconfig display some details */ + dev->base_addr = self->io.fir_base; + dev->irq = self->io.irq; + + rtnl_lock(); + err = register_netdevice(dev); + rtnl_unlock(); + if (err) { + ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); + kfree(self->tx_buff.head); + kfree(self->rx_buff.head); + kfree(self); + return -ENODEV; + } + MESSAGE("IrDA: Registered device %s\n", dev->name); + + return 0; +} + +/* + * Function smsc_ircc_net_ioctl (dev, rq, cmd) + * + * Process IOCTL commands for this device + * + */ +static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct smsc_ircc_cb *self; + unsigned long flags; + int ret = 0; + + ASSERT(dev != NULL, return -1;); + + self = dev->priv; + + ASSERT(self != NULL, return -1;); + + IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + ret = -EPERM; + else { + /* Make sure we are the only one touching + * self->io.speed and the hardware - Jean II */ + spin_lock_irqsave(&self->lock, flags); + smsc_ircc_change_speed(self, irq->ifr_baudrate); + spin_unlock_irqrestore(&self->lock, flags); + } + break; + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + irq->ifr_receiving = smsc_ircc_is_receiving(self); + break; + #if 0 + case SIOCSDTRRTS: + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + smsc_ircc_sir_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); + break; + #endif + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev) +{ + struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) dev->priv; + + return &self->stats; +} + +#if SMSC_IRCC2_C_NET_TIMEOUT +/* + * Function smsc_ircc_timeout (struct net_device *dev) + * + * The networking timeout management. + * + */ + +static void smsc_ircc_timeout(struct net_device *dev) +{ + struct smsc_ircc_cb *self; + unsigned long flags; + + self = (struct smsc_ircc_cb *) dev->priv; + + WARNING("%s: transmit timed out, changing speed to: %d\n", dev->name, self->io.speed); + spin_lock_irqsave(&self->lock, flags); + smsc_ircc_sir_start(self); + smsc_ircc_change_speed(self, self->io.speed); + dev->trans_start = jiffies; + netif_wake_queue(dev); + spin_unlock_irqrestore(&self->lock, flags); +} +#endif + +/* + * Function smsc_ircc_hard_xmit_sir (struct sk_buff *skb, struct net_device *dev) + * + * Transmits the current frame until FIFO is full, then + * waits until the next transmit interrupt, and continues until the + * frame is transmitted. + */ +int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) +{ + struct smsc_ircc_cb *self; + unsigned long flags; + int iobase; + s32 speed; + + IRDA_DEBUG(1, "%s\n", __FUNCTION__); + + ASSERT(dev != NULL, return 0;); + + self = (struct smsc_ircc_cb *) dev->priv; + ASSERT(self != NULL, return 0;); + + iobase = self->io.sir_base; + + netif_stop_queue(dev); + + /* Make sure test of self->io.speed & speed change are atomic */ + spin_lock_irqsave(&self->lock, flags); + + /* Check if we need to change the speed */ + speed = irda_get_next_speed(skb); + if ((speed != self->io.speed) && (speed != -1)) { + /* Check for empty frame */ + if (!skb->len) { + /* + * We send frames one by one in SIR mode (no + * pipelining), so at this point, if we were sending + * a previous frame, we just received the interrupt + * telling us it is finished (UART_IIR_THRI). + * Therefore, waiting for the transmitter to really + * finish draining the fifo won't take too long. + * And the interrupt handler is not expected to run. + * - Jean II */ + smsc_ircc_sir_wait_hw_transmitter_finish(self); + smsc_ircc_change_speed(self, speed); + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + return 0; + } else { + self->new_speed = speed; + } + } + + /* Init tx buffer */ + self->tx_buff.data = self->tx_buff.head; + + /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ + self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, + self->tx_buff.truesize); + + self->stats.tx_bytes += self->tx_buff.len; + + /* Turn on transmit finished interrupt. Will fire immediately! */ + outb(UART_IER_THRI, iobase+UART_IER); + + spin_unlock_irqrestore(&self->lock, flags); + + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function smsc_ircc_set_fir_speed (self, baud) + * + * Change the speed of the device + * + */ +static void smsc_ircc_set_fir_speed(struct smsc_ircc_cb *self, u32 speed) +{ + int fir_base, ir_mode, ctrl, fast; + + ASSERT(self != NULL, return;); + fir_base = self->io.fir_base; + + self->io.speed = speed; + + switch(speed) { + default: + case 576000: + ir_mode = IRCC_CFGA_IRDA_HDLC; + ctrl = IRCC_CRC; + fast = 0; + IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __FUNCTION__); + break; + case 1152000: + ir_mode = IRCC_CFGA_IRDA_HDLC; + ctrl = IRCC_1152 | IRCC_CRC; + fast = IRCC_LCR_A_FAST | IRCC_LCR_A_GP_DATA; + IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", + __FUNCTION__); + break; + case 4000000: + ir_mode = IRCC_CFGA_IRDA_4PPM; + ctrl = IRCC_CRC; + fast = IRCC_LCR_A_FAST; + IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", + __FUNCTION__); + break; + } + #if 0 + Now in tranceiver! + /* This causes an interrupt */ + register_bank(fir_base, 0); + outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast, fir_base+IRCC_LCR_A); + #endif + + register_bank(fir_base, 1); + outb(((inb(fir_base+IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | ir_mode), fir_base+IRCC_SCE_CFGA); + + register_bank(fir_base, 4); + outb((inb(fir_base+IRCC_CONTROL) & 0x30) | ctrl, fir_base+IRCC_CONTROL); +} + +/* + * Function smsc_ircc_fir_start(self) + * + * Change the speed of the device + * + */ +static void smsc_ircc_fir_start(struct smsc_ircc_cb *self) +{ + struct net_device *dev; + int fir_base; + + IRDA_DEBUG(1, "%s\n", __FUNCTION__); + + ASSERT(self != NULL, return;); + dev = self->netdev; + ASSERT(dev != NULL, return;); + + fir_base = self->io.fir_base; + + /* Reset everything */ + + /* Install FIR transmit handler */ + dev->hard_start_xmit = smsc_ircc_hard_xmit_fir; + + /* Clear FIFO */ + outb(inb(fir_base+IRCC_LCR_A)|IRCC_LCR_A_FIFO_RESET, fir_base+IRCC_LCR_A); + + /* Enable interrupt */ + /*outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base+IRCC_IER);*/ + + register_bank(fir_base, 1); + + /* Select the TX/RX interface */ +#ifdef SMSC_669 /* Uses pin 88/89 for Rx/Tx */ + outb(((inb(fir_base+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), + fir_base+IRCC_SCE_CFGB); +#else + outb(((inb(fir_base+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR), + fir_base+IRCC_SCE_CFGB); +#endif + (void) inb(fir_base+IRCC_FIFO_THRESHOLD); + + /* Enable SCE interrupts */ + outb(0, fir_base+IRCC_MASTER); + register_bank(fir_base, 0); + outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base+IRCC_IER); + outb(IRCC_MASTER_INT_EN, fir_base+IRCC_MASTER); +} + +/* + * Function smsc_ircc_fir_stop(self, baud) + * + * Change the speed of the device + * + */ +static void smsc_ircc_fir_stop(struct smsc_ircc_cb *self) +{ + int fir_base; + + IRDA_DEBUG(1, "%s\n", __FUNCTION__); + + ASSERT(self != NULL, return;); + + fir_base = self->io.fir_base; + register_bank(fir_base, 0); + /*outb(IRCC_MASTER_RESET, fir_base+IRCC_MASTER);*/ + outb(inb(fir_base+IRCC_LCR_B) & IRCC_LCR_B_SIP_ENABLE, fir_base+IRCC_LCR_B); +} + + +/* + * Function smsc_ircc_change_speed(self, baud) + * + * Change the speed of the device + * + * This function *must* be called with spinlock held, because it may + * be called from the irq handler. - Jean II + */ +static void smsc_ircc_change_speed(void *priv, u32 speed) +{ + struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) priv; + struct net_device *dev; + int iobase; + int last_speed_was_sir; + + IRDA_DEBUG(0, "%s() changing speed to: %d\n", __FUNCTION__, speed); + + ASSERT(self != NULL, return;); + dev = self->netdev; + iobase = self->io.fir_base; + + last_speed_was_sir = self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED; + + #if 0 + /* Temp Hack */ + speed= 1152000; + self->io.speed = speed; + last_speed_was_sir = 0; + smsc_ircc_fir_start(self); + #endif + + if(self->io.speed == 0) + smsc_ircc_sir_start(self); + + #if 0 + if(!last_speed_was_sir) speed = self->io.speed; + #endif + + if(self->io.speed != speed) smsc_ircc_set_transceiver_for_speed(self, speed); + + self->io.speed = speed; + + if(speed <= SMSC_IRCC2_MAX_SIR_SPEED) { + if(!last_speed_was_sir) { + smsc_ircc_fir_stop(self); + smsc_ircc_sir_start(self); + } + smsc_ircc_set_sir_speed(self, speed); + } + else { + if(last_speed_was_sir) { + #if SMSC_IRCC2_C_SIR_STOP + smsc_ircc_sir_stop(self); + #endif + smsc_ircc_fir_start(self); + } + smsc_ircc_set_fir_speed(self, speed); + + #if 0 + self->tx_buff.len = 10; + self->tx_buff.data = self->tx_buff.head; + + smsc_ircc_dma_xmit(self, iobase, 4000); + #endif + /* Be ready for incoming frames */ + smsc_ircc_dma_receive(self, iobase); + } + + netif_wake_queue(dev); +} + +/* + * Function smsc_ircc_set_sir_speed (self, speed) + * + * Set speed of IrDA port to specified baudrate + * + */ +void smsc_ircc_set_sir_speed(void *priv, __u32 speed) +{ + struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) priv; + int iobase; + int fcr; /* FIFO control reg */ + int lcr; /* Line control reg */ + int divisor; + + IRDA_DEBUG(0, "%s(), Setting speed to: %d\n", __FUNCTION__, speed); + + ASSERT(self != NULL, return;); + iobase = self->io.sir_base; + + /* Update accounting for new speed */ + self->io.speed = speed; + + /* Turn off interrupts */ + outb(0, iobase+UART_IER); + + divisor = SMSC_IRCC2_MAX_SIR_SPEED/speed; + + fcr = UART_FCR_ENABLE_FIFO; + + /* + * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and + * almost 1,7 ms at 19200 bps. At speeds above that we can just forget + * about this timeout since it will always be fast enough. + */ + if (self->io.speed < 38400) + fcr |= UART_FCR_TRIGGER_1; + else + fcr |= UART_FCR_TRIGGER_14; + + /* IrDA ports use 8N1 */ + lcr = UART_LCR_WLEN8; + + outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */ + outb(divisor & 0xff, iobase+UART_DLL); /* Set speed */ + outb(divisor >> 8, iobase+UART_DLM); + outb(lcr, iobase+UART_LCR); /* Set 8N1 */ + outb(fcr, iobase+UART_FCR); /* Enable FIFO's */ + + /* Turn on interrups */ + outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, iobase+UART_IER); + + IRDA_DEBUG(2, "%s() speed changed to: %d\n", __FUNCTION__, speed); +} + + +/* + * Function smsc_ircc_hard_xmit_fir (skb, dev) + * + * Transmit the frame! + * + */ +static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) +{ + struct smsc_ircc_cb *self; + unsigned long flags; + s32 speed; + int iobase; + int mtt; + + ASSERT(dev != NULL, return 0;); + self = (struct smsc_ircc_cb *) dev->priv; + ASSERT(self != NULL, return 0;); + + iobase = self->io.fir_base; + + netif_stop_queue(dev); + + /* Make sure test of self->io.speed & speed change are atomic */ + spin_lock_irqsave(&self->lock, flags); + + /* Check if we need to change the speed after this frame */ + speed = irda_get_next_speed(skb); + if ((speed != self->io.speed) && (speed != -1)) { + /* Check for empty frame */ + if (!skb->len) { + /* Note : you should make sure that speed changes + * are not going to corrupt any outgoing frame. + * Look at nsc-ircc for the gory details - Jean II */ + smsc_ircc_change_speed(self, speed); + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + return 0; + } else + self->new_speed = speed; + } + + memcpy(self->tx_buff.head, skb->data, skb->len); + + self->tx_buff.len = skb->len; + self->tx_buff.data = self->tx_buff.head; + + mtt = irda_get_mtt(skb); + if (mtt) { + int bofs; + + /* + * Compute how many BOFs (STA or PA's) we need to waste the + * min turn time given the speed of the link. + */ + bofs = mtt * (self->io.speed / 1000) / 8000; + if (bofs > 4095) + bofs = 4095; + + smsc_ircc_dma_xmit(self, iobase, bofs); + } else { + /* Transmit frame */ + smsc_ircc_dma_xmit(self, iobase, 0); + } + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function smsc_ircc_dma_xmit (self, iobase) + * + * Transmit data using DMA + * + */ +static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int iobase, int bofs) +{ + u8 ctrl; + + IRDA_DEBUG(3, "%s\n", __FUNCTION__); +#if 1 + /* Disable Rx */ + register_bank(iobase, 0); + outb(0x00, iobase+IRCC_LCR_B); +#endif + register_bank(iobase, 1); + outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + iobase+IRCC_SCE_CFGB); + + self->io.direction = IO_XMIT; + + /* Set BOF additional count for generating the min turn time */ + register_bank(iobase, 4); + outb(bofs & 0xff, iobase+IRCC_BOF_COUNT_LO); + ctrl = inb(iobase+IRCC_CONTROL) & 0xf0; + outb(ctrl | ((bofs >> 8) & 0x0f), iobase+IRCC_BOF_COUNT_HI); + + /* Set max Tx frame size */ + outb(self->tx_buff.len >> 8, iobase+IRCC_TX_SIZE_HI); + outb(self->tx_buff.len & 0xff, iobase+IRCC_TX_SIZE_LO); + + /*outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR);*/ + + /* Enable burst mode chip Tx DMA */ + register_bank(iobase, 1); + outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | + IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB); + + /* Setup DMA controller (must be done after enabling chip DMA) */ + setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len, + DMA_TX_MODE); + + /* Enable interrupt */ + + register_bank(iobase, 0); + outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER); + outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); + + /* Enable transmit */ + outb(IRCC_LCR_B_SCE_TRANSMIT | IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B); +} + +/* + * Function smsc_ircc_dma_xmit_complete (self) + * + * The transfer of a frame in finished. This function will only be called + * by the interrupt handler + * + */ +static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self, int iobase) +{ + IRDA_DEBUG(3, "%s\n", __FUNCTION__); +#if 0 + /* Disable Tx */ + register_bank(iobase, 0); + outb(0x00, iobase+IRCC_LCR_B); +#endif + register_bank(self->io.fir_base, 1); + outb(inb(self->io.fir_base+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + self->io.fir_base+IRCC_SCE_CFGB); + + /* Check for underrun! */ + register_bank(iobase, 0); + if (inb(iobase+IRCC_LSR) & IRCC_LSR_UNDERRUN) { + self->stats.tx_errors++; + self->stats.tx_fifo_errors++; + + /* Reset error condition */ + register_bank(iobase, 0); + outb(IRCC_MASTER_ERROR_RESET, iobase+IRCC_MASTER); + outb(0x00, iobase+IRCC_MASTER); + } else { + self->stats.tx_packets++; + self->stats.tx_bytes += self->tx_buff.len; + } + + /* Check if it's time to change the speed */ + if (self->new_speed) { + smsc_ircc_change_speed(self, self->new_speed); + self->new_speed = 0; + } + + netif_wake_queue(self->netdev); +} + +/* + * Function smsc_ircc_dma_receive(self) + * + * Get ready for receiving a frame. The device will initiate a DMA + * if it starts to receive a frame. + * + */ +static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase) +{ +#if 0 + /* Turn off chip DMA */ + register_bank(iobase, 1); + outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + iobase+IRCC_SCE_CFGB); +#endif + + /* Disable Tx */ + register_bank(iobase, 0); + outb(0x00, iobase+IRCC_LCR_B); + + /* Turn off chip DMA */ + register_bank(iobase, 1); + outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + iobase+IRCC_SCE_CFGB); + + self->io.direction = IO_RECV; + self->rx_buff.data = self->rx_buff.head; + + /* Set max Rx frame size */ + register_bank(iobase, 4); + outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI); + outb(2050 & 0xff, iobase+IRCC_RX_SIZE_LO); + + /* Setup DMA controller */ + setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, + DMA_RX_MODE); + + /* Enable burst mode chip Rx DMA */ + register_bank(iobase, 1); + outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | + IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB); + + /* Enable interrupt */ + register_bank(iobase, 0); + outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER); + outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); + + + /* Enable receiver */ + register_bank(iobase, 0); + outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE, + iobase+IRCC_LCR_B); + + return 0; +} + +/* + * Function smsc_ircc_dma_receive_complete(self, iobase) + * + * Finished with receiving frames + * + */ +static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase) +{ + struct sk_buff *skb; + int len, msgcnt, lsr; + + register_bank(iobase, 0); + + IRDA_DEBUG(3, "%s\n", __FUNCTION__); +#if 0 + /* Disable Rx */ + register_bank(iobase, 0); + outb(0x00, iobase+IRCC_LCR_B); +#endif + register_bank(iobase, 0); + outb(inb(iobase+IRCC_LSAR) & ~IRCC_LSAR_ADDRESS_MASK, iobase+IRCC_LSAR); + lsr= inb(iobase+IRCC_LSR); + msgcnt = inb(iobase+IRCC_LCR_B) & 0x08; + + IRDA_DEBUG(2, "%s: dma count = %d\n", __FUNCTION__, + get_dma_residue(self->io.dma)); + + len = self->rx_buff.truesize - get_dma_residue(self->io.dma); + + /* Look for errors + */ + + if(lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) { + self->stats.rx_errors++; + if(lsr & IRCC_LSR_FRAME_ERROR) self->stats.rx_frame_errors++; + if(lsr & IRCC_LSR_CRC_ERROR) self->stats.rx_crc_errors++; + if(lsr & IRCC_LSR_SIZE_ERROR) self->stats.rx_length_errors++; + if(lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN)) self->stats.rx_length_errors++; + return; + } + /* Remove CRC */ + if (self->io.speed < 4000000) + len -= 2; + else + len -= 4; + + if ((len < 2) || (len > 2050)) { + WARNING("%s(), bogus len=%d\n", __FUNCTION__, len); + return; + } + IRDA_DEBUG(2, "%s: msgcnt = %d, len=%d\n", __FUNCTION__, msgcnt, len); + + skb = dev_alloc_skb(len+1); + if (!skb) { + WARNING("%s(), memory squeeze, dropping frame.\n", + __FUNCTION__); + return; + } + /* Make sure IP header gets aligned */ + skb_reserve(skb, 1); + + memcpy(skb_put(skb, len), self->rx_buff.data, len); + self->stats.rx_packets++; + self->stats.rx_bytes += len; + + skb->dev = self->netdev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); +} + +/* + * Function smsc_ircc_sir_receive (self) + * + * Receive one frame from the infrared port + * + */ +static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self) +{ + int boguscount = 0; + int iobase; + + ASSERT(self != NULL, return;); + + iobase = self->io.sir_base; + + /* + * Receive all characters in Rx FIFO, unwrap and unstuff them. + * async_unwrap_char will deliver all found frames + */ + do { + async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, + inb(iobase+UART_RX)); + + /* Make sure we don't stay here to long */ + if (boguscount++ > 32) { + IRDA_DEBUG(2, "%s(), breaking!\n", __FUNCTION__); + break; + } + } while (inb(iobase+UART_LSR) & UART_LSR_DR); +} + + +/* + * Function smsc_ircc_interrupt (irq, dev_id, regs) + * + * An interrupt from the chip has arrived. Time to do some work + * + */ +static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct smsc_ircc_cb *self; + int iobase, iir, lcra, lsr; + + if (dev == NULL) { + printk(KERN_WARNING "%s: irq %d for unknown device.\n", + driver_name, irq); + return IRQ_NONE; + } + self = (struct smsc_ircc_cb *) dev->priv; + ASSERT(self != NULL, return IRQ_NONE;); + + /* Serialise the interrupt handler in various CPUs, stop Tx path */ + spin_lock(&self->lock); + + /* Check if we should use the SIR interrupt handler */ + if (self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED) { + smsc_ircc_interrupt_sir(irq, dev_id, regs); + spin_unlock(&self->lock); + return IRQ_HANDLED; + } + iobase = self->io.fir_base; + + register_bank(iobase, 0); + iir = inb(iobase+IRCC_IIR); + /* Disable interrupts */ + outb(0, iobase+IRCC_IER); + lcra = inb(iobase+IRCC_LCR_A); + lsr = inb(iobase+IRCC_LSR); + + IRDA_DEBUG(2, "%s(), iir = 0x%02x\n", __FUNCTION__, iir); + + if (iir & IRCC_IIR_EOM) { + if (self->io.direction == IO_RECV) + smsc_ircc_dma_receive_complete(self, iobase); + else + smsc_ircc_dma_xmit_complete(self, iobase); + + smsc_ircc_dma_receive(self, iobase); + } + + if (iir & IRCC_IIR_ACTIVE_FRAME) { + /*printk(KERN_WARNING __FUNCTION__ "(): Active Frame\n");*/ + } + + /* Enable interrupts again */ + + register_bank(iobase, 0); + outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER); + + spin_unlock(&self->lock); + return IRQ_HANDLED; +} + +/* + * Function irport_interrupt_sir (irq, dev_id, regs) + * + * Interrupt handler for SIR modes + */ +void smsc_ircc_interrupt_sir(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct smsc_ircc_cb *self; + int boguscount = 0; + int iobase; + int iir, lsr; + + if (!dev) { + WARNING("%s() irq %d for unknown device.\n", + __FUNCTION__, irq); + return; + } + self = (struct smsc_ircc_cb *) dev->priv; + + /* Already locked comming here in smsc_ircc_interrupt() */ + /*spin_lock(&self->lock);*/ + + iobase = self->io.sir_base; + + iir = inb(iobase+UART_IIR) & UART_IIR_ID; + while (iir) { + /* Clear interrupt */ + lsr = inb(iobase+UART_LSR); + + IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", + __FUNCTION__, iir, lsr, iobase); + + switch (iir) { + case UART_IIR_RLSI: + IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__); + break; + case UART_IIR_RDI: + /* Receive interrupt */ + smsc_ircc_sir_receive(self); + break; + case UART_IIR_THRI: + if (lsr & UART_LSR_THRE) + /* Transmitter ready for data */ + smsc_ircc_sir_write_wakeup(self); + break; + default: + IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", + __FUNCTION__, iir); + break; + } + + /* Make sure we don't stay here to long */ + if (boguscount++ > 100) + break; + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + } + /*spin_unlock(&self->lock);*/ +} + + +#if 0 /* unused */ +/* + * Function ircc_is_receiving (self) + * + * Return TRUE is we are currently receiving a frame + * + */ +static int ircc_is_receiving(struct smsc_ircc_cb *self) +{ + int status = FALSE; + /* int iobase; */ + + IRDA_DEBUG(1, "%s\n", __FUNCTION__); + + ASSERT(self != NULL, return FALSE;); + + IRDA_DEBUG(0, "%s: dma count = %d\n", __FUNCTION__, + get_dma_residue(self->io.dma)); + + status = (self->rx_buff.state != OUTSIDE_FRAME); + + return status; +} +#endif /* unused */ + +static int smsc_ircc_net_init(struct net_device *dev) +{ + /* Keep track of module usage */ + SET_MODULE_OWNER(dev); + + /* Set up to be a normal IrDA network device driver */ + irda_device_setup(dev); + + /* Insert overrides below this line! */ + + return 0; +} + +/* + * Function smsc_ircc_net_open (dev) + * + * Start the device + * + */ +static int smsc_ircc_net_open(struct net_device *dev) +{ + struct smsc_ircc_cb *self; + int iobase; + char hwname[16]; + unsigned long flags; + + IRDA_DEBUG(1, "%s\n", __FUNCTION__); + + ASSERT(dev != NULL, return -1;); + self = (struct smsc_ircc_cb *) dev->priv; + ASSERT(self != NULL, return 0;); + + iobase = self->io.fir_base; + + if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name, + (void *) dev)) { + IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n", + __FUNCTION__, self->io.irq); + return -EAGAIN; + } + + spin_lock_irqsave(&self->lock, flags); + /*smsc_ircc_sir_start(self);*/ + self->io.speed = 0; + smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); + spin_unlock_irqrestore(&self->lock, flags); + + /* Give self a hardware name */ + /* It would be cool to offer the chip revision here - Jean II */ + sprintf(hwname, "SMSC @ 0x%03x", self->io.fir_base); + + /* + * Open new IrLAP layer instance, now that everything should be + * initialized properly + */ + self->irlap = irlap_open(dev, &self->qos, hwname); + + /* + * Always allocate the DMA channel after the IRQ, + * and clean up on failure. + */ + if (request_dma(self->io.dma, dev->name)) { + smsc_ircc_net_close(dev); + + WARNING("%s(), unable to allocate DMA=%d\n", + __FUNCTION__, self->io.dma); + return -EAGAIN; + } + + netif_start_queue(dev); + + return 0; +} + +/* + * Function smsc_ircc_net_close (dev) + * + * Stop the device + * + */ +static int smsc_ircc_net_close(struct net_device *dev) +{ + struct smsc_ircc_cb *self; + int iobase; + + IRDA_DEBUG(1, "%s\n", __FUNCTION__); + + ASSERT(dev != NULL, return -1;); + self = (struct smsc_ircc_cb *) dev->priv; + ASSERT(self != NULL, return 0;); + + iobase = self->io.fir_base; + + /* Stop device */ + netif_stop_queue(dev); + + /* Stop and remove instance of IrLAP */ + if (self->irlap) + irlap_close(self->irlap); + self->irlap = NULL; + + free_irq(self->io.irq, dev); + + disable_dma(self->io.dma); + + free_dma(self->io.dma); + + return 0; +} + + +static void smsc_ircc_suspend(struct smsc_ircc_cb *self) +{ + MESSAGE("%s, Suspending\n", driver_name); + + if (self->io.suspended) + return; + + smsc_ircc_net_close(self->netdev); + + self->io.suspended = 1; +} + +static void smsc_ircc_wakeup(struct smsc_ircc_cb *self) +{ + if (!self->io.suspended) + return; + + /* The code was doing a "cli()" here, but this can't be right. + * If you need protection, do it in net_open with a spinlock + * or give a good reason. - Jean II */ + + smsc_ircc_net_open(self->netdev); + + MESSAGE("%s, Waking up\n", driver_name); +} + +static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + struct smsc_ircc_cb *self = (struct smsc_ircc_cb*) dev->data; + if (self) { + switch (rqst) { + case PM_SUSPEND: + smsc_ircc_suspend(self); + break; + case PM_RESUME: + smsc_ircc_wakeup(self); + break; + } + } + return 0; +} + +/* + * Function smsc_ircc_close (self) + * + * Close driver instance + * + */ +static int __exit smsc_ircc_close(struct smsc_ircc_cb *self) +{ + int iobase; + unsigned long flags; + + IRDA_DEBUG(1, "%s\n", __FUNCTION__); + + ASSERT(self != NULL, return -1;); + + iobase = self->io.fir_base; + + if (self->pmdev) + pm_unregister(self->pmdev); + + /* Remove netdevice */ + if (self->netdev) { + rtnl_lock(); + unregister_netdevice(self->netdev); + rtnl_unlock(); + } + + /* Make sure the irq handler is not exectuting */ + spin_lock_irqsave(&self->lock, flags); + + /* Stop interrupts */ + register_bank(iobase, 0); + outb(0, iobase+IRCC_IER); + outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER); + outb(0x00, iobase+IRCC_MASTER); +#if 0 + /* Reset to SIR mode */ + register_bank(iobase, 1); + outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA); + outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB); +#endif + spin_unlock_irqrestore(&self->lock, flags); + + /* Release the PORTS that this driver is using */ + IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__, + self->io.fir_base); + + release_region(self->io.fir_base, self->io.fir_ext); + + IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__, + self->io.sir_base); + + release_region(self->io.sir_base, self->io.sir_ext); + + if (self->tx_buff.head) + kfree(self->tx_buff.head); + + if (self->rx_buff.head) + kfree(self->rx_buff.head); + + kfree(self); + + return 0; +} + +void __exit smsc_ircc_cleanup(void) +{ + int i; + + IRDA_DEBUG(1, "%s\n", __FUNCTION__); + + for (i=0; i < 2; i++) { + if (dev_self[i]) + smsc_ircc_close(dev_self[i]); + } +} + +/* + * Start SIR operations + * + * This function *must* be called with spinlock held, because it may + * be called from the irq handler (via smsc_ircc_change_speed()). - Jean II + */ +void smsc_ircc_sir_start(struct smsc_ircc_cb *self) +{ + struct net_device *dev; + int fir_base, sir_base; + + IRDA_DEBUG(3, "%s\n", __FUNCTION__); + + ASSERT(self != NULL, return;); + dev= self->netdev; + ASSERT(dev != NULL, return;); + dev->hard_start_xmit = &smsc_ircc_hard_xmit_sir; + + fir_base = self->io.fir_base; + sir_base = self->io.sir_base; + + /* Reset everything */ + outb(IRCC_MASTER_RESET, fir_base+IRCC_MASTER); + + #if SMSC_IRCC2_C_SIR_STOP + /*smsc_ircc_sir_stop(self);*/ + #endif + + register_bank(fir_base, 1); + outb(((inb(fir_base+IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | IRCC_CFGA_IRDA_SIR_A), fir_base+IRCC_SCE_CFGA); + + /* Initialize UART */ + outb(UART_LCR_WLEN8, sir_base+UART_LCR); /* Reset DLAB */ + outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), sir_base+UART_MCR); + + /* Turn on interrups */ + outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base+UART_IER); + + IRDA_DEBUG(3, "%s() - exit\n", __FUNCTION__); + + outb(0x00, fir_base+IRCC_MASTER); +} + +#if SMSC_IRCC2_C_SIR_STOP +void smsc_ircc_sir_stop(struct smsc_ircc_cb *self) +{ + int iobase; + + IRDA_DEBUG(3, "%s\n", __FUNCTION__); + iobase = self->io.sir_base; + + /* Reset UART */ + outb(0, iobase+UART_MCR); + + /* Turn off interrupts */ + outb(0, iobase+UART_IER); +} +#endif + +/* + * Function smsc_sir_write_wakeup (self) + * + * Called by the SIR interrupt handler when there's room for more data. + * If we have more packets to send, we send them here. + * + */ +static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self) +{ + int actual = 0; + int iobase; + int fcr; + + ASSERT(self != NULL, return;); + + IRDA_DEBUG(4, "%s\n", __FUNCTION__); + + iobase = self->io.sir_base; + + /* Finished with frame? */ + if (self->tx_buff.len > 0) { + /* Write data left in transmit buffer */ + actual = smsc_ircc_sir_write(iobase, self->io.fifo_size, + self->tx_buff.data, self->tx_buff.len); + self->tx_buff.data += actual; + self->tx_buff.len -= actual; + } else { + + /*if (self->tx_buff.len ==0) {*/ + + /* + * Now serial buffer is almost free & we can start + * transmission of another packet. But first we must check + * if we need to change the speed of the hardware + */ + if (self->new_speed) { + IRDA_DEBUG(5, "%s(), Changing speed to %d.\n", + __FUNCTION__, self->new_speed); + smsc_ircc_sir_wait_hw_transmitter_finish(self); + smsc_ircc_change_speed(self, self->new_speed); + self->new_speed = 0; + } else { + /* Tell network layer that we want more frames */ + netif_wake_queue(self->netdev); + } + self->stats.tx_packets++; + + if(self->io.speed <= 115200) { + /* + * Reset Rx FIFO to make sure that all reflected transmit data + * is discarded. This is needed for half duplex operation + */ + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR; + if (self->io.speed < 38400) + fcr |= UART_FCR_TRIGGER_1; + else + fcr |= UART_FCR_TRIGGER_14; + + outb(fcr, iobase+UART_FCR); + + /* Turn on receive interrupts */ + outb(UART_IER_RDI, iobase+UART_IER); + } + } +} + +/* + * Function smsc_ircc_sir_write (iobase, fifo_size, buf, len) + * + * Fill Tx FIFO with transmit data + * + */ +static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len) +{ + int actual = 0; + + /* Tx FIFO should be empty! */ + if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { + WARNING("%s(), failed, fifo not empty!\n", __FUNCTION__); + return 0; + } + + /* Fill FIFO with current frame */ + while ((fifo_size-- > 0) && (actual < len)) { + /* Transmit next byte */ + outb(buf[actual], iobase+UART_TX); + actual++; + } + return actual; +} + +/* + * Function smsc_ircc_is_receiving (self) + * + * Returns true is we are currently receiving data + * + */ +static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self) +{ + return (self->rx_buff.state != OUTSIDE_FRAME); +} + + +/* + * Function smsc_ircc_probe_transceiver(self) + * + * Tries to find the used Transceiver + * + */ +static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self) +{ + unsigned int i; + + ASSERT(self != NULL, return;); + + for(i=0; smsc_transceivers[i].name!=NULL; i++) + if((*smsc_transceivers[i].probe)(self->io.fir_base)) { + MESSAGE(" %s transceiver found\n", smsc_transceivers[i].name); + self->transceiver= i+1; + return; + } + MESSAGE("No transceiver found. Defaulting to %s\n", smsc_transceivers[SMSC_IRCC2_C_DEFAULT_TRANSCEIVER].name); + + self->transceiver= SMSC_IRCC2_C_DEFAULT_TRANSCEIVER; +} + + +/* + * Function smsc_ircc_set_transceiver_for_speed(self, speed) + * + * Set the transceiver according to the speed + * + */ +static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed) +{ + unsigned int trx; + + trx = self->transceiver; + if(trx>0) (*smsc_transceivers[trx-1].set_for_speed)(self->io.fir_base, speed); +} + +/* + * Function smsc_ircc_wait_hw_transmitter_finish () + * + * Wait for the real end of HW transmission + * + * The UART is a strict FIFO, and we get called only when we have finished + * pushing data to the FIFO, so the maximum amount of time we must wait + * is only for the FIFO to drain out. + * + * We use a simple calibrated loop. We may need to adjust the loop + * delay (udelay) to balance I/O traffic and latency. And we also need to + * adjust the maximum timeout. + * It would probably be better to wait for the proper interrupt, + * but it doesn't seem to be available. + * + * We can't use jiffies or kernel timers because : + * 1) We are called from the interrupt handler, which disable softirqs, + * so jiffies won't be increased + * 2) Jiffies granularity is usually very coarse (10ms), and we don't + * want to wait that long to detect stuck hardware. + * Jean II + */ + +static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self) +{ + int iobase; + int count = SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US; + + iobase = self->io.sir_base; + + /* Calibrated busy loop */ + while((count-- > 0) && !(inb(iobase+UART_LSR) & UART_LSR_TEMT)) + udelay(1); + + if(count == 0) + IRDA_DEBUG(0, "%s(): stuck transmitter\n", __FUNCTION__); +} + + +/* PROBING + * + * + */ + +static int __init smsc_ircc_look_for_chips(void) +{ + smsc_chip_address_t *address; + char *type; + unsigned int cfg_base, found; + + found = 0; + address = possible_addresses; + + while(address->cfg_base){ + cfg_base = address->cfg_base; + + /*printk(KERN_WARNING __FUNCTION__ "(): probing: 0x%02x for: 0x%02x\n", cfg_base, address->type);*/ + + if( address->type & SMSCSIO_TYPE_FDC){ + type = "FDC"; + if((address->type) & SMSCSIO_TYPE_FLAT) { + if(!smsc_superio_flat(fdc_chips_flat,cfg_base, type)) found++; + } + if((address->type) & SMSCSIO_TYPE_PAGED) { + if(!smsc_superio_paged(fdc_chips_paged,cfg_base, type)) found++; + } + } + if( address->type & SMSCSIO_TYPE_LPC){ + type = "LPC"; + if((address->type) & SMSCSIO_TYPE_FLAT) { + if(!smsc_superio_flat(lpc_chips_flat,cfg_base,type)) found++; + } + if((address->type) & SMSCSIO_TYPE_PAGED) { + if(!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC")) found++; + } + } + address++; + } + return found; +} + +/* + * Function smsc_superio_flat (chip, base, type) + * + * Try to get configuration of a smc SuperIO chip with flat register model + * + */ +static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfgbase, char *type) +{ + unsigned short firbase, sirbase; + u8 mode, dma, irq; + int ret = -ENODEV; + + IRDA_DEBUG(1, "%s\n", __FUNCTION__); + + if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type)==NULL) + return ret; + + outb(SMSCSIOFLAT_UARTMODE0C_REG, cfgbase); + mode = inb(cfgbase+1); + + /*printk(KERN_WARNING __FUNCTION__ "(): mode: 0x%02x\n", mode);*/ + + if(!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA)) + WARNING("%s(): IrDA not enabled\n", __FUNCTION__); + + outb(SMSCSIOFLAT_UART2BASEADDR_REG, cfgbase); + sirbase = inb(cfgbase+1) << 2; + + /* FIR iobase */ + outb(SMSCSIOFLAT_FIRBASEADDR_REG, cfgbase); + firbase = inb(cfgbase+1) << 3; + + /* DMA */ + outb(SMSCSIOFLAT_FIRDMASELECT_REG, cfgbase); + dma = inb(cfgbase+1) & SMSCSIOFLAT_FIRDMASELECT_MASK; + + /* IRQ */ + outb(SMSCSIOFLAT_UARTIRQSELECT_REG, cfgbase); + irq = inb(cfgbase+1) & SMSCSIOFLAT_UART2IRQSELECT_MASK; + + MESSAGE("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", __FUNCTION__, firbase, sirbase, dma, irq, mode); + + if (firbase) { + if (smsc_ircc_open(firbase, sirbase, dma, irq) == 0) + ret=0; + } + + /* Exit configuration */ + outb(SMSCSIO_CFGEXITKEY, cfgbase); + + return ret; +} + +/* + * Function smsc_superio_paged (chip, base, type) + * + * Try to get configuration of a smc SuperIO chip with paged register model + * + */ +static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cfg_base, char *type) +{ + unsigned short fir_io, sir_io; + int ret = -ENODEV; + + IRDA_DEBUG(1, "%s\n", __FUNCTION__); + + if (smsc_ircc_probe(cfg_base,0x20,chips,type)==NULL) + return ret; + + /* Select logical device (UART2) */ + outb(0x07, cfg_base); + outb(0x05, cfg_base + 1); + + /* SIR iobase */ + outb(0x60, cfg_base); + sir_io = inb(cfg_base + 1) << 8; + outb(0x61, cfg_base); + sir_io |= inb(cfg_base + 1); + + /* Read FIR base */ + outb(0x62, cfg_base); + fir_io = inb(cfg_base + 1) << 8; + outb(0x63, cfg_base); + fir_io |= inb(cfg_base + 1); + outb(0x2b, cfg_base); /* ??? */ + + if (fir_io) { + if (smsc_ircc_open(fir_io, sir_io, ircc_dma, ircc_irq) == 0) + ret=0; + } + + /* Exit configuration */ + outb(SMSCSIO_CFGEXITKEY, cfg_base); + + return ret; +} + + +static int __init smsc_access(unsigned short cfg_base,unsigned char reg) +{ + IRDA_DEBUG(1, "%s\n", __FUNCTION__); + + outb(reg, cfg_base); + + if (inb(cfg_base)!=reg) + return -1; + + return 0; +} + +static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg,const smsc_chip_t *chip,char *type) +{ + u8 devid,xdevid,rev; + + IRDA_DEBUG(1, "%s\n", __FUNCTION__); + + /* Leave configuration */ + + outb(SMSCSIO_CFGEXITKEY, cfg_base); + + if (inb(cfg_base) == SMSCSIO_CFGEXITKEY) /* not a smc superio chip */ + return NULL; + + outb(reg, cfg_base); + + xdevid=inb(cfg_base+1); + + /* Enter configuration */ + + outb(SMSCSIO_CFGACCESSKEY, cfg_base); + + #if 0 + if (smsc_access(cfg_base,0x55)) /* send second key and check */ + return NULL; + #endif + + /* probe device ID */ + + if (smsc_access(cfg_base,reg)) + return NULL; + + devid=inb(cfg_base+1); + + if (devid==0) /* typical value for unused port */ + return NULL; + + if (devid==0xff) /* typical value for unused port */ + return NULL; + + /* probe revision ID */ + + if (smsc_access(cfg_base,reg+1)) + return NULL; + + rev=inb(cfg_base+1); + + if (rev>=128) /* i think this will make no sense */ + return NULL; + + if (devid==xdevid) /* protection against false positives */ + return NULL; + + /* Check for expected device ID; are there others? */ + + while(chip->devid!=devid) { + + chip++; + + if (chip->name==NULL) + return NULL; + } + + MESSAGE("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",devid,rev,cfg_base,type,chip->name); + + if (chip->rev>rev){ + MESSAGE("Revision higher than expected\n"); + return NULL; + } + + if (chip->flags&NoIRDA) + MESSAGE("chipset does not support IRDA\n"); + + return chip; +} + +static int __init smsc_superio_fdc(unsigned short cfg_base) +{ + if (check_region(cfg_base, 2) < 0) { + WARNING("%s: can't get cfg_base of 0x%03x\n", + __FUNCTION__, cfg_base); + return -1; + } + + if (!smsc_superio_flat(fdc_chips_flat,cfg_base,"FDC")||!smsc_superio_paged(fdc_chips_paged,cfg_base,"FDC")) + return 0; + + return -1; +} + +static int __init smsc_superio_lpc(unsigned short cfg_base) +{ +#if 0 + if (check_region(cfg_base, 2) < 0) { + IRDA_DEBUG(0, __FUNCTION__ ": can't get cfg_base of 0x%03x\n", + cfg_base); + return -1; + } +#endif + + if (!smsc_superio_flat(lpc_chips_flat,cfg_base,"LPC")||!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC")) + return 0; + + return -1; +} + +/************************************************ + * + * Transceivers specific functions + * + ************************************************/ + + +/* + * Function smsc_ircc_set_transceiver_smsc_ircc_atc(fir_base, speed) + * + * Program transceiver through smsc-ircc ATC circuitry + * + */ + +static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed) +{ + unsigned long jiffies_now, jiffies_timeout; + u8 val; + + jiffies_now= jiffies; + jiffies_timeout= jiffies+SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES; + + /* ATC */ + register_bank(fir_base, 4); + outb((inb(fir_base+IRCC_ATC) & IRCC_ATC_MASK) |IRCC_ATC_nPROGREADY|IRCC_ATC_ENABLE, fir_base+IRCC_ATC); + while((val=(inb(fir_base+IRCC_ATC) & IRCC_ATC_nPROGREADY)) && !time_after(jiffies, jiffies_timeout)); + if(val) + WARNING("%s(): ATC: 0x%02x\n", __FUNCTION__, + inb(fir_base+IRCC_ATC)); +} + +/* + * Function smsc_ircc_probe_transceiver_smsc_ircc_atc(fir_base) + * + * Probe transceiver smsc-ircc ATC circuitry + * + */ + +static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base) +{ + return 0; +} + +/* + * Function smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(self, speed) + * + * Set transceiver + * + */ + +static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed) +{ + u8 fast_mode; + + switch(speed) + { + default: + case 576000 : + fast_mode = 0; + break; + case 1152000 : + case 4000000 : + fast_mode = IRCC_LCR_A_FAST; + break; + + } + register_bank(fir_base, 0); + outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast_mode, fir_base+IRCC_LCR_A); +} + +/* + * Function smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(fir_base) + * + * Probe transceiver + * + */ + +static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base) +{ + return 0; +} + +/* + * Function smsc_ircc_set_transceiver_toshiba_sat1800(fir_base, speed) + * + * Set transceiver + * + */ + +static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed) +{ + u8 fast_mode; + + switch(speed) + { + default: + case 576000 : + fast_mode = 0; + break; + case 1152000 : + case 4000000 : + fast_mode = /*IRCC_LCR_A_FAST |*/ IRCC_LCR_A_GP_DATA; + break; + + } + /* This causes an interrupt */ + register_bank(fir_base, 0); + outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast_mode, fir_base+IRCC_LCR_A); +} + +/* + * Function smsc_ircc_probe_transceiver_toshiba_sat1800(fir_base) + * + * Probe transceiver + * + */ + +static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base) +{ + return 0; +} + + +module_init(smsc_ircc_init); +module_exit(smsc_ircc_cleanup); + +MODULE_AUTHOR("Daniele Peri <peri@csai.unipa.it>"); +MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(ircc_dma, "1i"); +MODULE_PARM_DESC(ircc_dma, "DMA channel"); +MODULE_PARM(ircc_irq, "1i"); +MODULE_PARM_DESC(ircc_irq, "IRQ line"); +MODULE_PARM(ircc_fir, "1-4i"); +MODULE_PARM_DESC(ircc_fir, "FIR Base Address"); +MODULE_PARM(ircc_sir, "1-4i"); +MODULE_PARM_DESC(ircc_sir, "SIR Base Address"); +MODULE_PARM(ircc_cfg, "1-4i"); +MODULE_PARM_DESC(ircc_cfg, "Configuration register base address"); +MODULE_PARM(ircc_transceiver, "1i"); +MODULE_PARM_DESC(ircc_transceiver, "Transceiver type"); diff --git a/drivers/net/irda/smsc-ircc2.h b/drivers/net/irda/smsc-ircc2.h new file mode 100644 index 000000000000..458611cc0d40 --- /dev/null +++ b/drivers/net/irda/smsc-ircc2.h @@ -0,0 +1,194 @@ +/********************************************************************* + * $Id: smsc-ircc2.h,v 1.12.2.1 2002/10/27 10:52:37 dip Exp $ + * + * Description: Definitions for the SMC IrCC chipset + * Status: Experimental. + * Author: Daniele Peri (peri@csai.unipa.it) + * + * Copyright (c) 2002 Daniele Peri + * All Rights Reserved. + * + * Based on smc-ircc.h: + * + * Copyright (c) 1999-2000, Dag Brattli <dagb@cs.uit.no> + * Copyright (c) 1998-1999, Thomas Davis (tadavis@jps.net> + * All Rights Reserved + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef SMSC_IRCC2_H +#define SMSC_IRCC2_H + +/* DMA modes needed */ +#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */ +#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */ + +/* Master Control Register */ +#define IRCC_MASTER 0x07 +#define IRCC_MASTER_POWERDOWN 0x80 +#define IRCC_MASTER_RESET 0x40 +#define IRCC_MASTER_INT_EN 0x20 +#define IRCC_MASTER_ERROR_RESET 0x10 + +/* Register block 0 */ + +/* Interrupt Identification */ +#define IRCC_IIR 0x01 +#define IRCC_IIR_ACTIVE_FRAME 0x80 +#define IRCC_IIR_EOM 0x40 +#define IRCC_IIR_RAW_MODE 0x20 +#define IRCC_IIR_FIFO 0x10 + +/* Interrupt Enable */ +#define IRCC_IER 0x02 +#define IRCC_IER_ACTIVE_FRAME 0x80 +#define IRCC_IER_EOM 0x40 +#define IRCC_IER_RAW_MODE 0x20 +#define IRCC_IER_FIFO 0x10 + +/* Line Status Register */ +#define IRCC_LSR 0x03 +#define IRCC_LSR_UNDERRUN 0x80 +#define IRCC_LSR_OVERRUN 0x40 +#define IRCC_LSR_FRAME_ERROR 0x20 +#define IRCC_LSR_SIZE_ERROR 0x10 +#define IRCC_LSR_CRC_ERROR 0x80 +#define IRCC_LSR_FRAME_ABORT 0x40 + +/* Line Status Address Register */ +#define IRCC_LSAR 0x03 +#define IRCC_LSAR_ADDRESS_MASK 0x07 + +/* Line Control Register A */ +#define IRCC_LCR_A 0x04 +#define IRCC_LCR_A_FIFO_RESET 0x80 +#define IRCC_LCR_A_FAST 0x40 +#define IRCC_LCR_A_GP_DATA 0x20 +#define IRCC_LCR_A_RAW_TX 0x10 +#define IRCC_LCR_A_RAW_RX 0x08 +#define IRCC_LCR_A_ABORT 0x04 +#define IRCC_LCR_A_DATA_DONE 0x02 + +/* Line Control Register B */ +#define IRCC_LCR_B 0x05 +#define IRCC_LCR_B_SCE_DISABLED 0x00 +#define IRCC_LCR_B_SCE_TRANSMIT 0x40 +#define IRCC_LCR_B_SCE_RECEIVE 0x80 +#define IRCC_LCR_B_SCE_UNDEFINED 0xc0 +#define IRCC_LCR_B_SIP_ENABLE 0x20 +#define IRCC_LCR_B_BRICK_WALL 0x10 + +/* Bus Status Register */ +#define IRCC_BSR 0x06 +#define IRCC_BSR_NOT_EMPTY 0x80 +#define IRCC_BSR_FIFO_FULL 0x40 +#define IRCC_BSR_TIMEOUT 0x20 + +/* Register block 1 */ + +#define IRCC_FIFO_THRESHOLD 0x02 + +#define IRCC_SCE_CFGA 0x00 +#define IRCC_CFGA_AUX_IR 0x80 +#define IRCC_CFGA_HALF_DUPLEX 0x04 +#define IRCC_CFGA_TX_POLARITY 0x02 +#define IRCC_CFGA_RX_POLARITY 0x01 + +#define IRCC_CFGA_COM 0x00 +#define IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK 0x87 +#define IRCC_CFGA_IRDA_SIR_A 0x08 +#define IRCC_CFGA_ASK_SIR 0x10 +#define IRCC_CFGA_IRDA_SIR_B 0x18 +#define IRCC_CFGA_IRDA_HDLC 0x20 +#define IRCC_CFGA_IRDA_4PPM 0x28 +#define IRCC_CFGA_CONSUMER 0x30 +#define IRCC_CFGA_RAW_IR 0x38 +#define IRCC_CFGA_OTHER 0x40 + +#define IRCC_IR_HDLC 0x04 +#define IRCC_IR_4PPM 0x01 +#define IRCC_IR_CONSUMER 0x02 + +#define IRCC_SCE_CFGB 0x01 +#define IRCC_CFGB_LOOPBACK 0x20 +#define IRCC_CFGB_LPBCK_TX_CRC 0x10 +#define IRCC_CFGB_NOWAIT 0x08 +#define IRCC_CFGB_STRING_MOVE 0x04 +#define IRCC_CFGB_DMA_BURST 0x02 +#define IRCC_CFGB_DMA_ENABLE 0x01 + +#define IRCC_CFGB_MUX_COM 0x00 +#define IRCC_CFGB_MUX_IR 0x40 +#define IRCC_CFGB_MUX_AUX 0x80 +#define IRCC_CFGB_MUX_INACTIVE 0xc0 + +/* Register block 3 - Identification Registers! */ +#define IRCC_ID_HIGH 0x00 /* 0x10 */ +#define IRCC_ID_LOW 0x01 /* 0xB8 */ +#define IRCC_CHIP_ID 0x02 /* 0xF1 */ +#define IRCC_VERSION 0x03 /* 0x01 */ +#define IRCC_INTERFACE 0x04 /* low 4 = DMA, high 4 = IRQ */ +#define IRCC_INTERFACE_DMA_MASK 0x0F /* low 4 = DMA, high 4 = IRQ */ +#define IRCC_INTERFACE_IRQ_MASK 0xF0 /* low 4 = DMA, high 4 = IRQ */ + +/* Register block 4 - IrDA */ +#define IRCC_CONTROL 0x00 +#define IRCC_BOF_COUNT_LO 0x01 /* Low byte */ +#define IRCC_BOF_COUNT_HI 0x00 /* High nibble (bit 0-3) */ +#define IRCC_BRICKWALL_CNT_LO 0x02 /* Low byte */ +#define IRCC_BRICKWALL_CNT_HI 0x03 /* High nibble (bit 4-7) */ +#define IRCC_TX_SIZE_LO 0x04 /* Low byte */ +#define IRCC_TX_SIZE_HI 0x03 /* High nibble (bit 0-3) */ +#define IRCC_RX_SIZE_HI 0x05 /* High nibble (bit 0-3) */ +#define IRCC_RX_SIZE_LO 0x06 /* Low byte */ + +#define IRCC_1152 0x80 +#define IRCC_CRC 0x40 + +/* Register block 5 - IrDA */ +#define IRCC_ATC 0x00 +#define IRCC_ATC_nPROGREADY 0x80 +#define IRCC_ATC_SPEED 0x40 +#define IRCC_ATC_ENABLE 0x20 +#define IRCC_ATC_MASK 0xE0 + + +#define IRCC_IRHALFDUPLEX_TIMEOUT 0x01 + +#define IRCC_SCE_TX_DELAY_TIMER 0x02 + +/* + * Other definitions + */ + +#define SMSC_IRCC2_MAX_SIR_SPEED 115200 +#define SMSC_IRCC2_FIR_CHIP_IO_EXTENT 8 +#define SMSC_IRCC2_SIR_CHIP_IO_EXTENT 8 +#define SMSC_IRCC2_FIFO_SIZE 16 +#define SMSC_IRCC2_FIFO_THRESHOLD 64 +/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ +#define SMSC_IRCC2_RX_BUFF_TRUESIZE 14384 +#define SMSC_IRCC2_TX_BUFF_TRUESIZE 14384 +#define SMSC_IRCC2_MIN_TURN_TIME 0x07 +#define SMSC_IRCC2_WINDOW_SIZE 0x07 +/* Maximum wait for hw transmitter to finish */ +#define SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US 1000 /* 1 ms */ +/* Maximum wait for ATC transceiver programming to finish */ +#define SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES 1 +#endif /* SMSC_IRCC2_H */ diff --git a/drivers/net/irda/smsc-sio.h b/drivers/net/irda/smsc-sio.h new file mode 100644 index 000000000000..59e20e653ebe --- /dev/null +++ b/drivers/net/irda/smsc-sio.h @@ -0,0 +1,100 @@ +#ifndef SMSC_SIO_H +#define SMSC_SIO_H + +/****************************************** + Keys. They should work with every SMsC SIO + ******************************************/ + +#define SMSCSIO_CFGACCESSKEY 0x55 +#define SMSCSIO_CFGEXITKEY 0xaa + +/***************************** + * Generic SIO Flat (!?) * + *****************************/ + +/* Register 0x0d */ +#define SMSCSIOFLAT_DEVICEID_REG 0x0d + +/* Register 0x0c */ +#define SMSCSIOFLAT_UARTMODE0C_REG 0x0c +#define SMSCSIOFLAT_UART2MODE_MASK 0x38 +#define SMSCSIOFLAT_UART2MODE_VAL_COM 0x00 +#define SMSCSIOFLAT_UART2MODE_VAL_IRDA 0x08 +#define SMSCSIOFLAT_UART2MODE_VAL_ASKIR 0x10 + +/* Register 0x25 */ +#define SMSCSIOFLAT_UART2BASEADDR_REG 0x25 + +/* Register 0x2b */ +#define SMSCSIOFLAT_FIRBASEADDR_REG 0x2b + +/* Register 0x2c */ +#define SMSCSIOFLAT_FIRDMASELECT_REG 0x2c +#define SMSCSIOFLAT_FIRDMASELECT_MASK 0x0f + +/* Register 0x28 */ +#define SMSCSIOFLAT_UARTIRQSELECT_REG 0x28 +#define SMSCSIOFLAT_UART2IRQSELECT_MASK 0x0f +#define SMSCSIOFLAT_UART1IRQSELECT_MASK 0xf0 +#define SMSCSIOFLAT_UARTIRQSELECT_VAL_NONE 0x00 + + +/********************* + * LPC47N227 * + *********************/ + +#define LPC47N227_CFGACCESSKEY 0x55 +#define LPC47N227_CFGEXITKEY 0xaa + +/* Register 0x00 */ +#define LPC47N227_FDCPOWERVALIDCONF_REG 0x00 +#define LPC47N227_FDCPOWER_MASK 0x08 +#define LPC47N227_VALID_MASK 0x80 + +/* Register 0x02 */ +#define LPC47N227_UART12POWER_REG 0x02 +#define LPC47N227_UART1POWERDOWN_MASK 0x08 +#define LPC47N227_UART2POWERDOWN_MASK 0x80 + +/* Register 0x07 */ +#define LPC47N227_APMBOOTDRIVE_REG 0x07 +#define LPC47N227_PARPORT2AUTOPWRDOWN_MASK 0x10 /* auto power down on if set */ +#define LPC47N227_UART2AUTOPWRDOWN_MASK 0x20 /* auto power down on if set */ +#define LPC47N227_UART1AUTOPWRDOWN_MASK 0x40 /* auto power down on if set */ + +/* Register 0x0c */ +#define LPC47N227_UARTMODE0C_REG 0x0c +#define LPC47N227_UART2MODE_MASK 0x38 +#define LPC47N227_UART2MODE_VAL_COM 0x00 +#define LPC47N227_UART2MODE_VAL_IRDA 0x08 +#define LPC47N227_UART2MODE_VAL_ASKIR 0x10 + +/* Register 0x0d */ +#define LPC47N227_DEVICEID_REG 0x0d +#define LPC47N227_DEVICEID_DEFVAL 0x5a + +/* Register 0x0e */ +#define LPC47N227_REVISIONID_REG 0x0e + +/* Register 0x25 */ +#define LPC47N227_UART2BASEADDR_REG 0x25 + +/* Register 0x28 */ +#define LPC47N227_UARTIRQSELECT_REG 0x28 +#define LPC47N227_UART2IRQSELECT_MASK 0x0f +#define LPC47N227_UART1IRQSELECT_MASK 0xf0 +#define LPC47N227_UARTIRQSELECT_VAL_NONE 0x00 + +/* Register 0x2b */ +#define LPC47N227_FIRBASEADDR_REG 0x2b + +/* Register 0x2c */ +#define LPC47N227_FIRDMASELECT_REG 0x2c +#define LPC47N227_FIRDMASELECT_MASK 0x0f +#define LPC47N227_FIRDMASELECT_VAL_DMA1 0x01 /* 47n227 has three dma channels */ +#define LPC47N227_FIRDMASELECT_VAL_DMA2 0x02 +#define LPC47N227_FIRDMASELECT_VAL_DMA3 0x03 +#define LPC47N227_FIRDMASELECT_VAL_NONE 0x0f + + +#endif diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 3013e4e821ab..709f375bb1d9 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -524,6 +524,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) /* Check for empty frame */ if (!skb->len) { w83977af_change_speed(self, speed); + dev->trans_start = jiffies; dev_kfree_skb(skb); return 0; } else @@ -579,6 +580,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) switch_bank(iobase, SET0); outb(ICR_ETXTHI, iobase+ICR); } + dev->trans_start = jiffies; dev_kfree_skb(skb); /* Restore set register */ diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 9f10842ab0dd..7f4e64360f15 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -541,6 +541,7 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs) struct myri_channel *chan = &mp->shmem->channel; unsigned long flags; u32 status; + int handled = 0; spin_lock_irqsave(&mp->irq_lock, flags); @@ -549,6 +550,7 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (status & ISTAT_HOST) { u32 softstate; + handled = 1; DIRQ(("IRQ_DISAB ")); myri_disable_irq(lregs, mp->cregs); softstate = sbus_readl(&chan->state); @@ -568,7 +570,7 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs) spin_unlock_irqrestore(&mp->irq_lock, flags); - return IRQ_HANDLED; + return IRQ_RETVAL(handled); } static int myri_open(struct net_device *dev) diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index c4c6e0d13d41..06feb5870fc8 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -202,7 +202,6 @@ ppp_sync_open(struct tty_struct *tty) struct syncppp *ap; int err; - MOD_INC_USE_COUNT; ap = kmalloc(sizeof(*ap), GFP_KERNEL); err = -ENOMEM; if (ap == 0) @@ -236,7 +235,6 @@ ppp_sync_open(struct tty_struct *tty) out_free: kfree(ap); out: - MOD_DEC_USE_COUNT; return err; } @@ -276,7 +274,6 @@ ppp_sync_close(struct tty_struct *tty) if (ap->tpkt != 0) kfree_skb(ap->tpkt); kfree(ap); - MOD_DEC_USE_COUNT; } /* @@ -404,6 +401,7 @@ ppp_sync_wakeup(struct tty_struct *tty) static struct tty_ldisc ppp_sync_ldisc = { + .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "pppsync", .open = ppp_sync_open, diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index d0b1dc9ffa1a..08cd543eda47 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -84,7 +84,7 @@ static int seeq8005_probe1(struct net_device *dev, int ioaddr); static int seeq8005_open(struct net_device *dev); static void seeq8005_timeout(struct net_device *dev); static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev); -static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void seeq8005_rx(struct net_device *dev); static int seeq8005_close(struct net_device *dev); static struct net_device_stats *seeq8005_get_stats(struct net_device *dev); @@ -400,11 +400,12 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) /* The typical workload of the driver: Handle the network interface interrupts. */ -static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; struct net_local *lp; int ioaddr, status, boguscount = 0; + int handled = 0; ioaddr = dev->base_addr; lp = (struct net_local *)dev->priv; @@ -416,17 +417,20 @@ static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs) } if (status & SEEQSTAT_WINDOW_INT) { + handled = 1; outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); if (net_debug) { printk("%s: window int!\n",dev->name); } } if (status & SEEQSTAT_TX_INT) { + handled = 1; outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); lp->stats.tx_packets++; netif_wake_queue(dev); /* Inform upper layers. */ } if (status & SEEQSTAT_RX_INT) { + handled = 1; /* Got a packet(s). */ seeq8005_rx(dev); } @@ -436,6 +440,7 @@ static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs) if(net_debug>2) { printk("%s: eoi\n",dev->name); } + return IRQ_RETVAL(handled); } /* We have a good packet(s), get it/them out of the buffers. */ diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index a80a2f87c3e1..93949db1e758 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -124,6 +124,7 @@ static void qe_init_rings(struct sunqe *qep) qb->qe_rxd[i].rx_flags = (RXD_OWN | ((RXD_PKT_SZ) & RXD_LENGTH)); } + return IRQ_HANDLED; } static int qe_init(struct sunqe *qep, int from_irq) diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 455702a8cd18..d74cb55dc3d9 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -201,7 +201,7 @@ static int streamer_open(struct net_device *dev); static int streamer_xmit(struct sk_buff *skb, struct net_device *dev); static int streamer_close(struct net_device *dev); static void streamer_set_rx_mode(struct net_device *dev); -static void streamer_interrupt(int irq, void *dev_id, +static irqreturn_t streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs); static struct net_device_stats *streamer_get_stats(struct net_device *dev); static int streamer_set_mac_address(struct net_device *dev, void *addr); @@ -1021,7 +1021,7 @@ static void streamer_rx(struct net_device *dev) } /* end for all completed rx descriptors */ } -static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; struct streamer_private *streamer_priv = @@ -1142,6 +1142,7 @@ static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs) } /* while() */ spin_unlock(&streamer_priv->streamer_lock) ; + return IRQ_HANDLED; } static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 9a534bb64557..8a74d3280e73 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -2027,7 +2027,7 @@ set_multicast_list(struct net_device *dev) } } - return; + return IRQ_HANDLED; } /* diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index d94ceadfcb9e..8685e91d5a9c 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -117,7 +117,7 @@ static int lmc_rx (struct net_device *dev); static int lmc_open(struct net_device *dev); static int lmc_close(struct net_device *dev); static struct net_device_stats *lmc_get_stats(struct net_device *dev); -static void lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static int lmc_set_config(struct net_device *dev, struct ifmap *map); static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size); static void lmc_softreset(lmc_softc_t * const); @@ -1388,7 +1388,7 @@ static int lmc_ifdown (struct net_device *dev) /*fold00*/ /* Interrupt handling routine. This will take an incoming packet, or clean * up after a trasmit. */ -static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/ +static irqreturn_t lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/ { struct net_device *dev = (struct net_device *) dev_instance; lmc_softc_t *sc; @@ -1398,6 +1398,7 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /* unsigned int badtx; u32 firstcsr; int max_work = LMC_RXDESCS; + int handled = 0; lmc_trace(dev, "lmc_interrupt in"); @@ -1421,6 +1422,8 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /* /* always go through this loop at least once */ while (csr & sc->lmc_intrmask) { + handled = 1; + /* * Clear interrupt bits, we handle all case below */ @@ -1580,6 +1583,7 @@ lmc_int_fail_out: spin_unlock(&sc->lmc_lock); lmc_trace(dev, "lmc_interrupt out"); + return IRQ_RETVAL(handled); } static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/ diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c index 7235f23f511a..d3cc5a0b4c67 100644 --- a/drivers/net/wireless/airport.c +++ b/drivers/net/wireless/airport.c @@ -275,15 +275,11 @@ init_airport(void) printk(KERN_DEBUG "%s\n", version); - MOD_INC_USE_COUNT; - /* Lookup card in device tree */ airport_node = find_devices("radio"); if (airport_node && !strcmp(airport_node->parent->name, "mac-io")) airport_dev = airport_attach(airport_node); - MOD_DEC_USE_COUNT; - return airport_dev ? 0 : -ENODEV; } diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index 869a3f5273e2..c82630ec1819 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -299,8 +299,8 @@ static int oprofilefs_fill_super(struct super_block * sb, void * data, int silen } -static struct super_block * oprofilefs_get_sb(struct file_system_type * fs_type, - int flags, char * dev_name, void * data) +static struct super_block *oprofilefs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { return get_sb_single(fs_type, flags, data, oprofilefs_fill_super); } diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 53f05b670bb6..8fcd56ebb4e3 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -489,7 +489,7 @@ static void fs_remove_file (struct dentry *dentry) static struct file_system_type usbdevice_fs_type; static struct super_block *usb_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { if (fs_type == &usbdevice_fs_type) printk (KERN_INFO "Please use the 'usbfs' filetype instead, " diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 14def9ef7385..d5b8294a2fa1 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -459,7 +459,7 @@ error: } static struct super_block *adfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, adfs_fill_super); } diff --git a/fs/affs/super.c b/fs/affs/super.c index f3e7aad77c4a..61c71fe3f785 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -210,9 +210,7 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s optn = "volume"; if (!value || !*value) goto out_no_arg; - if (strlen(value) > 30) - value[30] = 0; - strncpy(volume,value,30); + strlcpy(volume,value,31); } else if (!strcmp(this_char,"mode")) { optn = "mode"; if (!value || !*value) @@ -543,7 +541,7 @@ affs_statfs(struct super_block *sb, struct statfs *buf) } static struct super_block *affs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, affs_fill_super); } diff --git a/fs/afs/super.c b/fs/afs/super.c index 0e4603081774..f02009bf7bd6 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -40,7 +40,8 @@ static inline char *strdup(const char *s) static void afs_i_init_once(void *foo, kmem_cache_t *cachep, unsigned long flags); static struct super_block *afs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data); + int flags, const char *dev_name, + void *data); static struct inode *afs_alloc_inode(struct super_block *sb); @@ -407,10 +408,9 @@ static int afs_fill_super(struct super_block *sb, void *_data, int silent) * get an AFS superblock * - TODO: don't use get_sb_nodev(), but rather call sget() directly */ -static struct super_block *afs_get_sb(struct file_system_type *fs_type, - int flags, - char *dev_name, - void *options) +static struct super_block * +afs_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *options) { struct super_block *sb; void *data[2] = { dev_name, options }; diff --git a/fs/autofs/init.c b/fs/autofs/init.c index 87744e9bee0d..b977ece69f0c 100644 --- a/fs/autofs/init.c +++ b/fs/autofs/init.c @@ -15,7 +15,7 @@ #include "autofs_i.h" static struct super_block *autofs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_nodev(fs_type, flags, data, autofs_fill_super); } diff --git a/fs/autofs4/init.c b/fs/autofs4/init.c index d8d9c3cf8d13..acecec8578ce 100644 --- a/fs/autofs4/init.c +++ b/fs/autofs4/init.c @@ -15,7 +15,7 @@ #include "autofs_i.h" static struct super_block *autofs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_nodev(fs_type, flags, data, autofs4_fill_super); } diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index c2d5ca4d16f2..5295f9d97c84 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -916,8 +916,8 @@ befs_statfs(struct super_block *sb, struct statfs *buf) } static struct super_block * -befs_get_sb(struct file_system_type *fs_type, int flags, char *dev_name, - void *data) +befs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, + void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, befs_fill_super); } diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 0aeab591b8cf..7a28495b0a87 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -379,7 +379,7 @@ out: } static struct super_block *bfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, bfs_fill_super); } diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index d9e70fb1c0e1..bc72ed4d368e 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -113,10 +113,8 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) /* to keep locking time low, we copy the interpreter string */ read_lock(&entries_lock); fmt = check_file(bprm); - if (fmt) { - strncpy(iname, fmt->interpreter, BINPRM_BUF_SIZE - 1); - iname[BINPRM_BUF_SIZE - 1] = '\0'; - } + if (fmt) + strlcpy(iname, fmt->interpreter, BINPRM_BUF_SIZE); read_unlock(&entries_lock); if (!fmt) goto _ret; @@ -623,7 +621,7 @@ static int bm_fill_super(struct super_block * sb, void * data, int silent) } static struct super_block *bm_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_single(fs_type, flags, data, bm_fill_super); } diff --git a/fs/block_dev.c b/fs/block_dev.c index 58b7813539e9..52e956455310 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -196,7 +196,7 @@ static int block_fsync(struct file *filp, struct dentry *dentry, int datasync) */ static struct super_block *bd_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_pseudo(fs_type, "bdev:", NULL, 0x62646576); } diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index d6244d17f236..f754ff70c9d2 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -57,13 +57,14 @@ unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE; struct task_struct * oplockThread = NULL; extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, - char *); + const char *); extern int cifs_umount(struct super_block *, struct cifs_sb_info *); void cifs_proc_init(void); void cifs_proc_clean(void); static int -cifs_read_super(struct super_block *sb, void *data, char *devname, int silent) +cifs_read_super(struct super_block *sb, void *data, + const char *devname, int silent) { struct inode *inode; struct cifs_sb_info *cifs_sb; @@ -251,7 +252,7 @@ struct super_operations cifs_super_ops = { static struct super_block * cifs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { int rc; struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 89fd14b85887..d74c9e601293 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -342,7 +342,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } int -parse_mount_options(char *options, char *devname, struct smb_vol *vol) +parse_mount_options(char *options, const char *devname, struct smb_vol *vol) { char *value; char *data; @@ -795,7 +795,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) int cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, - char *mount_data, char *devname) + char *mount_data, const char *devname) { int rc = 0; int xid; @@ -811,7 +811,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, xid = GetXid(); cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); - if(parse_mount_options(mount_data, devname, &volume_info)) { + if (parse_mount_options(mount_data, devname, &volume_info)) { FreeXid(xid); return -EINVAL; } diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 2728e039f86a..03a21eb84918 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -303,7 +303,7 @@ static int coda_statfs(struct super_block *sb, struct statfs *buf) /* init_coda: used by filesystems.c to register coda */ static struct super_block *coda_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_nodev(fs_type, flags, data, coda_fill_super); } diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index af2c968a5571..7e7f162fc0e3 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -464,7 +464,7 @@ static struct super_operations cramfs_ops = { }; static struct super_block *cramfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, cramfs_fill_super); } diff --git a/fs/devfs/base.c b/fs/devfs/base.c index 6ca2544a5322..5e6374bc8d20 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -2554,8 +2554,9 @@ out_no_root: return -EINVAL; } /* End Function devfs_fill_super */ -static struct super_block *devfs_get_sb (struct file_system_type *fs_type, - int flags, char *dev_name, void *data) +static struct super_block * +devfs_get_sb (struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { return get_sb_single (fs_type, flags, data, devfs_fill_super); } diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 3f871c1fa42a..64a97888a1f1 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -73,7 +73,8 @@ static struct super_operations devpts_sops = { .remount_fs = devpts_remount, }; -static int devpts_fill_super(struct super_block *s, void *data, int silent) +static int +devpts_fill_super(struct super_block *s, void *data, int silent) { struct inode * inode; @@ -106,7 +107,7 @@ fail: } static struct super_block *devpts_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_single(fs_type, flags, data, devpts_fill_super); } diff --git a/fs/efs/super.c b/fs/efs/super.c index 21be0cb8cb50..d3f72b95208c 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -16,7 +16,7 @@ #include <linux/vfs.h> static struct super_block *efs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, efs_fill_super); } diff --git a/fs/eventpoll.c b/fs/eventpoll.c index da1114d24455..f264bc7f3ddf 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -260,17 +260,20 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi); static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync); static int ep_eventpoll_close(struct inode *inode, struct file *file); static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait); -static int ep_collect_ready_items(struct eventpoll *ep, struct list_head *txlist, int maxevents); +static int ep_collect_ready_items(struct eventpoll *ep, + struct list_head *txlist, int maxevents); static int ep_send_events(struct eventpoll *ep, struct list_head *txlist, struct epoll_event *events); static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist); -static int ep_events_transfer(struct eventpoll *ep, struct epoll_event *events, int maxevents); -static int ep_poll(struct eventpoll *ep, struct epoll_event *events, int maxevents, - long timeout); +static int ep_events_transfer(struct eventpoll *ep, + struct epoll_event *events, int maxevents); +static int ep_poll(struct eventpoll *ep, struct epoll_event *events, + int maxevents, long timeout); static int eventpollfs_delete_dentry(struct dentry *dentry); static struct inode *ep_eventpoll_inode(void); static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data); + int flags, const char *dev_name, + void *data); /* Safe wake up implementation */ @@ -1637,10 +1640,10 @@ eexit_1: } -static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) +static struct super_block * +eventpollfs_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { - return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC); } diff --git a/fs/ext2/super.c b/fs/ext2/super.c index dc7ced597149..48a3d099f9a0 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -989,7 +989,7 @@ static int ext2_statfs (struct super_block * sb, struct statfs * buf) } static struct super_block *ext2_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super); } diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 6d27c23210b8..272197d032a2 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -2029,7 +2029,7 @@ static int ext3_sync_dquot(struct dquot *dquot) #endif static struct super_block *ext3_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, ext3_fill_super); } diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index c3d3f301ba20..d3ebd64c780e 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -230,7 +230,7 @@ out: * The usual module blurb. */ static struct super_block *vxfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, vxfs_fill_super); } diff --git a/fs/hfs/super.c b/fs/hfs/super.c index f93f0e78789b..48be69ce4108 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -100,7 +100,7 @@ static struct super_operations hfs_super_operations = { /*================ File-local variables ================*/ static struct super_block *hfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, hfs_fill_super); } diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index aaa088d8601c..36aa38cd829a 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -637,7 +637,7 @@ bail0: } static struct super_block *hpfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, hpfs_fill_super); } diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index db0e1597caa3..a1fe7e32422f 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -501,7 +501,7 @@ hugetlbfs_fill_super(struct super_block * sb, void * data, int silent) } static struct super_block *hugetlbfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_nodev(fs_type, flags, data, hugetlbfs_fill_super); } diff --git a/fs/intermezzo/super.c b/fs/intermezzo/super.c index be225ba1155f..82104dd3093c 100644 --- a/fs/intermezzo/super.c +++ b/fs/intermezzo/super.c @@ -187,8 +187,9 @@ static int presto_set_channel(struct presto_cache *cache, char *channel) /* We always need to remove the presto options before passing mount options to cache FS */ -struct super_block * presto_get_sb(struct file_system_type *izo_type, - int flags, char *devname, void * data) +struct super_block * +presto_get_sb(struct file_system_type *izo_type, int flags, + const char *devname, void *data) { struct file_system_type *fstype; struct presto_cache *cache = NULL; diff --git a/fs/intermezzo/vfs.c b/fs/intermezzo/vfs.c index 2125ee5af0d9..f0352cb1f35f 100644 --- a/fs/intermezzo/vfs.c +++ b/fs/intermezzo/vfs.c @@ -2388,7 +2388,7 @@ int presto_do_set_ext_attr(struct presto_file_set *fset, /* We first "truncate" name to the maximum allowable in presto */ /* This simulates the strncpy_from_use code in fs/ext_attr.c */ - strncpy(temp,name,sizeof(temp)); + strlcpy(temp,name,sizeof(temp)); /* Pass down to cache*/ error = iops->set_ext_attr(inode,temp,buffer,buffer_len,flags); diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 9c47f2565297..b252fc2e3623 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -1376,7 +1376,7 @@ void leak_check_brelse(struct buffer_head * bh){ #endif static struct super_block *isofs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, isofs_fill_super); } diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index e74ce5fc40f8..e7e6d5442774 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -1783,7 +1783,7 @@ static struct super_operations jffs_ops = }; static struct super_block *jffs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, jffs_fill_super); } diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index bce925b6c9ab..e87cdaececb6 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -101,9 +101,9 @@ static int jffs2_sb_set(struct super_block *sb, void *data) return 0; } -static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, - int flags, char *dev_name, - void *data, struct mtd_info *mtd) +static struct super_block * +jffs2_get_sb_mtd(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, struct mtd_info *mtd) { struct super_block *sb; struct jffs2_sb_info *c; @@ -153,9 +153,9 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, return sb; } -static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type, - int flags, char *dev_name, - void *data, int mtdnr) +static struct super_block * +jffs2_get_sb_mtdnr(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, int mtdnr) { struct mtd_info *mtd; @@ -168,8 +168,9 @@ static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type, return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd); } -static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) +static struct super_block * +jffs2_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { int err; struct nameidata nd; diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 84ddb9e25483..ebb881e50ad2 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -372,8 +372,9 @@ static void jfs_unlockfs(struct super_block *sb) txResume(sb); } } -static struct super_block *jfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + +static struct super_block *jfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, jfs_fill_super); } diff --git a/fs/libfs.c b/fs/libfs.c index f7d965e92338..932fd24707ee 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -7,8 +7,6 @@ #include <linux/mount.h> #include <linux/vfs.h> -extern struct vfsmount *do_kern_mount(const char *, int, char *, void *); - int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { diff --git a/fs/minix/inode.c b/fs/minix/inode.c index aaaa4d9c3664..93005e83d319 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -554,7 +554,7 @@ void minix_truncate(struct inode * inode) } static struct super_block *minix_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, minix_fill_super); } diff --git a/fs/msdos/msdosfs_syms.c b/fs/msdos/msdosfs_syms.c index 54b493e9a2d4..29b3593fd733 100644 --- a/fs/msdos/msdosfs_syms.c +++ b/fs/msdos/msdosfs_syms.c @@ -25,7 +25,7 @@ EXPORT_SYMBOL(msdos_rmdir); EXPORT_SYMBOL(msdos_unlink); static struct super_block *msdos_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, msdos_fill_super); } diff --git a/fs/namespace.c b/fs/namespace.c index 0174d8400c9d..3ba38cc13f33 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -23,7 +23,6 @@ #include <linux/mount.h> #include <asm/uaccess.h> -extern struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data); extern int __init init_rootfs(void); extern int __init fs_subsys_init(void); @@ -39,7 +38,7 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) return tmp & hash_mask; } -struct vfsmount *alloc_vfsmnt(char *name) +struct vfsmount *alloc_vfsmnt(const char *name) { struct vfsmount *mnt = kmem_cache_alloc(mnt_cache, GFP_KERNEL); if (mnt) { @@ -63,8 +62,7 @@ struct vfsmount *alloc_vfsmnt(char *name) void free_vfsmnt(struct vfsmount *mnt) { - if (mnt->mnt_devname) - kfree(mnt->mnt_devname); + kfree(mnt->mnt_devname); kmem_cache_free(mnt_cache, mnt); } diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 9de41ad18cbf..0744ac038279 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -955,7 +955,7 @@ int ncp_current_malloced; #endif static struct super_block *ncp_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_nodev(fs_type, flags, data, ncp_fill_super); } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index b97f81b911a1..825108da3ef2 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1192,7 +1192,7 @@ static int nfs_compare_super(struct super_block *sb, void *data) } static struct super_block *nfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *raw_data) + int flags, const char *dev_name, void *raw_data) { int error; struct nfs_server *server; @@ -1421,7 +1421,7 @@ nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen) } static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *raw_data) + int flags, const char *dev_name, void *raw_data) { int error; struct nfs_server *server; diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 0e9370848f49..936d341c610a 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -226,10 +226,8 @@ static void __init root_nfs_parse(char *name, char *buf) } } } - if (name[0] && strcmp(name, "default")) { - strncpy(buf, name, NFS_MAXPATHLEN-1); - buf[NFS_MAXPATHLEN-1] = 0; - } + if (name[0] && strcmp(name, "default")) + strlcpy(buf, name, NFS_MAXPATHLEN); } @@ -340,8 +338,7 @@ int __init nfs_root_setup(char *line) { ROOT_DEV = Root_NFS; if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) { - strncpy(nfs_root_name, line, sizeof(nfs_root_name)); - nfs_root_name[sizeof(nfs_root_name)-1] = '\0'; + strlcpy(nfs_root_name, line, sizeof(nfs_root_name)); } else { int n = strlen(line) + strlen(NFS_ROOT); if (n >= sizeof(nfs_root_name)) diff --git a/fs/nfsctl.c b/fs/nfsctl.c index 46f0372bf2a5..12472dd2a99d 100644 --- a/fs/nfsctl.c +++ b/fs/nfsctl.c @@ -19,8 +19,6 @@ * open a file on nfsd fs */ -struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data); - static struct file *do_open(char *name, int flags) { struct nameidata nd; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index f5886a979e1b..93dfe60fdb3f 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -433,7 +433,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) } static struct super_block *nfsd_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_single(fs_type, flags, data, nfsd_fill_super); } diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 24afa0afcb3d..475799f476ac 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -1656,7 +1656,7 @@ unsigned long ntfs_nr_mounts = 0; DECLARE_MUTEX(ntfs_lock); static struct super_block *ntfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, ntfs_fill_super); } diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index a465eedc13f6..5a1fb89449be 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -1053,7 +1053,7 @@ out_no_root: } static struct super_block *openprom_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_single(fs_type, flags, data, openprom_fill_super); } diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 71a9cfd70968..8f09ea0494f8 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -308,7 +308,7 @@ void register_disk(struct gendisk *disk) int j; int err; - strncpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN); + strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN); /* ewww... some of these buggers have / in name... */ s = strchr(disk->kobj.name, '/'); if (s) diff --git a/fs/pipe.c b/fs/pipe.c index f3d1b93f75b5..3db9e975261d 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -627,7 +627,7 @@ no_files: */ static struct super_block *pipefs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_pseudo(fs_type, "pipe:", NULL, PIPEFS_MAGIC); } diff --git a/fs/proc/root.c b/fs/proc/root.c index d49f353378df..f6b7c065a969 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -25,7 +25,7 @@ struct proc_dir_entry *proc_sys_root; #endif static struct super_block *proc_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_single(fs_type, flags, data, proc_fill_super); } diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 8c6a4dc19cd4..90f7a0034e64 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -555,7 +555,7 @@ static void destroy_inodecache(void) } static struct super_block *qnx4_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, qnx4_fill_super); } diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 15418ab4f490..372f06515900 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -192,13 +192,13 @@ static int ramfs_fill_super(struct super_block * sb, void * data, int silent) } static struct super_block *ramfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_nodev(fs_type, flags, data, ramfs_fill_super); } static struct super_block *rootfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super); } diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index ae31cff05cd1..4f16c0cd9f1e 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1395,12 +1395,10 @@ static int reiserfs_statfs (struct super_block * s, struct statfs * buf) } static struct super_block* -get_super_block (struct file_system_type *fs_type, - int flags, - char *dev_name, - void *data) +get_super_block (struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { - return get_sb_bdev (fs_type, flags, dev_name, data, reiserfs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, reiserfs_fill_super); } static int __init diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index 7355ce94e60c..dd52de09689c 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -599,7 +599,7 @@ static struct super_operations romfs_ops = { }; static struct super_block *romfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super); } diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 74a424899996..abe004b1e78f 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -386,11 +386,11 @@ parse_options(struct smb_mount_data_kernel *mnt, char *options) mnt->dir_mode = (value & S_IRWXUGO) | S_IFDIR; break; case 'i': - strncpy(mnt->codepage.local_name, optarg, + strlcpy(mnt->codepage.local_name, optarg, SMB_NLS_MAXNAMELEN); break; case 'c': - strncpy(mnt->codepage.remote_name, optarg, + strlcpy(mnt->codepage.remote_name, optarg, SMB_NLS_MAXNAMELEN); break; case 't': @@ -535,9 +535,9 @@ int smb_fill_super(struct super_block *sb, void *raw_data, int silent) mnt = server->mnt; memset(mnt, 0, sizeof(struct smb_mount_data_kernel)); - strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT, + strlcpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT, SMB_NLS_MAXNAMELEN); - strncpy(mnt->codepage.remote_name, SMB_NLS_REMOTE, + strlcpy(mnt->codepage.remote_name, SMB_NLS_REMOTE, SMB_NLS_MAXNAMELEN); mnt->ttl = SMB_TTL_DEFAULT; @@ -759,7 +759,7 @@ int smb_current_vmalloced; #endif static struct super_block *smb_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_nodev(fs_type, flags, data, smb_fill_super); } diff --git a/fs/super.c b/fs/super.c index eba1a860a141..2aae8ed4cdcc 100644 --- a/fs/super.c +++ b/fs/super.c @@ -259,9 +259,6 @@ retry: return s; } -struct vfsmount *alloc_vfsmnt(char *name); -void free_vfsmnt(struct vfsmount *mnt); - void drop_super(struct super_block *sb) { up_read(&sb->s_umount); @@ -558,7 +555,7 @@ static int test_bdev_super(struct super_block *s, void *data) } struct super_block *get_sb_bdev(struct file_system_type *fs_type, - int flags, char *dev_name, void * data, + int flags, const char *dev_name, void *data, int (*fill_super)(struct super_block *, void *, int)) { struct block_device *bdev; @@ -663,7 +660,7 @@ struct super_block *get_sb_single(struct file_system_type *fs_type, } struct vfsmount * -do_kern_mount(const char *fstype, int flags, char *name, void *data) +do_kern_mount(const char *fstype, int flags, const char *name, void *data) { struct file_system_type *type = get_fs_type(fstype); struct super_block *sb = ERR_PTR(-ENOMEM); @@ -702,5 +699,5 @@ out: struct vfsmount *kern_mount(struct file_system_type *type) { - return do_kern_mount(type->name, 0, (char *)type->name, NULL); + return do_kern_mount(type->name, 0, type->name, NULL); } diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 940fbcc5a805..c3e5dbe1710a 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -55,7 +55,7 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) } static struct super_block *sysfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_single(fs_type, flags, data, sysfs_fill_super); } diff --git a/fs/sysv/super.c b/fs/sysv/super.c index 9bac127e5c68..baf3157204b3 100644 --- a/fs/sysv/super.c +++ b/fs/sysv/super.c @@ -497,13 +497,13 @@ failed: /* Every kernel module contains stuff like this. */ static struct super_block *sysv_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, sysv_fill_super); } static struct super_block *v7_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, v7_fill_super); } diff --git a/fs/udf/super.c b/fs/udf/super.c index e95e09fda8a8..00bfdd3d6a1b 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -99,7 +99,7 @@ static int udf_statfs(struct super_block *, struct statfs *); /* UDF filesystem type */ static struct super_block *udf_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, udf_fill_super); } diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 53029020b321..d9d96adb4672 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1055,7 +1055,7 @@ static struct super_operations ufs_super_ops = { }; static struct super_block *ufs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, ufs_fill_super); } diff --git a/fs/vfat/vfatfs_syms.c b/fs/vfat/vfatfs_syms.c index b94296c7b786..a8bad844ea86 100644 --- a/fs/vfat/vfatfs_syms.c +++ b/fs/vfat/vfatfs_syms.c @@ -12,7 +12,7 @@ #include <linux/msdos_fs.h> static struct super_block *vfat_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, vfat_fill_super); } diff --git a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c index a6821a542818..7d2662e59031 100644 --- a/fs/xfs/linux/xfs_super.c +++ b/fs/xfs/linux/xfs_super.c @@ -747,7 +747,7 @@ STATIC struct super_block * linvfs_get_sb( struct file_system_type *fs_type, int flags, - char *dev_name, + const char *dev_name, void *data) { return get_sb_bdev(fs_type, flags, dev_name, data, linvfs_fill_super); diff --git a/include/asm-m68knommu/cacheflush.h b/include/asm-m68knommu/cacheflush.h index dfa537d547b1..5429ea10ed3c 100644 --- a/include/asm-m68knommu/cacheflush.h +++ b/include/asm-m68knommu/cacheflush.h @@ -20,6 +20,11 @@ extern inline void __flush_cache_all(void) { #ifdef CONFIG_M5407 + /* + * Use cpushl to push and invalidate all cache lines. + * Gas doesn't seem to know how to generate the ColdFire + * cpushl instruction... Oh well, bit stuff it for now. + */ __asm__ __volatile__ ( "nop\n\t" "clrl %%d0\n\t" @@ -33,11 +38,6 @@ extern inline void __flush_cache_all(void) "addql #1,%%d0\n\t" "cmpil #4,%%d0\n\t" "bne 1b\n\t" - "movel #0x01040100,%%d0\n\t" - "movec %%d0,%%CACR\n\t" - "nop\n\t" - "movel #0x86088400,%%d0\n\t" - "movec %%d0,%%CACR\n\t" : : : "d0", "a0" ); #endif /* CONFIG_M5407 */ #ifdef CONFIG_M5272 diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h index 8ddb454c85b5..b706151a0003 100644 --- a/include/linux/arcdevice.h +++ b/include/linux/arcdevice.h @@ -329,7 +329,7 @@ void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc); #endif void arcnet_unregister_proto(struct ArcProto *proto); -void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs); void arcdev_setup(struct net_device *dev); void arcnet_rx(struct net_device *dev, int bufnum); diff --git a/include/linux/fs.h b/include/linux/fs.h index de57729940ef..78b45c4afd9c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -919,7 +919,8 @@ struct file_system_type { const char *name; struct subsystem subsys; int fs_flags; - struct super_block *(*get_sb) (struct file_system_type *, int, char *, void *); + struct super_block *(*get_sb) (struct file_system_type *, int, + const char *, void *); void (*kill_sb) (struct super_block *); struct module *owner; struct file_system_type * next; @@ -927,7 +928,7 @@ struct file_system_type { }; struct super_block *get_sb_bdev(struct file_system_type *fs_type, - int flags, char *dev_name, void * data, + int flags, const char *dev_name, void *data, int (*fill_super)(struct super_block *, void *, int)); struct super_block *get_sb_single(struct file_system_type *fs_type, int flags, void *data, @@ -1117,7 +1118,7 @@ extern void sync_filesystems(int wait); extern void emergency_sync(void); extern void emergency_remount(void); extern int do_remount_sb(struct super_block *sb, int flags, - void *data, int force); + void *data, int force); extern sector_t bmap(struct inode *, sector_t); extern int setattr_mask(unsigned int); extern int notify_change(struct dentry *, struct iattr *); diff --git a/include/linux/mount.h b/include/linux/mount.h index d02e7845565a..d6996e7c7310 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -50,5 +50,10 @@ static inline void mntput(struct vfsmount *mnt) } } +extern void free_vfsmnt(struct vfsmount *mnt); +extern struct vfsmount *alloc_vfsmnt(const char *name); +extern struct vfsmount *do_kern_mount(const char *fstype, int flags, + const char *name, void *data); + #endif #endif /* _LINUX_MOUNT_H */ diff --git a/include/linux/namespace.h b/include/linux/namespace.h index acd64b4ca117..e7b313a202b6 100644 --- a/include/linux/namespace.h +++ b/include/linux/namespace.h @@ -12,9 +12,8 @@ struct namespace { struct rw_semaphore sem; }; -void umount_tree(struct vfsmount *mnt); - extern void umount_tree(struct vfsmount *); +extern int copy_namespace(int, struct task_struct *); static inline void put_namespace(struct namespace *namespace) { @@ -38,7 +37,6 @@ static inline void exit_namespace(struct task_struct *p) put_namespace(namespace); } } -extern int copy_namespace(int, struct task_struct *); static inline void get_namespace(struct namespace *namespace) { diff --git a/include/linux/string.h b/include/linux/string.h index 0f9e63df583d..f37b7a6813d3 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -37,6 +37,9 @@ extern char * strcat(char *, const char *); #ifndef __HAVE_ARCH_STRNCAT extern char * strncat(char *, const char *, __kernel_size_t); #endif +#ifndef __HAVE_ARCH_STRLCAT +extern size_t strlcat(char *, const char *, __kernel_size_t); +#endif #ifndef __HAVE_ARCH_STRCMP extern int strcmp(const char *,const char *); #endif diff --git a/include/net/irda/iriap.h b/include/net/irda/iriap.h index 917e6701e7ab..ccd692fdef36 100644 --- a/include/net/irda/iriap.h +++ b/include/net/irda/iriap.h @@ -66,7 +66,7 @@ struct iriap_cb { __u32 daddr; __u8 operation; - struct sk_buff *skb; + struct sk_buff *request_skb; struct lsap_cb *lsap; __u8 slsap_sel; diff --git a/include/net/irda/irlan_common.h b/include/net/irda/irlan_common.h index 02ecaf8e30cb..de3a7fdbebc3 100644 --- a/include/net/irda/irlan_common.h +++ b/include/net/irda/irlan_common.h @@ -195,8 +195,6 @@ struct irlan_cb { struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr); void irlan_close(struct irlan_cb *self); void irlan_close_tsaps(struct irlan_cb *self); -void irlan_mod_inc_use_count(void); -void irlan_mod_dec_use_count(void); int irlan_register_netdev(struct irlan_cb *self); void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel); diff --git a/include/net/irda/irlmp_event.h b/include/net/irda/irlmp_event.h index b056e06c29d1..03c6f81a502a 100644 --- a/include/net/irda/irlmp_event.h +++ b/include/net/irda/irlmp_event.h @@ -79,26 +79,6 @@ typedef enum { LM_LAP_IDLE_TIMEOUT, } IRLMP_EVENT; -/* - * Information which is used by the current thread, when executing in the - * state machine. - */ -struct irlmp_event { - IRLMP_EVENT *event; - struct sk_buff *skb; - - __u8 hint; - __u32 daddr; - __u32 saddr; - - __u8 slsap; - __u8 dlsap; - - int reason; - - struct discovery_t *discovery; -}; - extern const char *irlmp_state[]; extern const char *irlsap_state[]; diff --git a/include/net/irda/irport.h b/include/net/irda/irport.h index 79b4d8904346..991f956c096c 100644 --- a/include/net/irda/irport.h +++ b/include/net/irda/irport.h @@ -67,6 +67,7 @@ struct irport_cb { __u32 new_speed; int mode; int index; /* Instance index */ + int transmitting; /* Are we transmitting ? */ spinlock_t lock; /* For serializing operations */ diff --git a/init/do_mounts.c b/init/do_mounts.c index 51f1ff56ff4d..0869bc8e6a2f 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -176,7 +176,7 @@ fail: static int __init root_dev_setup(char *line) { - strncpy(saved_root_name, line, 63); + strlcpy(saved_root_name, line, sizeof(saved_root_name)); return 1; } diff --git a/kernel/futex.c b/kernel/futex.c index df2dcbf557d0..5cd746c3c86c 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -545,7 +545,7 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, int val, static struct super_block * futexfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_pseudo(fs_type, "futex", NULL, 0xBAD1DEA); } diff --git a/lib/string.c b/lib/string.c index b19212bc5d00..112389ed554a 100644 --- a/lib/string.c +++ b/lib/string.c @@ -169,6 +169,33 @@ char * strncat(char *dest, const char *src, size_t count) } #endif +#ifndef __HAVE_ARCH_STRLCAT +/** + * strlcat - Append a length-limited, %NUL-terminated string to another + * @dest: The string to be appended to + * @src: The string to append to it + * @count: The size of the destination buffer. + */ +size_t strlcat(char *dest, const char *src, size_t count) +{ + size_t dsize = strlen(dest); + size_t len = strlen(src); + size_t res = dsize + len; + + /* This would be a bug */ + BUG_ON(dsize >= count); + + dest += dsize; + count -= dsize; + if (len >= count) + len = count-1; + memcpy(dest, src, len); + dest[len] = 0; + return res; +} +EXPORT_SYMBOL(strlcat); +#endif + #ifndef __HAVE_ARCH_STRCMP /** * strcmp - Compare two strings diff --git a/mm/nommu.c b/mm/nommu.c index a40138c746c2..cd7900bf3fe8 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -4,7 +4,7 @@ * Replacement code for mm functions to support CPU's that don't * have any form of memory management unit (thus no virtual memory). * - * Copyright (c) 2000-2002 David McCullough <davidm@snapgear.com> + * Copyright (c) 2000-2003 David McCullough <davidm@snapgear.com> * Copyright (c) 2000-2001 D Jeff Dionne <jeff@uClinux.org> * Copyright (c) 2002 Greg Ungerer <gerg@snapgear.com> */ @@ -30,6 +30,8 @@ unsigned long max_mapnr; unsigned long num_physpages; unsigned long askedalloc, realalloc; atomic_t vm_committed_space = ATOMIC_INIT(0); +int sysctl_overcommit_memory = 0; /* default is heuristic overcommit */ +int sysctl_overcommit_ratio = 50; /* default is 50% */ /* * Handle all mappings that got truncated by a "truncate()" @@ -102,6 +104,7 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, struct page **pages, struct vm_area_struct **vmas) { int i; + static struct vm_area_struct dummy_vma; for (i = 0; i < len; i++) { if (pages) { @@ -109,6 +112,8 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, if (pages[i]) page_cache_get(pages[i]); } + if (vmas) + vmas[i] = &dummy_vma; start += PAGE_SIZE; } return(i); @@ -180,7 +185,7 @@ void *vmalloc_32(unsigned long size) return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL); } -void *vmap(struct page **pages, unsigned int count) +void *vmap(struct page **pages, unsigned int count, unsigned long flags, pgprot_t prot) { BUG(); return NULL; diff --git a/mm/shmem.c b/mm/shmem.c index 6703b33d0458..83514240a7ef 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1647,7 +1647,8 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) } #endif -static int shmem_fill_super(struct super_block *sb, void *data, int silent) +static int shmem_fill_super(struct super_block *sb, + void *data, int silent) { struct inode *inode; struct dentry *root; @@ -1814,7 +1815,7 @@ static struct vm_operations_struct shmem_vm_ops = { }; static struct super_block *shmem_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_nodev(fs_type, flags, data, shmem_fill_super); } diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 90077d0f1168..6d0245b8c7b4 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -11,7 +11,7 @@ * Sources: af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc. * * Copyright (c) 1999 Dag Brattli <dagb@cs.uit.no> - * Copyright (c) 1999-2001 Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (c) 1999-2003 Jean Tourrilhes <jt@hpl.hp.com> * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -190,6 +190,9 @@ static void irda_connect_confirm(void *instance, void *sap, if (sk == NULL) return; + dev_kfree_skb(skb); + // Should be ??? skb_queue_tail(&sk->receive_queue, skb); + /* How much header space do we need to reserve */ self->max_header_size = max_header_size; @@ -220,8 +223,6 @@ static void irda_connect_confirm(void *instance, void *sap, self->max_data_size); memcpy(&self->qos_tx, qos, sizeof(struct qos_info)); - dev_kfree_skb(skb); - // Should be ??? skb_queue_tail(&sk->receive_queue, skb); /* We are now connected! */ sk->state = TCP_ESTABLISHED; @@ -260,6 +261,7 @@ static void irda_connect_indication(void *instance, void *sap, case SOCK_STREAM: if (max_sdu_size != 0) { ERROR("%s: max_sdu_size must be 0\n", __FUNCTION__); + kfree_skb(skb); return; } self->max_data_size = irttp_get_max_seg_size(self->tsap); @@ -267,6 +269,7 @@ static void irda_connect_indication(void *instance, void *sap, case SOCK_SEQPACKET: if (max_sdu_size == 0) { ERROR("%s: max_sdu_size cannot be 0\n", __FUNCTION__); + kfree_skb(skb); return; } self->max_data_size = max_sdu_size; @@ -359,7 +362,7 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) * doesn't touch the dtsap_sel and save the full value structure... */ static void irda_getvalue_confirm(int result, __u16 obj_id, - struct ias_value *value, void *priv) + struct ias_value *value, void *priv) { struct irda_sock *self; @@ -908,6 +911,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) new->tsap = irttp_dup(self->tsap, new); if (!new->tsap) { IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__); + kfree_skb(skb); return -1; } @@ -926,6 +930,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) /* Clean up the original one to keep it in listen state */ irttp_listen(self->tsap); + /* Wow ! What is that ? Jean II */ skb->sk = NULL; skb->destructor = NULL; kfree_skb(skb); diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c index 122e62971306..552a105d7a9c 100644 --- a/net/irda/ircomm/ircomm_core.c +++ b/net/irda/ircomm/ircomm_core.c @@ -10,6 +10,7 @@ * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -251,7 +252,6 @@ void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb, info->max_header_size, skb); else { IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); - dev_kfree_skb(skb); } } @@ -295,7 +295,6 @@ void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb, info->max_header_size, skb); else { IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); - dev_kfree_skb(skb); } } @@ -338,7 +337,6 @@ void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb) self->notify.data_indication(self->notify.instance, self, skb); else { IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); - dev_kfree_skb(skb); } } @@ -370,9 +368,8 @@ void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb) if (skb->len) ircomm_data_indication(self, skb); else { - IRDA_DEBUG(4, - "%s(), data was control info only!\n", __FUNCTION__ ); - dev_kfree_skb(skb); + IRDA_DEBUG(4, "%s(), data was control info only!\n", + __FUNCTION__ ); } } @@ -408,24 +405,28 @@ EXPORT_SYMBOL(ircomm_control_request); static void ircomm_control_indication(struct ircomm_cb *self, struct sk_buff *skb, int clen) { - struct sk_buff *ctrl_skb; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); - ctrl_skb = skb_clone(skb, GFP_ATOMIC); - if (!ctrl_skb) - return; + /* Use udata for delivering data on the control channel */ + if (self->notify.udata_indication) { + struct sk_buff *ctrl_skb; + + /* We don't own the skb, so clone it */ + ctrl_skb = skb_clone(skb, GFP_ATOMIC); + if (!ctrl_skb) + return; - /* Remove data channel from control channel */ - skb_trim(ctrl_skb, clen+1); + /* Remove data channel from control channel */ + skb_trim(ctrl_skb, clen+1); - /* Use udata for delivering data on the control channel */ - if (self->notify.udata_indication) self->notify.udata_indication(self->notify.instance, self, ctrl_skb); - else { + + /* Drop reference count - + * see ircomm_tty_control_indication(). */ + dev_kfree_skb(ctrl_skb); + } else { IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); - dev_kfree_skb(skb); } } @@ -470,7 +471,6 @@ void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb, info->reason, skb); } else { IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); - dev_kfree_skb(skb); } } diff --git a/net/irda/ircomm/ircomm_event.c b/net/irda/ircomm/ircomm_event.c index 21dbea74e50a..3ad421cbea83 100644 --- a/net/irda/ircomm/ircomm_event.c +++ b/net/irda/ircomm/ircomm_event.c @@ -109,9 +109,7 @@ static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event, default: IRDA_DEBUG(4, "%s(), unknown event: %s\n", __FUNCTION__ , ircomm_event[event]); - if (skb) - dev_kfree_skb(skb); - return -EINVAL; + ret = -EINVAL; } return ret; } @@ -141,8 +139,6 @@ static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event, default: IRDA_DEBUG(0, "%s(), unknown event: %s\n", __FUNCTION__ , ircomm_event[event]); - if (skb) - dev_kfree_skb(skb); ret = -EINVAL; } return ret; @@ -176,8 +172,6 @@ static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, default: IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ , ircomm_event[event]); - if (skb) - dev_kfree_skb(skb); ret = -EINVAL; } return ret; @@ -220,8 +214,6 @@ static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, default: IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ , ircomm_event[event]); - if (skb) - dev_kfree_skb(skb); ret = -EINVAL; } return ret; diff --git a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c index 6b01349b6d4d..af27a51d08c5 100644 --- a/net/irda/ircomm/ircomm_lmp.c +++ b/net/irda/ircomm/ircomm_lmp.c @@ -11,6 +11,7 @@ * Sources: Previous IrLPT work by Thomas Davis * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -93,6 +94,10 @@ int ircomm_lmp_connect_request(struct ircomm_cb *self, IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + /* Don't forget to refcount it - should be NULL anyway */ + if(userdata) + skb_get(userdata); + ret = irlmp_connect_request(self->lsap, info->dlsap_sel, info->saddr, info->daddr, NULL, userdata); return ret; @@ -106,29 +111,32 @@ int ircomm_lmp_connect_request(struct ircomm_cb *self, */ int ircomm_lmp_connect_response(struct ircomm_cb *self, struct sk_buff *userdata) { - struct sk_buff *skb; + struct sk_buff *tx_skb; int ret; IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); /* Any userdata supplied? */ if (userdata == NULL) { - skb = dev_alloc_skb(64); - if (!skb) + tx_skb = dev_alloc_skb(64); + if (!tx_skb) return -ENOMEM; /* Reserve space for MUX and LAP header */ - skb_reserve(skb, LMP_MAX_HEADER); + skb_reserve(tx_skb, LMP_MAX_HEADER); } else { - skb = userdata; /* * Check that the client has reserved enough space for * headers */ - ASSERT(skb_headroom(skb) >= LMP_MAX_HEADER, return -1;); + ASSERT(skb_headroom(userdata) >= LMP_MAX_HEADER, return -1;); + + /* Don't forget to refcount it - should be NULL anyway */ + skb_get(userdata); + tx_skb = userdata; } - ret = irlmp_connect_response(self->lsap, skb); + ret = irlmp_connect_response(self->lsap, tx_skb); return 0; } @@ -137,20 +145,24 @@ int ircomm_lmp_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata, struct ircomm_info *info) { - struct sk_buff *skb; + struct sk_buff *tx_skb; int ret; IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); if (!userdata) { - skb = dev_alloc_skb(64); - if (!skb) + tx_skb = dev_alloc_skb(64); + if (!tx_skb) return -ENOMEM; /* Reserve space for MUX and LAP header */ - skb_reserve(skb, LMP_MAX_HEADER); - userdata = skb; + skb_reserve(tx_skb, LMP_MAX_HEADER); + userdata = tx_skb; + } else { + /* Don't forget to refcount it - should be NULL anyway */ + skb_get(userdata); } + ret = irlmp_disconnect_request(self->lsap, userdata); return ret; @@ -217,8 +229,11 @@ int ircomm_lmp_data_request(struct ircomm_cb *self, struct sk_buff *skb, IRDA_DEBUG(4, "%s(), sending frame\n", __FUNCTION__ ); + /* Don't forget to refcount it - see ircomm_tty_do_softint() */ + skb_get(skb); + skb->destructor = ircomm_lmp_flow_control; - + if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) { IRDA_DEBUG(2, "%s(), asking TTY to slow down!\n", __FUNCTION__ ); self->flow_status = FLOW_STOP; @@ -229,7 +244,7 @@ int ircomm_lmp_data_request(struct ircomm_cb *self, struct sk_buff *skb, ret = irlmp_data_request(self->lsap, skb); if (ret) { ERROR("%s(), failed\n", __FUNCTION__); - dev_kfree_skb(skb); + /* irlmp_data_request already free the packet */ } return ret; @@ -254,6 +269,9 @@ int ircomm_lmp_data_indication(void *instance, void *sap, ircomm_do_event(self, IRCOMM_LMP_DATA_INDICATION, skb, NULL); + /* Drop reference count - see ircomm_tty_data_indication(). */ + dev_kfree_skb(skb); + return 0; } @@ -285,6 +303,9 @@ void ircomm_lmp_connect_confirm(void *instance, void *sap, info.qos = qos; ircomm_do_event(self, IRCOMM_LMP_CONNECT_CONFIRM, skb, &info); + + /* Drop reference count - see ircomm_tty_connect_confirm(). */ + dev_kfree_skb(skb); } /* @@ -315,6 +336,9 @@ void ircomm_lmp_connect_indication(void *instance, void *sap, info.qos = qos; ircomm_do_event(self, IRCOMM_LMP_CONNECT_INDICATION, skb, &info); + + /* Drop reference count - see ircomm_tty_connect_indication(). */ + dev_kfree_skb(skb); } /* @@ -338,4 +362,8 @@ void ircomm_lmp_disconnect_indication(void *instance, void *sap, info.reason = reason; ircomm_do_event(self, IRCOMM_LMP_DISCONNECT_INDICATION, skb, &info); + + /* Drop reference count - see ircomm_tty_disconnect_indication(). */ + if(skb) + dev_kfree_skb(skb); } diff --git a/net/irda/ircomm/ircomm_ttp.c b/net/irda/ircomm/ircomm_ttp.c index ec53428259b9..c3b946e40fe6 100644 --- a/net/irda/ircomm/ircomm_ttp.c +++ b/net/irda/ircomm/ircomm_ttp.c @@ -10,6 +10,7 @@ * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -94,9 +95,14 @@ int ircomm_ttp_connect_request(struct ircomm_cb *self, IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + /* Don't forget to refcount it - should be NULL anyway */ + if(userdata) + skb_get(userdata); + ret = irttp_connect_request(self->tsap, info->dlsap_sel, info->saddr, info->daddr, NULL, TTP_SAR_DISABLE, userdata); + return ret; } @@ -106,13 +112,18 @@ int ircomm_ttp_connect_request(struct ircomm_cb *self, * * */ -int ircomm_ttp_connect_response(struct ircomm_cb *self, struct sk_buff *skb) +int ircomm_ttp_connect_response(struct ircomm_cb *self, + struct sk_buff *userdata) { int ret; IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); - ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, skb); + /* Don't forget to refcount it - should be NULL anyway */ + if(userdata) + skb_get(userdata); + + ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, userdata); return ret; } @@ -126,7 +137,8 @@ int ircomm_ttp_connect_response(struct ircomm_cb *self, struct sk_buff *skb) * some of them are sent after connection establishment, so this can * increase the latency a bit. */ -int ircomm_ttp_data_request(struct ircomm_cb *self, struct sk_buff *skb, +int ircomm_ttp_data_request(struct ircomm_cb *self, + struct sk_buff *skb, int clen) { int ret; @@ -140,6 +152,10 @@ int ircomm_ttp_data_request(struct ircomm_cb *self, struct sk_buff *skb, * only frames, to make things easier and avoid queueing */ ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;); + + /* Don't forget to refcount it - see ircomm_tty_do_softint() */ + skb_get(skb); + skb_push(skb, IRCOMM_HEADER_SIZE); skb->data[0] = clen; @@ -147,7 +163,7 @@ int ircomm_ttp_data_request(struct ircomm_cb *self, struct sk_buff *skb, ret = irttp_data_request(self->tsap, skb); if (ret) { ERROR("%s(), failed\n", __FUNCTION__); - dev_kfree_skb(skb); + /* irttp_data_request already free the packet */ } return ret; @@ -172,6 +188,9 @@ int ircomm_ttp_data_indication(void *instance, void *sap, ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL); + /* Drop reference count - see ircomm_tty_data_indication(). */ + dev_kfree_skb(skb); + return 0; } @@ -189,12 +208,11 @@ void ircomm_ttp_connect_confirm(void *instance, void *sap, ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_MAGIC, return;); ASSERT(skb != NULL, return;); - ASSERT(qos != NULL, return;); + ASSERT(qos != NULL, goto out;); if (max_sdu_size != TTP_SAR_DISABLE) { ERROR("%s(), SAR not allowed for IrCOMM!\n", __FUNCTION__); - dev_kfree_skb(skb); - return; + goto out; } info.max_data_size = irttp_get_max_seg_size(self->tsap) @@ -203,6 +221,10 @@ void ircomm_ttp_connect_confirm(void *instance, void *sap, info.qos = qos; ircomm_do_event(self, IRCOMM_TTP_CONNECT_CONFIRM, skb, &info); + +out: + /* Drop reference count - see ircomm_tty_connect_confirm(). */ + dev_kfree_skb(skb); } /* @@ -226,12 +248,11 @@ void ircomm_ttp_connect_indication(void *instance, void *sap, ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_MAGIC, return;); ASSERT(skb != NULL, return;); - ASSERT(qos != NULL, return;); + ASSERT(qos != NULL, goto out;); if (max_sdu_size != TTP_SAR_DISABLE) { ERROR("%s(), SAR not allowed for IrCOMM!\n", __FUNCTION__); - dev_kfree_skb(skb); - return; + goto out; } info.max_data_size = irttp_get_max_seg_size(self->tsap) @@ -240,6 +261,10 @@ void ircomm_ttp_connect_indication(void *instance, void *sap, info.qos = qos; ircomm_do_event(self, IRCOMM_TTP_CONNECT_INDICATION, skb, &info); + +out: + /* Drop reference count - see ircomm_tty_connect_indication(). */ + dev_kfree_skb(skb); } /* @@ -254,6 +279,10 @@ int ircomm_ttp_disconnect_request(struct ircomm_cb *self, { int ret; + /* Don't forget to refcount it - should be NULL anyway */ + if(userdata) + skb_get(userdata); + ret = irttp_disconnect_request(self->tsap, userdata, P_NORMAL); return ret; @@ -280,6 +309,10 @@ void ircomm_ttp_disconnect_indication(void *instance, void *sap, info.reason = reason; ircomm_do_event(self, IRCOMM_TTP_DISCONNECT_INDICATION, skb, &info); + + /* Drop reference count - see ircomm_tty_disconnect_indication(). */ + if(skb) + dev_kfree_skb(skb); } /* diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index e8ba645fc366..19a25ea6c3b9 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -11,6 +11,7 @@ * Sources: serial.c and previous IrCOMM work by Takahide Higuchi * * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -663,8 +664,12 @@ static void ircomm_tty_do_softint(void *private_) spin_unlock_irqrestore(&self->spinlock, flags); /* Flush control buffer if any */ - if (ctrl_skb && self->flow == FLOW_START) - ircomm_control_request(self->ircomm, ctrl_skb); + if(ctrl_skb) { + if(self->flow == FLOW_START) + ircomm_control_request(self->ircomm, ctrl_skb); + /* Drop reference count - see ircomm_ttp_data_request(). */ + dev_kfree_skb(ctrl_skb); + } if (tty->hw_stopped) return; @@ -678,8 +683,11 @@ static void ircomm_tty_do_softint(void *private_) spin_unlock_irqrestore(&self->spinlock, flags); /* Flush transmit buffer if any */ - if (skb) + if (skb) { ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL); + /* Drop reference count - see ircomm_ttp_data_request(). */ + dev_kfree_skb(skb); + } /* Check if user (still) wants to be waken up */ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && @@ -1179,7 +1187,6 @@ static int ircomm_tty_data_indication(void *instance, void *sap, if (!self->tty) { IRDA_DEBUG(0, "%s(), no tty!\n", __FUNCTION__ ); - dev_kfree_skb(skb); return 0; } @@ -1204,7 +1211,8 @@ static int ircomm_tty_data_indication(void *instance, void *sap, * handler */ self->tty->ldisc.receive_buf(self->tty, skb->data, NULL, skb->len); - dev_kfree_skb(skb); + + /* No need to kfree_skb - see ircomm_ttp_data_indication() */ return 0; } @@ -1231,7 +1239,8 @@ static int ircomm_tty_control_indication(void *instance, void *sap, irda_param_extract_all(self, skb->data+1, IRDA_MIN(skb->len-1, clen), &ircomm_param_info); - dev_kfree_skb(skb); + + /* No need to kfree_skb - see ircomm_control_indication() */ return 0; } diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index 2261d8ca5528..fa066ee2026a 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c @@ -10,6 +10,7 @@ * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -236,8 +237,9 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self) irias_insert_object(self->obj); } self->skey = irlmp_register_service(hints); - self->ckey = irlmp_register_client( - hints, ircomm_tty_discovery_indication, NULL, (void *) self); + self->ckey = irlmp_register_client(hints, + ircomm_tty_discovery_indication, + NULL, (void *) self); } /* @@ -459,7 +461,7 @@ void ircomm_tty_connect_confirm(void *instance, void *sap, ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL); - dev_kfree_skb(skb); + /* No need to kfree_skb - see ircomm_ttp_connect_confirm() */ } /* @@ -496,7 +498,7 @@ void ircomm_tty_connect_indication(void *instance, void *sap, ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL); - dev_kfree_skb(skb); + /* No need to kfree_skb - see ircomm_ttp_connect_indication() */ } /* @@ -647,7 +649,7 @@ static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, default: IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , ircomm_tty_event[event]); - return -EINVAL; + ret = -EINVAL; } return ret; } @@ -718,7 +720,7 @@ static int ircomm_tty_state_search(struct ircomm_tty_cb *self, default: IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , ircomm_tty_event[event]); - return -EINVAL; + ret = -EINVAL; } return ret; } @@ -774,7 +776,7 @@ static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self, default: IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , ircomm_tty_event[event]); - return -EINVAL; + ret = -EINVAL; } return ret; } @@ -822,7 +824,7 @@ static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self, default: IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , ircomm_tty_event[event]); - return -EINVAL; + ret = -EINVAL; } return ret; } @@ -874,7 +876,7 @@ static int ircomm_tty_state_setup(struct ircomm_tty_cb *self, default: IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , ircomm_tty_event[event]); - return -EINVAL; + ret = -EINVAL; } return ret; } @@ -917,7 +919,7 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, default: IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , ircomm_tty_event[event]); - return -EINVAL; + ret = -EINVAL; } return ret; } diff --git a/net/irda/iriap.c b/net/irda/iriap.c index 6a16559dab9e..232fb7a78a6e 100644 --- a/net/irda/iriap.c +++ b/net/irda/iriap.c @@ -11,7 +11,7 @@ * * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. - * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -210,8 +210,8 @@ static void __iriap_close(struct iriap_cb *self) del_timer(&self->watchdog_timer); - if (self->skb) - dev_kfree_skb(self->skb); + if (self->request_skb) + dev_kfree_skb(self->request_skb); self->magic = 0; @@ -278,7 +278,7 @@ static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode) */ static void iriap_disconnect_indication(void *instance, void *sap, LM_REASON reason, - struct sk_buff *userdata) + struct sk_buff *skb) { struct iriap_cb *self; @@ -293,6 +293,10 @@ static void iriap_disconnect_indication(void *instance, void *sap, del_timer(&self->watchdog_timer); + /* Not needed */ + if (skb) + dev_kfree_skb(skb); + if (self->mode == IAS_CLIENT) { IRDA_DEBUG(4, "%s(), disconnect as client\n", __FUNCTION__); @@ -312,9 +316,6 @@ static void iriap_disconnect_indication(void *instance, void *sap, NULL); iriap_close(self); } - - if (userdata) - dev_kfree_skb(userdata); } /* @@ -322,15 +323,15 @@ static void iriap_disconnect_indication(void *instance, void *sap, */ void iriap_disconnect_request(struct iriap_cb *self) { - struct sk_buff *skb; + struct sk_buff *tx_skb; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == IAS_MAGIC, return;); - skb = dev_alloc_skb(64); - if (skb == NULL) { + tx_skb = dev_alloc_skb(64); + if (tx_skb == NULL) { IRDA_DEBUG(0, "%s(), Could not allocate an sk_buff of length %d\n", __FUNCTION__, 64); return; @@ -339,9 +340,9 @@ void iriap_disconnect_request(struct iriap_cb *self) /* * Reserve space for MUX control and LAP header */ - skb_reserve(skb, LMP_MAX_HEADER); + skb_reserve(tx_skb, LMP_MAX_HEADER); - irlmp_disconnect_request(self->lsap, skb); + irlmp_disconnect_request(self->lsap, tx_skb); } void iriap_getinfobasedetails_request(void) @@ -379,7 +380,7 @@ int iriap_getvaluebyclass_request(struct iriap_cb *self, __u32 saddr, __u32 daddr, char *name, char *attr) { - struct sk_buff *skb; + struct sk_buff *tx_skb; int name_len, attr_len, skb_len; __u8 *frame; @@ -405,14 +406,14 @@ int iriap_getvaluebyclass_request(struct iriap_cb *self, attr_len = strlen(attr); /* Up to IAS_MAX_ATTRIBNAME = 60 */ skb_len = self->max_header_size+2+name_len+1+attr_len+4; - skb = dev_alloc_skb(skb_len); - if (!skb) + tx_skb = dev_alloc_skb(skb_len); + if (!tx_skb) return -ENOMEM; /* Reserve space for MUX and LAP header */ - skb_reserve(skb, self->max_header_size); - skb_put(skb, 3+name_len+attr_len); - frame = skb->data; + skb_reserve(tx_skb, self->max_header_size); + skb_put(tx_skb, 3+name_len+attr_len); + frame = tx_skb->data; /* Build frame */ frame[0] = IAP_LST | GET_VALUE_BY_CLASS; @@ -421,7 +422,10 @@ int iriap_getvaluebyclass_request(struct iriap_cb *self, frame[2+name_len] = attr_len; /* Insert length of attr */ memcpy(frame+3+name_len, attr, attr_len); /* Insert attr */ - iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, skb); + iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, tx_skb); + + /* Drop reference count - see state_s_disconnect(). */ + dev_kfree_skb(tx_skb); return 0; } @@ -495,7 +499,6 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb) /* Aborting, close connection! */ iriap_disconnect_request(self); - dev_kfree_skb(skb); return; /* break; */ } @@ -533,7 +536,6 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb) IRDA_DEBUG(0, "%s(), missing handler!\n", __FUNCTION__); irias_delete_value(value); } - dev_kfree_skb(skb); } /* @@ -545,7 +547,7 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb) void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id, __u8 ret_code, struct ias_value *value) { - struct sk_buff *skb; + struct sk_buff *tx_skb; int n; __u32 tmp_be32, tmp_be16; __u8 *fp; @@ -565,15 +567,15 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id, * value. We add 32 bytes because of the 6 bytes for the frame and * max 5 bytes for the value coding. */ - skb = dev_alloc_skb(value->len + self->max_header_size + 32); - if (!skb) + tx_skb = dev_alloc_skb(value->len + self->max_header_size + 32); + if (!tx_skb) return; /* Reserve space for MUX and LAP header */ - skb_reserve(skb, self->max_header_size); - skb_put(skb, 6); + skb_reserve(tx_skb, self->max_header_size); + skb_put(tx_skb, 6); - fp = skb->data; + fp = tx_skb->data; /* Build frame */ fp[n++] = GET_VALUE_BY_CLASS | IAP_LST; @@ -589,21 +591,21 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id, switch (value->type) { case IAS_STRING: - skb_put(skb, 3 + value->len); + skb_put(tx_skb, 3 + value->len); fp[n++] = value->type; fp[n++] = 0; /* ASCII */ fp[n++] = (__u8) value->len; memcpy(fp+n, value->t.string, value->len); n+=value->len; break; case IAS_INTEGER: - skb_put(skb, 5); + skb_put(tx_skb, 5); fp[n++] = value->type; tmp_be32 = cpu_to_be32(value->t.integer); memcpy(fp+n, &tmp_be32, 4); n += 4; break; case IAS_OCT_SEQ: - skb_put(skb, 3 + value->len); + skb_put(tx_skb, 3 + value->len); fp[n++] = value->type; tmp_be16 = cpu_to_be16(value->len); @@ -612,14 +614,17 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id, break; case IAS_MISSING: IRDA_DEBUG( 3, "%s: sending IAS_MISSING\n", __FUNCTION__); - skb_put(skb, 1); + skb_put(tx_skb, 1); fp[n++] = value->type; break; default: IRDA_DEBUG(0, "%s(), type not implemented!\n", __FUNCTION__); break; } - iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, skb); + iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, tx_skb); + + /* Drop reference count - see state_r_execute(). */ + dev_kfree_skb(tx_skb); } /* @@ -657,9 +662,6 @@ void iriap_getvaluebyclass_indication(struct iriap_cb *self, memcpy(attr, fp+n, attr_len); n+=attr_len; attr[attr_len] = '\0'; - /* We do not need the buffer anymore */ - dev_kfree_skb(skb); - IRDA_DEBUG(4, "LM-IAS: Looking up %s: %s\n", name, attr); obj = irias_find_object(name); @@ -694,7 +696,7 @@ void iriap_getvaluebyclass_indication(struct iriap_cb *self, */ void iriap_send_ack(struct iriap_cb *self) { - struct sk_buff *skb; + struct sk_buff *tx_skb; __u8 *frame; IRDA_DEBUG(2, "%s()\n", __FUNCTION__); @@ -702,19 +704,19 @@ void iriap_send_ack(struct iriap_cb *self) ASSERT(self != NULL, return;); ASSERT(self->magic == IAS_MAGIC, return;); - skb = dev_alloc_skb(64); - if (!skb) + tx_skb = dev_alloc_skb(64); + if (!tx_skb) return; /* Reserve space for MUX and LAP header */ - skb_reserve(skb, self->max_header_size); - skb_put(skb, 1); - frame = skb->data; + skb_reserve(tx_skb, self->max_header_size); + skb_put(tx_skb, 1); + frame = tx_skb->data; /* Build frame */ frame[0] = IAP_LST | IAP_ACK | self->operation; - irlmp_data_request(self->lsap, skb); + irlmp_data_request(self->lsap, tx_skb); } void iriap_connect_request(struct iriap_cb *self) @@ -742,7 +744,7 @@ void iriap_connect_request(struct iriap_cb *self) static void iriap_connect_confirm(void *instance, void *sap, struct qos_info *qos, __u32 max_seg_size, __u8 max_header_size, - struct sk_buff *userdata) + struct sk_buff *skb) { struct iriap_cb *self; @@ -750,14 +752,17 @@ static void iriap_connect_confirm(void *instance, void *sap, ASSERT(self != NULL, return;); ASSERT(self->magic == IAS_MAGIC, return;); - ASSERT(userdata != NULL, return;); + ASSERT(skb != NULL, return;); self->max_data_size = max_seg_size; self->max_header_size = max_header_size; del_timer(&self->watchdog_timer); - iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, userdata); + iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, skb); + + /* Drop reference count - see state_s_make_call(). */ + dev_kfree_skb(skb); } /* @@ -769,7 +774,7 @@ static void iriap_connect_confirm(void *instance, void *sap, static void iriap_connect_indication(void *instance, void *sap, struct qos_info *qos, __u32 max_seg_size, __u8 max_header_size, - struct sk_buff *userdata) + struct sk_buff *skb) { struct iriap_cb *self, *new; @@ -777,22 +782,22 @@ static void iriap_connect_indication(void *instance, void *sap, self = (struct iriap_cb *) instance; - ASSERT(self != NULL, return;); - ASSERT(self->magic == IAS_MAGIC, return;); + ASSERT(skb != NULL, return;); + ASSERT(self != NULL, goto out;); + ASSERT(self->magic == IAS_MAGIC, goto out;); /* Start new server */ new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); if (!new) { IRDA_DEBUG(0, "%s(), open failed\n", __FUNCTION__); - dev_kfree_skb(userdata); - return; + goto out; } /* Now attach up the new "socket" */ new->lsap = irlmp_dup(self->lsap, new); if (!new->lsap) { IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__); - return; + goto out; } new->max_data_size = max_seg_size; @@ -801,7 +806,11 @@ static void iriap_connect_indication(void *instance, void *sap, /* Clean up the original one to keep it in listen state */ irlmp_listen(self->lsap); - iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, userdata); + iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, skb); + +out: + /* Drop reference count - see state_r_disconnect(). */ + dev_kfree_skb(skb); } /* @@ -821,10 +830,9 @@ static int iriap_data_indication(void *instance, void *sap, self = (struct iriap_cb *) instance; - ASSERT(self != NULL, return 0;); - ASSERT(self->magic == IAS_MAGIC, return 0;); - ASSERT(skb != NULL, return 0;); + ASSERT(self != NULL, goto out;); + ASSERT(self->magic == IAS_MAGIC, goto out;); frame = skb->data; @@ -832,22 +840,19 @@ static int iriap_data_indication(void *instance, void *sap, /* Call server */ IRDA_DEBUG(4, "%s(), Calling server!\n", __FUNCTION__); iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb); - - return 0; + goto out; } opcode = frame[0]; if (~opcode & IAP_LST) { WARNING("%s:, IrIAS multiframe commands or " "results is not implemented yet!\n", __FUNCTION__); - dev_kfree_skb(skb); - return 0; + goto out; } /* Check for ack frames since they don't contain any data */ if (opcode & IAP_ACK) { IRDA_DEBUG(0, "%s() Got ack frame!\n", __FUNCTION__); - dev_kfree_skb(skb); - return 0; + goto out; } opcode &= ~IAP_LST; /* Mask away LST bit */ @@ -855,7 +860,6 @@ static int iriap_data_indication(void *instance, void *sap, switch (opcode) { case GET_INFO_BASE: IRDA_DEBUG(0, "IrLMP GetInfoBaseDetails not implemented!\n"); - dev_kfree_skb(skb); break; case GET_VALUE_BY_CLASS: iriap_do_call_event(self, IAP_RECV_F_LST, NULL); @@ -876,7 +880,6 @@ static int iriap_data_indication(void *instance, void *sap, if (self->confirm) self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, self->priv); - dev_kfree_skb(skb); break; case IAS_ATTRIB_UNKNOWN: IRDA_DEBUG(1, "%s(), No such attribute!\n", __FUNCTION__); @@ -890,16 +893,18 @@ static int iriap_data_indication(void *instance, void *sap, if (self->confirm) self->confirm(IAS_ATTRIB_UNKNOWN, 0, NULL, self->priv); - dev_kfree_skb(skb); break; } break; default: IRDA_DEBUG(0, "%s(), Unknown op-code: %02x\n", __FUNCTION__, opcode); - dev_kfree_skb(skb); break; } + +out: + /* Cleanup - sub-calls will have done skb_get() as needed. */ + dev_kfree_skb(skb); return 0; } @@ -939,6 +944,7 @@ void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb) iriap_getvaluebyclass_indication(self, skb); break; } + /* skb will be cleaned up in iriap_data_indication */ } /* diff --git a/net/irda/iriap_event.c b/net/irda/iriap_event.c index 07f27182e743..ce209ad44eaf 100644 --- a/net/irda/iriap_event.c +++ b/net/irda/iriap_event.c @@ -11,6 +11,7 @@ * * Copyright (c) 1997, 1999-2000 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -174,8 +175,11 @@ static void state_s_disconnect(struct iriap_cb *self, IRIAP_EVENT event, switch (event) { case IAP_CALL_REQUEST_GVBC: iriap_next_client_state(self, S_CONNECTING); - ASSERT(self->skb == NULL, return;); - self->skb = skb; + ASSERT(self->request_skb == NULL, return;); + /* Don't forget to refcount it - + * see iriap_getvaluebyclass_request(). */ + skb_get(skb); + self->request_skb = skb; iriap_connect_request(self); break; case IAP_LM_DISCONNECT_INDICATION: @@ -251,20 +255,21 @@ static void state_s_call(struct iriap_cb *self, IRIAP_EVENT event, static void state_s_make_call(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { + struct sk_buff *tx_skb; + ASSERT(self != NULL, return;); switch (event) { case IAP_CALL_REQUEST: - skb = self->skb; - self->skb = NULL; + /* Already refcounted - see state_s_disconnect() */ + tx_skb = self->request_skb; + self->request_skb = NULL; - irlmp_data_request(self->lsap, skb); + irlmp_data_request(self->lsap, tx_skb); iriap_next_call_state(self, S_OUTSTANDING); break; default: IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event); - if (skb) - dev_kfree_skb(skb); break; } } @@ -379,10 +384,6 @@ static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event, * care about LM_Idle_request()! */ iriap_next_r_connect_state(self, R_RECEIVING); - - if (skb) - dev_kfree_skb(skb); - break; default: IRDA_DEBUG(0, "%s(), unknown event %d\n", __FUNCTION__, event); @@ -450,7 +451,6 @@ static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event, IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__); break; } - } /* @@ -465,11 +465,8 @@ static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event, IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(skb != NULL, return;); - - if (!self || self->magic != IAS_MAGIC) { - IRDA_DEBUG(0, "%s(), bad pointer self\n", __FUNCTION__); - return; - } + ASSERT(self != NULL, return;); + ASSERT(self->magic == IAS_MAGIC, return;); switch (event) { case IAP_CALL_RESPONSE: @@ -479,6 +476,10 @@ static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event, */ iriap_next_r_connect_state(self, R_RECEIVING); + /* Don't forget to refcount it - see + * iriap_getvaluebyclass_response(). */ + skb_get(skb); + irlmp_data_request(self->lsap, skb); break; default: diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c index 727c1eb64c2f..69236887ac55 100644 --- a/net/irda/irlan/irlan_common.c +++ b/net/irda/irlan/irlan_common.c @@ -1180,20 +1180,6 @@ void print_ret_code(__u8 code) } } -void irlan_mod_inc_use_count(void) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void irlan_mod_dec_use_count(void) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); MODULE_DESCRIPTION("The Linux IrDA LAN protocol"); MODULE_LICENSE("GPL"); diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index 8639f6a5ea07..6ba413f5e82b 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -31,6 +31,7 @@ #include <linux/inetdevice.h> #include <linux/if_arp.h> #include <linux/random.h> +#include <linux/module.h> #include <net/arp.h> #include <net/irda/irda.h> @@ -61,6 +62,7 @@ int irlan_eth_init(struct net_device *dev) dev->hard_start_xmit = irlan_eth_xmit; dev->get_stats = irlan_eth_get_stats; dev->set_multicast_list = irlan_eth_set_multicast_list; + SET_MODULE_OWNER(dev); ether_setup(dev); @@ -112,8 +114,6 @@ int irlan_eth_open(struct net_device *dev) self->disconnect_reason = 0; irlan_client_wakeup(self, self->saddr, self->daddr); - irlan_mod_inc_use_count(); - /* Make sure we have a hardware address before we return, so DHCP clients gets happy */ interruptible_sleep_on(&self->open_wait); @@ -138,8 +138,6 @@ int irlan_eth_close(struct net_device *dev) /* Stop device */ netif_stop_queue(dev); - irlan_mod_dec_use_count(); - irlan_close_data_channel(self); irlan_close_tsaps(self); @@ -206,7 +204,7 @@ int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev) * confuse do_dev_queue_xmit() in dev.c! I have * tried :-) DB */ - dev_kfree_skb(skb); + /* irttp_data_request already free the packet */ self->stats.tx_dropped++; } else { self->stats.tx_packets++; diff --git a/net/irda/irlap.c b/net/irda/irlap.c index 59b08f0d698c..627278c5fef9 100644 --- a/net/irda/irlap.c +++ b/net/irda/irlap.c @@ -10,7 +10,7 @@ * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -244,7 +244,6 @@ void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb) irlap_init_qos_capabilities(self, NULL); /* No user QoS! */ - skb_get(skb); /*LEVEL4*/ irlmp_link_connect_indication(self->notify.instance, self->saddr, self->daddr, &self->qos_tx, skb); } @@ -255,12 +254,11 @@ void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb) * Service user has accepted incoming connection * */ -void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb) +void irlap_connect_response(struct irlap_cb *self, struct sk_buff *userdata) { IRDA_DEBUG(4, "%s()\n", __FUNCTION__); - irlap_do_event(self, CONNECT_RESPONSE, skb, NULL); - kfree_skb(skb); + irlap_do_event(self, CONNECT_RESPONSE, userdata, NULL); } /* @@ -305,7 +303,6 @@ void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb) ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); - skb_get(skb); /*LEVEL4*/ irlmp_link_connect_confirm(self->notify.instance, &self->qos_tx, skb); } @@ -322,7 +319,6 @@ void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb, /* Hide LAP header from IrLMP layer */ skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); - skb_get(skb); /*LEVEL4*/ irlmp_link_data_indication(self->notify.instance, skb, unreliable); } @@ -354,6 +350,9 @@ void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb, else skb->data[1] = I_FRAME; + /* Don't forget to refcount it - see irlmp_connect_request(). */ + skb_get(skb); + /* Add at the end of the queue (keep ordering) - Jean II */ skb_queue_tail(&self->txq, skb); @@ -392,6 +391,8 @@ void irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb) skb->data[0] = CBROADCAST; skb->data[1] = UI_FRAME; + /* Don't need to refcount, see irlmp_connless_data_request() */ + skb_queue_tail(&self->txq_ultra, skb); irlap_do_event(self, SEND_UI_FRAME, NULL, NULL); @@ -416,7 +417,6 @@ void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb) /* Hide LAP header from IrLMP layer */ skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); - skb_get(skb); /*LEVEL4*/ irlmp_link_unitdata_indication(self->notify.instance, skb); } #endif /* CONFIG_IRDA_ULTRA */ diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c index 975c30d3d119..b6df8f99d6f6 100644 --- a/net/irda/irlap_event.c +++ b/net/irda/irlap_event.c @@ -12,7 +12,7 @@ * Copyright (c) 1998-2000 Dag Brattli <dag@brattli.net>, * Copyright (c) 1998 Thomas Davis <ratbert@radiks.net> * All Rights Reserved. - * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -287,6 +287,9 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, /* Send one frame */ ret = (*state[self->state])(self, SEND_I_CMD, skb, NULL); + /* Drop reference count. + * It will be increase as needed in + * irlap_send_data_xxx() */ kfree_skb(skb); /* Poll the higher layers for one more frame */ @@ -517,6 +520,8 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event, CMD_FRAME); else break; + /* irlap_send_ui_frame() won't increase skb reference + * count, so no dev_kfree_skb() - Jean II */ } if (i == 2) { /* Force us to listen 500 ms again */ diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c index c40c1197c129..856c3c63cfe4 100644 --- a/net/irda/irlap_frame.c +++ b/net/irda/irlap_frame.c @@ -11,7 +11,7 @@ * * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. - * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -106,7 +106,7 @@ void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb) */ void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos) { - struct sk_buff *skb; + struct sk_buff *tx_skb; struct snrm_frame *frame; int ret; @@ -114,11 +114,11 @@ void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos) ASSERT(self->magic == LAP_MAGIC, return;); /* Allocate frame */ - skb = dev_alloc_skb(64); - if (!skb) + tx_skb = dev_alloc_skb(64); + if (!tx_skb) return; - frame = (struct snrm_frame *) skb_put(skb, 2); + frame = (struct snrm_frame *) skb_put(tx_skb, 2); /* Insert connection address field */ if (qos) @@ -133,19 +133,19 @@ void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos) * If we are establishing a connection then insert QoS paramerters */ if (qos) { - skb_put(skb, 9); /* 21 left */ + skb_put(tx_skb, 9); /* 21 left */ frame->saddr = cpu_to_le32(self->saddr); frame->daddr = cpu_to_le32(self->daddr); frame->ncaddr = self->caddr; - ret = irlap_insert_qos_negotiation_params(self, skb); + ret = irlap_insert_qos_negotiation_params(self, tx_skb); if (ret < 0) { - dev_kfree_skb(skb); + dev_kfree_skb(tx_skb); return; } } - irlap_queue_xmit(self, skb); + irlap_queue_xmit(self, tx_skb); } /* @@ -162,8 +162,8 @@ static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb, frame = (struct snrm_frame *) skb->data; if (skb->len >= sizeof(struct snrm_frame)) { - /* Copy the new connection address */ - info->caddr = frame->ncaddr; + /* Copy the new connection address ignoring the C/R bit */ + info->caddr = frame->ncaddr & 0xFE; /* Check if the new connection address is valid */ if ((info->caddr == 0x00) || (info->caddr == 0xfe)) { @@ -197,7 +197,7 @@ static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb, */ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos) { - struct sk_buff *skb; + struct sk_buff *tx_skb; struct ua_frame *frame; int ret; @@ -206,14 +206,12 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos) ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); - skb = NULL; - /* Allocate frame */ - skb = dev_alloc_skb(64); - if (!skb) + tx_skb = dev_alloc_skb(64); + if (!tx_skb) return; - frame = (struct ua_frame *) skb_put(skb, 10); + frame = (struct ua_frame *) skb_put(tx_skb, 10); /* Build UA response */ frame->caddr = self->caddr; @@ -224,14 +222,14 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos) /* Should we send QoS negotiation parameters? */ if (qos) { - ret = irlap_insert_qos_negotiation_params(self, skb); + ret = irlap_insert_qos_negotiation_params(self, tx_skb); if (ret < 0) { - dev_kfree_skb(skb); + dev_kfree_skb(tx_skb); return; } } - irlap_queue_xmit(self, skb); + irlap_queue_xmit(self, tx_skb); } @@ -243,17 +241,17 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos) */ void irlap_send_dm_frame( struct irlap_cb *self) { - struct sk_buff *skb = NULL; + struct sk_buff *tx_skb = NULL; __u8 *frame; ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); - skb = dev_alloc_skb(32); - if (!skb) + tx_skb = dev_alloc_skb(32); + if (!tx_skb) return; - frame = skb_put( skb, 2); + frame = skb_put(tx_skb, 2); if (self->state == LAP_NDM) frame[0] = CBROADCAST; @@ -262,7 +260,7 @@ void irlap_send_dm_frame( struct irlap_cb *self) frame[1] = DM_RSP | PF_BIT; - irlap_queue_xmit(self, skb); + irlap_queue_xmit(self, tx_skb); } /* @@ -273,7 +271,7 @@ void irlap_send_dm_frame( struct irlap_cb *self) */ void irlap_send_disc_frame(struct irlap_cb *self) { - struct sk_buff *skb = NULL; + struct sk_buff *tx_skb = NULL; __u8 *frame; IRDA_DEBUG(3, "%s()\n", __FUNCTION__); @@ -281,16 +279,16 @@ void irlap_send_disc_frame(struct irlap_cb *self) ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); - skb = dev_alloc_skb(16); - if (!skb) + tx_skb = dev_alloc_skb(16); + if (!tx_skb) return; - frame = skb_put(skb, 2); + frame = skb_put(tx_skb, 2); frame[0] = self->caddr | CMD_FRAME; frame[1] = DISC_CMD | PF_BIT; - irlap_queue_xmit(self, skb); + irlap_queue_xmit(self, tx_skb); } /* @@ -302,7 +300,7 @@ void irlap_send_disc_frame(struct irlap_cb *self) void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s, __u8 command, discovery_t *discovery) { - struct sk_buff *skb = NULL; + struct sk_buff *tx_skb = NULL; struct xid_frame *frame; __u32 bcast = BROADCAST; __u8 *info; @@ -314,12 +312,12 @@ void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s, ASSERT(self->magic == LAP_MAGIC, return;); ASSERT(discovery != NULL, return;); - skb = dev_alloc_skb(64); - if (!skb) + tx_skb = dev_alloc_skb(64); + if (!tx_skb) return; - skb_put(skb, 14); - frame = (struct xid_frame *) skb->data; + skb_put(tx_skb, 14); + frame = (struct xid_frame *) tx_skb->data; if (command) { frame->caddr = CBROADCAST | CMD_FRAME; @@ -367,21 +365,21 @@ void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s, int len; if (discovery->data.hints[0] & HINT_EXTENSION) { - info = skb_put(skb, 2); + info = skb_put(tx_skb, 2); info[0] = discovery->data.hints[0]; info[1] = discovery->data.hints[1]; } else { - info = skb_put(skb, 1); + info = skb_put(tx_skb, 1); info[0] = discovery->data.hints[0]; } - info = skb_put(skb, 1); + info = skb_put(tx_skb, 1); info[0] = discovery->data.charset; - len = IRDA_MIN(discovery->name_len, skb_tailroom(skb)); - info = skb_put(skb, len); + len = IRDA_MIN(discovery->name_len, skb_tailroom(tx_skb)); + info = skb_put(tx_skb, len); memcpy(info, discovery->data.info, len); } - irlap_queue_xmit(self, skb); + irlap_queue_xmit(self, tx_skb); } /* @@ -498,7 +496,6 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, break; default: /* Error!! */ - dev_kfree_skb(skb); return; } info->s = xid->slotnr; @@ -561,21 +558,21 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, */ void irlap_send_rr_frame(struct irlap_cb *self, int command) { - struct sk_buff *skb; + struct sk_buff *tx_skb; __u8 *frame; - skb = dev_alloc_skb(16); - if (!skb) + tx_skb = dev_alloc_skb(16); + if (!tx_skb) return; - frame = skb_put(skb, 2); + frame = skb_put(tx_skb, 2); frame[0] = self->caddr; frame[0] |= (command) ? CMD_FRAME : 0; frame[1] = RR | PF_BIT | (self->vr << 5); - irlap_queue_xmit(self, skb); + irlap_queue_xmit(self, tx_skb); } /* @@ -586,19 +583,19 @@ void irlap_send_rr_frame(struct irlap_cb *self, int command) */ void irlap_send_rd_frame(struct irlap_cb *self) { - struct sk_buff *skb; + struct sk_buff *tx_skb; __u8 *frame; - skb = dev_alloc_skb(16); - if (!skb) + tx_skb = dev_alloc_skb(16); + if (!tx_skb) return; - frame = skb_put(skb, 2); + frame = skb_put(tx_skb, 2); frame[0] = self->caddr; frame[1] = RD_RSP | PF_BIT; - irlap_queue_xmit(self, skb); + irlap_queue_xmit(self, tx_skb); } /* @@ -623,17 +620,17 @@ static inline void irlap_recv_rr_frame(struct irlap_cb *self, void irlap_send_frmr_frame( struct irlap_cb *self, int command) { - struct sk_buff *skb = NULL; + struct sk_buff *tx_skb = NULL; __u8 *frame; ASSERT( self != NULL, return;); ASSERT( self->magic == LAP_MAGIC, return;); - skb = dev_alloc_skb( 32); - if (!skb) + tx_skb = dev_alloc_skb( 32); + if (!tx_skb) return; - frame = skb_put( skb, 2); + frame = skb_put(tx_skb, 2); frame[0] = self->caddr; frame[0] |= (command) ? CMD_FRAME : 0; @@ -646,7 +643,7 @@ void irlap_send_frmr_frame( struct irlap_cb *self, int command) IRDA_DEBUG(4, "%s(), vr=%d, %ld\n", __FUNCTION__, self->vr, jiffies); - irlap_queue_xmit(self, skb); + irlap_queue_xmit(self, tx_skb); } /* @@ -739,17 +736,19 @@ void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb) */ skb->data[1] = I_FRAME | (self->vs << 1); + /* + * Insert frame in store, in case of retransmissions + * Increase skb reference count, see irlap_do_event() + */ + skb_get(skb); + skb_queue_tail(&self->wx_list, skb); + /* Copy buffer */ tx_skb = skb_clone(skb, GFP_ATOMIC); if (tx_skb == NULL) { return; } - /* - * Insert frame in store, in case of retransmissions - */ - skb_queue_tail(&self->wx_list, skb_get(skb)); - self->vs = (self->vs + 1) % 8; self->ack_required = FALSE; self->window -= 1; @@ -782,6 +781,13 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) */ skb->data[1] = I_FRAME | (self->vs << 1); + /* + * Insert frame in store, in case of retransmissions + * Increase skb reference count, see irlap_do_event() + */ + skb_get(skb); + skb_queue_tail(&self->wx_list, skb); + /* Copy buffer */ tx_skb = skb_clone(skb, GFP_ATOMIC); if (tx_skb == NULL) { @@ -789,11 +795,6 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) } /* - * Insert frame in store, in case of retransmissions - */ - skb_queue_tail(&self->wx_list, skb_get(skb)); - - /* * Set poll bit if necessary. We do this to the copied * skb, since retransmitted need to set or clear the poll * bit depending on when they are sent. @@ -850,14 +851,18 @@ void irlap_send_data_secondary_final(struct irlap_cb *self, */ skb->data[1] = I_FRAME | (self->vs << 1); + /* + * Insert frame in store, in case of retransmissions + * Increase skb reference count, see irlap_do_event() + */ + skb_get(skb); + skb_queue_tail(&self->wx_list, skb); + tx_skb = skb_clone(skb, GFP_ATOMIC); if (tx_skb == NULL) { return; } - /* Insert frame in store */ - skb_queue_tail(&self->wx_list, skb_get(skb)); - tx_skb->data[1] |= PF_BIT; self->vs = (self->vs + 1) % 8; @@ -903,14 +908,18 @@ void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb) */ skb->data[1] = I_FRAME | (self->vs << 1); + /* + * Insert frame in store, in case of retransmissions + * Increase skb reference count, see irlap_do_event() + */ + skb_get(skb); + skb_queue_tail(&self->wx_list, skb); + tx_skb = skb_clone(skb, GFP_ATOMIC); if (tx_skb == NULL) { return; } - /* Insert frame in store */ - skb_queue_tail(&self->wx_list, skb_get(skb)); - self->vs = (self->vs + 1) % 8; self->ack_required = FALSE; self->window -= 1; @@ -939,8 +948,6 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command) ASSERT(self->magic == LAP_MAGIC, return;); /* Initialize variables */ - skb = tx_skb = NULL; - count = skb_queue_len(&self->wx_list); /* Resend unacknowledged frame(s) */ @@ -1020,9 +1027,6 @@ void irlap_resend_rejected_frame(struct irlap_cb *self, int command) ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); - /* Initialize variables */ - skb = tx_skb = NULL; - /* Resend unacknowledged frame(s) */ skb = skb_peek(&self->wx_list); if (skb != NULL) { @@ -1186,35 +1190,35 @@ static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb, void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, struct sk_buff *cmd) { - struct sk_buff *skb; + struct sk_buff *tx_skb; struct test_frame *frame; __u8 *info; - skb = dev_alloc_skb(cmd->len+sizeof(struct test_frame)); - if (!skb) + tx_skb = dev_alloc_skb(cmd->len+sizeof(struct test_frame)); + if (!tx_skb) return; /* Broadcast frames must include saddr and daddr fields */ if (caddr == CBROADCAST) { frame = (struct test_frame *) - skb_put(skb, sizeof(struct test_frame)); + skb_put(tx_skb, sizeof(struct test_frame)); /* Insert the swapped addresses */ frame->saddr = cpu_to_le32(self->saddr); frame->daddr = cpu_to_le32(daddr); } else - frame = (struct test_frame *) skb_put(skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER); + frame = (struct test_frame *) skb_put(tx_skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER); frame->caddr = caddr; frame->control = TEST_RSP | PF_BIT; /* Copy info */ - info = skb_put(skb, cmd->len); + info = skb_put(tx_skb, cmd->len); memcpy(info, cmd->data, cmd->len); /* Return to sender */ irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_queue_xmit(self, skb); + irlap_queue_xmit(self, tx_skb); } /* @@ -1263,6 +1267,15 @@ static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, * Called when a frame is received. Dispatches the right receive function * for processing of the frame. * + * Note on skb management : + * After calling the higher layers of the IrDA stack, we always + * kfree() the skb, which drop the reference count (and potentially + * destroy it). + * If a higher layer of the stack want to keep the skb around (to put + * in a queue or pass it to the higher layer), it will need to use + * skb_get() to keep a reference on it. This is usually done at the + * LMP level in irlmp.c. + * Jean II */ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype) @@ -1286,6 +1299,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, * we don't need to be clever about it. Jean II */ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { ERROR("%s: can't clone shared skb!\n", __FUNCTION__); + dev_kfree_skb(skb); return -1; } if (skb_is_nonlinear(skb)) @@ -1390,6 +1404,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, break; } out: + /* Always drop our reference on the skb */ dev_kfree_skb(skb); return 0; } diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c index a44327be74d8..b6d41fc2772f 100644 --- a/net/irda/irlmp.c +++ b/net/irda/irlmp.c @@ -11,7 +11,7 @@ * * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. - * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -345,9 +345,10 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, __u32 saddr, __u32 daddr, struct qos_info *qos, struct sk_buff *userdata) { - struct sk_buff *skb = NULL; + struct sk_buff *tx_skb = userdata; struct lap_cb *lap; struct lsap_cb *lsap; + int ret; ASSERT(self != NULL, return -EBADR;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;); @@ -356,26 +357,29 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, "%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n", __FUNCTION__, self->slsap_sel, dlsap_sel, saddr, daddr); - if (test_bit(0, &self->connected)) - return -EISCONN; + if (test_bit(0, &self->connected)) { + ret = -EISCONN; + goto err; + } /* Client must supply destination device address */ - if (!daddr) - return -EINVAL; + if (!daddr) { + ret = -EINVAL; + goto err; + } /* Any userdata? */ - if (userdata == NULL) { - skb = dev_alloc_skb(64); - if (!skb) + if (tx_skb == NULL) { + tx_skb = dev_alloc_skb(64); + if (!tx_skb) return -ENOMEM; - skb_reserve(skb, LMP_MAX_HEADER); - } else - skb = userdata; + skb_reserve(tx_skb, LMP_MAX_HEADER); + } /* Make room for MUX control header (3 bytes) */ - ASSERT(skb_headroom(skb) >= LMP_CONTROL_HEADER, return -1;); - skb_push(skb, LMP_CONTROL_HEADER); + ASSERT(skb_headroom(tx_skb) >= LMP_CONTROL_HEADER, return -1;); + skb_push(tx_skb, LMP_CONTROL_HEADER); self->dlsap_sel = dlsap_sel; @@ -409,7 +413,8 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, lap = hashbin_lock_find(irlmp->links, saddr, NULL); if (lap == NULL) { IRDA_DEBUG(1, "%s(), Unable to find a usable link!\n", __FUNCTION__); - return -EHOSTUNREACH; + ret = -EHOSTUNREACH; + goto err; } /* Check if LAP is disconnected or already connected */ @@ -423,13 +428,15 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, * Maybe we could give LAP a bit of help in this case. */ IRDA_DEBUG(0, "%s(), sorry, but I'm waiting for LAP to timeout!\n", __FUNCTION__); - return -EAGAIN; + ret = -EAGAIN; + goto err; } /* LAP is already connected to a different node, and LAP * can only talk to one node at a time */ IRDA_DEBUG(0, "%s(), sorry, but link is busy!\n", __FUNCTION__); - return -EBUSY; + ret = -EBUSY; + goto err; } self->lap = lap; @@ -456,9 +463,18 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, if (qos) self->qos = *qos; - irlmp_do_lsap_event(self, LM_CONNECT_REQUEST, skb); + irlmp_do_lsap_event(self, LM_CONNECT_REQUEST, tx_skb); + + /* Drop reference count - see irlap_data_request(). */ + dev_kfree_skb(tx_skb); return 0; + +err: + /* Cleanup */ + if(tx_skb) + dev_kfree_skb(tx_skb); + return ret; } /* @@ -495,12 +511,13 @@ void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb) /* Hide LMP_CONTROL_HEADER header from layer above */ skb_pull(skb, LMP_CONTROL_HEADER); - if (self->notify.connect_indication) + if (self->notify.connect_indication) { + /* Don't forget to refcount it - see irlap_driver_rcv(). */ + skb_get(skb); self->notify.connect_indication(self->notify.instance, self, &self->qos, max_seg_size, max_header_size, skb); - else - dev_kfree_skb(skb); + } } /* @@ -526,6 +543,9 @@ int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata) irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata); + /* Drop reference count - see irlap_data_request(). */ + dev_kfree_skb(userdata); + return 0; } @@ -560,11 +580,12 @@ void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb) skb_pull(skb, LMP_CONTROL_HEADER); if (self->notify.connect_confirm) { + /* Don't forget to refcount it - see irlap_driver_rcv() */ + skb_get(skb); self->notify.connect_confirm(self->notify.instance, self, &self->qos, max_seg_size, max_header_size, skb); - } else - dev_kfree_skb(skb); + } } /* @@ -602,6 +623,7 @@ struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance) memcpy(new, orig, sizeof(struct lsap_cb)); /* new->lap = orig->lap; => done in the memcpy() */ /* new->slsap_sel = orig->slsap_sel; => done in the memcpy() */ + new->conn_skb = NULL; spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); @@ -653,6 +675,9 @@ int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata) */ irlmp_do_lsap_event(self, LM_DISCONNECT_REQUEST, userdata); + /* Drop reference count - see irlap_data_request(). */ + dev_kfree_skb(userdata); + /* * Remove LSAP from list of connected LSAPs for the particular link * and insert it into the list of unconnected LSAPs @@ -686,7 +711,7 @@ int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata) * LSAP is being closed! */ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, - struct sk_buff *userdata) + struct sk_buff *skb) { struct lsap_cb *lsap; @@ -703,8 +728,6 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, * Jean II */ if (! test_and_clear_bit(0, &self->connected)) { IRDA_DEBUG(0, "%s(), already disconnected!\n", __FUNCTION__); - if (userdata) - dev_kfree_skb(userdata); return; } @@ -730,13 +753,14 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, /* * Inform service user */ - if (self->notify.disconnect_indication) + if (self->notify.disconnect_indication) { + /* Don't forget to refcount it - see irlap_driver_rcv(). */ + if(skb) + skb_get(skb); self->notify.disconnect_indication(self->notify.instance, - self, reason, userdata); - else { + self, reason, skb); + } else { IRDA_DEBUG(0, "%s(), no handler\n", __FUNCTION__); - if (userdata) - dev_kfree_skb(userdata); } } @@ -1047,17 +1071,31 @@ discovery_t *irlmp_get_discovery_response() * * Send some data to peer device * + * Note on skb management : + * After calling the lower layers of the IrDA stack, we always + * kfree() the skb, which drop the reference count (and potentially + * destroy it). + * IrLMP and IrLAP may queue the packet, and in those cases will need + * to use skb_get() to keep it around. + * Jean II */ -int irlmp_data_request(struct lsap_cb *self, struct sk_buff *skb) +int irlmp_data_request(struct lsap_cb *self, struct sk_buff *userdata) { + int ret; + ASSERT(self != NULL, return -1;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); /* Make room for MUX header */ - ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;); - skb_push(skb, LMP_HEADER); + ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;); + skb_push(userdata, LMP_HEADER); + + ret = irlmp_do_lsap_event(self, LM_DATA_REQUEST, userdata); - return irlmp_do_lsap_event(self, LM_DATA_REQUEST, skb); + /* Drop reference count - see irlap_data_request(). */ + dev_kfree_skb(userdata); + + return ret; } /* @@ -1071,26 +1109,34 @@ void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb) /* Hide LMP header from layer above */ skb_pull(skb, LMP_HEADER); - if (self->notify.data_indication) + if (self->notify.data_indication) { + /* Don't forget to refcount it - see irlap_driver_rcv(). */ + skb_get(skb); self->notify.data_indication(self->notify.instance, self, skb); - else - dev_kfree_skb(skb); + } } /* * Function irlmp_udata_request (self, skb) */ -int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *skb) +int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *userdata) { + int ret; + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); - ASSERT(skb != NULL, return -1;); + ASSERT(userdata != NULL, return -1;); /* Make room for MUX header */ - ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;); - skb_push(skb, LMP_HEADER); + ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;); + skb_push(userdata, LMP_HEADER); + + ret = irlmp_do_lsap_event(self, LM_UDATA_REQUEST, userdata); - return irlmp_do_lsap_event(self, LM_UDATA_REQUEST, skb); + /* Drop reference count - see irlap_data_request(). */ + dev_kfree_skb(userdata); + + return ret; } /* @@ -1110,51 +1156,57 @@ void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb) /* Hide LMP header from layer above */ skb_pull(skb, LMP_HEADER); - if (self->notify.udata_indication) + if (self->notify.udata_indication) { + /* Don't forget to refcount it - see irlap_driver_rcv(). */ + skb_get(skb); self->notify.udata_indication(self->notify.instance, self, skb); - else - dev_kfree_skb(skb); + } } /* * Function irlmp_connless_data_request (self, skb) */ #ifdef CONFIG_IRDA_ULTRA -int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *skb) +int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *userdata) { struct sk_buff *clone_skb; struct lap_cb *lap; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); - ASSERT(skb != NULL, return -1;); + ASSERT(userdata != NULL, return -1;); /* Make room for MUX and PID header */ - ASSERT(skb_headroom(skb) >= LMP_HEADER+LMP_PID_HEADER, return -1;); + ASSERT(skb_headroom(userdata) >= LMP_HEADER+LMP_PID_HEADER, + return -1;); /* Insert protocol identifier */ - skb_push(skb, LMP_PID_HEADER); - skb->data[0] = self->pid; + skb_push(userdata, LMP_PID_HEADER); + userdata->data[0] = self->pid; /* Connectionless sockets must use 0x70 */ - skb_push(skb, LMP_HEADER); - skb->data[0] = skb->data[1] = LSAP_CONNLESS; + skb_push(userdata, LMP_HEADER); + userdata->data[0] = userdata->data[1] = LSAP_CONNLESS; /* Try to send Connectionless packets out on all links */ lap = (struct lap_cb *) hashbin_get_first(irlmp->links); while (lap != NULL) { ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;); - clone_skb = skb_clone(skb, GFP_ATOMIC); - if (!clone_skb) + clone_skb = skb_clone(userdata, GFP_ATOMIC); + if (!clone_skb) { + dev_kfree_skb(userdata); return -ENOMEM; + } irlap_unitdata_request(lap->irlap, clone_skb); + /* irlap_unitdata_request() don't increase refcount, + * so no dev_kfree_skb() - Jean II */ lap = (struct lap_cb *) hashbin_get_next(irlmp->links); } - dev_kfree_skb(skb); + dev_kfree_skb(userdata); return 0; } @@ -1178,11 +1230,12 @@ void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb) /* Hide LMP and PID header from layer above */ skb_pull(skb, LMP_HEADER+LMP_PID_HEADER); - if (self->notify.udata_indication) + if (self->notify.udata_indication) { + /* Don't forget to refcount it - see irlap_driver_rcv(). */ + skb_get(skb); self->notify.udata_indication(self->notify.instance, self, skb); - else - dev_kfree_skb(skb); + } } #endif /* CONFIG_IRDA_ULTRA */ diff --git a/net/irda/irlmp_event.c b/net/irda/irlmp_event.c index 0d976b6662c6..91f8ad67bc33 100644 --- a/net/irda/irlmp_event.c +++ b/net/irda/irlmp_event.c @@ -11,7 +11,7 @@ * * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. - * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -295,8 +295,6 @@ static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event, default: IRDA_DEBUG(0, "%s(), Unknown event %s\n", __FUNCTION__, irlmp_event[event]); - if (skb) - dev_kfree_skb(skb); break; } } @@ -373,8 +371,6 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event, default: IRDA_DEBUG(0, "%s(), Unknown event %s\n", __FUNCTION__, irlmp_event[event]); - if (skb) - dev_kfree_skb(skb); break; } } @@ -468,8 +464,6 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event, default: IRDA_DEBUG(0, "%s(), Unknown event %s\n", __FUNCTION__, irlmp_event[event]); - if (skb) - dev_kfree_skb(skb); break; } } @@ -499,6 +493,9 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event, switch (event) { #ifdef CONFIG_IRDA_ULTRA case LM_UDATA_INDICATION: + /* This is most bizzare. Those packets are aka unreliable + * connected, aka IrLPT or SOCK_DGRAM/IRDAPROTO_UNITDATA. + * Why do we pass them as Ultra ??? Jean II */ irlmp_connless_data_indication(self, skb); break; #endif /* CONFIG_IRDA_ULTRA */ @@ -510,6 +507,8 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event, __FUNCTION__); return -EBUSY; } + /* Don't forget to refcount it (see irlmp_connect_request()) */ + skb_get(skb); self->conn_skb = skb; irlmp_next_lsap_state(self, LSAP_SETUP_PEND); @@ -525,6 +524,8 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event, __FUNCTION__); return -EBUSY; } + /* Don't forget to refcount it (see irlap_driver_rcv()) */ + skb_get(skb); self->conn_skb = skb; irlmp_next_lsap_state(self, LSAP_CONNECT_PEND); @@ -547,8 +548,6 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event, default: IRDA_DEBUG(1, "%s(), Unknown event %s on LSAP %#02x\n", __FUNCTION__, irlmp_event[event], self->slsap_sel); - if (skb) - dev_kfree_skb(skb); break; } return ret; @@ -606,8 +605,6 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event, default: IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", __FUNCTION__, irlmp_event[event], self->slsap_sel); - if (skb) - dev_kfree_skb(skb); break; } return ret; @@ -622,6 +619,7 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event, static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event, struct sk_buff *skb) { + struct sk_buff *tx_skb; int ret = 0; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); @@ -647,10 +645,12 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event, IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n", __FUNCTION__); irlmp_next_lsap_state(self, LSAP_CONNECT); - skb = self->conn_skb; + tx_skb = self->conn_skb; self->conn_skb = NULL; - irlmp_connect_indication(self, skb); + irlmp_connect_indication(self, tx_skb); + /* Drop reference count - see irlmp_connect_indication(). */ + dev_kfree_skb(tx_skb); break; case LM_WATCHDOG_TIMEOUT: /* Will happen in some rare cases because of a race condition. @@ -668,8 +668,6 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event, default: IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", __FUNCTION__, irlmp_event[event], self->slsap_sel); - if (skb) - dev_kfree_skb(skb); break; } return ret; @@ -759,8 +757,6 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event, default: IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", __FUNCTION__, irlmp_event[event], self->slsap_sel); - if (skb) - dev_kfree_skb(skb); break; } return ret; @@ -832,8 +828,6 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event, default: IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", __FUNCTION__, irlmp_event[event], self->slsap_sel); - if (skb) - dev_kfree_skb(skb); break; } return ret; @@ -850,6 +844,7 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event, static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event, struct sk_buff *skb) { + struct sk_buff *tx_skb; LM_REASON reason; int ret = 0; @@ -862,11 +857,13 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event, case LM_LAP_CONNECT_CONFIRM: ASSERT(self->conn_skb != NULL, return -1;); - skb = self->conn_skb; + tx_skb = self->conn_skb; self->conn_skb = NULL; irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, - self->slsap_sel, CONNECT_CMD, skb); + self->slsap_sel, CONNECT_CMD, tx_skb); + /* Drop reference count - see irlap_data_request(). */ + dev_kfree_skb(tx_skb); irlmp_next_lsap_state(self, LSAP_SETUP); break; @@ -891,8 +888,6 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event, default: IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", __FUNCTION__, irlmp_event[event], self->slsap_sel); - if (skb) - dev_kfree_skb(skb); break; } return ret; diff --git a/net/irda/irlmp_frame.c b/net/irda/irlmp_frame.c index 616fd22f01d1..c00ccfd31022 100644 --- a/net/irda/irlmp_frame.c +++ b/net/irda/irlmp_frame.c @@ -11,7 +11,7 @@ * * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no> * All Rights Reserved. - * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -144,7 +144,6 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb, } else { IRDA_DEBUG(2, "%s(), received data frame\n", __FUNCTION__); } - dev_kfree_skb(skb); return; } @@ -168,16 +167,13 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb, break; case ACCESSMODE_CMD: IRDA_DEBUG(0, "Access mode cmd not implemented!\n"); - dev_kfree_skb(skb); break; case ACCESSMODE_CNF: IRDA_DEBUG(0, "Access mode cnf not implemented!\n"); - dev_kfree_skb(skb); break; default: IRDA_DEBUG(0, "%s(), Unknown control frame %02x\n", __FUNCTION__, fp[2]); - dev_kfree_skb(skb); break; } } else if (unreliable) { @@ -230,16 +226,12 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb) if (pid & 0x80) { IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __FUNCTION__); - dev_kfree_skb(skb); - return; } /* Check if frame is addressed to the connectionless LSAP */ if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) { IRDA_DEBUG(0, "%s(), dropping frame!\n", __FUNCTION__); - dev_kfree_skb(skb); - return; } @@ -264,7 +256,6 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb) irlmp_connless_data_indication(lsap, skb); else { IRDA_DEBUG(0, "%s(), found no matching LSAP!\n", __FUNCTION__); - dev_kfree_skb(skb); } } #endif /* CONFIG_IRDA_ULTRA */ @@ -278,7 +269,7 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb) void irlmp_link_disconnect_indication(struct lap_cb *lap, struct irlap_cb *irlap, LAP_REASON reason, - struct sk_buff *userdata) + struct sk_buff *skb) { IRDA_DEBUG(2, "%s()\n", __FUNCTION__); @@ -288,9 +279,7 @@ void irlmp_link_disconnect_indication(struct lap_cb *lap, lap->reason = reason; lap->daddr = DEV_ADDR_ANY; - /* FIXME: must do something with the userdata if any */ - if (userdata) - dev_kfree_skb(userdata); + /* FIXME: must do something with the skb if any */ /* * Inform station state machine @@ -327,7 +316,7 @@ void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr, * */ void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos, - struct sk_buff *userdata) + struct sk_buff *skb) { IRDA_DEBUG(4, "%s()\n", __FUNCTION__); @@ -335,9 +324,7 @@ void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos, ASSERT(self->magic == LMP_LAP_MAGIC, return;); ASSERT(qos != NULL, return;); - /* Don't need use the userdata for now */ - if (userdata) - dev_kfree_skb(userdata); + /* Don't need use the skb for now */ /* Copy QoS settings for this session */ self->qos = qos; diff --git a/net/irda/irnet/irnet.h b/net/irda/irnet/irnet.h index 37aa3d7e4b9f..0ed25a123047 100644 --- a/net/irda/irnet/irnet.h +++ b/net/irda/irnet/irnet.h @@ -229,6 +229,11 @@ * v14 - 20.2.03 - Jean II * o Add discovery hint bits in the control channel. * o Remove obsolete MOD_INC/DEC_USE_COUNT in favor of .owner + * + * v15 - 7.4.03 - Jean II + * o Replace spin_lock_irqsave() with spin_lock_bh() so that we can + * use ppp_unit_number(). It's probably also better overall... + * o Disable call to ppp_unregister_channel(), because we can't do it. */ /***************************** INCLUDES *****************************/ @@ -276,6 +281,7 @@ #undef CONNECT_INDIC_KICK /* Might mess IrDA, not needed */ #undef FAIL_SEND_DISCONNECT /* Might mess IrDA, not needed */ #undef PASS_CONNECT_PACKETS /* Not needed ? Safe */ +#undef MISSING_PPP_API /* Stuff I wish I could do */ /* PPP side of the business */ #define BLOCK_WHEN_CONNECT /* Block packets when connecting */ diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c index 517b76e3281e..83966549d07f 100644 --- a/net/irda/irnet/irnet_irda.c +++ b/net/irda/irnet/irnet_irda.c @@ -31,7 +31,6 @@ irnet_post_event(irnet_socket * ap, char * name, __u16 hints) { - unsigned long flags; /* For spinlock */ int index; /* In the log */ DENTER(CTRL_TRACE, "(ap=0x%X, event=%d, daddr=%08x, name=``%s'')\n", @@ -41,7 +40,7 @@ irnet_post_event(irnet_socket * ap, * Note : as we are the only event producer, we only need to exclude * ourself when touching the log, which is nice and easy. */ - spin_lock_irqsave(&irnet_events.spinlock, flags); + spin_lock_bh(&irnet_events.spinlock); /* Copy the event in the log */ index = irnet_events.index; @@ -69,7 +68,7 @@ irnet_post_event(irnet_socket * ap, DEBUG(CTRL_INFO, "New event index is %d\n", irnet_events.index); /* Spin lock end */ - spin_unlock_irqrestore(&irnet_events.spinlock, flags); + spin_unlock_bh(&irnet_events.spinlock); /* Now : wake up everybody waiting for events... */ wake_up_interruptible_all(&irnet_events.rwait); @@ -536,10 +535,9 @@ irda_irnet_connect(irnet_socket * self) * Can't re-insert (MUST remove first) so check for that... */ if((irnet_server.running) && (self->q.q_next == NULL)) { - unsigned long flags; - spin_lock_irqsave(&irnet_server.spinlock, flags); + spin_lock_bh(&irnet_server.spinlock); hashbin_insert(irnet_server.list, (irda_queue_t *) self, 0, self->rname); - spin_unlock_irqrestore(&irnet_server.spinlock, flags); + spin_unlock_bh(&irnet_server.spinlock); DEBUG(IRDA_SOCK_INFO, "Inserted ``%s'' in hashbin...\n", self->rname); } @@ -596,12 +594,11 @@ irda_irnet_destroy(irnet_socket * self) if((irnet_server.running) && (self->q.q_next != NULL)) { struct irnet_socket * entry; - unsigned long flags; DEBUG(IRDA_SOCK_INFO, "Removing from hash..\n"); - spin_lock_irqsave(&irnet_server.spinlock, flags); + spin_lock_bh(&irnet_server.spinlock); entry = hashbin_remove_this(irnet_server.list, (irda_queue_t *) self); self->q.q_next = NULL; - spin_unlock_irqrestore(&irnet_server.spinlock, flags); + spin_unlock_bh(&irnet_server.spinlock); DASSERT(entry == self, , IRDA_SOCK_ERROR, "Can't remove from hash.\n"); } @@ -723,7 +720,6 @@ static inline irnet_socket * irnet_find_socket(irnet_socket * self) { irnet_socket * new = (irnet_socket *) NULL; - unsigned long flags; int err; DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self); @@ -736,7 +732,7 @@ irnet_find_socket(irnet_socket * self) err = irnet_daddr_to_dname(self); /* Protect access to the instance list */ - spin_lock_irqsave(&irnet_server.spinlock, flags); + spin_lock_bh(&irnet_server.spinlock); /* So now, try to get an socket having specifically * requested that nickname */ @@ -790,7 +786,7 @@ irnet_find_socket(irnet_socket * self) } /* Spin lock end */ - spin_unlock_irqrestore(&irnet_server.spinlock, flags); + spin_unlock_bh(&irnet_server.spinlock); DEXIT(IRDA_SERV_TRACE, " - new = 0x%X\n", (unsigned int) new); return new; @@ -1135,10 +1131,15 @@ irnet_disconnect_indication(void * instance, { if(test_open) { +#ifdef MISSING_PPP_API + /* ppp_unregister_channel() wants a user context, which we + * are guaranteed to NOT have here. What are we supposed + * to do here ? Jean II */ /* If we were connected, cleanup & close the PPP channel, * which will kill pppd (hangup) and the rest */ ppp_unregister_channel(&self->chan); self->ppp_open = 0; +#endif } else { @@ -1711,7 +1712,6 @@ irnet_proc_read(char * buf, { irnet_socket * self; char * state; - unsigned long flags; int i = 0; len = 0; @@ -1728,7 +1728,7 @@ irnet_proc_read(char * buf, return len; /* Protect access to the instance list */ - spin_lock_irqsave(&irnet_server.spinlock, flags); + spin_lock_bh(&irnet_server.spinlock); /* Get the sockets one by one... */ self = (irnet_socket *) hashbin_get_first(irnet_server.list); @@ -1780,7 +1780,7 @@ irnet_proc_read(char * buf, } /* Spin lock end */ - spin_unlock_irqrestore(&irnet_server.spinlock, flags); + spin_unlock_bh(&irnet_server.spinlock); return len; } diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c index 6f5125b289cf..187871a4208a 100644 --- a/net/irda/irnet/irnet_ppp.c +++ b/net/irda/irnet/irnet_ppp.c @@ -927,7 +927,7 @@ ppp_irnet_send(struct ppp_channel * chan, * Jean II */ DERROR(PPP_ERROR, "IrTTP doesn't like this packet !!! (0x%X)\n", ret); - dev_kfree_skb(skb); + /* irttp_data_request already free the packet */ } DEXIT(PPP_TRACE, "\n"); diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 5ddded65c67d..bb51edc7d99b 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -11,7 +11,7 @@ * * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. - * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -259,11 +259,17 @@ static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self) dev_kfree_skb(frag); } - IRDA_DEBUG(2, "%s(), frame len=%d\n", __FUNCTION__, n); - IRDA_DEBUG(2, "%s(), rx_sdu_size=%d\n", __FUNCTION__, - self->rx_sdu_size); - ASSERT(n <= self->rx_sdu_size, return NULL;); + IRDA_DEBUG(2, + "%s(), frame len=%d, rx_sdu_size=%d, rx_max_sdu_size=%d\n", + __FUNCTION__, n, self->rx_sdu_size, self->rx_max_sdu_size); + /* Note : irttp_run_rx_queue() calculate self->rx_sdu_size + * by summing the size of all fragments, so we should always + * have n == self->rx_sdu_size, except in cases where we + * droped the last fragment (when self->rx_sdu_size exceed + * self->rx_max_sdu_size), where n < self->rx_sdu_size. + * Jean II */ + ASSERT(n <= self->rx_sdu_size, n = self->rx_sdu_size;); /* Set the new length */ skb_trim(skb, n); @@ -537,19 +543,23 @@ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb) if ((skb->len == 0) || (!self->connected)) { IRDA_DEBUG(1, "%s(), No data, or not connected\n", __FUNCTION__); - return -1; + goto err; } if (skb->len > self->max_seg_size) { IRDA_DEBUG(1, "%s(), UData is to large for IrLAP!\n", __FUNCTION__); - return -1; + goto err; } irlmp_udata_request(self->lsap, skb); self->stats.tx_packets++; return 0; + +err: + dev_kfree_skb(skb); + return -1; } /* @@ -561,6 +571,7 @@ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb) int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) { __u8 *frame; + int ret; ASSERT(self != NULL, return -1;); ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); @@ -572,7 +583,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) /* Check that nothing bad happens */ if ((skb->len == 0) || (!self->connected)) { WARNING("%s: No data, or not connected\n", __FUNCTION__); - return -ENOTCONN; + ret = -ENOTCONN; + goto err; } /* @@ -582,7 +594,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) { ERROR("%s: SAR disabled, and data is to large for IrLAP!\n", __FUNCTION__); - return -EMSGSIZE; + ret = -EMSGSIZE; + goto err; } /* @@ -595,7 +608,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) { ERROR("%s: SAR enabled, but data is larger than TxMaxSduSize!\n", __FUNCTION__); - return -EMSGSIZE; + ret = -EMSGSIZE; + goto err; } /* * Check if transmit queue is full @@ -607,8 +621,9 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) irttp_run_tx_queue(self); /* Drop packet. This error code should trigger the caller - * to requeue the packet in the client code - Jean II */ - return -ENOBUFS; + * to resend the data in the client code - Jean II */ + ret = -ENOBUFS; + goto err; } /* Queue frame, or queue frame segments */ @@ -651,6 +666,10 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) irttp_run_tx_queue(self); return 0; + +err: + dev_kfree_skb(skb); + return ret; } /* @@ -822,6 +841,7 @@ static int irttp_udata_indication(void *instance, void *sap, struct sk_buff *skb) { struct tsap_cb *self; + int err; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); @@ -831,14 +851,19 @@ static int irttp_udata_indication(void *instance, void *sap, ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); ASSERT(skb != NULL, return -1;); - /* Just pass data to layer above */ - if (self->notify.udata_indication) - self->notify.udata_indication(self->notify.instance, self,skb); - else - dev_kfree_skb(skb); - self->stats.rx_packets++; + /* Just pass data to layer above */ + if (self->notify.udata_indication) { + err = self->notify.udata_indication(self->notify.instance, + self,skb); + /* Same comment as in irttp_do_data_indication() */ + if (err != -ENOMEM) + return 0; + } + /* Either no handler, or -ENOMEM */ + dev_kfree_skb(skb); + return 0; } @@ -1040,7 +1065,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, struct qos_info *qos, __u32 max_sdu_size, struct sk_buff *userdata) { - struct sk_buff *skb; + struct sk_buff *tx_skb; __u8 *frame; __u8 n; @@ -1049,19 +1074,22 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, ASSERT(self != NULL, return -EBADR;); ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;); - if (self->connected) + if (self->connected) { + if(userdata) + dev_kfree_skb(userdata); return -EISCONN; + } /* Any userdata supplied? */ if (userdata == NULL) { - skb = dev_alloc_skb(64); - if (!skb) + tx_skb = dev_alloc_skb(64); + if (!tx_skb) return -ENOMEM; /* Reserve space for MUX_CONTROL and LAP header */ - skb_reserve(skb, TTP_MAX_HEADER); + skb_reserve(tx_skb, TTP_MAX_HEADER); } else { - skb = userdata; + tx_skb = userdata; /* * Check that the client has reserved enough space for * headers @@ -1094,11 +1122,11 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, /* SAR enabled? */ if (max_sdu_size > 0) { - ASSERT(skb_headroom(skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER), + ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER), return -1;); /* Insert SAR parameters */ - frame = skb_push(skb, TTP_HEADER+TTP_SAR_HEADER); + frame = skb_push(tx_skb, TTP_HEADER+TTP_SAR_HEADER); frame[0] = TTP_PARAMETERS | n; frame[1] = 0x04; /* Length */ @@ -1109,7 +1137,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, (__u16 *)(frame+4)); } else { /* Insert plain TTP header */ - frame = skb_push(skb, TTP_HEADER); + frame = skb_push(tx_skb, TTP_HEADER); /* Insert initial credit in frame */ frame[0] = n & 0x7f; @@ -1117,7 +1145,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, /* Connect with IrLMP. No QoS parameters for now */ return irlmp_connect_request(self->lsap, dtsap_sel, saddr, daddr, qos, - skb); + tx_skb); } /* @@ -1201,7 +1229,8 @@ static void irttp_connect_confirm(void *instance, void *sap, self->notify.connect_confirm(self->notify.instance, self, qos, self->tx_max_sdu_size, self->max_header_size, skb); - } + } else + dev_kfree_skb(skb); } /* @@ -1286,7 +1315,7 @@ void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos, int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, struct sk_buff *userdata) { - struct sk_buff *skb; + struct sk_buff *tx_skb; __u8 *frame; int ret; __u8 n; @@ -1299,19 +1328,19 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, /* Any userdata supplied? */ if (userdata == NULL) { - skb = dev_alloc_skb(64); - if (!skb) + tx_skb = dev_alloc_skb(64); + if (!tx_skb) return -ENOMEM; /* Reserve space for MUX_CONTROL and LAP header */ - skb_reserve(skb, TTP_MAX_HEADER); + skb_reserve(tx_skb, TTP_MAX_HEADER); } else { - skb = userdata; + tx_skb = userdata; /* * Check that the client has reserved enough space for * headers */ - ASSERT(skb_headroom(skb) >= TTP_MAX_HEADER, return -1;); + ASSERT(skb_headroom(tx_skb) >= TTP_MAX_HEADER, return -1;); } self->avail_credit = 0; @@ -1333,11 +1362,11 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, /* SAR enabled? */ if (max_sdu_size > 0) { - ASSERT(skb_headroom(skb) >= (TTP_MAX_HEADER+TTP_SAR_HEADER), + ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER+TTP_SAR_HEADER), return -1;); /* Insert TTP header with SAR parameters */ - frame = skb_push(skb, TTP_HEADER+TTP_SAR_HEADER); + frame = skb_push(tx_skb, TTP_HEADER+TTP_SAR_HEADER); frame[0] = TTP_PARAMETERS | n; frame[1] = 0x04; /* Length */ @@ -1352,12 +1381,12 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, (__u16 *)(frame+4)); } else { /* Insert TTP header */ - frame = skb_push(skb, TTP_HEADER); + frame = skb_push(tx_skb, TTP_HEADER); frame[0] = n & 0x7f; } - ret = irlmp_connect_response(self->lsap, skb); + ret = irlmp_connect_response(self->lsap, tx_skb); return ret; } @@ -1423,7 +1452,6 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance) int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, int priority) { - struct sk_buff *skb; int ret; ASSERT(self != NULL, return -1;); @@ -1488,16 +1516,17 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, self->connected = FALSE; if (!userdata) { - skb = dev_alloc_skb(64); - if (!skb) + struct sk_buff *tx_skb; + tx_skb = dev_alloc_skb(64); + if (!tx_skb) return -ENOMEM; /* * Reserve space for MUX and LAP header */ - skb_reserve(skb, TTP_MAX_HEADER); + skb_reserve(tx_skb, TTP_MAX_HEADER); - userdata = skb; + userdata = tx_skb; } ret = irlmp_disconnect_request(self->lsap, userdata); @@ -1556,7 +1585,7 @@ void irttp_disconnect_indication(void *instance, void *sap, LM_REASON reason, /* * Function irttp_do_data_indication (self, skb) * - * Try to deliver reassebled skb to layer above, and requeue it if that + * Try to deliver reassembled skb to layer above, and requeue it if that * for some reason should fail. We mark rx sdu as busy to apply back * pressure is necessary. */ diff --git a/net/socket.c b/net/socket.c index 4d62ac970ca6..76d29acb146a 100644 --- a/net/socket.c +++ b/net/socket.c @@ -325,7 +325,7 @@ static struct super_operations sockfs_ops = { }; static struct super_block *sockfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC); } diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 768d5b373fd2..abcb5ee4b890 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -749,7 +749,7 @@ out: static struct super_block * rpc_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_single(fs_type, flags, data, rpc_fill_super); } diff --git a/sound/core/control.c b/sound/core/control.c index c01a2ce81cd3..14541cd122f5 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -222,7 +222,7 @@ snd_kcontrol_t *snd_ctl_new1(snd_kcontrol_new_t * ncontrol, void *private_data) kctl.id.device = ncontrol->device; kctl.id.subdevice = ncontrol->subdevice; if (ncontrol->name) - strncpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name)-1); + strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name)); kctl.id.index = ncontrol->index; kctl.count = ncontrol->count ? ncontrol->count : 1; access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : @@ -449,12 +449,12 @@ static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl, memset(&info, 0, sizeof(info)); down_read(&snd_ioctl_rwsem); info.card = card->number; - strncpy(info.id, card->id, sizeof(info.id) - 1); - strncpy(info.driver, card->driver, sizeof(info.driver) - 1); - strncpy(info.name, card->shortname, sizeof(info.name) - 1); - strncpy(info.longname, card->longname, sizeof(info.longname) - 1); - strncpy(info.mixername, card->mixername, sizeof(info.mixername) - 1); - strncpy(info.components, card->components, sizeof(info.components) - 1); + strlcpy(info.id, card->id, sizeof(info.id)); + strlcpy(info.driver, card->driver, sizeof(info.driver)); + strlcpy(info.name, card->shortname, sizeof(info.name)); + strlcpy(info.longname, card->longname, sizeof(info.longname)); + strlcpy(info.mixername, card->mixername, sizeof(info.mixername)); + strlcpy(info.components, card->components, sizeof(info.components)); up_read(&snd_ioctl_rwsem); if (copy_to_user((void *) arg, &info, sizeof(snd_ctl_card_info_t))) return -EFAULT; diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 2f9dbfaffdf8..94f7feffabed 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -169,8 +169,8 @@ static int snd_hwdep_info(snd_hwdep_t *hw, snd_hwdep_info_t *_info) memset(&info, 0, sizeof(info)); info.card = hw->card->number; - strncpy(info.id, hw->id, sizeof(info.id) - 1); - strncpy(info.name, hw->name, sizeof(info.name) - 1); + strlcpy(info.id, hw->id, sizeof(info.id)); + strlcpy(info.name, hw->name, sizeof(info.name)); info.iface = hw->iface; if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; @@ -343,7 +343,7 @@ int snd_hwdep_new(snd_card_t * card, char *id, int device, snd_hwdep_t ** rhwdep hwdep->card = card; hwdep->device = device; if (id) { - strncpy(hwdep->id, id, sizeof(hwdep->id) - 1); + strlcpy(hwdep->id, id, sizeof(hwdep->id)); } #ifdef CONFIG_SND_OSSEMUL hwdep->oss_type = -1; diff --git a/sound/core/init.c b/sound/core/init.c index 5a45b82f4993..e34e8480f1c7 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -76,7 +76,7 @@ snd_card_t *snd_card_new(int idx, const char *xid, if (xid) { if (!snd_info_check_reserved_words(xid)) goto __error; - strncpy(card->id, xid, sizeof(card->id) - 1); + strlcpy(card->id, xid, sizeof(card->id)); } write_lock(&snd_card_rwlock); if (idx < 0) { diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index c01b1fffad65..cd1dd357d292 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -85,8 +85,8 @@ static int snd_mixer_oss_info(snd_mixer_oss_file_t *fmixer, struct mixer_info info; memset(&info, 0, sizeof(info)); - strncpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id) - 1); - strncpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name) - 1); + strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id)); + strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name)); info.modify_counter = card->mixer_oss_change_count; if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; @@ -101,8 +101,8 @@ static int snd_mixer_oss_info_obsolete(snd_mixer_oss_file_t *fmixer, _old_mixer_info info; memset(&info, 0, sizeof(info)); - strncpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id) - 1); - strncpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name) - 1); + strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id)); + strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name)); if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; return 0; @@ -1215,11 +1215,10 @@ static int snd_mixer_oss_notify_handler(snd_card_t * card, int cmd) } mixer->oss_dev_alloc = 1; mixer->card = card; - if (*card->mixername) { - strncpy(mixer->name, card->mixername, sizeof(mixer->name) - 1); - mixer->name[sizeof(mixer->name)-1] = 0; - } else - strcpy(mixer->name, name); + if (*card->mixername) + strlcpy(mixer->name, card->mixername, sizeof(mixer->name)); + else + strlcpy(mixer->name, name, sizeof(mixer->name)); #ifdef SNDRV_OSS_INFO_DEV_MIXERS snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS, card->number, diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 427e6f5de9d1..a494f3c1eb62 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -639,7 +639,7 @@ int snd_pcm_new(snd_card_t * card, char *id, int device, pcm->card = card; pcm->device = device; if (id) { - strncpy(pcm->id, id, sizeof(pcm->id) - 1); + strlcpy(pcm->id, id, sizeof(pcm->id)); } if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) { snd_pcm_free(pcm); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 4b3fab10f1e5..c1f9a5041aa9 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -92,13 +92,13 @@ int snd_pcm_info(snd_pcm_substream_t * substream, snd_pcm_info_t *info) info->device = pcm->device; info->stream = substream->stream; info->subdevice = substream->number; - strncpy(info->id, pcm->id, sizeof(info->id)-1); - strncpy(info->name, pcm->name, sizeof(info->name)-1); + strlcpy(info->id, pcm->id, sizeof(info->id)); + strlcpy(info->name, pcm->name, sizeof(info->name)); info->dev_class = pcm->dev_class; info->dev_subclass = pcm->dev_subclass; info->subdevices_count = pstr->substream_count; info->subdevices_avail = pstr->substream_count - pstr->substream_opened; - strncpy(info->subname, substream->name, sizeof(info->subname)-1); + strlcpy(info->subname, substream->name, sizeof(info->subname)); runtime = substream->runtime; /* AB: FIXME!!! This is definitely nonsense */ if (runtime) { diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 8285d83f4b0f..7071db966506 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1394,7 +1394,7 @@ int snd_rawmidi_new(snd_card_t * card, char *id, int device, init_MUTEX(&rmidi->open_mutex); init_waitqueue_head(&rmidi->open_wait); if (id != NULL) - strncpy(rmidi->id, id, sizeof(rmidi->id) - 1); + strlcpy(rmidi->id, id, sizeof(rmidi->id)); if ((err = snd_rawmidi_alloc_substreams(rmidi, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT], SNDRV_RAWMIDI_STREAM_INPUT, input_count)) < 0) { snd_rawmidi_free(rmidi); return err; diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index 599d0c71d3b4..17d8712cf4a9 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -184,8 +184,7 @@ snd_seq_oss_midi_check_new_port(snd_seq_port_info_t *pinfo) snd_use_lock_init(&mdev->use_lock); /* copy and truncate the name of synth device */ - strncpy(mdev->name, pinfo->name, sizeof(mdev->name)); - mdev->name[sizeof(mdev->name) - 1] = 0; + strlcpy(mdev->name, pinfo->name, sizeof(mdev->name)); /* create MIDI coder */ if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) { @@ -659,7 +658,7 @@ snd_seq_oss_midi_make_info(seq_oss_devinfo_t *dp, int dev, struct midi_info *inf inf->device = dev; inf->dev_type = 0; /* FIXME: ?? */ inf->capabilities = 0; /* FIXME: ?? */ - strncpy(inf->name, mdev->name, sizeof(inf->name)); + strlcpy(inf->name, mdev->name, sizeof(inf->name)); snd_use_lock_free(&mdev->use_lock); return 0; } diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index a8bc4a7b999d..bbc7cb8dda11 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -117,8 +117,7 @@ snd_seq_oss_synth_register(snd_seq_device_t *dev) snd_use_lock_init(&rec->use_lock); /* copy and truncate the name of synth device */ - strncpy(rec->name, dev->name, sizeof(rec->name)); - rec->name[sizeof(rec->name)-1] = 0; + strlcpy(rec->name, dev->name, sizeof(rec->name)); /* registration */ spin_lock_irqsave(®ister_lock, flags); @@ -611,7 +610,7 @@ snd_seq_oss_synth_make_info(seq_oss_devinfo_t *dp, int dev, struct synth_info *i inf->synth_subtype = 0; inf->nr_voices = 16; inf->device = dev; - strncpy(inf->name, minf.name, sizeof(inf->name)); + strlcpy(inf->name, minf.name, sizeof(inf->name)); } else { if ((rec = get_synthdev(dp, dev)) == NULL) return -ENXIO; @@ -619,7 +618,7 @@ snd_seq_oss_synth_make_info(seq_oss_devinfo_t *dp, int dev, struct synth_info *i inf->synth_subtype = rec->synth_subtype; inf->nr_voices = rec->nr_voices; inf->device = dev; - strncpy(inf->name, rec->name, sizeof(inf->name)); + strlcpy(inf->name, rec->name, sizeof(inf->name)); snd_use_lock_free(&rec->use_lock); } return 0; diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 6be15ff87c7b..7f39dfc9d2cb 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1184,10 +1184,9 @@ static int snd_seq_ioctl_set_client_info(client_t * client, void __user *arg) return -EINVAL; /* fill the info fields */ - if (client_info.name[0]) { - strncpy(client->name, client_info.name, sizeof(client->name)-1); - client->name[sizeof(client->name)-1] = '\0'; - } + if (client_info.name[0]) + strlcpy(client->name, client_info.name, sizeof(client->name)); + client->filter = client_info.filter; client->event_lost = client_info.event_lost; memcpy(client->event_filter, client_info.event_filter, 32); @@ -1487,9 +1486,8 @@ static int snd_seq_ioctl_create_queue(client_t *client, void __user *arg) /* set queue name */ if (! info.name[0]) - sprintf(info.name, "Queue-%d", q->queue); - strncpy(q->name, info.name, sizeof(q->name)-1); - q->name[sizeof(q->name)-1] = 0; + snprintf(info.name, sizeof(info.name), "Queue-%d", q->queue); + strlcpy(q->name, info.name, sizeof(q->name)); queuefree(q); if (copy_to_user(arg, &info, sizeof(info))) @@ -1526,8 +1524,7 @@ static int snd_seq_ioctl_get_queue_info(client_t *client, void __user *arg) info.queue = q->queue; info.owner = q->owner; info.locked = q->locked; - strncpy(info.name, q->name, sizeof(info.name) - 1); - info.name[sizeof(info.name)-1] = 0; + strlcpy(info.name, q->name, sizeof(info.name)); queuefree(q); if (copy_to_user(arg, &info, sizeof(info))) @@ -1565,8 +1562,7 @@ static int snd_seq_ioctl_set_queue_info(client_t *client, void __user *arg) queuefree(q); return -EPERM; } - strncpy(q->name, info.name, sizeof(q->name) - 1); - q->name[sizeof(q->name)-1] = 0; + strlcpy(q->name, info.name, sizeof(q->name)); queuefree(q); return 0; diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 64ccb69b4865..297f918522e8 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -187,8 +187,7 @@ int snd_seq_device_new(snd_card_t *card, int device, char *id, int argsize, /* set up device info */ dev->card = card; dev->device = device; - strncpy(dev->id, id, sizeof(dev->id) - 1); - dev->id[sizeof(dev->id) - 1] = 0; + strlcpy(dev->id, id, sizeof(dev->id)); dev->argsize = argsize; dev->status = SNDRV_SEQ_DEVICE_FREE; @@ -350,8 +349,7 @@ static ops_list_t * create_driver(char *id) memset(ops, 0, sizeof(*ops)); /* set up driver entry */ - strncpy(ops->id, id, sizeof(ops->id) - 1); - ops->id[sizeof(ops->id) - 1] = 0; + strlcpy(ops->id, id, sizeof(ops->id)); init_MUTEX(&ops->reg_mutex); ops->driver = DRIVER_EMPTY; INIT_LIST_HEAD(&ops->dev_list); diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c index 97e5b740816d..d8ca16f6f293 100644 --- a/sound/core/seq/seq_instr.c +++ b/sound/core/seq/seq_instr.c @@ -478,8 +478,7 @@ static int instr_put(snd_seq_kinstr_ops_t *ops, } instr->ops = ops; instr->instr = put.id.instr; - strncpy(instr->name, put.data.name, sizeof(instr->name)-1); - instr->name[sizeof(instr->name)-1] = '\0'; + strlcpy(instr->name, put.data.name, sizeof(instr->name)); instr->type = put.data.type; if (instr->type == SNDRV_SEQ_INSTR_ATYPE_DATA) { result = ops->put(ops->private_data, diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 2988ba6c5691..9167e164d592 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -338,10 +338,8 @@ int snd_seq_set_port_info(client_port_t * port, snd_seq_port_info_t * info) snd_assert(port && info, return -EINVAL); /* set port name */ - if (info->name[0]) { - strncpy(port->name, info->name, sizeof(port->name)-1); - port->name[sizeof(port->name)-1] = '\0'; - } + if (info->name[0]) + strlcpy(port->name, info->name, sizeof(port->name)); /* set capabilities */ port->capability = info->capability; @@ -363,7 +361,7 @@ int snd_seq_get_port_info(client_port_t * port, snd_seq_port_info_t * info) snd_assert(port && info, return -EINVAL); /* get port name */ - strncpy(info->name, port->name, sizeof(info->name)); + strlcpy(info->name, port->name, sizeof(info->name)); /* get capabilities */ info->capability = port->capability; @@ -621,10 +619,8 @@ int snd_seq_event_port_attach(int client, /* Set up the port */ memset(&portinfo, 0, sizeof(portinfo)); portinfo.addr.client = client; - if (portname) - strncpy(portinfo.name, portname, sizeof(portinfo.name)); - else - sprintf(portinfo.name, "Unamed port"); + strlcpy(portinfo.name, portname ? portname : "Unamed port", + sizeof(portinfo.name)); portinfo.capability = cap; portinfo.type = type; diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index b16f02b0026c..e81f8fcfd6f6 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -241,7 +241,7 @@ queue_t *snd_seq_queue_find_name(char *name) for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { if ((q = queueptr(i)) != NULL) { - if (strncpy(q->name, name, sizeof(q->name)) == 0) + if (strncmp(q->name, name, sizeof(q->name)) == 0) return q; queuefree(q); } diff --git a/sound/core/timer.c b/sound/core/timer.c index c426c77e45c3..1a2f9285ccdb 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -749,7 +749,7 @@ int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t * timer->tmr_device = tid->device; timer->tmr_subdevice = tid->subdevice; if (id) - strncpy(timer->id, id, sizeof(timer->id) - 1); + strlcpy(timer->id, id, sizeof(timer->id)); INIT_LIST_HEAD(&timer->device_list); INIT_LIST_HEAD(&timer->open_list_head); INIT_LIST_HEAD(&timer->active_list_head); @@ -1317,8 +1317,8 @@ static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t *_ginfo) ginfo.card = t->card ? t->card->number : -1; if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) ginfo.flags |= SNDRV_TIMER_FLG_SLAVE; - strncpy(ginfo.id, t->id, sizeof(ginfo.id)-1); - strncpy(ginfo.name, t->name, sizeof(ginfo.name)-1); + strlcpy(ginfo.id, t->id, sizeof(ginfo.id)); + strlcpy(ginfo.name, t->name, sizeof(ginfo.name)); ginfo.resolution = t->hw.resolution; if (t->hw.resolution_min > 0) { ginfo.resolution_min = t->hw.resolution_min; @@ -1457,8 +1457,8 @@ static int snd_timer_user_info(struct file *file, snd_timer_info_t *_info) info.card = t->card ? t->card->number : -1; if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) info.flags |= SNDRV_TIMER_FLG_SLAVE; - strncpy(info.id, t->id, sizeof(info.id)-1); - strncpy(info.name, t->name, sizeof(info.name)-1); + strlcpy(info.id, t->id, sizeof(info.id)); + strlcpy(info.name, t->name, sizeof(info.name)); info.resolution = t->hw.resolution; if (copy_to_user(_info, &info, sizeof(*_info))) return -EFAULT; diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c index 80c6545d72fd..5504605adc74 100644 --- a/sound/drivers/opl3/opl3_oss.c +++ b/sound/drivers/opl3/opl3_oss.c @@ -123,8 +123,7 @@ void snd_opl3_init_seq_oss(opl3_t *opl3, char *name) return; opl3->oss_seq_dev = dev; - strncpy(dev->name, name, sizeof(dev->name) - 1); - dev->name[sizeof(dev->name) - 1] = 0; + strlcpy(dev->name, name, sizeof(dev->name)); arg = SNDRV_SEQ_DEVICE_ARGPTR(dev); arg->type = SYNTH_TYPE_FM; if (opl3->hardware < OPL3_HW_OPL3) { diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c index 5015a8bc8c0d..cdb9c74adc5c 100644 --- a/sound/i2c/i2c.c +++ b/sound/i2c/i2c.c @@ -93,7 +93,7 @@ int snd_i2c_bus_create(snd_card_t *card, const char *name, snd_i2c_bus_t *master list_add_tail(&bus->buses, &master->buses); bus->master = master; } - strncpy(bus->name, name, sizeof(bus->name) - 1); + strlcpy(bus->name, name, sizeof(bus->name)); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, bus, &ops)) < 0) { snd_i2c_bus_free(bus); return err; @@ -112,7 +112,7 @@ int snd_i2c_device_create(snd_i2c_bus_t *bus, const char *name, unsigned char ad if (device == NULL) return -ENOMEM; device->addr = addr; - strncpy(device->name, name, sizeof(device->name)-1); + strlcpy(device->name, name, sizeof(device->name)); list_add_tail(&device->list, &bus->devices); device->bus = bus; *rdevice = device; diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c index 1ea965fbc635..125fd3507ce5 100644 --- a/sound/isa/ad1848/ad1848_lib.c +++ b/sound/isa/ad1848/ad1848_lib.c @@ -1148,7 +1148,7 @@ int snd_ad1848_add_ctl(ad1848_t *chip, const char *name, int index, int type, un ctl = snd_ctl_new1(&newctls[type], chip); if (! ctl) return -ENOMEM; - strncpy(ctl->id.name, name, sizeof(ctl->id.name)-1); + strlcpy(ctl->id.name, name, sizeof(ctl->id.name)); ctl->id.index = index; ctl->private_value = value; if ((err = snd_ctl_add(chip->card, ctl)) < 0) { diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 8ea3dae9d802..524e43db882a 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -393,8 +393,7 @@ static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t * mcode return err; /* fill in codec header */ - strncpy(p->codec_name, info.codec_name, sizeof(p->codec_name) - 1); - p->codec_name[sizeof(p->codec_name) - 1] = 0; + strlcpy(p->codec_name, info.codec_name, sizeof(p->codec_name)); p->func_nr = func_nr; p->mode = LE_SHORT(funcdesc_h.flags_play_rec); switch (LE_SHORT(funcdesc_h.VOC_type)) { diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index b5532d9e19da..31baf2030e26 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -452,7 +452,7 @@ int snd_sbmixer_add_ctl(sb_t *chip, const char *name, int index, int type, unsig ctl = snd_ctl_new1(&newctls[type], chip); if (! ctl) return -ENOMEM; - strncpy(ctl->id.name, name, sizeof(ctl->id.name)-1); + strlcpy(ctl->id.name, name, sizeof(ctl->id.name)); ctl->id.index = index; ctl->private_value = value; if ((err = snd_ctl_add(chip->card, ctl)) < 0) { diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c index 7eaad4f5c9ce..be1820ea876f 100644 --- a/sound/oss/ac97_codec.c +++ b/sound/oss/ac97_codec.c @@ -487,8 +487,8 @@ static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned if (cmd == SOUND_MIXER_INFO) { mixer_info info; - strncpy(info.id, codec->name, sizeof(info.id)); - strncpy(info.name, codec->name, sizeof(info.name)); + strlcpy(info.id, codec->name, sizeof(info.id)); + strlcpy(info.name, codec->name, sizeof(info.name)); info.modify_counter = codec->modcnt; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; @@ -496,8 +496,8 @@ static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned } if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; - strncpy(info.id, codec->name, sizeof(info.id)); - strncpy(info.name, codec->name, sizeof(info.name)); + strlcpy(info.id, codec->name, sizeof(info.id)); + strlcpy(info.name, codec->name, sizeof(info.name)); if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c index 0585b44d67b5..22e3b6cfd817 100644 --- a/sound/oss/btaudio.c +++ b/sound/oss/btaudio.c @@ -328,8 +328,8 @@ static int btaudio_mixer_ioctl(struct inode *inode, struct file *file, if (cmd == SOUND_MIXER_INFO) { mixer_info info; memset(&info,0,sizeof(info)); - strncpy(info.id,"bt878",sizeof(info.id)-1); - strncpy(info.name,"Brooktree Bt878 audio",sizeof(info.name)-1); + strlcpy(info.id,"bt878",sizeof(info.id)); + strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name)); info.modify_counter = bta->mixcount; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; @@ -338,8 +338,8 @@ static int btaudio_mixer_ioctl(struct inode *inode, struct file *file, if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; memset(&info,0,sizeof(info)); - strncpy(info.id,"bt878",sizeof(info.id)-1); - strncpy(info.name,"Brooktree Bt878 audio",sizeof(info.name)-1); + strlcpy(info.id,"bt878",sizeof(info.id)-1); + strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name)); if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; diff --git a/sound/oss/cmpci.c b/sound/oss/cmpci.c index 967b6521b803..f9d784231635 100644 --- a/sound/oss/cmpci.c +++ b/sound/oss/cmpci.c @@ -1268,8 +1268,8 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg) VALIDATE_STATE(s); if (cmd == SOUND_MIXER_INFO) { mixer_info info; - strncpy(info.id, "cmpci", sizeof(info.id)); - strncpy(info.name, "C-Media PCI", sizeof(info.name)); + strlcpy(info.id, "cmpci", sizeof(info.id)); + strlcpy(info.name, "C-Media PCI", sizeof(info.name)); info.modify_counter = s->mix.modcnt; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; @@ -1277,8 +1277,8 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg) } if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; - strncpy(info.id, "cmpci", sizeof(info.id)); - strncpy(info.name, "C-Media cmpci", sizeof(info.name)); + strlcpy(info.id, "cmpci", sizeof(info.id)); + strlcpy(info.name, "C-Media cmpci", sizeof(info.name)); if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; diff --git a/sound/oss/cs4281/cs4281m.c b/sound/oss/cs4281/cs4281m.c index 5757af590054..3d23a8006f97 100644 --- a/sound/oss/cs4281/cs4281m.c +++ b/sound/oss/cs4281/cs4281m.c @@ -2266,8 +2266,8 @@ static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, } if (cmd == SOUND_MIXER_INFO) { mixer_info info; - strncpy(info.id, "CS4281", sizeof(info.id)); - strncpy(info.name, "Crystal CS4281", sizeof(info.name)); + strlcpy(info.id, "CS4281", sizeof(info.id)); + strlcpy(info.name, "Crystal CS4281", sizeof(info.name)); info.modify_counter = s->mix.modcnt; if (copy_to_user((void *) arg, &info, sizeof(info))) return -EFAULT; @@ -2275,8 +2275,8 @@ static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, } if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; - strncpy(info.id, "CS4281", sizeof(info.id)); - strncpy(info.name, "Crystal CS4281", sizeof(info.name)); + strlcpy(info.id, "CS4281", sizeof(info.id)); + strlcpy(info.name, "Crystal CS4281", sizeof(info.name)); if (copy_to_user((void *) arg, &info, sizeof(info))) return -EFAULT; return 0; diff --git a/sound/oss/dev_table.c b/sound/oss/dev_table.c index 96e8fd9eef17..4658e62d24ca 100644 --- a/sound/oss/dev_table.c +++ b/sound/oss/dev_table.c @@ -22,7 +22,7 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, { struct audio_driver *d; struct audio_operations *op; - int l, num; + int num; if (vers != AUDIO_DRIVER_VERSION || driver_size > sizeof(struct audio_driver)) { printk(KERN_ERR "Sound: Incompatible audio driver for %s\n", name); @@ -58,11 +58,7 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, memcpy((char *) d, (char *) driver, driver_size); op->d = d; - l = strlen(name) + 1; - if (l > sizeof(op->name)) - l = sizeof(op->name); - strncpy(op->name, name, l); - op->name[l - 1] = 0; + strlcpy(op->name, name, sizeof(op->name)); op->flags = flags; op->format_mask = format_mask; op->devc = devc; @@ -82,7 +78,6 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, int driver_size, void *devc) { struct mixer_operations *op; - int l; int n = sound_alloc_mixerdev(); @@ -110,11 +105,7 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, memset((char *) op, 0, sizeof(struct mixer_operations)); memcpy((char *) op, (char *) driver, driver_size); - l = strlen(name) + 1; - if (l > sizeof(op->name)) - l = sizeof(op->name); - strncpy(op->name, name, l); - op->name[l - 1] = 0; + strlcpy(op->name, name, sizeof(op->name)); op->devc = devc; mixer_devs[n] = op; diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index 98627ddea56f..069bd881589c 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c @@ -351,9 +351,8 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, case SOUND_MIXER_INFO: { mixer_info info; - strncpy(info.id, dmasound.mach.name2, sizeof(info.id)); - strncpy(info.name, dmasound.mach.name2, sizeof(info.name)); - info.name[sizeof(info.name)-1] = 0; + strlcpy(info.id, dmasound.mach.name2, sizeof(info.id)); + strlcpy(info.name, dmasound.mach.name2, sizeof(info.name)); info.modify_counter = mixer.modify_counter; if (copy_to_user((int *)arg, &info, sizeof(info))) return -EFAULT; diff --git a/sound/oss/emu10k1/mixer.c b/sound/oss/emu10k1/mixer.c index 6ca3b79430a1..d61778e096d3 100644 --- a/sound/oss/emu10k1/mixer.c +++ b/sound/oss/emu10k1/mixer.c @@ -623,8 +623,8 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned if (cmd == SOUND_MIXER_INFO) { mixer_info info; - strncpy(info.id, card->ac97.name, sizeof(info.id)); - strncpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name)); + strlcpy(info.id, card->ac97.name, sizeof(info.id)); + strlcpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name)); info.modify_counter = card->ac97.modcnt; if (copy_to_user((void *)arg, &info, sizeof(info))) diff --git a/sound/oss/es1370.c b/sound/oss/es1370.c index 6f9aef48f5ba..835d2170e8c9 100644 --- a/sound/oss/es1370.c +++ b/sound/oss/es1370.c @@ -889,8 +889,8 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a } if (cmd == SOUND_MIXER_INFO) { mixer_info info; - strncpy(info.id, "ES1370", sizeof(info.id)); - strncpy(info.name, "Ensoniq ES1370", sizeof(info.name)); + strlcpy(info.id, "ES1370", sizeof(info.id)); + strlcpy(info.name, "Ensoniq ES1370", sizeof(info.name)); info.modify_counter = s->mix.modcnt; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; @@ -898,8 +898,8 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a } if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; - strncpy(info.id, "ES1370", sizeof(info.id)); - strncpy(info.name, "Ensoniq ES1370", sizeof(info.name)); + strlcpy(info.id, "ES1370", sizeof(info.id)); + strlcpy(info.name, "Ensoniq ES1370", sizeof(info.name)); if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c index 78a6adad3d7d..d78a4dd797a4 100644 --- a/sound/oss/esssolo1.c +++ b/sound/oss/esssolo1.c @@ -721,8 +721,8 @@ static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long ar } if (cmd == SOUND_MIXER_INFO) { mixer_info info; - strncpy(info.id, "Solo1", sizeof(info.id)); - strncpy(info.name, "ESS Solo1", sizeof(info.name)); + strlcpy(info.id, "Solo1", sizeof(info.id)); + strlcpy(info.name, "ESS Solo1", sizeof(info.name)); info.modify_counter = s->mix.modcnt; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; @@ -730,8 +730,8 @@ static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long ar } if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; - strncpy(info.id, "Solo1", sizeof(info.id)); - strncpy(info.name, "ESS Solo1", sizeof(info.name)); + strlcpy(info.id, "Solo1", sizeof(info.id)); + strlcpy(info.name, "ESS Solo1", sizeof(info.name)); if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; diff --git a/sound/oss/gus_wave.c b/sound/oss/gus_wave.c index 722e48137967..8be49423b6d9 100644 --- a/sound/oss/gus_wave.c +++ b/sound/oss/gus_wave.c @@ -2851,7 +2851,7 @@ void __init gus_wave_init(struct address_info *hw_config) unsigned long flags; unsigned char val; char *model_num = "2.4"; - char tmp[64], tmp2[64]; + char tmp[64]; int gus_type = 0x24; /* 2.4 */ int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2; @@ -2998,19 +2998,14 @@ void __init gus_wave_init(struct address_info *hw_config) } if (hw_config->name) - { - strncpy(tmp, hw_config->name, 45); - tmp[45] = 0; - sprintf(tmp2, "%s (%dk)", tmp, (int) gus_mem_size / 1024); - tmp2[sizeof(tmp2) - 1] = 0; - } + snprintf(tmp, sizeof(tmp), "%s (%dk)", hw_config->name, + (int) gus_mem_size / 1024); else if (gus_pnp_flag) - { - sprintf(tmp2, "Gravis UltraSound PnP (%dk)", - (int) gus_mem_size / 1024); - } + snprintf(tmp, sizeof(tmp), "Gravis UltraSound PnP (%dk)", + (int) gus_mem_size / 1024); else - sprintf(tmp2, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024); + snprintf(tmp, sizeof(tmp), "Gravis UltraSound %s (%dk)", model_num, + (int) gus_mem_size / 1024); samples = (struct patch_info *)vmalloc((MAX_SAMPLE + 1) * sizeof(*samples)); @@ -3019,9 +3014,8 @@ void __init gus_wave_init(struct address_info *hw_config) printk(KERN_WARNING "gus_init: Cant allocate memory for instrument tables\n"); return; } - conf_printf(tmp2, hw_config); - tmp2[sizeof(gus_info.name) - 1] = 0; - strcpy(gus_info.name, tmp2); + conf_printf(tmp, hw_config); + strlcpy(gus_info.name, tmp, sizeof(gus_info.name)); if ((sdev = sound_alloc_synthdev()) == -1) printk(KERN_WARNING "gus_init: Too many synthesizers\n"); diff --git a/sound/oss/maestro.c b/sound/oss/maestro.c index 013b70187245..f62ad9be51e9 100644 --- a/sound/oss/maestro.c +++ b/sound/oss/maestro.c @@ -2024,8 +2024,8 @@ static int mixer_ioctl(struct ess_card *card, unsigned int cmd, unsigned long ar VALIDATE_CARD(card); if (cmd == SOUND_MIXER_INFO) { mixer_info info; - strncpy(info.id, card_names[card->card_type], sizeof(info.id)); - strncpy(info.name,card_names[card->card_type],sizeof(info.name)); + strlcpy(info.id, card_names[card->card_type], sizeof(info.id)); + strlcpy(info.name, card_names[card->card_type], sizeof(info.name)); info.modify_counter = card->mix.modcnt; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; @@ -2033,8 +2033,8 @@ static int mixer_ioctl(struct ess_card *card, unsigned int cmd, unsigned long ar } if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; - strncpy(info.id, card_names[card->card_type], sizeof(info.id)); - strncpy(info.name,card_names[card->card_type],sizeof(info.name)); + strlcpy(info.id, card_names[card->card_type], sizeof(info.id)); + strlcpy(info.name, card_names[card->card_type], sizeof(info.name)); if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c index 760a617ec17a..25977734cc6a 100644 --- a/sound/oss/msnd_pinnacle.c +++ b/sound/oss/msnd_pinnacle.c @@ -555,8 +555,8 @@ static unsigned long force_recsrc(unsigned long recsrc) } #define set_mixer_info() \ - strncpy(info.id, "MSNDMIXER", sizeof(info.id)); \ - strncpy(info.name, "MultiSound Mixer", sizeof(info.name)); + strlcpy(info.id, "MSNDMIXER", sizeof(info.id)); \ + strlcpy(info.name, "MultiSound Mixer", sizeof(info.name)); static int mixer_ioctl(unsigned int cmd, unsigned long arg) { diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c index 8a2f0055f1ac..d2031bc12434 100644 --- a/sound/oss/sequencer.c +++ b/sound/oss/sequencer.c @@ -1477,7 +1477,7 @@ int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg) if (!(synth_open_mask & (1 << dev)) && !orig_dev) return -EBUSY; memcpy(&inf, synth_devs[dev]->info, sizeof(inf)); - strncpy(inf.name, synth_devs[dev]->id, sizeof(inf.name)); + strlcpy(inf.name, synth_devs[dev]->id, sizeof(inf.name)); inf.device = dev; return copy_to_user(arg, &inf, sizeof(inf))?-EFAULT:0; diff --git a/sound/oss/sonicvibes.c b/sound/oss/sonicvibes.c index 975e1c42ed78..5c042a70dda1 100644 --- a/sound/oss/sonicvibes.c +++ b/sound/oss/sonicvibes.c @@ -1046,8 +1046,8 @@ static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg) VALIDATE_STATE(s); if (cmd == SOUND_MIXER_INFO) { mixer_info info; - strncpy(info.id, "SonicVibes", sizeof(info.id)); - strncpy(info.name, "S3 SonicVibes", sizeof(info.name)); + strlcpy(info.id, "SonicVibes", sizeof(info.id)); + strlcpy(info.name, "S3 SonicVibes", sizeof(info.name)); info.modify_counter = s->mix.modcnt; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; @@ -1055,8 +1055,8 @@ static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg) } if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; - strncpy(info.id, "SonicVibes", sizeof(info.id)); - strncpy(info.name, "S3 SonicVibes", sizeof(info.name)); + strlcpy(info.id, "SonicVibes", sizeof(info.id)); + strlcpy(info.name, "S3 SonicVibes", sizeof(info.name)); if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index 220a5faa8d70..087f1af7c7e5 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -289,9 +289,8 @@ static int get_mixer_info(int dev, caddr_t arg) { mixer_info info; - strncpy(info.id, mixer_devs[dev]->id, sizeof(info.id)); - strncpy(info.name, mixer_devs[dev]->name, sizeof(info.name)); - info.name[sizeof(info.name)-1] = 0; + strlcpy(info.id, mixer_devs[dev]->id, sizeof(info.id)); + strlcpy(info.name, mixer_devs[dev]->name, sizeof(info.name)); info.modify_counter = mixer_devs[dev]->modify_counter; if (__copy_to_user(arg, &info, sizeof(info))) return -EFAULT; @@ -302,9 +301,8 @@ static int get_old_mixer_info(int dev, caddr_t arg) { _old_mixer_info info; - strncpy(info.id, mixer_devs[dev]->id, sizeof(info.id)); - strncpy(info.name, mixer_devs[dev]->name, sizeof(info.name)); - info.name[sizeof(info.name)-1] = 0; + strlcpy(info.id, mixer_devs[dev]->id, sizeof(info.id)); + strlcpy(info.name, mixer_devs[dev]->name, sizeof(info.name)); if (copy_to_user(arg, &info, sizeof(info))) return -EFAULT; return 0; diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 02e2ec335502..9dcc09318548 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -1033,7 +1033,7 @@ static int snd_emu10k1_list_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icod memset(&gctl, 0, sizeof(gctl)); id = &ctl->kcontrol->id; gctl.id.iface = id->iface; - strncpy(gctl.id.name, id->name, sizeof(gctl.id.name)); + strlcpy(gctl.id.name, id->name, sizeof(gctl.id.name)); gctl.id.index = id->index; gctl.id.device = id->device; gctl.id.subdevice = id->subdevice; @@ -1063,8 +1063,7 @@ static int snd_emu10k1_icode_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) down(&emu->fx8010.lock); if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0) goto __error; - strncpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name)-1); - emu->fx8010.name[sizeof(emu->fx8010.name)-1] = '\0'; + strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name)); /* stop FX processor - this may be dangerous, but it's better to miss some samples than generate wrong ones - [jk] */ if (emu->audigy) @@ -1092,8 +1091,7 @@ static int snd_emu10k1_icode_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) int err; down(&emu->fx8010.lock); - strncpy(icode->name, emu->fx8010.name, sizeof(icode->name)-1); - emu->fx8010.name[sizeof(emu->fx8010.name)-1] = '\0'; + strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name)); /* ok, do the main job */ snd_emu10k1_gpr_peek(emu, icode); snd_emu10k1_tram_peek(emu, icode); diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index c8d3b928e108..47772eb33250 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2392,8 +2392,7 @@ static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev, len = 0; if (len <= 0) { if (quirk && quirk->product_name) { - strncpy(card->shortname, quirk->product_name, sizeof(card->shortname) - 1); - card->shortname[sizeof(card->shortname) - 1] = '\0'; + strlcpy(card->shortname, quirk->product_name, sizeof(card->shortname)); } else { sprintf(card->shortname, "USB Device %#04x:%#04x", dev->descriptor.idVendor, dev->descriptor.idProduct); @@ -2403,37 +2402,32 @@ static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev, /* retrieve the vendor and device strings as longname */ if (dev->descriptor.iManufacturer) len = usb_string(dev, dev->descriptor.iManufacturer, - card->longname, sizeof(card->longname) - 1); + card->longname, sizeof(card->longname)); else len = 0; if (len <= 0) { if (quirk && quirk->vendor_name) { - strncpy(card->longname, quirk->vendor_name, sizeof(card->longname) - 2); - card->longname[sizeof(card->longname) - 2] = '\0'; - len = strlen(card->longname); + len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname)); } else { len = 0; } } - if (len > 0) { - card->longname[len] = ' '; - len++; - } - card->longname[len] = '\0'; + if (len > 0) + strlcat(card->longname, ' ', sizeof(card->longname)); + + len = strlen(card->longname); + if ((!dev->descriptor.iProduct || usb_string(dev, dev->descriptor.iProduct, card->longname + len, sizeof(card->longname) - len) <= 0) && quirk && quirk->product_name) { - strncpy(card->longname + len, quirk->product_name, sizeof(card->longname) - len - 1); - card->longname[sizeof(card->longname) - 1] = '\0'; + strlcat(card->longname, quirk->product_name, sizeof(card->longname)); } - /* add device path to longname */ - len = strlen(card->longname); - if (sizeof(card->longname) - len > 10) { - strcpy(card->longname + len, " at "); - len += 4; + + len = strlcat(card->longname, " at ", sizeof(card->longname)); + + if (len < sizeof(card->longname)) usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); - } *rchip = chip; return 0; diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index c9a5b382bda5..b5b04447f499 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -164,9 +164,7 @@ static int check_mapped_name(mixer_build_t *state, int unitid, int control, char if (p->id == unitid && (! control || ! p->control || control == p->control)) { buflen--; - strncpy(buf, p->name, buflen); - buf[buflen] = 0; - return strlen(buf); + return strlcpy(buf, p->name, buflen); } } return 0; @@ -816,7 +814,8 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, if (! len) len = get_term_name(state, &state->oterm, kctl->id.name, sizeof(kctl->id.name), 1); if (! len) - len = sprintf(kctl->id.name, "Feature %d", unitid); + len = snprintf(kctl->id.name, sizeof(kctl->id.name), + "Feature %d", unitid); } /* determine the stream direction: * if the connected output is USB stream, then it's likely a @@ -824,24 +823,19 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, */ if (! mapped_name && ! (state->oterm.type >> 16)) { if ((state->oterm.type & 0xff00) == 0x0100) { - if (len + 8 < sizeof(kctl->id.name)) { - strcpy(kctl->id.name + len, " Capture"); - len += 8; - } + len = strlcat(kctl->id.name, " Capture", sizeof(kctl->id.name)); } else { - if (len + 9 < sizeof(kctl->id.name)) { - strcpy(kctl->id.name + len, " Playback"); - len += 9; - } + len = strlcat(kctl->id.name + len, " Playback", sizeof(kctl->id.name)); } } - if (len + 7 < sizeof(kctl->id.name)) - strcpy(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume"); + strlcat(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume", + sizeof(kctl->id.name)); break; default: if (! len) - strcpy(kctl->id.name, audio_feature_info[control-1].name); + strlcpy(kctl->id.name, audio_feature_info[control-1].name, + sizeof(kctl->id.name)); break; } @@ -969,8 +963,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc, len = get_term_name(state, &iterm, kctl->id.name, sizeof(kctl->id.name), 0); if (! len) len = sprintf(kctl->id.name, "Mixer Source %d", in_ch); - if (len + 7 < sizeof(kctl->id.name)) - strcpy(kctl->id.name + len, " Volume"); + strlcat(kctl->id.name + len, " Volume", sizeof(kctl->id.name)); snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max); @@ -1189,22 +1182,18 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char if (check_mapped_name(state, unitid, cval->control, kctl->id.name, sizeof(kctl->id.name))) ; else if (info->name) - strcpy(kctl->id.name, info->name); + strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); else { nameid = dsc[12 + num_ins + dsc[11 + num_ins]]; len = 0; if (nameid) len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); - if (! len) { - strncpy(kctl->id.name, name, sizeof(kctl->id.name) - 1); - kctl->id.name[sizeof(kctl->id.name)-1] = 0; - } - } - len = strlen(kctl->id.name); - if (len + sizeof(valinfo->suffix) + 1 < sizeof(kctl->id.name)) { - kctl->id.name[len] = ' '; - strcpy(kctl->id.name + len + 1, valinfo->suffix); + if (! len) + strlcpy(kctl->id.name, name, sizeof(kctl->id.name)); } + strlcat(kctl->id.name, ' ', sizeof(kctl->id.name)); + strlcat(kctl->id.name, valinfo->suffix, sizeof(kctl->id.name)); + snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max); if ((err = add_control_to_empty(state->chip->card, kctl)) < 0) @@ -1402,14 +1391,12 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned len = get_term_name(state, &state->oterm, kctl->id.name, sizeof(kctl->id.name), 0); if (! len) - len = sprintf(kctl->id.name, "USB"); - if ((state->oterm.type & 0xff00) == 0x0100) { - if (len + 15 < sizeof(kctl->id.name)) - strcpy(kctl->id.name + len, " Capture Source"); - } else { - if (len + 16 < sizeof(kctl->id.name)) - strcpy(kctl->id.name + len, " Playback Source"); - } + strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); + + if ((state->oterm.type & 0xff00) == 0x0100) + strlcat(kctl->id.name, " Capture Source", sizeof(kctl->id.name)); + else + strlcat(kctl->id.name, " Playback Source", sizeof(kctl->id.name)); } snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", |
